shithub: qk2

Download patch

ref: 372afde46e7defc9dd2d719a1732b8ace1fa096e
author: Travis Bradshaw <[email protected]>
date: Tue Jan 31 08:57:11 EST 2012

The original Quake 2 sources as originally released under the GPL license on December 21, 2001.

diff: cannot open b/baseq2/save/save0//null: file does not exist: 'b/baseq2/save/save0//null' diff: cannot open b/baseq2/save//null: file does not exist: 'b/baseq2/save//null' diff: cannot open b/baseq2//null: file does not exist: 'b/baseq2//null' diff: cannot open b/client//null: file does not exist: 'b/client//null' diff: cannot open b/ctf/docs//null: file does not exist: 'b/ctf/docs//null' diff: cannot open b/ctf//null: file does not exist: 'b/ctf//null' diff: cannot open b/game//null: file does not exist: 'b/game//null' diff: cannot open b/irix//null: file does not exist: 'b/irix//null' diff: cannot open b/linux//null: file does not exist: 'b/linux//null' diff: cannot open b/null//null: file does not exist: 'b/null//null' diff: cannot open b/qcommon//null: file does not exist: 'b/qcommon//null' diff: cannot open b/ref_gl//null: file does not exist: 'b/ref_gl//null' diff: cannot open b/ref_soft//null: file does not exist: 'b/ref_soft//null' diff: cannot open b/rhapsody//null: file does not exist: 'b/rhapsody//null' diff: cannot open b/server//null: file does not exist: 'b/server//null' diff: cannot open b/solaris//null: file does not exist: 'b/solaris//null' diff: cannot open b/unix/next//null: file does not exist: 'b/unix/next//null' diff: cannot open b/unix//null: file does not exist: 'b/unix//null' diff: cannot open b/win32//null: file does not exist: 'b/win32//null'
--- /dev/null
+++ b/3.15_Changes.txt
@@ -1,0 +1,107 @@
+
+Quake2 3.15 Upgrade
+-------------------
+
+This upgrade addresses several features, including security, playability, and
+enhancements.
+
+A new map is also included (in baseq2\pak3.pak) called match1, Reckless
+Abandon.  This map is designed for one on one deathmatch play.  It was built
+by American McGee and Dave "Zoid" Kirsch.
+
+This patch replaces the following files:
+
+	quake2.exe
+	3dfxgl.dll
+	pvrgl.dll
+	ref_gl.dll
+	ref_soft.dll
+	baseq2\gamex86.dll
+
+Changes
+-------
+
+- Added visible weapons support.  This is precached with a special symbol, i.e.
+  gi.modelindex("#w_shotgun.md2") which causes the client to autobind it to
+  the players current weapon model.  Plug in player models can optionally 
+  support the visible weapons.  Any that do not support it will use their
+  default weapon.md2 files automatically.
+  Visible weapons files for plug in player models are not downloaded
+  automatically--only the default weapon.md2 (and skin) is.
+  The Visible weapon models themselves are not included.  They can be
+  downloaded from http://www.telefragged.com/vwep/
+- Rewrote the some of the net code to use optimized network packets for 
+  projectiles.  This is transparent to the game code, but improves netplay
+  substancially.  The hyperblaster doesn't flood modem players anymore.
+- Rewrote the packet checksum code to be more portable and defeat proxy bots
+  yet again.
+- Autodownload support is in.  The following items will be automatcally
+  downloaded as needed:
+    - world map (and textures)
+    - models
+    - sounds (precached ones)
+    - plug in player model, skin, skin_i and weapon.md2
+  downloads go to a temp file (maps/blah.tmp for example) and get renamed
+  when done.  autoresume is supported (if you lose connect during the
+  download, just reconnect and resume).  Server has fine control over
+  the downloads with the following new cvars:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  maps that are in pak files will _not_ autodownload from the server, this
+  is for copyright considerations.
+  The QuakeWorld bug of the server map changing while download a map has
+  been fixed.
+- New option in the Multiplayer/Player Setup menu for setting your connection
+  speed.  This sets a default rate for the player and can improve net
+  performance for modem connections.
+- Rewrote some of the save game code to make it more portable.  I wanted to
+  completely rewrite the entire save game system and make it portable across
+  versions and operating systems, but this would require an enormous amount
+  of work.
+- Added another 512 configure strings for general usage for mod makers.
+  This gives lots of room for general string displays on the HUD and in other
+  data.
+- Player movement code re-written to be similiar to that of NetQuake and
+  later versions of QuakeWorld.  Player has more control in the air and
+  gets a boost in vertical speed when jumping off the top of ramps.
+- Fixed up serverrecord so that it works correctly with the later versions.
+  serverrecord lets the server do a recording of the current game that
+  demo editors can use to make demos from any PVS in the level.  Server
+  recorded demos are BIG.  Will look at using delta compression in them
+  to cut down the size.
+- Copy protection CD check has been removed.
+- Quake2 3.15 has changed the protocol (so old servers will not run) but
+  all existing game dlls can run on the new version (albiet without the
+  new features such as visible weapons).
+- Added flood protection.  Controlled from the following cvars:
+   flood_msgs - maximum number of messages allowed in the time period
+                specified by flood_persecond
+   flood_persecond - time period that a maximum of flood_msgs messages are
+                     permitted
+   flood_waitdelay - amount of time a client gets muzzled for flooding
+- fixed it so blaster/hyperblaster shots aren't treated as solid when
+  predicting--you aren't clipped against them now.
+- gender support is now in.  The userinfo cvar "gender" can be set to
+  male/female/none (none for neutral messages).  This doesn't affect sounds
+  but does affect death messages in the game.  The models male and cyborg
+  default to gender male, and female and crackhor default to female.
+  Everything else defaults to none, but you can set it by typing
+  "gender male" or "gender female" as appropriate.
+- IP banning support ala QW.  It's built into the game dll as 'sv' console
+  commands.  This list is:
+    sv addip <ip-mask>  - adds an ip to the ban list
+	sv listip <ip-mask> - removes an ip from the ban list
+	sv writeip - writes the ban list to <gamedir>/listip.cfg.  You can
+	  exec this on a server load to load the list on subsequent server runs.
+	  like so:  quake2 +set dedicated 1 +exec listip.cfg
+	sv removeip <ip-mask> - remove an ip from the list
+  the ip list is a simple mask system.  Adding 192.168 to the list
+  would block out everyone in the 192.168.*.* net block.  You get 1024 bans,
+  if you need more, recompile the game dll. :)
+  A new cvar is also supported called 'filterban'.  It defaults to one which
+  means "allow everyone to connect _except_ those matching in the ban list."
+  If you set it to zero, the meaning reverses like so, "don't allow anyone
+  to connect unless they are in the list."
--- /dev/null
+++ b/3.16_Changes.txt
@@ -1,0 +1,127 @@
+
+Quake2 3.16 Upgrade
+-------------------
+
+This upgrade addresses several features, including security, playability, and
+enhancements.
+
+A new map is also included (in baseq2\pak3.pak) called match1, Reckless
+Abandon.  This map is designed for one on one deathmatch play.  It was built
+by American McGee and Dave "Zoid" Kirsch.
+
+Changes for 3.16
+----------------
+
+- Fixed infinite grenade bug
+- Fixed autodownloading to actually download sounds and console pics
+- Fixed autodownload to not create empty directories for files not on
+  the server.
+- Added customized client downloading.  cvars are the same as the server side:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  They can also be (more easily) set with a new Download Options menu 
+  accessible in Multiplayer/Player Setup/Download Options
+- Changed checksumming code to be more portable and faster.
+  The checksum in 3.15 was seriously broken.
+  This change makes 3.16 incompatible with previous servers.
+- Fixed it so sounds played for PPMs that default to male are only checked
+  on disk once.
+- Fixed player 'warping' present in 3.15 (this was an artifact of the
+  hyperblaster optimizations).
+- Fixed the autodownload in 3.15 so that stuff like skins for models are
+  downloaded as well as pics.
+
+Changes for 3.15
+----------------
+
+- Added visible weapons support.  This is precached with a special symbol, i.e.
+  gi.modelindex("#w_shotgun.md2") which causes the client to autobind it to
+  the players current weapon model.  Plug in player models can optionally 
+  support the visible weapons.  Any that do not support it will use their
+  default weapon.md2 files automatically.
+  Visible weapons files for plug in player models are not downloaded
+  automatically--only the default weapon.md2 (and skin) is.
+  The Visible weapon models themselves are not included.  They can be
+  downloaded from http://www.telefragged.com/vwep/
+- Rewrote the some of the net code to use optimized network packets for 
+  projectiles.  This is transparent to the game code, but improves netplay
+  substancially.  The hyperblaster doesn't flood modem players anymore.
+- Rewrote the packet checksum code to be more portable and defeat proxy bots
+  yet again.
+- Autodownload support is in.  The following items will be automatcally
+  downloaded as needed:
+    - world map (and textures)
+    - models
+    - sounds (precached ones)
+    - plug in player model, skin, skin_i and weapon.md2
+  downloads go to a temp file (maps/blah.tmp for example) and get renamed
+  when done.  autoresume is supported (if you lose connect during the
+  download, just reconnect and resume).  Server has fine control over
+  the downloads with the following new cvars:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  maps that are in pak files will _not_ autodownload from the server, this
+  is for copyright considerations.
+  The QuakeWorld bug of the server map changing while download a map has
+  been fixed.
+- New option in the Multiplayer/Player Setup menu for setting your connection
+  speed.  This sets a default rate for the player and can improve net
+  performance for modem connections.
+- Rewrote some of the save game code to make it more portable.  I wanted to
+  completely rewrite the entire save game system and make it portable across
+  versions and operating systems, but this would require an enormous amount
+  of work.
+- Added another 512 configure strings for general usage for mod makers.
+  This gives lots of room for general string displays on the HUD and in other
+  data.
+- Player movement code re-written to be similiar to that of NetQuake and
+  later versions of QuakeWorld.  Player has more control in the air and
+  gets a boost in vertical speed when jumping off the top of ramps.
+- Fixed up serverrecord so that it works correctly with the later versions.
+  serverrecord lets the server do a recording of the current game that
+  demo editors can use to make demos from any PVS in the level.  Server
+  recorded demos are BIG.  Will look at using delta compression in them
+  to cut down the size.
+- Copy protection CD check has been removed.
+- Quake2 3.15 has changed the protocol (so old servers will not run) but
+  all existing game dlls can run on the new version (albiet without the
+  new features such as visible weapons).
+- Added flood protection.  Controlled from the following cvars:
+   flood_msgs - maximum number of messages allowed in the time period
+                specified by flood_persecond
+   flood_persecond - time period that a maximum of flood_msgs messages are
+                     permitted
+   flood_waitdelay - amount of time a client gets muzzled for flooding
+  (gamex86 DLL specific)
+- fixed it so blaster/hyperblaster shots aren't treated as solid when
+  predicting--you aren't clipped against them now.
+  (gamex86 DLL specific, the SVF_DEADMONSTER flag is set on projectiles)
+- gender support is now in.  The userinfo cvar "gender" can be set to
+  male/female/none (none for neutral messages).  This doesn't affect sounds
+  but does affect death messages in the game.  The models male and cyborg
+  default to gender male, and female and crackhor default to female.
+  Everything else defaults to none, but you can set it by typing
+  "gender male" or "gender female" as appropriate.
+- IP banning support ala QW.  It's built into the game dll as 'sv' console
+  commands.  This list is:
+    sv addip <ip-mask>  - adds an ip to the ban list
+	sv listip <ip-mask> - removes an ip from the ban list
+	sv writeip - writes the ban list to <gamedir>/listip.cfg.  You can
+	  exec this on a server load to load the list on subsequent server runs.
+	  like so:  quake2 +set dedicated 1 +exec listip.cfg
+	sv removeip <ip-mask> - remove an ip from the list
+  the ip list is a simple mask system.  Adding 192.168 to the list
+  would block out everyone in the 192.168.*.* net block.  You get 1024 bans,
+  if you need more, recompile the game dll. :)
+  A new cvar is also supported called 'filterban'.  It defaults to one which
+  means "allow everyone to connect _except_ those matching in the ban list."
+  If you set it to zero, the meaning reverses like so, "don't allow anyone
+  to connect unless they are in the list."
+  (gamex86 DLL specific)
+
--- /dev/null
+++ b/3.17_Changes.txt
@@ -1,0 +1,158 @@
+
+Quake2 3.17 Upgrade
+-------------------
+
+This upgrade addresses several features, including security, playability, and
+enhancements.
+
+Changes for 3.17
+----------------
+
+- Fixed possible NAN resulting from handing zero to second arg of atan2
+- Autodownloading is now DISABLED by DEFAULT.  It must be enabled by typing
+  'allow_download 1' at the console, or using the download options menu
+  in Multiplayer/PlayerSetup/Download Options
+- Server demos now include a svc_serverdata block at the beginning with the
+  attractloop byte set to '2' to indicate server demo (byte before gamedir
+  in the svc_serverdata block).  This allows easy identification of
+  serverrecorded demos (serverrecord demos are only for demo editors, they
+  can not be played back in Quake2 without being first edited).
+- New options for setting texture formats in ref_gl:
+  gl_texturealphamode:  default, GL_RGBA, GL_RGBA8, GL_RGB5_A1, GL_RGBA4, 
+    GL_RGBA2
+  gl_texturesolidmode:  default, GL_RGB, GL_RGB8, GL_RGB5, GL_RGB4,
+    GL_R3_G3_B2, GL_RGB2 (SGI only)
+- Player movement during Air acceleration changed to reflect more real-world 
+  physics while airborne.
+- Fixed a bug when riding trains that caused drift in a southwest direction
+  (Thanks to Jim Dose at Ritual for pointing this one out).
+- Linux:  Now correctly reports out of memory rather than segfaulting (mmap
+  returns (void *)-1 and not NULL on error).
+- Fixed autodownloading to not create paths for files that can't be downloaded
+  (this was creating many empty directories in baseq2/players).
+- When downloading a file from a server that doesn't have it, the message is
+  now "Server does not have this file" rather than "File not found."
+- Fixed some coop keys in 3.15 weren't being handled correctly (pyramid key).
+- Highbits are now stripped from console when using condump
+- Restored support for gl_modulate in multiplayer play
+- Fixed it so that players with a model/skin you don't have aren't checked for 
+  on disk more than once.
+- Fixed it so sounds played for PPMs that default to male are only checked
+  on disk once.
+- Byte ordering/portability fixes in cinematics, PCX and other file handling.
+- Client state during static image cinematic (PCX image) so that client can 
+  continue to next unit.
+- Fixed it so that dedicated coop servers no longer get stuck at victory.pcx,
+  if a server is in coop mode, hitting a button at the victory.pcx screen
+  while cause the server to restart at base1
+- Fixed infinite grenade bug
+- Fixed autodownloading to actually download sounds and console pics
+- Fixed autodownload to not create empty directories for files not on
+  the server.
+- Added customized client downloading.  cvars are the same as the server side:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  They can also be (more easily) set with a new Download Options menu 
+  accessible in Multiplayer/Player Setup/Download Options
+- Changed checksumming code to be more portable and faster.
+  The checksum in 3.15 was seriously broken.
+  This change makes 3.17 incompatible with previous servers.
+- Fixed player 'warping' present in 3.15 (this was an artifact of the
+  hyperblaster optimizations).
+- Fixed the autodownload in 3.15 so that stuff like skins for models are
+  downloaded as well as pics.
+
+Changes for 3.15
+----------------
+
+- Added visible weapons support.  This is precached with a special symbol, i.e.
+  gi.modelindex("#w_shotgun.md2") which causes the client to autobind it to
+  the players current weapon model.  Plug in player models can optionally 
+  support the visible weapons.  Any that do not support it will use their
+  default weapon.md2 files automatically.
+  Visible weapons files for plug in player models are not downloaded
+  automatically--only the default weapon.md2 (and skin) is.
+  The Visible weapon models themselves are not included.  They can be
+  downloaded from http://www.telefragged.com/vwep/
+- Rewrote the some of the net code to use optimized network packets for 
+  projectiles.  This is transparent to the game code, but improves netplay
+  substancially.  The hyperblaster doesn't flood modem players anymore.
+- Rewrote the packet checksum code to be more portable and defeat proxy bots
+  yet again.
+- Autodownload support is in.  The following items will be automatcally
+  downloaded as needed:
+    - world map (and textures)
+    - models
+    - sounds (precached ones)
+    - plug in player model, skin, skin_i and weapon.md2
+  downloads go to a temp file (maps/blah.tmp for example) and get renamed
+  when done.  autoresume is supported (if you lose connect during the
+  download, just reconnect and resume).  Server has fine control over
+  the downloads with the following new cvars:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  maps that are in pak files will _not_ autodownload from the server, this
+  is for copyright considerations.
+  The QuakeWorld bug of the server map changing while download a map has
+  been fixed.
+- New option in the Multiplayer/Player Setup menu for setting your connection
+  speed.  This sets a default rate for the player and can improve net
+  performance for modem connections.
+- Rewrote some of the save game code to make it more portable.  I wanted to
+  completely rewrite the entire save game system and make it portable across
+  versions and operating systems, but this would require an enormous amount
+  of work.
+- Added another 512 configure strings for general usage for mod makers.
+  This gives lots of room for general string displays on the HUD and in other
+  data.
+- Player movement code re-written to be similiar to that of NetQuake and
+  later versions of QuakeWorld.  Player has more control in the air and
+  gets a boost in vertical speed when jumping off the top of ramps.
+- Fixed up serverrecord so that it works correctly with the later versions.
+  serverrecord lets the server do a recording of the current game that
+  demo editors can use to make demos from any PVS in the level.  Server
+  recorded demos are BIG.  Will look at using delta compression in them
+  to cut down the size.
+- Copy protection CD check has been removed.
+- Quake2 3.15 has changed the protocol (so old servers will not run) but
+  all existing game dlls can run on the new version (albiet without the
+  new features such as visible weapons).
+- Added flood protection.  Controlled from the following cvars:
+   flood_msgs - maximum number of messages allowed in the time period
+                specified by flood_persecond
+   flood_persecond - time period that a maximum of flood_msgs messages are
+                     permitted
+   flood_waitdelay - amount of time a client gets muzzled for flooding
+  (gamex86 DLL specific)
+- fixed it so blaster/hyperblaster shots aren't treated as solid when
+  predicting--you aren't clipped against them now.
+  (gamex86 DLL specific, the SVF_DEADMONSTER flag is set on projectiles)
+- gender support is now in.  The userinfo cvar "gender" can be set to
+  male/female/none (none for neutral messages).  This doesn't affect sounds
+  but does affect death messages in the game.  The models male and cyborg
+  default to gender male, and female and crackhor default to female.
+  Everything else defaults to none, but you can set it by typing
+  "gender male" or "gender female" as appropriate.
+- IP banning support ala QW.  It's built into the game dll as 'sv' console
+  commands.  This list is:
+    sv addip <ip-mask>  - adds an ip to the ban list
+	sv listip <ip-mask> - removes an ip from the ban list
+	sv writeip - writes the ban list to <gamedir>/listip.cfg.  You can
+	  exec this on a server load to load the list on subsequent server runs.
+	  like so:  quake2 +set dedicated 1 +exec listip.cfg
+	sv removeip <ip-mask> - remove an ip from the list
+  the ip list is a simple mask system.  Adding 192.168 to the list
+  would block out everyone in the 192.168.*.* net block.  You get 1024 bans,
+  if you need more, recompile the game dll. :)
+  A new cvar is also supported called 'filterban'.  It defaults to one which
+  means "allow everyone to connect _except_ those matching in the ban list."
+  If you set it to zero, the meaning reverses like so, "don't allow anyone
+  to connect unless they are in the list."
+  (gamex86 DLL specific)
+
--- /dev/null
+++ b/3.18_changes.txt
@@ -1,0 +1,53 @@
+3.18 Changes
+
+- "Water surfing" that was present in 3.17 has been fixed (holding jump while
+  on the surface of water let you swim at full speed).
+- Environment maps (env) are now autodownloaded (if allow_download_maps is set).
+- Spectator support added.  A new cvar is built into the client, "spectator"
+  Setting it to value other than "0" will allow you join a game as a spectator.
+  While in spectator mode, you can press the attack button to enter a chasecam
+  mode and follow other players.  Using the inventory keys (by default the
+  left and right square brackets) you can switch between players in the game
+  while using the chasecam.
+  You may enter and leave spectator mode while connected.  Doing so resets
+  your score to zero.
+  ***The new spectator support requires a new game.dll and may not work for
+  user mods until they update their code.  The default game.dll that comes
+  with 3.18 supports chasecam as well as the new included Xatrix game.dll.
+- Fixed it so that when a model defaults to male/grunt (don't have the
+  necessary model or skin for the player), VWep support is still enabled.
+- New console command for players, "playerlist".  This will cause the server
+  to give you a text list of the players on the server, including their
+  connect time, score, ping and spectator status.  This is handy if not
+  everyone fits on the scoreboard on busy servers.
+- New cvar for the game.dll:  spectator_password.  If set to a value (other
+  than "none"), users must set their spectator variable to this value in order
+  to join the server as a spectator.  This password is independant of the
+  normal user password.
+- New cvar for the game.dll:  maxspectators (defaults to 4).  This value is
+  not seperate from maxclients (a spectator is still a client).
+- New cvar for the game.dll:  sv_maplist.  This can be set to a list of map
+  names that the server should autorotate through, rather than using the
+  nextmap set in the actual map files themselves.
+  For example:  set sv_maplist "base1 q2dm1 q2dm3 fact3" will cause the server
+  to rotate through those maps.
+  ***This requires a game.dll update and will not work with user mods until
+  they update their code.
+- A new facility has been added to ClientConnect() in the game.dll to allow
+  the game.dll to pass a message back to the user for the reason of disallowing
+  a connection.  It is done by setting a key of "rejmsg" in the passed userinfo.
+  For example:
+  Info_SetValueforKey(userinfo, "rejmsg", "Password required or incorrect.");
+- The server cvar, password, may be set to "none" to clear the password.  This
+  is needed because rcon can not set a blank password.
+- New server cvar:  sv_airaccelerate.  This controls the optional air
+  acceleration facility.  The default value is 0, which disables air control.
+  The usual value to replicate the air control seen in the original Quake and
+  later versions of Quakeworld is 10.  10 allows for much more
+  air control (as was seen in 3.15).  This value is ignored in single player
+  and coop.
+- Fixed NoSuchFrame/BAD_MODELTYPE errors when doing a vid_restart while
+  connected.
+- NoSuchFrame errors now include model name to assist in debugging user mods.
+- Fixed the remote status query response (ServerInfo) to not include error 
+  messages and be more consistent.
--- /dev/null
+++ b/baseq2/config.cfg
@@ -1,0 +1,150 @@
+// generated by quake, do not modify
+bind TAB "inven"
+bind ENTER "invuse"
+bind ESCAPE "togglemenu"
+bind SPACE "+moveup"
+bind ' "inven_drop"
+bind + "sizeup"
+bind , "+moveleft"
+bind - "sizedown"
+bind . "+moveright"
+bind / "weapnext"
+bind 0 "use BFG10K"
+bind 1 "use Blaster"
+bind 2 "use Shotgun"
+bind 3 "use Super Shotgun"
+bind 4 "use Machinegun"
+bind 5 "use Chaingun"
+bind 6 "use Grenade Launcher"
+bind 7 "use Rocket Launcher"
+bind 8 "use HyperBlaster"
+bind 9 "use Railgun"
+bind = "sizeup"
+bind [ "invprev"
+bind \ "+mlook"
+bind ] "invnext"
+bind ` "toggleconsole"
+bind a "+moveleft"
+bind b "use rebreather"
+bind c "+movedown"
+bind d "+moveright"
+bind e "weapnext"
+bind g "use grenades"
+bind h "wave 0"
+bind i "use invulnerability"
+bind j "wave 1"
+bind k "wave 2"
+bind l "wave 3"
+bind p "use shield"
+bind q "invprev"
+bind r "invuse"
+bind s "+back"
+bind t "messagemode"
+bind u "wave 4"
+bind w "+forward"
+bind x "centerview"
+bind z "+movedown"
+bind ~ "toggleconsole"
+bind BACKSPACE "invdrop"
+bind UPARROW "+forward"
+bind DOWNARROW "+back"
+bind LEFTARROW "+left"
+bind RIGHTARROW "+right"
+bind ALT "+strafe"
+bind CTRL "+attack"
+bind SHIFT "+speed"
+bind F1 "cmd help"
+bind F2 "menu_savegame"
+bind F3 "menu_loadgame"
+bind F4 "give ammo"
+bind F5 "give weapons"
+bind F6 "r_speeds 0"
+bind F7 "r_speeds 1"
+bind F8 "notarget"
+bind F9 "noclip"
+bind F10 "god"
+bind F11 "screenshot"
+bind F12 "quit"
+bind INS "+klook"
+bind DEL "+lookdown"
+bind PGDN "+lookup"
+bind PGUP "+lookup"
+bind END "centerview"
+bind MOUSE1 "+attack"
+bind MOUSE2 "+strafe"
+bind MOUSE3 "+mlook"
+bind PAUSE "pause"
+set gl_3dlabs_broken "1"
+set gl_swapinterval "1"
+set gl_ext_compiled_vertex_array "1"
+set gl_ext_pointparameters "1"
+set gl_ext_multitexture "1"
+set gl_ext_palettedtexture "1"
+set gl_ext_swapinterval "1"
+set gl_vertex_arrays "0"
+set gl_texturesolidmode "default"
+set gl_texturealphamode "default"
+set gl_texturemode "GL_LINEAR_MIPMAP_NEAREST"
+set gl_driver "opengl32"
+set gl_finish "0"
+set gl_shadows "0"
+set gl_mode "3"
+set gl_modulate "1"
+set gl_particle_att_c "0.01"
+set gl_particle_att_b "0.0"
+set gl_particle_att_a "0.01"
+set gl_particle_size "40"
+set gl_particle_max_size "40"
+set gl_particle_min_size "2"
+set g_select_empty "0"
+set in_joystick "0"
+set in_mouse "1"
+set cl_vwep "1"
+set gender_auto "1"
+set gender "male"
+set fov "90"
+set msg "1"
+set rate "25000"
+set freelook "0"
+set cl_stereo_separation "0.4"
+set adr8 ""
+set adr7 ""
+set adr6 ""
+set adr5 ""
+set adr4 ""
+set adr3 ""
+set adr2 ""
+set adr1 ""
+set adr0 ""
+set cd_nocd "0"
+set s_primary "0"
+set s_mixahead "0.2"
+set s_loadas8bit "1"
+set s_khz "11"
+set s_volume "0.7"
+set sw_mode "0"
+set sw_stipplealpha "0"
+set sw_allow_modex "1"
+set vid_gamma "1"
+set vid_ypos "32"
+set vid_xpos "115"
+set vid_ref "gl"
+set sv_reconnect_limit "3"
+set allow_download_maps "1"
+set allow_download_sounds "1"
+set allow_download_models "1"
+set allow_download_players "0"
+set allow_download "0"
+set hostname "noname"
+set skin "male/grunt"
+set name "hook"
+set lookstrafe "0"
+set lookspring "1"
+set m_pitch "-0.022000"
+set hand "2"
+set cl_run "0"
+set crosshair "1"
+set sensitivity "9.000000"
+set win_noalttab "0"
+set vid_fullscreen "0"
+set viewsize "100"
binary files /dev/null b/baseq2/save/save0/game.ssv differ
binary files /dev/null b/baseq2/save/save0/server.ssv differ
--- /dev/null
+++ b/changes.txt
@@ -1,0 +1,166 @@
+
+Quake2 3.16 changes:
+
+- Fixed infinite grenade bug
+- Fixed autodownloading to actually download sounds and console pics
+- Fixed autodownload to not create empty directories for files not on
+  the server.
+- Added customized client downloading.  cvars are the same as the server side:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  They can also be (more easily) set with a new Download Options menu 
+  accessible in Multiplayer/Player Setup/Download Options
+- Changed checksumming code to be more portable and faster.
+
+
+Quake2 3.15 changes:
+
+- Added visible weapons support.  This is precached with a special symbol, i.e.
+  gi.modelindex("#w_shotgun.md2") which causes the client to autobind it to
+  the players current weapon model.  Plug in player models can optionally 
+  support the visible weapons.  Any that do not support it will use their
+  default weapon.md2 files automatically.
+  Visible weapons files for plug in player models are not downloaded
+  automatically--only the default weapon.md2 (and skin) is.
+- New cvar cl_vwep controls whether visible weapons is enabled on the client.
+  If you turn it off, the visible weapons models are not loaded.  This can offer
+  a speed up on slow or memory starved machines.
+- Rewrote the some of the net code to use optimized network packets for 
+  projectiles.  This is transparent to the game code, but improves netplay
+  substancially.  The hyperblaster doesn't flood modem players anymore.
+- Rewrote the packet checksum code to be more portable and defeat proxy bots
+  yet again.
+- Autodownload support is in.  The following items will be automatcally
+  downloaded as needed:
+    - world map (and textures)
+    - models
+    - sounds (precached ones)
+    - plug in player model, skin, skin_i and weapon.md2
+  downloads go to a temp file (maps/blah.tmp for example) and get renamed
+  when done.  autoresume is supported (if you lose connect during the
+  download, just reconnect and resume).  Server has fine control over
+  the downloads with the following new cvars:
+    allow_download - global download on/off
+    allow_download_players - players download on/off
+    allow_download_models - models download on/off
+    allow_download_sounds - sounds download on/off
+    allow_download_maps - maps download on/off
+  maps that are in pak files will _not_ autodownload from the server, this
+  is for copyright considerations.
+  The QuakeWorld bug of the server map changing while download a map has
+  been fixed.
+- New option in the Multiplayer/Player Setup menu for setting your connection
+  speed.  This sets a default rate for the player and can improve net
+  performance for modem connections.
+- Rewrote some of the save game code to make it more portable.  I wanted to
+  completely rewrite the entire save game system and make it portable across
+  versions and operating systems, but this would require an enormous amount
+  of work.
+- Added another 512 configure strings for general usage for mod makers.
+  This gives lots of room for general string displays on the HUD and in other
+  data.
+- Player movement code re-written to be similiar to that of NetQuake and
+  later versions of QuakeWorld.  Player has more control in the air and
+  gets a boost in vertical speed when jumping off the top of ramps.
+- Fixed up serverrecord so that it works correctly with the later versions.
+  serverrecord lets the server do a recording of the current game that
+  demo editors can use to make demos from any PVS in the level.  Server
+  recorded demos are BIG.  Will look at using delta compression in them
+  to cut down the size.
+- Copy protection CD check has been removed.
+- Quake2 3.15 has changed the protocol (so old servers will not run) but
+  all existing game dlls can run on the new version (albiet without the
+  new features such as visible weapons).
+- Added flood protection.  Controlled from the following cvars:
+   flood_msgs - maximum number of messages allowed in the time period
+                specified by flood_persecond
+   flood_persecond - time period that a maximum of flood_msgs messages are
+                     permitted
+   flood_waitdelay - amount of time a client gets muzzled for flooding
+- fixed it so blaster/hyperblaster shots aren't treated as solid when
+  predicting--you aren't clipped against them now.
+- gender support is now in.  The userinfo cvar "gender" can be set to
+  male/female/none (none for neutral messages).  This doesn't affect sounds
+  but does affect death messages in the game.  The models male and cyborg
+  default to gender male, and female and crackhor default to female.
+  Everything else defaults to none, but you can set it by typing
+  "gender male" or "gender female" as appropriate.
+- IP banning support ala QW.  It's built into the game dll as 'sv' console
+  commands.  This list is:
+    sv addip <ip-mask>  - adds an ip to the ban list
+	sv listip <ip-mask> - removes an ip from the ban list
+	sv writeip - writes the ban list to <gamedir>/listip.cfg.  You can
+	  exec this on a server load to load the list on subsequent server runs.
+	  like so:  quake2 +set dedicated 1 +exec listip.cfg
+	sv removeip <ip-mask> - remove an ip from the list
+  the ip list is a simple mask system.  Adding 192.168 to the list
+  would block out everyone in the 192.168.*.* net block.  You get 1024 bans,
+  if you need more, recompile the game dll. :)
+  A new cvar is also supported called 'filterban'.  It defaults to one which
+  means "allow everyone to connect _except_ those matching in the ban list."
+  If you set it to zero, the meaning reverses like so, "don't allow anyone
+  to connect unless they are in the list."
+
+Quake2 CTF 1.09a Changes:
+
+- Q2CTF 1.09 requires 3.15 now.
+- Competition Match mode added.  Server can be reset into a timed match mode.
+  Includes a pregame setup time, countdown until game start, timed match,
+  statistics on players, admin functions and a post game time.
+- The server command 'gamemap' now works correctly.  On a server, you can
+  change maps with two commands:  map and gamemap.  Map will cause all teams
+  to reset, gamemap will change maps with the teams intact.
+- New console commands:
+    yes - vote yes on an election
+    no - vote no on an election
+    ready - ready oneself for a match
+    notready - remove oneself from the ready list (stop the clock)
+    ghost - ghost back into a match if connection was lost
+    admin - become an admin or access the admin menu
+    stats - show statistics on players in a match
+    warp - warp to a new level
+    boot - kick a player of the server (you must be an admin)
+    playerlist - show player list and connect times
+- New cvars:
+    competition - set to 1 to allow the server to be voted by players into
+      competition mode.  Set to 3 for a dedicated competition server.
+      The default, 0, disables competition features.
+    matchlock - controls whether players are allowed into a match in progress
+      in competition mode.  Defaults to on (1).
+    electpercentage - the precentage of yes votes needed to win an election.
+      Defaults to 66%.
+    matchtime - length of a match, defaulting to 20 minutes.  Can be changed
+      by admins.
+    matchsetuptime - length of time allowed to setup a match (after which
+      the server will reset itself back into normal pickup play).  Defaults
+      to 10 mins.
+    matchstarttime - The countdown after match setup has been completed
+      until the match begins.  Defaults to 20 seconds.
+    admin_password - Password for admin access (allowing access to the admin
+      menu without needing to be elected).
+- Minor bug fixes in team selection to help balance the teams better (the
+  default option on the menu is now the team with the fewer players).
+- Don't get base defenses for telefragging your teammates in base.
+- Telefrags at start of game no longer count (to help with game spawning).
+- Instant weapon changing is now a server option (and can be changed by
+  admin menu).
+- New admin menu that allows remote changes of the following items:
+    Match length (time)
+    Match setup length (time)
+    Match start length (time)
+    Weapons Stay
+    Instant Items
+    Quad Drop
+    Instant Weapons
+- As part of the match code, a new 'ghost' option is included.  When a match
+  begins, all players are printed a randomly generated five digit ghost code
+  in their consoles.  If the player loses connection for some reason during
+  the match, they can reconnect and reenter the game keeping their score
+  intact at the time of disconnection.
+- Visible weapon support (as with the 3.15 release).
+- Some minor changes to the pmenu code to allow more flexability
+
+    
--- /dev/null
+++ b/client/adivtab.h
@@ -1,0 +1,1058 @@
+// table of quotients and remainders for [-15...16] / [-15...16]
+
+// numerator = -15
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{1, -7},
+{2, -1},
+{2, -3},
+{3, 0},
+{3, -3},
+{5, 0},
+{7, -1},
+{15, 0},
+{0, 0},
+{-15, 0},
+{-8, 1},
+{-5, 0},
+{-4, 1},
+{-3, 0},
+{-3, 3},
+{-3, 6},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-2, 13},
+{-1, 0},
+{-1, 1},
+// numerator = -14
+{0, -14},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, 0},
+{2, -2},
+{2, -4},
+{3, -2},
+{4, -2},
+{7, 0},
+{14, 0},
+{0, 0},
+{-14, 0},
+{-7, 0},
+{-5, 1},
+{-4, 2},
+{-3, 1},
+{-3, 4},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-2, 12},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+// numerator = -13
+{0, -13},
+{0, -13},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, -1},
+{2, -3},
+{3, -1},
+{4, -1},
+{6, -1},
+{13, 0},
+{0, 0},
+{-13, 0},
+{-7, 1},
+{-5, 2},
+{-4, 3},
+{-3, 2},
+{-3, 5},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+// numerator = -12
+{0, -12},
+{0, -12},
+{0, -12},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, 0},
+{2, -2},
+{3, 0},
+{4, 0},
+{6, 0},
+{12, 0},
+{0, 0},
+{-12, 0},
+{-6, 0},
+{-4, 0},
+{-3, 0},
+{-3, 3},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+// numerator = -11
+{0, -11},
+{0, -11},
+{0, -11},
+{0, -11},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, -1},
+{2, -3},
+{3, -2},
+{5, -1},
+{11, 0},
+{0, 0},
+{-11, 0},
+{-6, 1},
+{-4, 1},
+{-3, 1},
+{-3, 4},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+// numerator = -10
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, 0},
+{2, -2},
+{3, -1},
+{5, 0},
+{10, 0},
+{0, 0},
+{-10, 0},
+{-5, 0},
+{-4, 2},
+{-3, 2},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+// numerator = -9
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, -1},
+{3, 0},
+{4, -1},
+{9, 0},
+{0, 0},
+{-9, 0},
+{-5, 1},
+{-3, 0},
+{-3, 3},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+// numerator = -8
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, 0},
+{2, -2},
+{4, 0},
+{8, 0},
+{0, 0},
+{-8, 0},
+{-4, 0},
+{-3, 1},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+// numerator = -7
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, -1},
+{3, -1},
+{7, 0},
+{0, 0},
+{-7, 0},
+{-4, 1},
+{-3, 2},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+// numerator = -6
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, 0},
+{3, 0},
+{6, 0},
+{0, 0},
+{-6, 0},
+{-3, 0},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+// numerator = -5
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, -1},
+{5, 0},
+{0, 0},
+{-5, 0},
+{-3, 1},
+{-2, 1},
+{-2, 3},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+// numerator = -4
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{1, 0},
+{1, -1},
+{2, 0},
+{4, 0},
+{0, 0},
+{-4, 0},
+{-2, 0},
+{-2, 2},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+// numerator = -3
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{1, 0},
+{1, -1},
+{3, 0},
+{0, 0},
+{-3, 0},
+{-2, 1},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+// numerator = -2
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{1, 0},
+{2, 0},
+{0, 0},
+{-2, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+// numerator = -1
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{1, 0},
+{0, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+{-1, 15},
+// numerator = 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},
+{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},
+// numerator = 1
+{-1, -14},
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{0, 0},
+{1, 0},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+// numerator = 2
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, 0},
+{0, 0},
+{2, 0},
+{1, 0},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+// numerator = 3
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -1},
+{-3, 0},
+{0, 0},
+{3, 0},
+{1, 1},
+{1, 0},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+// numerator = 4
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -2},
+{-2, 0},
+{-4, 0},
+{0, 0},
+{4, 0},
+{2, 0},
+{1, 1},
+{1, 0},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+// numerator = 5
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -3},
+{-2, -1},
+{-3, -1},
+{-5, 0},
+{0, 0},
+{5, 0},
+{2, 1},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+// numerator = 6
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, 0},
+{-6, 0},
+{0, 0},
+{6, 0},
+{3, 0},
+{2, 0},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+// numerator = 7
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -2},
+{-4, -1},
+{-7, 0},
+{0, 0},
+{7, 0},
+{3, 1},
+{2, 1},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+// numerator = 8
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -1},
+{-4, 0},
+{-8, 0},
+{0, 0},
+{8, 0},
+{4, 0},
+{2, 2},
+{2, 0},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+// numerator = 9
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -3},
+{-3, 0},
+{-5, -1},
+{-9, 0},
+{0, 0},
+{9, 0},
+{4, 1},
+{3, 0},
+{2, 1},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+// numerator = 10
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -2},
+{-4, -2},
+{-5, 0},
+{-10, 0},
+{0, 0},
+{10, 0},
+{5, 0},
+{3, 1},
+{2, 2},
+{2, 0},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+// numerator = 11
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -4},
+{-3, -1},
+{-4, -1},
+{-6, -1},
+{-11, 0},
+{0, 0},
+{11, 0},
+{5, 1},
+{3, 2},
+{2, 3},
+{2, 1},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+// numerator = 12
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -3},
+{-3, 0},
+{-4, 0},
+{-6, 0},
+{-12, 0},
+{0, 0},
+{12, 0},
+{6, 0},
+{4, 0},
+{3, 0},
+{2, 2},
+{2, 0},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 12},
+{0, 12},
+{0, 12},
+{0, 12},
+// numerator = 13
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -5},
+{-3, -2},
+{-4, -3},
+{-5, -2},
+{-7, -1},
+{-13, 0},
+{0, 0},
+{13, 0},
+{6, 1},
+{4, 1},
+{3, 1},
+{2, 3},
+{2, 1},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 13},
+{0, 13},
+{0, 13},
+// numerator = 14
+{-1, -1},
+{-1, 0},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -4},
+{-3, -1},
+{-4, -2},
+{-5, -1},
+{-7, 0},
+{-14, 0},
+{0, 0},
+{14, 0},
+{7, 0},
+{4, 2},
+{3, 2},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 14},
+{0, 14},
+// numerator = 15
+{-1, 0},
+{-2, -13},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -6},
+{-3, -3},
+{-3, 0},
+{-4, -1},
+{-5, 0},
+{-8, -1},
+{-15, 0},
+{0, 0},
+{15, 0},
+{7, 1},
+{5, 0},
+{3, 3},
+{3, 0},
+{2, 3},
+{2, 1},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 15},
+// numerator = 16
+{-2, -14},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -5},
+{-3, -2},
+{-4, -4},
+{-4, 0},
+{-6, -2},
+{-8, 0},
+{-16, 0},
+{0, 0},
+{16, 0},
+{8, 0},
+{5, 1},
+{4, 0},
+{3, 1},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
--- /dev/null
+++ b/client/anorms.h
@@ -1,0 +1,181 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+{-0.525731, 0.000000, 0.850651}, 
+{-0.442863, 0.238856, 0.864188}, 
+{-0.295242, 0.000000, 0.955423}, 
+{-0.309017, 0.500000, 0.809017}, 
+{-0.162460, 0.262866, 0.951056}, 
+{0.000000, 0.000000, 1.000000}, 
+{0.000000, 0.850651, 0.525731}, 
+{-0.147621, 0.716567, 0.681718}, 
+{0.147621, 0.716567, 0.681718}, 
+{0.000000, 0.525731, 0.850651}, 
+{0.309017, 0.500000, 0.809017}, 
+{0.525731, 0.000000, 0.850651}, 
+{0.295242, 0.000000, 0.955423}, 
+{0.442863, 0.238856, 0.864188}, 
+{0.162460, 0.262866, 0.951056}, 
+{-0.681718, 0.147621, 0.716567}, 
+{-0.809017, 0.309017, 0.500000}, 
+{-0.587785, 0.425325, 0.688191}, 
+{-0.850651, 0.525731, 0.000000}, 
+{-0.864188, 0.442863, 0.238856}, 
+{-0.716567, 0.681718, 0.147621}, 
+{-0.688191, 0.587785, 0.425325}, 
+{-0.500000, 0.809017, 0.309017}, 
+{-0.238856, 0.864188, 0.442863}, 
+{-0.425325, 0.688191, 0.587785}, 
+{-0.716567, 0.681718, -0.147621}, 
+{-0.500000, 0.809017, -0.309017}, 
+{-0.525731, 0.850651, 0.000000}, 
+{0.000000, 0.850651, -0.525731}, 
+{-0.238856, 0.864188, -0.442863}, 
+{0.000000, 0.955423, -0.295242}, 
+{-0.262866, 0.951056, -0.162460}, 
+{0.000000, 1.000000, 0.000000}, 
+{0.000000, 0.955423, 0.295242}, 
+{-0.262866, 0.951056, 0.162460}, 
+{0.238856, 0.864188, 0.442863}, 
+{0.262866, 0.951056, 0.162460}, 
+{0.500000, 0.809017, 0.309017}, 
+{0.238856, 0.864188, -0.442863}, 
+{0.262866, 0.951056, -0.162460}, 
+{0.500000, 0.809017, -0.309017}, 
+{0.850651, 0.525731, 0.000000}, 
+{0.716567, 0.681718, 0.147621}, 
+{0.716567, 0.681718, -0.147621}, 
+{0.525731, 0.850651, 0.000000}, 
+{0.425325, 0.688191, 0.587785}, 
+{0.864188, 0.442863, 0.238856}, 
+{0.688191, 0.587785, 0.425325}, 
+{0.809017, 0.309017, 0.500000}, 
+{0.681718, 0.147621, 0.716567}, 
+{0.587785, 0.425325, 0.688191}, 
+{0.955423, 0.295242, 0.000000}, 
+{1.000000, 0.000000, 0.000000}, 
+{0.951056, 0.162460, 0.262866}, 
+{0.850651, -0.525731, 0.000000}, 
+{0.955423, -0.295242, 0.000000}, 
+{0.864188, -0.442863, 0.238856}, 
+{0.951056, -0.162460, 0.262866}, 
+{0.809017, -0.309017, 0.500000}, 
+{0.681718, -0.147621, 0.716567}, 
+{0.850651, 0.000000, 0.525731}, 
+{0.864188, 0.442863, -0.238856}, 
+{0.809017, 0.309017, -0.500000}, 
+{0.951056, 0.162460, -0.262866}, 
+{0.525731, 0.000000, -0.850651}, 
+{0.681718, 0.147621, -0.716567}, 
+{0.681718, -0.147621, -0.716567}, 
+{0.850651, 0.000000, -0.525731}, 
+{0.809017, -0.309017, -0.500000}, 
+{0.864188, -0.442863, -0.238856}, 
+{0.951056, -0.162460, -0.262866}, 
+{0.147621, 0.716567, -0.681718}, 
+{0.309017, 0.500000, -0.809017}, 
+{0.425325, 0.688191, -0.587785}, 
+{0.442863, 0.238856, -0.864188}, 
+{0.587785, 0.425325, -0.688191}, 
+{0.688191, 0.587785, -0.425325}, 
+{-0.147621, 0.716567, -0.681718}, 
+{-0.309017, 0.500000, -0.809017}, 
+{0.000000, 0.525731, -0.850651}, 
+{-0.525731, 0.000000, -0.850651}, 
+{-0.442863, 0.238856, -0.864188}, 
+{-0.295242, 0.000000, -0.955423}, 
+{-0.162460, 0.262866, -0.951056}, 
+{0.000000, 0.000000, -1.000000}, 
+{0.295242, 0.000000, -0.955423}, 
+{0.162460, 0.262866, -0.951056}, 
+{-0.442863, -0.238856, -0.864188}, 
+{-0.309017, -0.500000, -0.809017}, 
+{-0.162460, -0.262866, -0.951056}, 
+{0.000000, -0.850651, -0.525731}, 
+{-0.147621, -0.716567, -0.681718}, 
+{0.147621, -0.716567, -0.681718}, 
+{0.000000, -0.525731, -0.850651}, 
+{0.309017, -0.500000, -0.809017}, 
+{0.442863, -0.238856, -0.864188}, 
+{0.162460, -0.262866, -0.951056}, 
+{0.238856, -0.864188, -0.442863}, 
+{0.500000, -0.809017, -0.309017}, 
+{0.425325, -0.688191, -0.587785}, 
+{0.716567, -0.681718, -0.147621}, 
+{0.688191, -0.587785, -0.425325}, 
+{0.587785, -0.425325, -0.688191}, 
+{0.000000, -0.955423, -0.295242}, 
+{0.000000, -1.000000, 0.000000}, 
+{0.262866, -0.951056, -0.162460}, 
+{0.000000, -0.850651, 0.525731}, 
+{0.000000, -0.955423, 0.295242}, 
+{0.238856, -0.864188, 0.442863}, 
+{0.262866, -0.951056, 0.162460}, 
+{0.500000, -0.809017, 0.309017}, 
+{0.716567, -0.681718, 0.147621}, 
+{0.525731, -0.850651, 0.000000}, 
+{-0.238856, -0.864188, -0.442863}, 
+{-0.500000, -0.809017, -0.309017}, 
+{-0.262866, -0.951056, -0.162460}, 
+{-0.850651, -0.525731, 0.000000}, 
+{-0.716567, -0.681718, -0.147621}, 
+{-0.716567, -0.681718, 0.147621}, 
+{-0.525731, -0.850651, 0.000000}, 
+{-0.500000, -0.809017, 0.309017}, 
+{-0.238856, -0.864188, 0.442863}, 
+{-0.262866, -0.951056, 0.162460}, 
+{-0.864188, -0.442863, 0.238856}, 
+{-0.809017, -0.309017, 0.500000}, 
+{-0.688191, -0.587785, 0.425325}, 
+{-0.681718, -0.147621, 0.716567}, 
+{-0.442863, -0.238856, 0.864188}, 
+{-0.587785, -0.425325, 0.688191}, 
+{-0.309017, -0.500000, 0.809017}, 
+{-0.147621, -0.716567, 0.681718}, 
+{-0.425325, -0.688191, 0.587785}, 
+{-0.162460, -0.262866, 0.951056}, 
+{0.442863, -0.238856, 0.864188}, 
+{0.162460, -0.262866, 0.951056}, 
+{0.309017, -0.500000, 0.809017}, 
+{0.147621, -0.716567, 0.681718}, 
+{0.000000, -0.525731, 0.850651}, 
+{0.425325, -0.688191, 0.587785}, 
+{0.587785, -0.425325, 0.688191}, 
+{0.688191, -0.587785, 0.425325}, 
+{-0.955423, 0.295242, 0.000000}, 
+{-0.951056, 0.162460, 0.262866}, 
+{-1.000000, 0.000000, 0.000000}, 
+{-0.850651, 0.000000, 0.525731}, 
+{-0.955423, -0.295242, 0.000000}, 
+{-0.951056, -0.162460, 0.262866}, 
+{-0.864188, 0.442863, -0.238856}, 
+{-0.951056, 0.162460, -0.262866}, 
+{-0.809017, 0.309017, -0.500000}, 
+{-0.864188, -0.442863, -0.238856}, 
+{-0.951056, -0.162460, -0.262866}, 
+{-0.809017, -0.309017, -0.500000}, 
+{-0.681718, 0.147621, -0.716567}, 
+{-0.681718, -0.147621, -0.716567}, 
+{-0.850651, 0.000000, -0.525731}, 
+{-0.688191, 0.587785, -0.425325}, 
+{-0.587785, 0.425325, -0.688191}, 
+{-0.425325, 0.688191, -0.587785}, 
+{-0.425325, -0.688191, -0.587785}, 
+{-0.587785, -0.425325, -0.688191}, 
+{-0.688191, -0.587785, -0.425325}, 
--- /dev/null
+++ b/client/asm_i386.h
@@ -1,0 +1,81 @@
+
+#ifndef __ASM_I386__
+#define __ASM_I386__
+
+#ifdef ELF
+#define C(label) label
+#else
+#define C(label) _##label
+#endif
+
+//
+// !!! note that this file must match the corresponding C structures at all
+// times !!!
+//
+
+// plane_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+// !!! if the size of this is changed, the array lookup in SV_HullPointContents
+//     must be changed too !!!
+#define pl_normal	0
+#define pl_dist		12
+#define pl_type		16
+#define pl_signbits	17
+#define pl_pad		18
+#define pl_size		20
+
+// hull_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define	hu_clipnodes		0
+#define	hu_planes			4
+#define	hu_firstclipnode	8
+#define	hu_lastclipnode		12
+#define	hu_clip_mins		16
+#define	hu_clip_maxs		28
+#define hu_size  			40
+
+// dnode_t structure
+// !!! if this is changed, it must be changed in bspfile.h too !!!
+#define	nd_planenum		0
+#define	nd_children		4
+#define	nd_mins			8
+#define	nd_maxs			20
+#define	nd_firstface	32
+#define	nd_numfaces		36
+#define nd_size			40
+
+// sfxcache_t structure
+// !!! if this is changed, it much be changed in sound.h too !!!
+#define sfxc_length		0
+#define sfxc_loopstart	4
+#define sfxc_speed		8
+#define sfxc_width		12
+#define sfxc_stereo		16
+#define sfxc_data		20
+
+// channel_t structure
+// !!! if this is changed, it much be changed in sound.h too !!!
+#define ch_sfx			0
+#define ch_leftvol		4
+#define ch_rightvol		8
+#define ch_end			12
+#define ch_pos			16
+#define ch_looping		20
+#define ch_entnum		24
+#define ch_entchannel	28
+#define ch_origin		32
+#define ch_dist_mult	44
+#define ch_master_vol	48
+#define ch_size			52
+
+// portable_samplepair_t structure
+// !!! if this is changed, it much be changed in sound.h too !!!
+#define psp_left		0
+#define psp_right		4
+#define psp_size		8
+
+// !!! must be kept the same as in d_iface.h !!!
+#define TRANSPARENT_COLOR	255
+
+#endif
+
--- /dev/null
+++ b/client/block16.h
@@ -1,0 +1,123 @@
+LEnter16_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch0:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch1:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch2:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch3:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch4:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch5:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch6:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch7:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+LEnter8_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch8:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch9:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch10:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch11:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+LEnter4_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch12:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch13:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+LEnter2_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch14:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch15:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
--- /dev/null
+++ b/client/block8.h
@@ -1,0 +1,124 @@
+LEnter16_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch0:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch1:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch2:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch3:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch4:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch5:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch6:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch7:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+LEnter8_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch8:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch9:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch10:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch11:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+LEnter4_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch12:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch13:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+LEnter2_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch14:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch15:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
--- /dev/null
+++ b/client/cdaudio.h
@@ -1,0 +1,26 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+int		CDAudio_Init(void);
+void	CDAudio_Shutdown(void);
+void	CDAudio_Play(int track, qboolean looping);
+void	CDAudio_Stop(void);
+void	CDAudio_Update(void);
+void	CDAudio_Activate (qboolean active);
--- /dev/null
+++ b/client/cl_cin.c
@@ -1,0 +1,650 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+
+typedef struct
+{
+	byte	*data;
+	int		count;
+} cblock_t;
+
+typedef struct
+{
+	qboolean	restart_sound;
+	int		s_rate;
+	int		s_width;
+	int		s_channels;
+
+	int		width;
+	int		height;
+	byte	*pic;
+	byte	*pic_pending;
+
+	// order 1 huffman stuff
+	int		*hnodes1;	// [256][256][2];
+	int		numhnodes1[256];
+
+	int		h_used[512];
+	int		h_count[512];
+} cinematics_t;
+
+cinematics_t	cin;
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+
+/*
+==============
+SCR_LoadPCX
+==============
+*/
+void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+	byte	*raw;
+	pcx_t	*pcx;
+	int		x, y;
+	int		len;
+	int		dataByte, runLength;
+	byte	*out, *pix;
+
+	*pic = NULL;
+
+	//
+	// load the file
+	//
+	len = FS_LoadFile (filename, (void **)&raw);
+	if (!raw)
+		return;	// Com_Printf ("Bad pcx file %s\n", filename);
+
+	//
+	// parse the PCX file
+	//
+	pcx = (pcx_t *)raw;
+	raw = &pcx->data;
+
+	if (pcx->manufacturer != 0x0a
+		|| pcx->version != 5
+		|| pcx->encoding != 1
+		|| pcx->bits_per_pixel != 8
+		|| pcx->xmax >= 640
+		|| pcx->ymax >= 480)
+	{
+		Com_Printf ("Bad pcx file %s\n", filename);
+		return;
+	}
+
+	out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+	*pic = out;
+
+	pix = out;
+
+	if (palette)
+	{
+		*palette = Z_Malloc(768);
+		memcpy (*palette, (byte *)pcx + len - 768, 768);
+	}
+
+	if (width)
+		*width = pcx->xmax+1;
+	if (height)
+		*height = pcx->ymax+1;
+
+	for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+	{
+		for (x=0 ; x<=pcx->xmax ; )
+		{
+			dataByte = *raw++;
+
+			if((dataByte & 0xC0) == 0xC0)
+			{
+				runLength = dataByte & 0x3F;
+				dataByte = *raw++;
+			}
+			else
+				runLength = 1;
+
+			while(runLength-- > 0)
+				pix[x++] = dataByte;
+		}
+
+	}
+
+	if ( raw - (byte *)pcx > len)
+	{
+		Com_Printf ("PCX file %s was malformed", filename);
+		Z_Free (*pic);
+		*pic = NULL;
+	}
+
+	FS_FreeFile (pcx);
+}
+
+//=============================================================
+
+/*
+==================
+SCR_StopCinematic
+==================
+*/
+void SCR_StopCinematic (void)
+{
+	cl.cinematictime = 0;	// done
+	if (cin.pic)
+	{
+		Z_Free (cin.pic);
+		cin.pic = NULL;
+	}
+	if (cin.pic_pending)
+	{
+		Z_Free (cin.pic_pending);
+		cin.pic_pending = NULL;
+	}
+	if (cl.cinematicpalette_active)
+	{
+		re.CinematicSetPalette(NULL);
+		cl.cinematicpalette_active = false;
+	}
+	if (cl.cinematic_file)
+	{
+		fclose (cl.cinematic_file);
+		cl.cinematic_file = NULL;
+	}
+	if (cin.hnodes1)
+	{
+		Z_Free (cin.hnodes1);
+		cin.hnodes1 = NULL;
+	}
+
+	// switch back down to 11 khz sound if necessary
+	if (cin.restart_sound)
+	{
+		cin.restart_sound = false;
+		CL_Snd_Restart_f ();
+	}
+
+}
+
+/*
+====================
+SCR_FinishCinematic
+
+Called when either the cinematic completes, or it is aborted
+====================
+*/
+void SCR_FinishCinematic (void)
+{
+	// tell the server to advance to the next map / cinematic
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
+}
+
+//==========================================================================
+
+/*
+==================
+SmallestNode1
+==================
+*/
+int	SmallestNode1 (int numhnodes)
+{
+	int		i;
+	int		best, bestnode;
+
+	best = 99999999;
+	bestnode = -1;
+	for (i=0 ; i<numhnodes ; i++)
+	{
+		if (cin.h_used[i])
+			continue;
+		if (!cin.h_count[i])
+			continue;
+		if (cin.h_count[i] < best)
+		{
+			best = cin.h_count[i];
+			bestnode = i;
+		}
+	}
+
+	if (bestnode == -1)
+		return -1;
+
+	cin.h_used[bestnode] = true;
+	return bestnode;
+}
+
+
+/*
+==================
+Huff1TableInit
+
+Reads the 64k counts table and initializes the node trees
+==================
+*/
+void Huff1TableInit (void)
+{
+	int		prev;
+	int		j;
+	int		*node, *nodebase;
+	byte	counts[256];
+	int		numhnodes;
+
+	cin.hnodes1 = Z_Malloc (256*256*2*4);
+	memset (cin.hnodes1, 0, 256*256*2*4);
+
+	for (prev=0 ; prev<256 ; prev++)
+	{
+		memset (cin.h_count,0,sizeof(cin.h_count));
+		memset (cin.h_used,0,sizeof(cin.h_used));
+
+		// read a row of counts
+		FS_Read (counts, sizeof(counts), cl.cinematic_file);
+		for (j=0 ; j<256 ; j++)
+			cin.h_count[j] = counts[j];
+
+		// build the nodes
+		numhnodes = 256;
+		nodebase = cin.hnodes1 + prev*256*2;
+
+		while (numhnodes != 511)
+		{
+			node = nodebase + (numhnodes-256)*2;
+
+			// pick two lowest counts
+			node[0] = SmallestNode1 (numhnodes);
+			if (node[0] == -1)
+				break;	// no more
+
+			node[1] = SmallestNode1 (numhnodes);
+			if (node[1] == -1)
+				break;
+
+			cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
+			numhnodes++;
+		}
+
+		cin.numhnodes1[prev] = numhnodes-1;
+	}
+}
+
+/*
+==================
+Huff1Decompress
+==================
+*/
+cblock_t Huff1Decompress (cblock_t in)
+{
+	byte		*input;
+	byte		*out_p;
+	int			nodenum;
+	int			count;
+	cblock_t	out;
+	int			inbyte;
+	int			*hnodes, *hnodesbase;
+//int		i;
+
+	// get decompressed count
+	count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
+	input = in.data + 4;
+	out_p = out.data = Z_Malloc (count);
+
+	// read bits
+
+	hnodesbase = cin.hnodes1 - 256*2;	// nodes 0-255 aren't stored
+
+	hnodes = hnodesbase;
+	nodenum = cin.numhnodes1[0];
+	while (count)
+	{
+		inbyte = *input++;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+		//-----------
+		if (nodenum < 256)
+		{
+			hnodes = hnodesbase + (nodenum<<9);
+			*out_p++ = nodenum;
+			if (!--count)
+				break;
+			nodenum = cin.numhnodes1[nodenum];
+		}
+		nodenum = hnodes[nodenum*2 + (inbyte&1)];
+		inbyte >>=1;
+	}
+
+	if (input - in.data != in.count && input - in.data != in.count+1)
+	{
+		Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
+	}
+	out.count = out_p - out.data;
+
+	return out;
+}
+
+/*
+==================
+SCR_ReadNextFrame
+==================
+*/
+byte *SCR_ReadNextFrame (void)
+{
+	int		r;
+	int		command;
+	byte	samples[22050/14*4];
+	byte	compressed[0x20000];
+	int		size;
+	byte	*pic;
+	cblock_t	in, huf1;
+	int		start, end, count;
+
+	// read the next frame
+	r = fread (&command, 4, 1, cl.cinematic_file);
+	if (r == 0)		// we'll give it one more chance
+		r = fread (&command, 4, 1, cl.cinematic_file);
+
+	if (r != 1)
+		return NULL;
+	command = LittleLong(command);
+	if (command == 2)
+		return NULL;	// last frame marker
+
+	if (command == 1)
+	{	// read palette
+		FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
+		cl.cinematicpalette_active=0;	// dubious....  exposes an edge case
+	}
+
+	// decompress the next frame
+	FS_Read (&size, 4, cl.cinematic_file);
+	size = LittleLong(size);
+	if (size > sizeof(compressed) || size < 1)
+		Com_Error (ERR_DROP, "Bad compressed frame size");
+	FS_Read (compressed, size, cl.cinematic_file);
+
+	// read sound
+	start = cl.cinematicframe*cin.s_rate/14;
+	end = (cl.cinematicframe+1)*cin.s_rate/14;
+	count = end - start;
+
+	FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
+
+	S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
+
+	in.data = compressed;
+	in.count = size;
+
+	huf1 = Huff1Decompress (in);
+
+	pic = huf1.data;
+
+	cl.cinematicframe++;
+
+	return pic;
+}
+
+
+/*
+==================
+SCR_RunCinematic
+
+==================
+*/
+void SCR_RunCinematic (void)
+{
+	int		frame;
+
+	if (cl.cinematictime <= 0)
+	{
+		SCR_StopCinematic ();
+		return;
+	}
+
+	if (cl.cinematicframe == -1)
+		return;		// static image
+
+	if (cls.key_dest != key_game)
+	{	// pause if menu or console is up
+		cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+		return;
+	}
+
+	frame = (cls.realtime - cl.cinematictime)*14.0/1000;
+	if (frame <= cl.cinematicframe)
+		return;
+	if (frame > cl.cinematicframe+1)
+	{
+		Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
+		cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+	}
+	if (cin.pic)
+		Z_Free (cin.pic);
+	cin.pic = cin.pic_pending;
+	cin.pic_pending = NULL;
+	cin.pic_pending = SCR_ReadNextFrame ();
+	if (!cin.pic_pending)
+	{
+		SCR_StopCinematic ();
+		SCR_FinishCinematic ();
+		cl.cinematictime = 1;	// hack to get the black screen behind loading
+		SCR_BeginLoadingPlaque ();
+		cl.cinematictime = 0;
+		return;
+	}
+}
+
+/*
+==================
+SCR_DrawCinematic
+
+Returns true if a cinematic is active, meaning the view rendering
+should be skipped
+==================
+*/
+qboolean SCR_DrawCinematic (void)
+{
+	if (cl.cinematictime <= 0)
+	{
+		return false;
+	}
+
+	if (cls.key_dest == key_menu)
+	{	// blank screen and pause if menu is up
+		re.CinematicSetPalette(NULL);
+		cl.cinematicpalette_active = false;
+		return true;
+	}
+
+	if (!cl.cinematicpalette_active)
+	{
+		re.CinematicSetPalette(cl.cinematicpalette);
+		cl.cinematicpalette_active = true;
+	}
+
+	if (!cin.pic)
+		return true;
+
+	re.DrawStretchRaw (0, 0, viddef.width, viddef.height,
+		cin.width, cin.height, cin.pic);
+
+	return true;
+}
+
+/*
+==================
+SCR_PlayCinematic
+
+==================
+*/
+void SCR_PlayCinematic (char *arg)
+{
+	int		width, height;
+	byte	*palette;
+	char	name[MAX_OSPATH], *dot;
+	int		old_khz;
+
+	// make sure CD isn't playing music
+	CDAudio_Stop();
+
+	cl.cinematicframe = 0;
+	dot = strstr (arg, ".");
+	if (dot && !strcmp (dot, ".pcx"))
+	{	// static pcx image
+		Com_sprintf (name, sizeof(name), "pics/%s", arg);
+		SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
+		cl.cinematicframe = -1;
+		cl.cinematictime = 1;
+		SCR_EndLoadingPlaque ();
+		cls.state = ca_active;
+		if (!cin.pic)
+		{
+			Com_Printf ("%s not found.\n", name);
+			cl.cinematictime = 0;
+		}
+		else
+		{
+			memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
+			Z_Free (palette);
+		}
+		return;
+	}
+
+	Com_sprintf (name, sizeof(name), "video/%s", arg);
+	FS_FOpenFile (name, &cl.cinematic_file);
+	if (!cl.cinematic_file)
+	{
+//		Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
+		SCR_FinishCinematic ();
+		cl.cinematictime = 0;	// done
+		return;
+	}
+
+	SCR_EndLoadingPlaque ();
+
+	cls.state = ca_active;
+
+	FS_Read (&width, 4, cl.cinematic_file);
+	FS_Read (&height, 4, cl.cinematic_file);
+	cin.width = LittleLong(width);
+	cin.height = LittleLong(height);
+
+	FS_Read (&cin.s_rate, 4, cl.cinematic_file);
+	cin.s_rate = LittleLong(cin.s_rate);
+	FS_Read (&cin.s_width, 4, cl.cinematic_file);
+	cin.s_width = LittleLong(cin.s_width);
+	FS_Read (&cin.s_channels, 4, cl.cinematic_file);
+	cin.s_channels = LittleLong(cin.s_channels);
+
+	Huff1TableInit ();
+
+	// switch up to 22 khz sound if necessary
+	old_khz = Cvar_VariableValue ("s_khz");
+	if (old_khz != cin.s_rate/1000)
+	{
+		cin.restart_sound = true;
+		Cvar_SetValue ("s_khz", cin.s_rate/1000);
+		CL_Snd_Restart_f ();
+		Cvar_SetValue ("s_khz", old_khz);
+	}
+
+	cl.cinematicframe = 0;
+	cin.pic = SCR_ReadNextFrame ();
+	cl.cinematictime = Sys_Milliseconds ();
+}
--- /dev/null
+++ b/client/cl_ents.c
@@ -1,0 +1,1500 @@
+/*
+Copyright (C) 1997-2001 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_ents.c -- entity parsing and management
+
+#include "client.h"
+
+
+extern	struct model_s	*cl_mod_powerscreen;
+
+//PGM
+int	vidref_val;
+//PGM
+
+/*
+=========================================================================
+
+FRAME PARSING
+
+=========================================================================
+*/
+
+#if 0
+
+typedef struct
+{
+	int		modelindex;
+	int		num; // entity number
+	int		effects;
+	vec3_t	origin;
+	vec3_t	oldorigin;
+	vec3_t	angles;
+	qboolean present;
+} projectile_t;
+
+#define	MAX_PROJECTILES	64
+projectile_t	cl_projectiles[MAX_PROJECTILES];
+
+void CL_ClearProjectiles (void)
+{
+	int i;
+
+	for (i = 0; i < MAX_PROJECTILES; i++) {
+//		if (cl_projectiles[i].present)
+//			Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
+		cl_projectiles[i].present = false;
+	}
+}
+
+/*
+=====================
+CL_ParseProjectiles
+
+Flechettes are passed as efficient temporary entities
+=====================
+*/
+void CL_ParseProjectiles (void)
+{
+	int		i, c, j;
+	byte	bits[8];
+	byte	b;
+	projectile_t	pr;
+	int lastempty = -1;
+	qboolean old = false;
+
+	c = MSG_ReadByte (&net_message);
+	for (i=0 ; i<c ; i++)
+	{
+		bits[0] = MSG_ReadByte (&net_message);
+		bits[1] = MSG_ReadByte (&net_message);
+		bits[2] = MSG_ReadByte (&net_message);
+		bits[3] = MSG_ReadByte (&net_message);
+		bits[4] = MSG_ReadByte (&net_message);
+		pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+		pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+		pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+		VectorCopy(pr.origin, pr.oldorigin);
+
+		if (bits[4] & 64)
+			pr.effects = EF_BLASTER;
+		else
+			pr.effects = 0;
+
+		if (bits[4] & 128) {
+			old = true;
+			bits[0] = MSG_ReadByte (&net_message);
+			bits[1] = MSG_ReadByte (&net_message);
+			bits[2] = MSG_ReadByte (&net_message);
+			bits[3] = MSG_ReadByte (&net_message);
+			bits[4] = MSG_ReadByte (&net_message);
+			pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+			pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+			pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+		}
+
+		bits[0] = MSG_ReadByte (&net_message);
+		bits[1] = MSG_ReadByte (&net_message);
+		bits[2] = MSG_ReadByte (&net_message);
+
+		pr.angles[0] = 360*bits[0]/256;
+		pr.angles[1] = 360*bits[1]/256;
+		pr.modelindex = bits[2];
+
+		b = MSG_ReadByte (&net_message);
+		pr.num = (b & 0x7f);
+		if (b & 128) // extra entity number byte
+			pr.num |= (MSG_ReadByte (&net_message) << 7);
+
+		pr.present = true;
+
+		// find if this projectile already exists from previous frame 
+		for (j = 0; j < MAX_PROJECTILES; j++) {
+			if (cl_projectiles[j].modelindex) {
+				if (cl_projectiles[j].num == pr.num) {
+					// already present, set up oldorigin for interpolation
+					if (!old)
+						VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
+					cl_projectiles[j] = pr;
+					break;
+				}
+			} else
+				lastempty = j;
+		}
+
+		// not present previous frame, add it
+		if (j == MAX_PROJECTILES) {
+			if (lastempty != -1) {
+				cl_projectiles[lastempty] = pr;
+			}
+		}
+	}
+}
+
+/*
+=============
+CL_LinkProjectiles
+
+=============
+*/
+void CL_AddProjectiles (void)
+{
+	int		i, j;
+	projectile_t	*pr;
+	entity_t		ent;
+
+	memset (&ent, 0, sizeof(ent));
+
+	for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
+	{
+		// grab an entity to fill in
+		if (pr->modelindex < 1)
+			continue;
+		if (!pr->present) {
+			pr->modelindex = 0;
+			continue; // not present this frame (it was in the previous frame)
+		}
+
+		ent.model = cl.model_draw[pr->modelindex];
+
+		// interpolate origin
+		for (j=0 ; j<3 ; j++)
+		{
+			ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac * 
+				(pr->origin[j] - pr->oldorigin[j]);
+
+		}
+
+		if (pr->effects & EF_BLASTER)
+			CL_BlasterTrail (pr->oldorigin, ent.origin);
+		V_AddLight (pr->origin, 200, 1, 1, 0);
+
+		VectorCopy (pr->angles, ent.angles);
+		V_AddEntity (&ent);
+	}
+}
+#endif
+
+/*
+=================
+CL_ParseEntityBits
+
+Returns the entity number and the header bits
+=================
+*/
+int	bitcounts[32];	/// just for protocol profiling
+int CL_ParseEntityBits (unsigned *bits)
+{
+	unsigned	b, total;
+	int			i;
+	int			number;
+
+	total = MSG_ReadByte (&net_message);
+	if (total & U_MOREBITS1)
+	{
+		b = MSG_ReadByte (&net_message);
+		total |= b<<8;
+	}
+	if (total & U_MOREBITS2)
+	{
+		b = MSG_ReadByte (&net_message);
+		total |= b<<16;
+	}
+	if (total & U_MOREBITS3)
+	{
+		b = MSG_ReadByte (&net_message);
+		total |= b<<24;
+	}
+
+	// count the bits for net profiling
+	for (i=0 ; i<32 ; i++)
+		if (total&(1<<i))
+			bitcounts[i]++;
+
+	if (total & U_NUMBER16)
+		number = MSG_ReadShort (&net_message);
+	else
+		number = MSG_ReadByte (&net_message);
+
+	*bits = total;
+
+	return number;
+}
+
+/*
+==================
+CL_ParseDelta
+
+Can go from either a baseline or a previous packet_entity
+==================
+*/
+void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
+{
+	// set everything to the state we are delta'ing from
+	*to = *from;
+
+	VectorCopy (from->origin, to->old_origin);
+	to->number = number;
+
+	if (bits & U_MODEL)
+		to->modelindex = MSG_ReadByte (&net_message);
+	if (bits & U_MODEL2)
+		to->modelindex2 = MSG_ReadByte (&net_message);
+	if (bits & U_MODEL3)
+		to->modelindex3 = MSG_ReadByte (&net_message);
+	if (bits & U_MODEL4)
+		to->modelindex4 = MSG_ReadByte (&net_message);
+		
+	if (bits & U_FRAME8)
+		to->frame = MSG_ReadByte (&net_message);
+	if (bits & U_FRAME16)
+		to->frame = MSG_ReadShort (&net_message);
+
+	if ((bits & U_SKIN8) && (bits & U_SKIN16))		//used for laser colors
+		to->skinnum = MSG_ReadLong(&net_message);
+	else if (bits & U_SKIN8)
+		to->skinnum = MSG_ReadByte(&net_message);
+	else if (bits & U_SKIN16)
+		to->skinnum = MSG_ReadShort(&net_message);
+
+	if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+		to->effects = MSG_ReadLong(&net_message);
+	else if (bits & U_EFFECTS8)
+		to->effects = MSG_ReadByte(&net_message);
+	else if (bits & U_EFFECTS16)
+		to->effects = MSG_ReadShort(&net_message);
+
+	if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+		to->renderfx = MSG_ReadLong(&net_message);
+	else if (bits & U_RENDERFX8)
+		to->renderfx = MSG_ReadByte(&net_message);
+	else if (bits & U_RENDERFX16)
+		to->renderfx = MSG_ReadShort(&net_message);
+
+	if (bits & U_ORIGIN1)
+		to->origin[0] = MSG_ReadCoord (&net_message);
+	if (bits & U_ORIGIN2)
+		to->origin[1] = MSG_ReadCoord (&net_message);
+	if (bits & U_ORIGIN3)
+		to->origin[2] = MSG_ReadCoord (&net_message);
+		
+	if (bits & U_ANGLE1)
+		to->angles[0] = MSG_ReadAngle(&net_message);
+	if (bits & U_ANGLE2)
+		to->angles[1] = MSG_ReadAngle(&net_message);
+	if (bits & U_ANGLE3)
+		to->angles[2] = MSG_ReadAngle(&net_message);
+
+	if (bits & U_OLDORIGIN)
+		MSG_ReadPos (&net_message, to->old_origin);
+
+	if (bits & U_SOUND)
+		to->sound = MSG_ReadByte (&net_message);
+
+	if (bits & U_EVENT)
+		to->event = MSG_ReadByte (&net_message);
+	else
+		to->event = 0;
+
+	if (bits & U_SOLID)
+		to->solid = MSG_ReadShort (&net_message);
+}
+
+/*
+==================
+CL_DeltaEntity
+
+Parses deltas from the given base and adds the resulting entity
+to the current frame
+==================
+*/
+void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
+{
+	centity_t	*ent;
+	entity_state_t	*state;
+
+	ent = &cl_entities[newnum];
+
+	state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
+	cl.parse_entities++;
+	frame->num_entities++;
+
+	CL_ParseDelta (old, state, newnum, bits);
+
+	// some data changes will force no lerping
+	if (state->modelindex != ent->current.modelindex
+		|| state->modelindex2 != ent->current.modelindex2
+		|| state->modelindex3 != ent->current.modelindex3
+		|| state->modelindex4 != ent->current.modelindex4
+		|| abs(state->origin[0] - ent->current.origin[0]) > 512
+		|| abs(state->origin[1] - ent->current.origin[1]) > 512
+		|| abs(state->origin[2] - ent->current.origin[2]) > 512
+		|| state->event == EV_PLAYER_TELEPORT
+		|| state->event == EV_OTHER_TELEPORT
+		)
+	{
+		ent->serverframe = -99;
+	}
+
+	if (ent->serverframe != cl.frame.serverframe - 1)
+	{	// wasn't in last update, so initialize some things
+		ent->trailcount = 1024;		// for diminishing rocket / grenade trails
+		// duplicate the current state so lerping doesn't hurt anything
+		ent->prev = *state;
+		if (state->event == EV_OTHER_TELEPORT)
+		{
+			VectorCopy (state->origin, ent->prev.origin);
+			VectorCopy (state->origin, ent->lerp_origin);
+		}
+		else
+		{
+			VectorCopy (state->old_origin, ent->prev.origin);
+			VectorCopy (state->old_origin, ent->lerp_origin);
+		}
+	}
+	else
+	{	// shuffle the last state to previous
+		ent->prev = ent->current;
+	}
+
+	ent->serverframe = cl.frame.serverframe;
+	ent->current = *state;
+}
+
+/*
+==================
+CL_ParsePacketEntities
+
+An svc_packetentities has just been parsed, deal with the
+rest of the data stream.
+==================
+*/
+void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
+{
+	int			newnum;
+	int			bits;
+	entity_state_t	*oldstate;
+	int			oldindex, oldnum;
+
+	newframe->parse_entities = cl.parse_entities;
+	newframe->num_entities = 0;
+
+	// delta from the entities present in oldframe
+	oldindex = 0;
+	if (!oldframe)
+		oldnum = 99999;
+	else
+	{
+		if (oldindex >= oldframe->num_entities)
+			oldnum = 99999;
+		else
+		{
+			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+			oldnum = oldstate->number;
+		}
+	}
+
+	while (1)
+	{
+		newnum = CL_ParseEntityBits (&bits);
+		if (newnum >= MAX_EDICTS)
+			Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
+
+		if (net_message.readcount > net_message.cursize)
+			Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
+
+		if (!newnum)
+			break;
+
+		while (oldnum < newnum)
+		{	// one or more entities from the old packet are unchanged
+			if (cl_shownet->value == 3)
+				Com_Printf ("   unchanged: %i\n", oldnum);
+			CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+			
+			oldindex++;
+
+			if (oldindex >= oldframe->num_entities)
+				oldnum = 99999;
+			else
+			{
+				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+				oldnum = oldstate->number;
+			}
+		}
+
+		if (bits & U_REMOVE)
+		{	// the entity present in oldframe is not in the current frame
+			if (cl_shownet->value == 3)
+				Com_Printf ("   remove: %i\n", newnum);
+			if (oldnum != newnum)
+				Com_Printf ("U_REMOVE: oldnum != newnum\n");
+
+			oldindex++;
+
+			if (oldindex >= oldframe->num_entities)
+				oldnum = 99999;
+			else
+			{
+				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+				oldnum = oldstate->number;
+			}
+			continue;
+		}
+
+		if (oldnum == newnum)
+		{	// delta from previous state
+			if (cl_shownet->value == 3)
+				Com_Printf ("   delta: %i\n", newnum);
+			CL_DeltaEntity (newframe, newnum, oldstate, bits);
+
+			oldindex++;
+
+			if (oldindex >= oldframe->num_entities)
+				oldnum = 99999;
+			else
+			{
+				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+				oldnum = oldstate->number;
+			}
+			continue;
+		}
+
+		if (oldnum > newnum)
+		{	// delta from baseline
+			if (cl_shownet->value == 3)
+				Com_Printf ("   baseline: %i\n", newnum);
+			CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
+			continue;
+		}
+
+	}
+
+	// any remaining entities in the old frame are copied over
+	while (oldnum != 99999)
+	{	// one or more entities from the old packet are unchanged
+		if (cl_shownet->value == 3)
+			Com_Printf ("   unchanged: %i\n", oldnum);
+		CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+		
+		oldindex++;
+
+		if (oldindex >= oldframe->num_entities)
+			oldnum = 99999;
+		else
+		{
+			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+			oldnum = oldstate->number;
+		}
+	}
+}
+
+
+
+/*
+===================
+CL_ParsePlayerstate
+===================
+*/
+void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
+{
+	int			flags;
+	player_state_t	*state;
+	int			i;
+	int			statbits;
+
+	state = &newframe->playerstate;
+
+	// clear to old value before delta parsing
+	if (oldframe)
+		*state = oldframe->playerstate;
+	else
+		memset (state, 0, sizeof(*state));
+
+	flags = MSG_ReadShort (&net_message);
+
+	//
+	// parse the pmove_state_t
+	//
+	if (flags & PS_M_TYPE)
+		state->pmove.pm_type = MSG_ReadByte (&net_message);
+
+	if (flags & PS_M_ORIGIN)
+	{
+		state->pmove.origin[0] = MSG_ReadShort (&net_message);
+		state->pmove.origin[1] = MSG_ReadShort (&net_message);
+		state->pmove.origin[2] = MSG_ReadShort (&net_message);
+	}
+
+	if (flags & PS_M_VELOCITY)
+	{
+		state->pmove.velocity[0] = MSG_ReadShort (&net_message);
+		state->pmove.velocity[1] = MSG_ReadShort (&net_message);
+		state->pmove.velocity[2] = MSG_ReadShort (&net_message);
+	}
+
+	if (flags & PS_M_TIME)
+		state->pmove.pm_time = MSG_ReadByte (&net_message);
+
+	if (flags & PS_M_FLAGS)
+		state->pmove.pm_flags = MSG_ReadByte (&net_message);
+
+	if (flags & PS_M_GRAVITY)
+		state->pmove.gravity = MSG_ReadShort (&net_message);
+
+	if (flags & PS_M_DELTA_ANGLES)
+	{
+		state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
+		state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
+		state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
+	}
+
+	if (cl.attractloop)
+		state->pmove.pm_type = PM_FREEZE;		// demo playback
+
+	//
+	// parse the rest of the player_state_t
+	//
+	if (flags & PS_VIEWOFFSET)
+	{
+		state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
+		state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
+		state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
+	}
+
+	if (flags & PS_VIEWANGLES)
+	{
+		state->viewangles[0] = MSG_ReadAngle16 (&net_message);
+		state->viewangles[1] = MSG_ReadAngle16 (&net_message);
+		state->viewangles[2] = MSG_ReadAngle16 (&net_message);
+	}
+
+	if (flags & PS_KICKANGLES)
+	{
+		state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
+		state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
+		state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
+	}
+
+	if (flags & PS_WEAPONINDEX)
+	{
+		state->gunindex = MSG_ReadByte (&net_message);
+	}
+
+	if (flags & PS_WEAPONFRAME)
+	{
+		state->gunframe = MSG_ReadByte (&net_message);
+		state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
+		state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
+		state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
+		state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
+		state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
+		state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
+	}
+
+	if (flags & PS_BLEND)
+	{
+		state->blend[0] = MSG_ReadByte (&net_message)/255.0;
+		state->blend[1] = MSG_ReadByte (&net_message)/255.0;
+		state->blend[2] = MSG_ReadByte (&net_message)/255.0;
+		state->blend[3] = MSG_ReadByte (&net_message)/255.0;
+	}
+
+	if (flags & PS_FOV)
+		state->fov = MSG_ReadByte (&net_message);
+
+	if (flags & PS_RDFLAGS)
+		state->rdflags = MSG_ReadByte (&net_message);
+
+	// parse stats
+	statbits = MSG_ReadLong (&net_message);
+	for (i=0 ; i<MAX_STATS ; i++)
+		if (statbits & (1<<i) )
+			state->stats[i] = MSG_ReadShort(&net_message);
+}
+
+
+/*
+==================
+CL_FireEntityEvents
+
+==================
+*/
+void CL_FireEntityEvents (frame_t *frame)
+{
+	entity_state_t		*s1;
+	int					pnum, num;
+
+	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+	{
+		num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
+		s1 = &cl_parse_entities[num];
+		if (s1->event)
+			CL_EntityEvent (s1);
+
+		// EF_TELEPORTER acts like an event, but is not cleared each frame
+		if (s1->effects & EF_TELEPORTER)
+			CL_TeleporterParticles (s1);
+	}
+}
+
+
+/*
+================
+CL_ParseFrame
+================
+*/
+void CL_ParseFrame (void)
+{
+	int			cmd;
+	int			len;
+	frame_t		*old;
+
+	memset (&cl.frame, 0, sizeof(cl.frame));
+
+#if 0
+	CL_ClearProjectiles(); // clear projectiles for new frame
+#endif
+
+	cl.frame.serverframe = MSG_ReadLong (&net_message);
+	cl.frame.deltaframe = MSG_ReadLong (&net_message);
+	cl.frame.servertime = cl.frame.serverframe*100;
+
+	// BIG HACK to let old demos continue to work
+	if (cls.serverProtocol != 26)
+		cl.surpressCount = MSG_ReadByte (&net_message);
+
+	if (cl_shownet->value == 3)
+		Com_Printf ("   frame:%i  delta:%i\n", cl.frame.serverframe,
+		cl.frame.deltaframe);
+
+	// If the frame is delta compressed from data that we
+	// no longer have available, we must suck up the rest of
+	// the frame, but not use it, then ask for a non-compressed
+	// message 
+	if (cl.frame.deltaframe <= 0)
+	{
+		cl.frame.valid = true;		// uncompressed frame
+		old = NULL;
+		cls.demowaiting = false;	// we can start recording now
+	}
+	else
+	{
+		old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
+		if (!old->valid)
+		{	// should never happen
+			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
+		}
+		if (old->serverframe != cl.frame.deltaframe)
+		{	// The frame that the server did the delta from
+			// is too old, so we can't reconstruct it properly.
+			Com_Printf ("Delta frame too old.\n");
+		}
+		else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
+		{
+			Com_Printf ("Delta parse_entities too old.\n");
+		}
+		else
+			cl.frame.valid = true;	// valid delta parse
+	}
+
+	// clamp time 
+	if (cl.time > cl.frame.servertime)
+		cl.time = cl.frame.servertime;
+	else if (cl.time < cl.frame.servertime - 100)
+		cl.time = cl.frame.servertime - 100;
+
+	// read areabits
+	len = MSG_ReadByte (&net_message);
+	MSG_ReadData (&net_message, &cl.frame.areabits, len);
+
+	// read playerinfo
+	cmd = MSG_ReadByte (&net_message);
+	SHOWNET(svc_strings[cmd]);
+	if (cmd != svc_playerinfo)
+		Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
+	CL_ParsePlayerstate (old, &cl.frame);
+
+	// read packet entities
+	cmd = MSG_ReadByte (&net_message);
+	SHOWNET(svc_strings[cmd]);
+	if (cmd != svc_packetentities)
+		Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
+	CL_ParsePacketEntities (old, &cl.frame);
+
+#if 0
+	if (cmd == svc_packetentities2)
+		CL_ParseProjectiles();
+#endif
+
+	// save the frame off in the backup array for later delta comparisons
+	cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
+
+	if (cl.frame.valid)
+	{
+		// getting a valid frame message ends the connection process
+		if (cls.state != ca_active)
+		{
+			cls.state = ca_active;
+			cl.force_refdef = true;
+			cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
+			cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
+			cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
+			VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
+			if (cls.disable_servercount != cl.servercount
+				&& cl.refresh_prepped)
+				SCR_EndLoadingPlaque ();	// get rid of loading plaque
+		}
+		cl.sound_prepped = true;	// can start mixing ambient sounds
+	
+		// fire entity events
+		CL_FireEntityEvents (&cl.frame);
+		CL_CheckPredictionError ();
+	}
+}
+
+/*
+==========================================================================
+
+INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
+
+==========================================================================
+*/
+
+struct model_s *S_RegisterSexedModel (entity_state_t *ent, char *base)
+{
+	int				n;
+	char			*p;
+	struct model_s	*mdl;
+	char			model[MAX_QPATH];
+	char			buffer[MAX_QPATH];
+
+	// determine what model the client is using
+	model[0] = 0;
+	n = CS_PLAYERSKINS + ent->number - 1;
+	if (cl.configstrings[n][0])
+	{
+		p = strchr(cl.configstrings[n], '\\');
+		if (p)
+		{
+			p += 1;
+			strcpy(model, p);
+			p = strchr(model, '/');
+			if (p)
+				*p = 0;
+		}
+	}
+	// if we can't figure it out, they're male
+	if (!model[0])
+		strcpy(model, "male");
+
+	Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
+	mdl = re.RegisterModel(buffer);
+	if (!mdl) {
+		// not found, try default weapon model
+		Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
+		mdl = re.RegisterModel(buffer);
+		if (!mdl) {
+			// no, revert to the male model
+			Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
+			mdl = re.RegisterModel(buffer);
+			if (!mdl) {
+				// last try, default male weapon.md2
+				Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
+				mdl = re.RegisterModel(buffer);
+			}
+		} 
+	}
+
+	return mdl;
+}
+
+/*
+===============
+CL_AddPacketEntities
+
+===============
+*/
+void CL_AddPacketEntities (frame_t *frame)
+{
+	entity_t			ent;
+	entity_state_t		*s1;
+	float				autorotate;
+	int					i;
+	int					pnum;
+	centity_t			*cent;
+	int					autoanim;
+	clientinfo_t		*ci;
+	unsigned int		effects, renderfx;
+
+	// bonus items rotate at a fixed rate
+	autorotate = anglemod(cl.time/10);
+
+	// brush models can auto animate their frames
+	autoanim = 2*cl.time/1000;
+
+	memset (&ent, 0, sizeof(ent));
+
+	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+	{
+		s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
+
+		cent = &cl_entities[s1->number];
+
+		effects = s1->effects;
+		renderfx = s1->renderfx;
+
+			// set frame
+		if (effects & EF_ANIM01)
+			ent.frame = autoanim & 1;
+		else if (effects & EF_ANIM23)
+			ent.frame = 2 + (autoanim & 1);
+		else if (effects & EF_ANIM_ALL)
+			ent.frame = autoanim;
+		else if (effects & EF_ANIM_ALLFAST)
+			ent.frame = cl.time / 100;
+		else
+			ent.frame = s1->frame;
+
+		// quad and pent can do different things on client
+		if (effects & EF_PENT)
+		{
+			effects &= ~EF_PENT;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_RED;
+		}
+
+		if (effects & EF_QUAD)
+		{
+			effects &= ~EF_QUAD;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_BLUE;
+		}
+//======
+// PMM
+		if (effects & EF_DOUBLE)
+		{
+			effects &= ~EF_DOUBLE;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_DOUBLE;
+		}
+
+		if (effects & EF_HALF_DAMAGE)
+		{
+			effects &= ~EF_HALF_DAMAGE;
+			effects |= EF_COLOR_SHELL;
+			renderfx |= RF_SHELL_HALF_DAM;
+		}
+// pmm
+//======
+		ent.oldframe = cent->prev.frame;
+		ent.backlerp = 1.0 - cl.lerpfrac;
+
+		if (renderfx & (RF_FRAMELERP|RF_BEAM))
+		{	// step origin discretely, because the frames
+			// do the animation properly
+			VectorCopy (cent->current.origin, ent.origin);
+			VectorCopy (cent->current.old_origin, ent.oldorigin);
+		}
+		else
+		{	// interpolate origin
+			for (i=0 ; i<3 ; i++)
+			{
+				ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac * 
+					(cent->current.origin[i] - cent->prev.origin[i]);
+			}
+		}
+
+		// create a new entity
+	
+		// tweak the color of beams
+		if ( renderfx & RF_BEAM )
+		{	// the four beam colors are encoded in 32 bits of skinnum (hack)
+			ent.alpha = 0.30;
+			ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
+			ent.model = NULL;
+		}
+		else
+		{
+			// set skin
+			if (s1->modelindex == 255)
+			{	// use custom player skin
+				ent.skinnum = 0;
+				ci = &cl.clientinfo[s1->skinnum & 0xff];
+				ent.skin = ci->skin;
+				ent.model = ci->model;
+				if (!ent.skin || !ent.model)
+				{
+					ent.skin = cl.baseclientinfo.skin;
+					ent.model = cl.baseclientinfo.model;
+				}
+
+//============
+//PGM
+				if (renderfx & RF_USE_DISGUISE)
+				{
+					if(!strncmp((char *)ent.skin, "players/male", 12))
+					{
+						ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
+						ent.model = re.RegisterModel ("players/male/tris.md2");
+					}
+					else if(!strncmp((char *)ent.skin, "players/female", 14))
+					{
+						ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
+						ent.model = re.RegisterModel ("players/female/tris.md2");
+					}
+					else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
+					{
+						ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
+						ent.model = re.RegisterModel ("players/cyborg/tris.md2");
+					}
+				}
+//PGM
+//============
+			}
+			else
+			{
+				ent.skinnum = s1->skinnum;
+				ent.skin = NULL;
+				ent.model = cl.model_draw[s1->modelindex];
+			}
+		}
+
+		// only used for black hole model right now, FIXME: do better
+		if (renderfx == RF_TRANSLUCENT)
+			ent.alpha = 0.70;
+
+		// render effects (fullbright, translucent, etc)
+		if ((effects & EF_COLOR_SHELL))
+			ent.flags = 0;	// renderfx go on color shell entity
+		else
+			ent.flags = renderfx;
+
+		// calculate angles
+		if (effects & EF_ROTATE)
+		{	// some bonus items auto-rotate
+			ent.angles[0] = 0;
+			ent.angles[1] = autorotate;
+			ent.angles[2] = 0;
+		}
+		// RAFAEL
+		else if (effects & EF_SPINNINGLIGHTS)
+		{
+			ent.angles[0] = 0;
+			ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
+			ent.angles[2] = 180;
+			{
+				vec3_t forward;
+				vec3_t start;
+
+				AngleVectors (ent.angles, forward, NULL, NULL);
+				VectorMA (ent.origin, 64, forward, start);
+				V_AddLight (start, 100, 1, 0, 0);
+			}
+		}
+		else
+		{	// interpolate angles
+			float	a1, a2;
+
+			for (i=0 ; i<3 ; i++)
+			{
+				a1 = cent->current.angles[i];
+				a2 = cent->prev.angles[i];
+				ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
+			}
+		}
+
+		if (s1->number == cl.playernum+1)
+		{
+			ent.flags |= RF_VIEWERMODEL;	// only draw from mirrors
+			// FIXME: still pass to refresh
+
+			if (effects & EF_FLAG1)
+				V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
+			else if (effects & EF_FLAG2)
+				V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
+			else if (effects & EF_TAGTRAIL)						//PGM
+				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);	//PGM
+			else if (effects & EF_TRACKERTRAIL)					//PGM
+				V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);	//PGM
+
+			continue;
+		}
+
+		// if set to invisible, skip
+		if (!s1->modelindex)
+			continue;
+
+		if (effects & EF_BFG)
+		{
+			ent.flags |= RF_TRANSLUCENT;
+			ent.alpha = 0.30;
+		}
+
+		// RAFAEL
+		if (effects & EF_PLASMA)
+		{
+			ent.flags |= RF_TRANSLUCENT;
+			ent.alpha = 0.6;
+		}
+
+		if (effects & EF_SPHERETRANS)
+		{
+			ent.flags |= RF_TRANSLUCENT;
+			// PMM - *sigh*  yet more EF overloading
+			if (effects & EF_TRACKERTRAIL)
+				ent.alpha = 0.6;
+			else
+				ent.alpha = 0.3;
+		}
+//pmm
+
+		// add to refresh list
+		V_AddEntity (&ent);
+
+		// color shells generate a seperate entity for the main model
+		if (effects & EF_COLOR_SHELL)
+		{
+			ent.flags = renderfx | RF_TRANSLUCENT;
+			ent.alpha = 0.30;
+			V_AddEntity (&ent);
+		}
+
+		ent.skin = NULL;		// never use a custom skin on others
+		ent.skinnum = 0;
+		ent.flags = 0;
+		ent.alpha = 0;
+
+		// duplicate for linked models
+		if (s1->modelindex2)
+		{
+			if (s1->modelindex2 == 255)
+			{	// custom weapon
+				ci = &cl.clientinfo[s1->skinnum & 0xff];
+				i = (s1->skinnum >> 8); // 0 is default weapon model
+				if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
+					i = 0;
+				ent.model = ci->weaponmodel[i];
+				if (!ent.model) {
+					if (i != 0)
+						ent.model = ci->weaponmodel[0];
+					if (!ent.model)
+						ent.model = cl.baseclientinfo.weaponmodel[0];
+				}
+			}
+			//PGM - hack to allow translucent linked models (defender sphere's shell)
+			//		set the high bit 0x80 on modelindex2 to enable translucency
+			else if(s1->modelindex2 & 0x80)
+			{
+				ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
+				ent.alpha = 0.32;
+				ent.flags = RF_TRANSLUCENT;
+			}
+			//PGM
+			else
+				ent.model = cl.model_draw[s1->modelindex2];
+			V_AddEntity (&ent);
+
+			//PGM - make sure these get reset.
+			ent.flags = 0;
+			ent.alpha = 0;
+			//PGM
+		}
+		if (s1->modelindex3)
+		{
+			ent.model = cl.model_draw[s1->modelindex3];
+			V_AddEntity (&ent);
+		}
+		if (s1->modelindex4)
+		{
+			ent.model = cl.model_draw[s1->modelindex4];
+			V_AddEntity (&ent);
+		}
+
+		if ( effects & EF_POWERSCREEN )
+		{
+			ent.model = cl_mod_powerscreen;
+			ent.oldframe = 0;
+			ent.frame = 0;
+			ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
+			ent.alpha = 0.30;
+			V_AddEntity (&ent);
+		}
+
+		// add automatic particle trails
+		if ( (effects&~EF_ROTATE) )
+		{
+			if (effects & EF_ROCKET)
+			{
+				CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
+				V_AddLight (ent.origin, 200, 1, 1, 0);
+			}
+			// PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER. 
+			// EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
+			else if (effects & EF_BLASTER)
+			{
+//				CL_BlasterTrail (cent->lerp_origin, ent.origin);
+//PGM
+				if (effects & EF_TRACKER)	// lame... problematic?
+				{
+					CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
+					V_AddLight (ent.origin, 200, 0, 1, 0);		
+				}
+				else
+				{
+					CL_BlasterTrail (cent->lerp_origin, ent.origin);
+					V_AddLight (ent.origin, 200, 1, 1, 0);
+				}
+//PGM
+			}
+			else if (effects & EF_HYPERBLASTER)
+			{
+				if (effects & EF_TRACKER)						// PGM	overloaded for blaster2.
+					V_AddLight (ent.origin, 200, 0, 1, 0);		// PGM
+				else											// PGM
+					V_AddLight (ent.origin, 200, 1, 1, 0);
+			}
+			else if (effects & EF_GIB)
+			{
+				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+			}
+			else if (effects & EF_GRENADE)
+			{
+				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+			}
+			else if (effects & EF_FLIES)
+			{
+				CL_FlyEffect (cent, ent.origin);
+			}
+			else if (effects & EF_BFG)
+			{
+				static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
+
+				if (effects & EF_ANIM_ALLFAST)
+				{
+					CL_BfgParticles (&ent);
+					i = 200;
+				}
+				else
+				{
+					i = bfg_lightramp[s1->frame];
+				}
+				V_AddLight (ent.origin, i, 0, 1, 0);
+			}
+			// RAFAEL
+			else if (effects & EF_TRAP)
+			{
+				ent.origin[2] += 32;
+				CL_TrapParticles (&ent);
+				i = (rand()%100) + 100;
+				V_AddLight (ent.origin, i, 1, 0.8, 0.1);
+			}
+			else if (effects & EF_FLAG1)
+			{
+				CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
+				V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
+			}
+			else if (effects & EF_FLAG2)
+			{
+				CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
+				V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
+			}
+//======
+//ROGUE
+			else if (effects & EF_TAGTRAIL)
+			{
+				CL_TagTrail (cent->lerp_origin, ent.origin, 220);
+				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
+			}
+			else if (effects & EF_TRACKERTRAIL)
+			{
+				if (effects & EF_TRACKER)
+				{
+					float intensity;
+
+					intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
+					// FIXME - check out this effect in rendition
+					if(vidref_val == VIDREF_GL)
+						V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
+					else
+						V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
+					}
+				else
+				{
+					CL_Tracker_Shell (cent->lerp_origin);
+					V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
+				}
+			}
+			else if (effects & EF_TRACKER)
+			{
+				CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
+				// FIXME - check out this effect in rendition
+				if(vidref_val == VIDREF_GL)
+					V_AddLight (ent.origin, 200, -1, -1, -1);
+				else
+					V_AddLight (ent.origin, -200, 1, 1, 1);
+			}
+//ROGUE
+//======
+			// RAFAEL
+			else if (effects & EF_GREENGIB)
+			{
+				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);				
+			}
+			// RAFAEL
+			else if (effects & EF_IONRIPPER)
+			{
+				CL_IonripperTrail (cent->lerp_origin, ent.origin);
+				V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
+			}
+			// RAFAEL
+			else if (effects & EF_BLUEHYPERBLASTER)
+			{
+				V_AddLight (ent.origin, 200, 0, 0, 1);
+			}
+			// RAFAEL
+			else if (effects & EF_PLASMA)
+			{
+				if (effects & EF_ANIM_ALLFAST)
+				{
+					CL_BlasterTrail (cent->lerp_origin, ent.origin);
+				}
+				V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
+			}
+		}
+
+		VectorCopy (ent.origin, cent->lerp_origin);
+	}
+}
+
+
+
+/*
+==============
+CL_AddViewWeapon
+==============
+*/
+void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
+{
+	entity_t	gun;		// view model
+	int			i;
+
+	// allow the gun to be completely removed
+	if (!cl_gun->value)
+		return;
+
+	// don't draw gun if in wide angle view
+	if (ps->fov > 90)
+		return;
+
+	memset (&gun, 0, sizeof(gun));
+
+	if (gun_model)
+		gun.model = gun_model;	// development tool
+	else
+		gun.model = cl.model_draw[ps->gunindex];
+	if (!gun.model)
+		return;
+
+	// set up gun position
+	for (i=0 ; i<3 ; i++)
+	{
+		gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
+			+ cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
+		gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
+			ps->gunangles[i], cl.lerpfrac);
+	}
+
+	if (gun_frame)
+	{
+		gun.frame = gun_frame;	// development tool
+		gun.oldframe = gun_frame;	// development tool
+	}
+	else
+	{
+		gun.frame = ps->gunframe;
+		if (gun.frame == 0)
+			gun.oldframe = 0;	// just changed weapons, don't lerp from old
+		else
+			gun.oldframe = ops->gunframe;
+	}
+
+	gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
+	gun.backlerp = 1.0 - cl.lerpfrac;
+	VectorCopy (gun.origin, gun.oldorigin);	// don't lerp at all
+	V_AddEntity (&gun);
+}
+
+
+/*
+===============
+CL_CalcViewValues
+
+Sets cl.refdef view values
+===============
+*/
+void CL_CalcViewValues (void)
+{
+	int			i;
+	float		lerp, backlerp;
+	centity_t	*ent;
+	frame_t		*oldframe;
+	player_state_t	*ps, *ops;
+
+	// find the previous frame to interpolate from
+	ps = &cl.frame.playerstate;
+	i = (cl.frame.serverframe - 1) & UPDATE_MASK;
+	oldframe = &cl.frames[i];
+	if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+		oldframe = &cl.frame;		// previous frame was dropped or involid
+	ops = &oldframe->playerstate;
+
+	// see if the player entity was teleported this frame
+	if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
+		|| abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
+		|| abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
+		ops = ps;		// don't interpolate
+
+	ent = &cl_entities[cl.playernum+1];
+	lerp = cl.lerpfrac;
+
+	// calculate the origin
+	if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+	{	// use predicted values
+		unsigned	delta;
+
+		backlerp = 1.0 - lerp;
+		for (i=0 ; i<3 ; i++)
+		{
+			cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i] 
+				+ cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
+				- backlerp * cl.prediction_error[i];
+		}
+
+		// smooth out stair climbing
+		delta = cls.realtime - cl.predicted_step_time;
+		if (delta < 100)
+			cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
+	}
+	else
+	{	// just use interpolated values
+		for (i=0 ; i<3 ; i++)
+			cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i] 
+				+ lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i] 
+				- (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
+	}
+
+	// if not running a demo or on a locked frame, add the local angle movement
+	if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
+	{	// use predicted values
+		for (i=0 ; i<3 ; i++)
+			cl.refdef.viewangles[i] = cl.predicted_angles[i];
+	}
+	else
+	{	// just use interpolated values
+		for (i=0 ; i<3 ; i++)
+			cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
+	}
+
+	for (i=0 ; i<3 ; i++)
+		cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
+
+	AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
+
+	// interpolate field of view
+	cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
+
+	// don't interpolate blend color
+	for (i=0 ; i<4 ; i++)
+		cl.refdef.blend[i] = ps->blend[i];
+
+	// add the weapon
+	CL_AddViewWeapon (ps, ops);
+}
+
+/*
+===============
+CL_AddEntities
+
+Emits all entities, particles, and lights to the refresh
+===============
+*/
+void CL_AddEntities (void)
+{
+	if (cls.state != ca_active)
+		return;
+
+	if (cl.time > cl.frame.servertime)
+	{
+		if (cl_showclamp->value)
+			Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
+		cl.time = cl.frame.servertime;
+		cl.lerpfrac = 1.0;
+	}
+	else if (cl.time < cl.frame.servertime - 100)
+	{
+		if (cl_showclamp->value)
+			Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
+		cl.time = cl.frame.servertime - 100;
+		cl.lerpfrac = 0;
+	}
+	else
+		cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
+
+	if (cl_timedemo->value)
+		cl.lerpfrac = 1.0;
+
+//	CL_AddPacketEntities (&cl.frame);
+//	CL_AddTEnts ();
+//	CL_AddParticles ();
+//	CL_AddDLights ();
+//	CL_AddLightStyles ();
+
+	CL_CalcViewValues ();
+	// PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
+	CL_AddPacketEntities (&cl.frame);
+#if 0
+	CL_AddProjectiles ();
+#endif
+	CL_AddTEnts ();
+	CL_AddParticles ();
+	CL_AddDLights ();
+	CL_AddLightStyles ();
+}
+
+
+
+/*
+===============
+CL_GetEntitySoundOrigin
+
+Called to get the sound spatialization origin
+===============
+*/
+void CL_GetEntitySoundOrigin (int ent, vec3_t org)
+{
+	centity_t	*old;
+
+	if (ent < 0 || ent >= MAX_EDICTS)
+		Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
+	old = &cl_entities[ent];
+	VectorCopy (old->lerp_origin, org);
+
+	// FIXME: bmodel issues...
+}
--- /dev/null
+++ b/client/cl_fx.c
@@ -1,0 +1,2298 @@
+/*
+Copyright (C) 1997-2001 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_fx.c -- entity effects parsing and management
+
+#include "client.h"
+
+void CL_LogoutEffect (vec3_t org, int type);
+void CL_ItemRespawnParticles (vec3_t org);
+
+static vec3_t avelocities [NUMVERTEXNORMALS];
+
+extern	struct model_s	*cl_mod_smoke;
+extern	struct model_s	*cl_mod_flash;
+
+/*
+==============================================================
+
+LIGHT STYLE MANAGEMENT
+
+==============================================================
+*/
+
+typedef struct
+{
+	int		length;
+	float	value[3];
+	float	map[MAX_QPATH];
+} clightstyle_t;
+
+clightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
+int			lastofs;
+
+/*
+================
+CL_ClearLightStyles
+================
+*/
+void CL_ClearLightStyles (void)
+{
+	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
+	lastofs = -1;
+}
+
+/*
+================
+CL_RunLightStyles
+================
+*/
+void CL_RunLightStyles (void)
+{
+	int		ofs;
+	int		i;
+	clightstyle_t	*ls;
+
+	ofs = cl.time / 100;
+	if (ofs == lastofs)
+		return;
+	lastofs = ofs;
+
+	for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+	{
+		if (!ls->length)
+		{
+			ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
+			continue;
+		}
+		if (ls->length == 1)
+			ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
+		else
+			ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
+	}
+}
+
+
+void CL_SetLightstyle (int i)
+{
+	char	*s;
+	int		j, k;
+
+	s = cl.configstrings[i+CS_LIGHTS];
+
+	j = strlen (s);
+	if (j >= MAX_QPATH)
+		Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
+
+	cl_lightstyle[i].length = j;
+
+	for (k=0 ; k<j ; k++)
+		cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
+}
+
+/*
+================
+CL_AddLightStyles
+================
+*/
+void CL_AddLightStyles (void)
+{
+	int		i;
+	clightstyle_t	*ls;
+
+	for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+		V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
+}
+
+/*
+==============================================================
+
+DLIGHT MANAGEMENT
+
+==============================================================
+*/
+
+cdlight_t		cl_dlights[MAX_DLIGHTS];
+
+/*
+================
+CL_ClearDlights
+================
+*/
+void CL_ClearDlights (void)
+{
+	memset (cl_dlights, 0, sizeof(cl_dlights));
+}
+
+/*
+===============
+CL_AllocDlight
+
+===============
+*/
+cdlight_t *CL_AllocDlight (int key)
+{
+	int		i;
+	cdlight_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_NewDlight
+===============
+*/
+void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
+{
+	cdlight_t	*dl;
+
+	dl = CL_AllocDlight (key);
+	dl->origin[0] = x;
+	dl->origin[1] = y;
+	dl->origin[2] = z;
+	dl->radius = radius;
+	dl->die = cl.time + time;
+}
+
+
+/*
+===============
+CL_RunDLights
+
+===============
+*/
+void CL_RunDLights (void)
+{
+	int			i;
+	cdlight_t	*dl;
+
+	dl = cl_dlights;
+	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+	{
+		if (!dl->radius)
+			continue;
+		
+		if (dl->die < cl.time)
+		{
+			dl->radius = 0;
+			return;
+		}
+		dl->radius -= cls.frametime*dl->decay;
+		if (dl->radius < 0)
+			dl->radius = 0;
+	}
+}
+
+/*
+==============
+CL_ParseMuzzleFlash
+==============
+*/
+void CL_ParseMuzzleFlash (void)
+{
+	vec3_t		fv, rv;
+	cdlight_t	*dl;
+	int			i, weapon;
+	centity_t	*pl;
+	int			silenced;
+	float		volume;
+	char		soundname[64];
+
+	i = MSG_ReadShort (&net_message);
+	if (i < 1 || i >= MAX_EDICTS)
+		Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
+
+	weapon = MSG_ReadByte (&net_message);
+	silenced = weapon & MZ_SILENCED;
+	weapon &= ~MZ_SILENCED;
+
+	pl = &cl_entities[i];
+
+	dl = CL_AllocDlight (i);
+	VectorCopy (pl->current.origin,  dl->origin);
+	AngleVectors (pl->current.angles, fv, rv, NULL);
+	VectorMA (dl->origin, 18, fv, dl->origin);
+	VectorMA (dl->origin, 16, rv, dl->origin);
+	if (silenced)
+		dl->radius = 100 + (rand()&31);
+	else
+		dl->radius = 200 + (rand()&31);
+	dl->minlight = 32;
+	dl->die = cl.time; // + 0.1;
+
+	if (silenced)
+		volume = 0.2;
+	else
+		volume = 1;
+
+	switch (weapon)
+	{
+	case MZ_BLASTER:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_BLUEHYPERBLASTER:
+		dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_HYPERBLASTER:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_MACHINEGUN:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		break;
+	case MZ_SHOTGUN:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
+		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
+		break;
+	case MZ_SSHOTGUN:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_CHAINGUN1:
+		dl->radius = 200 + (rand()&31);
+		dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		break;
+	case MZ_CHAINGUN2:
+		dl->radius = 225 + (rand()&31);
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+		dl->die = cl.time  + 0.1;	// long delay
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
+		break;
+	case MZ_CHAINGUN3:
+		dl->radius = 250 + (rand()&31);
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time  + 0.1;	// long delay
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
+		Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
+		break;
+	case MZ_RAILGUN:
+		dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_ROCKET:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
+		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
+		break;
+	case MZ_GRENADE:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
+		S_StartSound (NULL, i, CHAN_AUTO,   S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
+		break;
+	case MZ_BFG:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
+		break;
+
+	case MZ_LOGIN:
+		dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
+		dl->die = cl.time + 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+		CL_LogoutEffect (pl->current.origin, weapon);
+		break;
+	case MZ_LOGOUT:
+		dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
+		dl->die = cl.time + 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+		CL_LogoutEffect (pl->current.origin, weapon);
+		break;
+	case MZ_RESPAWN:
+		dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
+		dl->die = cl.time + 1.0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+		CL_LogoutEffect (pl->current.origin, weapon);
+		break;
+	// RAFAEL
+	case MZ_PHALANX:
+		dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
+		break;
+	// RAFAEL
+	case MZ_IONRIPPER:	
+		dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
+		break;
+
+// ======================
+// PGM
+	case MZ_ETF_RIFLE:
+		dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_SHOTGUN2:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_HEATBEAM:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time + 100;
+//		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_BLASTER2:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+		// FIXME - different sound for blaster2 ??
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+		break;
+	case MZ_TRACKER:
+		// negative flashes handled the same in gl/soft until CL_AddDLights
+		dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+		S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
+		break;		
+	case MZ_NUKE1:
+		dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
+		dl->die = cl.time + 100;
+		break;
+	case MZ_NUKE2:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time + 100;
+		break;
+	case MZ_NUKE4:
+		dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+		dl->die = cl.time + 100;
+		break;
+	case MZ_NUKE8:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
+		dl->die = cl.time + 100;
+		break;
+// PGM
+// ======================
+	}
+}
+
+
+/*
+==============
+CL_ParseMuzzleFlash2
+==============
+*/
+void CL_ParseMuzzleFlash2 (void) 
+{
+	int			ent;
+	vec3_t		origin;
+	int			flash_number;
+	cdlight_t	*dl;
+	vec3_t		forward, right;
+	char		soundname[64];
+
+	ent = MSG_ReadShort (&net_message);
+	if (ent < 1 || ent >= MAX_EDICTS)
+		Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
+
+	flash_number = MSG_ReadByte (&net_message);
+
+	// locate the origin
+	AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
+	origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
+	origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
+	origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
+
+	dl = CL_AllocDlight (ent);
+	VectorCopy (origin,  dl->origin);
+	dl->radius = 200 + (rand()&31);
+	dl->minlight = 32;
+	dl->die = cl.time;	// + 0.1;
+
+	switch (flash_number)
+	{
+	case MZ2_INFANTRY_MACHINEGUN_1:
+	case MZ2_INFANTRY_MACHINEGUN_2:
+	case MZ2_INFANTRY_MACHINEGUN_3:
+	case MZ2_INFANTRY_MACHINEGUN_4:
+	case MZ2_INFANTRY_MACHINEGUN_5:
+	case MZ2_INFANTRY_MACHINEGUN_6:
+	case MZ2_INFANTRY_MACHINEGUN_7:
+	case MZ2_INFANTRY_MACHINEGUN_8:
+	case MZ2_INFANTRY_MACHINEGUN_9:
+	case MZ2_INFANTRY_MACHINEGUN_10:
+	case MZ2_INFANTRY_MACHINEGUN_11:
+	case MZ2_INFANTRY_MACHINEGUN_12:
+	case MZ2_INFANTRY_MACHINEGUN_13:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_SOLDIER_MACHINEGUN_1:
+	case MZ2_SOLDIER_MACHINEGUN_2:
+	case MZ2_SOLDIER_MACHINEGUN_3:
+	case MZ2_SOLDIER_MACHINEGUN_4:
+	case MZ2_SOLDIER_MACHINEGUN_5:
+	case MZ2_SOLDIER_MACHINEGUN_6:
+	case MZ2_SOLDIER_MACHINEGUN_7:
+	case MZ2_SOLDIER_MACHINEGUN_8:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_GUNNER_MACHINEGUN_1:
+	case MZ2_GUNNER_MACHINEGUN_2:
+	case MZ2_GUNNER_MACHINEGUN_3:
+	case MZ2_GUNNER_MACHINEGUN_4:
+	case MZ2_GUNNER_MACHINEGUN_5:
+	case MZ2_GUNNER_MACHINEGUN_6:
+	case MZ2_GUNNER_MACHINEGUN_7:
+	case MZ2_GUNNER_MACHINEGUN_8:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_ACTOR_MACHINEGUN_1:
+	case MZ2_SUPERTANK_MACHINEGUN_1:
+	case MZ2_SUPERTANK_MACHINEGUN_2:
+	case MZ2_SUPERTANK_MACHINEGUN_3:
+	case MZ2_SUPERTANK_MACHINEGUN_4:
+	case MZ2_SUPERTANK_MACHINEGUN_5:
+	case MZ2_SUPERTANK_MACHINEGUN_6:
+	case MZ2_TURRET_MACHINEGUN:			// PGM
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_BOSS2_MACHINEGUN_L1:
+	case MZ2_BOSS2_MACHINEGUN_L2:
+	case MZ2_BOSS2_MACHINEGUN_L3:
+	case MZ2_BOSS2_MACHINEGUN_L4:
+	case MZ2_BOSS2_MACHINEGUN_L5:
+	case MZ2_CARRIER_MACHINEGUN_L1:		// PMM
+	case MZ2_CARRIER_MACHINEGUN_L2:		// PMM
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
+		break;
+
+	case MZ2_SOLDIER_BLASTER_1:
+	case MZ2_SOLDIER_BLASTER_2:
+	case MZ2_SOLDIER_BLASTER_3:
+	case MZ2_SOLDIER_BLASTER_4:
+	case MZ2_SOLDIER_BLASTER_5:
+	case MZ2_SOLDIER_BLASTER_6:
+	case MZ2_SOLDIER_BLASTER_7:
+	case MZ2_SOLDIER_BLASTER_8:
+	case MZ2_TURRET_BLASTER:			// PGM
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_FLYER_BLASTER_1:
+	case MZ2_FLYER_BLASTER_2:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_MEDIC_BLASTER_1:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_HOVER_BLASTER_1:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_FLOAT_BLASTER_1:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_SOLDIER_SHOTGUN_1:
+	case MZ2_SOLDIER_SHOTGUN_2:
+	case MZ2_SOLDIER_SHOTGUN_3:
+	case MZ2_SOLDIER_SHOTGUN_4:
+	case MZ2_SOLDIER_SHOTGUN_5:
+	case MZ2_SOLDIER_SHOTGUN_6:
+	case MZ2_SOLDIER_SHOTGUN_7:
+	case MZ2_SOLDIER_SHOTGUN_8:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_TANK_BLASTER_1:
+	case MZ2_TANK_BLASTER_2:
+	case MZ2_TANK_BLASTER_3:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_TANK_MACHINEGUN_1:
+	case MZ2_TANK_MACHINEGUN_2:
+	case MZ2_TANK_MACHINEGUN_3:
+	case MZ2_TANK_MACHINEGUN_4:
+	case MZ2_TANK_MACHINEGUN_5:
+	case MZ2_TANK_MACHINEGUN_6:
+	case MZ2_TANK_MACHINEGUN_7:
+	case MZ2_TANK_MACHINEGUN_8:
+	case MZ2_TANK_MACHINEGUN_9:
+	case MZ2_TANK_MACHINEGUN_10:
+	case MZ2_TANK_MACHINEGUN_11:
+	case MZ2_TANK_MACHINEGUN_12:
+	case MZ2_TANK_MACHINEGUN_13:
+	case MZ2_TANK_MACHINEGUN_14:
+	case MZ2_TANK_MACHINEGUN_15:
+	case MZ2_TANK_MACHINEGUN_16:
+	case MZ2_TANK_MACHINEGUN_17:
+	case MZ2_TANK_MACHINEGUN_18:
+	case MZ2_TANK_MACHINEGUN_19:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_CHICK_ROCKET_1:
+	case MZ2_TURRET_ROCKET:			// PGM
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_TANK_ROCKET_1:
+	case MZ2_TANK_ROCKET_2:
+	case MZ2_TANK_ROCKET_3:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_SUPERTANK_ROCKET_1:
+	case MZ2_SUPERTANK_ROCKET_2:
+	case MZ2_SUPERTANK_ROCKET_3:
+	case MZ2_BOSS2_ROCKET_1:
+	case MZ2_BOSS2_ROCKET_2:
+	case MZ2_BOSS2_ROCKET_3:
+	case MZ2_BOSS2_ROCKET_4:
+	case MZ2_CARRIER_ROCKET_1:
+//	case MZ2_CARRIER_ROCKET_2:
+//	case MZ2_CARRIER_ROCKET_3:
+//	case MZ2_CARRIER_ROCKET_4:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_GUNNER_GRENADE_1:
+	case MZ2_GUNNER_GRENADE_2:
+	case MZ2_GUNNER_GRENADE_3:
+	case MZ2_GUNNER_GRENADE_4:
+		dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_GLADIATOR_RAILGUN_1:
+	// PMM
+	case MZ2_CARRIER_RAILGUN:
+	case MZ2_WIDOW_RAIL:
+	// pmm
+		dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+		break;
+
+// --- Xian's shit starts ---
+	case MZ2_MAKRON_BFG:
+		dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+		//S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_MAKRON_BLASTER_1:
+	case MZ2_MAKRON_BLASTER_2:
+	case MZ2_MAKRON_BLASTER_3:
+	case MZ2_MAKRON_BLASTER_4:
+	case MZ2_MAKRON_BLASTER_5:
+	case MZ2_MAKRON_BLASTER_6:
+	case MZ2_MAKRON_BLASTER_7:
+	case MZ2_MAKRON_BLASTER_8:
+	case MZ2_MAKRON_BLASTER_9:
+	case MZ2_MAKRON_BLASTER_10:
+	case MZ2_MAKRON_BLASTER_11:
+	case MZ2_MAKRON_BLASTER_12:
+	case MZ2_MAKRON_BLASTER_13:
+	case MZ2_MAKRON_BLASTER_14:
+	case MZ2_MAKRON_BLASTER_15:
+	case MZ2_MAKRON_BLASTER_16:
+	case MZ2_MAKRON_BLASTER_17:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
+		break;
+	
+	case MZ2_JORG_MACHINEGUN_L1:
+	case MZ2_JORG_MACHINEGUN_L2:
+	case MZ2_JORG_MACHINEGUN_L3:
+	case MZ2_JORG_MACHINEGUN_L4:
+	case MZ2_JORG_MACHINEGUN_L5:
+	case MZ2_JORG_MACHINEGUN_L6:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_JORG_MACHINEGUN_R1:
+	case MZ2_JORG_MACHINEGUN_R2:
+	case MZ2_JORG_MACHINEGUN_R3:
+	case MZ2_JORG_MACHINEGUN_R4:
+	case MZ2_JORG_MACHINEGUN_R5:
+	case MZ2_JORG_MACHINEGUN_R6:
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		break;
+
+	case MZ2_JORG_BFG_1:
+		dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+		break;
+
+	case MZ2_BOSS2_MACHINEGUN_R1:
+	case MZ2_BOSS2_MACHINEGUN_R2:
+	case MZ2_BOSS2_MACHINEGUN_R3:
+	case MZ2_BOSS2_MACHINEGUN_R4:
+	case MZ2_BOSS2_MACHINEGUN_R5:
+	case MZ2_CARRIER_MACHINEGUN_R1:			// PMM
+	case MZ2_CARRIER_MACHINEGUN_R2:			// PMM
+
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+		CL_ParticleEffect (origin, vec3_origin, 0, 40);
+		CL_SmokeAndFlash(origin);
+		break;
+
+// ======
+// ROGUE
+	case MZ2_STALKER_BLASTER:
+	case MZ2_DAEDALUS_BLASTER:
+	case MZ2_MEDIC_BLASTER_2:
+	case MZ2_WIDOW_BLASTER:
+	case MZ2_WIDOW_BLASTER_SWEEP1:
+	case MZ2_WIDOW_BLASTER_SWEEP2:
+	case MZ2_WIDOW_BLASTER_SWEEP3:
+	case MZ2_WIDOW_BLASTER_SWEEP4:
+	case MZ2_WIDOW_BLASTER_SWEEP5:
+	case MZ2_WIDOW_BLASTER_SWEEP6:
+	case MZ2_WIDOW_BLASTER_SWEEP7:
+	case MZ2_WIDOW_BLASTER_SWEEP8:
+	case MZ2_WIDOW_BLASTER_SWEEP9:
+	case MZ2_WIDOW_BLASTER_100:
+	case MZ2_WIDOW_BLASTER_90:
+	case MZ2_WIDOW_BLASTER_80:
+	case MZ2_WIDOW_BLASTER_70:
+	case MZ2_WIDOW_BLASTER_60:
+	case MZ2_WIDOW_BLASTER_50:
+	case MZ2_WIDOW_BLASTER_40:
+	case MZ2_WIDOW_BLASTER_30:
+	case MZ2_WIDOW_BLASTER_20:
+	case MZ2_WIDOW_BLASTER_10:
+	case MZ2_WIDOW_BLASTER_0:
+	case MZ2_WIDOW_BLASTER_10L:
+	case MZ2_WIDOW_BLASTER_20L:
+	case MZ2_WIDOW_BLASTER_30L:
+	case MZ2_WIDOW_BLASTER_40L:
+	case MZ2_WIDOW_BLASTER_50L:
+	case MZ2_WIDOW_BLASTER_60L:
+	case MZ2_WIDOW_BLASTER_70L:
+	case MZ2_WIDOW_RUN_1:
+	case MZ2_WIDOW_RUN_2:
+	case MZ2_WIDOW_RUN_3:
+	case MZ2_WIDOW_RUN_4:
+	case MZ2_WIDOW_RUN_5:
+	case MZ2_WIDOW_RUN_6:
+	case MZ2_WIDOW_RUN_7:
+	case MZ2_WIDOW_RUN_8:
+		dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_WIDOW_DISRUPTOR:
+		dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+		S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
+		break;
+
+	case MZ2_WIDOW_PLASMABEAM:
+	case MZ2_WIDOW2_BEAMER_1:
+	case MZ2_WIDOW2_BEAMER_2:
+	case MZ2_WIDOW2_BEAMER_3:
+	case MZ2_WIDOW2_BEAMER_4:
+	case MZ2_WIDOW2_BEAMER_5:
+	case MZ2_WIDOW2_BEAM_SWEEP_1:
+	case MZ2_WIDOW2_BEAM_SWEEP_2:
+	case MZ2_WIDOW2_BEAM_SWEEP_3:
+	case MZ2_WIDOW2_BEAM_SWEEP_4:
+	case MZ2_WIDOW2_BEAM_SWEEP_5:
+	case MZ2_WIDOW2_BEAM_SWEEP_6:
+	case MZ2_WIDOW2_BEAM_SWEEP_7:
+	case MZ2_WIDOW2_BEAM_SWEEP_8:
+	case MZ2_WIDOW2_BEAM_SWEEP_9:
+	case MZ2_WIDOW2_BEAM_SWEEP_10:
+	case MZ2_WIDOW2_BEAM_SWEEP_11:
+		dl->radius = 300 + (rand()&100);
+		dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+		dl->die = cl.time + 200;
+		break;
+// ROGUE
+// ======
+
+// --- Xian's shit ends ---
+
+	}
+}
+
+
+/*
+===============
+CL_AddDLights
+
+===============
+*/
+void CL_AddDLights (void)
+{
+	int			i;
+	cdlight_t	*dl;
+
+	dl = cl_dlights;
+
+//=====
+//PGM
+	if(vidref_val == VIDREF_GL)
+	{
+		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+		{
+			if (!dl->radius)
+				continue;
+			V_AddLight (dl->origin, dl->radius,
+				dl->color[0], dl->color[1], dl->color[2]);
+		}
+	}
+	else
+	{
+		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+		{
+			if (!dl->radius)
+				continue;
+
+			// negative light in software. only black allowed
+			if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
+			{
+				dl->radius = -(dl->radius);
+				dl->color[0] = 1;
+				dl->color[1] = 1;
+				dl->color[2] = 1;
+			}
+			V_AddLight (dl->origin, dl->radius,
+				dl->color[0], dl->color[1], dl->color[2]);
+		}
+	}
+//PGM
+//=====
+}
+
+
+
+/*
+==============================================================
+
+PARTICLE MANAGEMENT
+
+==============================================================
+*/
+
+/*
+// THIS HAS BEEN RELOCATED TO CLIENT.H
+typedef struct particle_s
+{
+	struct particle_s	*next;
+
+	float		time;
+
+	vec3_t		org;
+	vec3_t		vel;
+	vec3_t		accel;
+	float		color;
+	float		colorvel;
+	float		alpha;
+	float		alphavel;
+} cparticle_t;
+
+
+#define	PARTICLE_GRAVITY	40
+*/
+
+cparticle_t	*active_particles, *free_particles;
+
+cparticle_t	particles[MAX_PARTICLES];
+int			cl_numparticles = MAX_PARTICLES;
+
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CL_ClearParticles (void)
+{
+	int		i;
+	
+	free_particles = &particles[0];
+	active_particles = NULL;
+
+	for (i=0 ;i<cl_numparticles ; i++)
+		particles[i].next = &particles[i+1];
+	particles[cl_numparticles-1].next = NULL;
+}
+
+
+/*
+===============
+CL_ParticleEffect
+
+Wall impact puffs
+===============
+*/
+void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		d = rand()&31;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_ParticleEffect2
+===============
+*/
+void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color;
+
+		d = rand()&7;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+
+// RAFAEL
+/*
+===============
+CL_ParticleEffect3
+===============
+*/
+void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color;
+
+		d = rand()&7;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+/*
+===============
+CL_TeleporterParticles
+===============
+*/
+void CL_TeleporterParticles (entity_state_t *ent)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<8 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xdb;
+
+		for (j=0 ; j<2 ; j++)
+		{
+			p->org[j] = ent->origin[j] - 16 + (rand()&31);
+			p->vel[j] = crand()*14;
+		}
+
+		p->org[2] = ent->origin[2] - 8 + (rand()&7);
+		p->vel[2] = 80 + (rand()&7);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.5;
+	}
+}
+
+
+/*
+===============
+CL_LogoutEffect
+
+===============
+*/
+void CL_LogoutEffect (vec3_t org, int type)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<500 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		if (type == MZ_LOGIN)
+			p->color = 0xd0 + (rand()&7);	// green
+		else if (type == MZ_LOGOUT)
+			p->color = 0x40 + (rand()&7);	// red
+		else
+			p->color = 0xe0 + (rand()&7);	// yellow
+
+		p->org[0] = org[0] - 16 + frand()*32;
+		p->org[1] = org[1] - 16 + frand()*32;
+		p->org[2] = org[2] - 24 + frand()*56;
+
+		for (j=0 ; j<3 ; j++)
+			p->vel[j] = crand()*20;
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (1.0 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_ItemRespawnParticles
+
+===============
+*/
+void CL_ItemRespawnParticles (vec3_t org)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<64 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		p->color = 0xd4 + (rand()&3);	// green
+
+		p->org[0] = org[0] + crand()*8;
+		p->org[1] = org[1] + crand()*8;
+		p->org[2] = org[2] + crand()*8;
+
+		for (j=0 ; j<3 ; j++)
+			p->vel[j] = crand()*8;
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY*0.2;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (1.0 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_ExplosionParticles
+===============
+*/
+void CL_ExplosionParticles (vec3_t org)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xe0 + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%384)-192;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.8 / (0.5 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_BigTeleportParticles
+===============
+*/
+void CL_BigTeleportParticles (vec3_t org)
+{
+	int			i;
+	cparticle_t	*p;
+	float		angle, dist;
+	static int colortable[4] = {2*8,13*8,21*8,18*8};
+
+	for (i=0 ; i<4096 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+
+		p->color = colortable[rand()&3];
+
+		angle = M_PI*2*(rand()&1023)/1023.0;
+		dist = rand()&31;
+		p->org[0] = org[0] + cos(angle)*dist;
+		p->vel[0] = cos(angle)*(70+(rand()&63));
+		p->accel[0] = -cos(angle)*100;
+
+		p->org[1] = org[1] + sin(angle)*dist;
+		p->vel[1] = sin(angle)*(70+(rand()&63));
+		p->accel[1] = -sin(angle)*100;
+
+		p->org[2] = org[2] + 8 + (rand()%90);
+		p->vel[2] = -100 + (rand()&31);
+		p->accel[2] = PARTICLE_GRAVITY*4;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.3 / (0.5 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_BlasterParticles
+
+Wall impact puffs
+===============
+*/
+void CL_BlasterParticles (vec3_t org, vec3_t dir)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	int			count;
+
+	count = 40;
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xe0 + (rand()&7);
+
+		d = rand()&15;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = dir[j] * 30 + crand()*40;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_BlasterTrail
+
+===============
+*/
+void CL_BlasterTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.3+frand()*0.2);
+		p->color = 0xe0;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand();
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_QuadTrail
+
+===============
+*/
+void CL_QuadTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.8+frand()*0.2);
+		p->color = 115;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*16;
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_FlagTrail
+
+===============
+*/
+void CL_FlagTrail (vec3_t start, vec3_t end, float color)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.8+frand()*0.2);
+		p->color = color;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*16;
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_DiminishingTrail
+
+===============
+*/
+void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	float		dec;
+	float		orgscale;
+	float		velscale;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 0.5;
+	VectorScale (vec, dec, vec);
+
+	if (old->trailcount > 900)
+	{
+		orgscale = 4;
+		velscale = 15;
+	}
+	else if (old->trailcount > 800)
+	{
+		orgscale = 2;
+		velscale = 10;
+	}
+	else
+	{
+		orgscale = 1;
+		velscale = 5;
+	}
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+
+		// drop less particles as it flies
+		if ((rand()&1023) < old->trailcount)
+		{
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			VectorClear (p->accel);
+		
+			p->time = cl.time;
+
+			if (flags & EF_GIB)
+			{
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (1+frand()*0.4);
+				p->color = 0xe8 + (rand()&7);
+				for (j=0 ; j<3 ; j++)
+				{
+					p->org[j] = move[j] + crand()*orgscale;
+					p->vel[j] = crand()*velscale;
+					p->accel[j] = 0;
+				}
+				p->vel[2] -= PARTICLE_GRAVITY;
+			}
+			else if (flags & EF_GREENGIB)
+			{
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (1+frand()*0.4);
+				p->color = 0xdb + (rand()&7);
+				for (j=0; j< 3; j++)
+				{
+					p->org[j] = move[j] + crand()*orgscale;
+					p->vel[j] = crand()*velscale;
+					p->accel[j] = 0;
+				}
+				p->vel[2] -= PARTICLE_GRAVITY;
+			}
+			else
+			{
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (1+frand()*0.2);
+				p->color = 4 + (rand()&7);
+				for (j=0 ; j<3 ; j++)
+				{
+					p->org[j] = move[j] + crand()*orgscale;
+					p->vel[j] = crand()*velscale;
+				}
+				p->accel[2] = 20;
+			}
+		}
+
+		old->trailcount -= 5;
+		if (old->trailcount < 100)
+			old->trailcount = 100;
+		VectorAdd (move, vec, move);
+	}
+}
+
+void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
+{
+	float		d;
+
+	// this rotate and negat guarantees a vector
+	// not colinear with the original
+	right[1] = -forward[0];
+	right[2] = forward[1];
+	right[0] = forward[2];
+
+	d = DotProduct (right, forward);
+	VectorMA (right, -d, forward, right);
+	VectorNormalize (right);
+	CrossProduct (right, forward, up);
+}
+
+/*
+===============
+CL_RocketTrail
+
+===============
+*/
+void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	float		dec;
+
+	// smoke
+	CL_DiminishingTrail (start, end, old, EF_ROCKET);
+
+	// fire
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 1;
+	VectorScale (vec, dec, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+
+		if ( (rand()&7) == 0)
+		{
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			VectorClear (p->accel);
+			p->time = cl.time;
+
+			p->alpha = 1.0;
+			p->alphavel = -1.0 / (1+frand()*0.2);
+			p->color = 0xdc + (rand()&3);
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + crand()*5;
+				p->vel[j] = crand()*20;
+			}
+			p->accel[2] = -PARTICLE_GRAVITY;
+		}
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_RailTrail
+
+===============
+*/
+void CL_RailTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	float		dec;
+	vec3_t		right, up;
+	int			i;
+	float		d, c, s;
+	vec3_t		dir;
+	byte		clr = 0x74;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	MakeNormalVectors (vec, right, up);
+
+	for (i=0 ; i<len ; i++)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		p->time = cl.time;
+		VectorClear (p->accel);
+
+		d = i * 0.1;
+		c = cos(d);
+		s = sin(d);
+
+		VectorScale (right, c, dir);
+		VectorMA (dir, s, up, dir);
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+frand()*0.2);
+		p->color = clr + (rand()&7);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + dir[j]*3;
+			p->vel[j] = dir[j]*6;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+
+	dec = 0.75;
+	VectorScale (vec, dec, vec);
+	VectorCopy (start, move);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		VectorClear (p->accel);
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.6+frand()*0.2);
+		p->color = 0x0 + rand()&15;
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*3;
+			p->vel[j] = crand()*3;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+// RAFAEL
+/*
+===============
+CL_IonripperTrail
+===============
+*/
+void CL_IonripperTrail (vec3_t start, vec3_t ent)
+{
+	vec3_t	move;
+	vec3_t	vec;
+	float	len;
+	int		j;
+	cparticle_t *p;
+	int		dec;
+	int     left = 0;
+
+	VectorCopy (start, move);
+	VectorSubtract (ent, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+
+		p->time = cl.time;
+		p->alpha = 0.5;
+		p->alphavel = -1.0 / (0.3 + frand() * 0.2);
+		p->color = 0xe4 + (rand()&3);
+
+		for (j=0; j<3; j++)
+		{
+			p->org[j] = move[j];
+			p->accel[j] = 0;
+		}
+		if (left)
+		{
+			left = 0;
+			p->vel[0] = 10;
+		}
+		else 
+		{
+			left = 1;
+			p->vel[0] = -10;
+		}
+
+		p->vel[1] = 0;
+		p->vel[2] = 0;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+
+/*
+===============
+CL_BubbleTrail
+
+===============
+*/
+void CL_BubbleTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			i, j;
+	cparticle_t	*p;
+	float		dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 32;
+	VectorScale (vec, dec, vec);
+
+	for (i=0 ; i<len ; i+=dec)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		VectorClear (p->accel);
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+frand()*0.2);
+		p->color = 4 + (rand()&7);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*2;
+			p->vel[j] = crand()*5;
+		}
+		p->vel[2] += 6;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+
+/*
+===============
+CL_FlyParticles
+===============
+*/
+
+#define	BEAMLENGTH			16
+void CL_FlyParticles (vec3_t origin, int count)
+{
+	int			i;
+	cparticle_t	*p;
+	float		angle;
+	float		sr, sp, sy, cr, cp, cy;
+	vec3_t		forward;
+	float		dist = 64;
+	float		ltime;
+
+
+	if (count > NUMVERTEXNORMALS)
+		count = NUMVERTEXNORMALS;
+
+	if (!avelocities[0][0])
+	{
+		for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+			avelocities[0][i] = (rand()&255) * 0.01;
+	}
+
+
+	ltime = (float)cl.time / 1000.0;
+	for (i=0 ; i<count ; i+=2)
+	{
+		angle = ltime * avelocities[i][0];
+		sy = sin(angle);
+		cy = cos(angle);
+		angle = ltime * avelocities[i][1];
+		sp = sin(angle);
+		cp = cos(angle);
+		angle = ltime * 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->time = cl.time;
+
+		dist = sin(ltime + i)*64;
+		p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+		p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+		p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+		VectorClear (p->vel);
+		VectorClear (p->accel);
+
+		p->color = 0;
+		p->colorvel = 0;
+
+		p->alpha = 1;
+		p->alphavel = -100;
+	}
+}
+
+void CL_FlyEffect (centity_t *ent, vec3_t origin)
+{
+	int		n;
+	int		count;
+	int		starttime;
+
+	if (ent->fly_stoptime < cl.time)
+	{
+		starttime = cl.time;
+		ent->fly_stoptime = cl.time + 60000;
+	}
+	else
+	{
+		starttime = ent->fly_stoptime - 60000;
+	}
+
+	n = cl.time - starttime;
+	if (n < 20000)
+		count = n * 162 / 20000.0;
+	else
+	{
+		n = ent->fly_stoptime - cl.time;
+		if (n < 20000)
+			count = n * 162 / 20000.0;
+		else
+			count = 162;
+	}
+
+	CL_FlyParticles (origin, count);
+}
+
+
+/*
+===============
+CL_BfgParticles
+===============
+*/
+
+#define	BEAMLENGTH			16
+void CL_BfgParticles (entity_t *ent)
+{
+	int			i;
+	cparticle_t	*p;
+	float		angle;
+	float		sr, sp, sy, cr, cp, cy;
+	vec3_t		forward;
+	float		dist = 64;
+	vec3_t		v;
+	float		ltime;
+	
+	if (!avelocities[0][0])
+	{
+		for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+			avelocities[0][i] = (rand()&255) * 0.01;
+	}
+
+
+	ltime = (float)cl.time / 1000.0;
+	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+	{
+		angle = ltime * avelocities[i][0];
+		sy = sin(angle);
+		cy = cos(angle);
+		angle = ltime * avelocities[i][1];
+		sp = sin(angle);
+		cp = cos(angle);
+		angle = ltime * 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->time = cl.time;
+
+		dist = sin(ltime + i)*64;
+		p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+		p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+		p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+		VectorClear (p->vel);
+		VectorClear (p->accel);
+
+		VectorSubtract (p->org, ent->origin, v);
+		dist = VectorLength(v) / 90.0;
+		p->color = floor (0xd0 + dist * 7);
+		p->colorvel = 0;
+
+		p->alpha = 1.0 - dist;
+		p->alphavel = -100;
+	}
+}
+
+
+/*
+===============
+CL_TrapParticles
+===============
+*/
+// RAFAEL
+void CL_TrapParticles (entity_t *ent)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	vec3_t		start, end;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	ent->origin[2]-=14;
+	VectorCopy (ent->origin, start);
+	VectorCopy (ent->origin, end);
+	end[2]+=64;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.3+frand()*0.2);
+		p->color = 0xe0;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand();
+			p->vel[j] = crand()*15;
+			p->accel[j] = 0;
+		}
+		p->accel[2] = PARTICLE_GRAVITY;
+
+		VectorAdd (move, vec, move);
+	}
+
+	{
+
+	
+	int			i, j, k;
+	cparticle_t	*p;
+	float		vel;
+	vec3_t		dir;
+	vec3_t		org;
+
+	
+	ent->origin[2]+=14;
+	VectorCopy (ent->origin, org);
+
+
+	for (i=-2 ; i<=2 ; i+=4)
+		for (j=-2 ; j<=2 ; j+=4)
+			for (k=-2 ; k<=4 ; k+=4)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+
+				p->time = cl.time;
+				p->color = 0xe0 + (rand()&3);
+
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+				
+				p->org[0] = org[0] + i + ((rand()&23) * crand());
+				p->org[1] = org[1] + j + ((rand()&23) * crand());
+				p->org[2] = org[2] + k + ((rand()&23) * crand());
+	
+				dir[0] = j * 8;
+				dir[1] = i * 8;
+				dir[2] = k * 8;
+	
+				VectorNormalize (dir);						
+				vel = 50 + rand()&63;
+				VectorScale (dir, vel, p->vel);
+
+				p->accel[0] = p->accel[1] = 0;
+				p->accel[2] = -PARTICLE_GRAVITY;
+			}
+	}
+}
+
+
+/*
+===============
+CL_BFGExplosionParticles
+===============
+*/
+//FIXME combined with CL_ExplosionParticles
+void CL_BFGExplosionParticles (vec3_t org)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = 0xd0 + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%384)-192;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.8 / (0.5 + frand()*0.3);
+	}
+}
+
+
+/*
+===============
+CL_TeleportParticles
+
+===============
+*/
+void CL_TeleportParticles (vec3_t org)
+{
+	int			i, j, k;
+	cparticle_t	*p;
+	float		vel;
+	vec3_t		dir;
+
+	for (i=-16 ; i<=16 ; i+=4)
+		for (j=-16 ; j<=16 ; j+=4)
+			for (k=-16 ; k<=32 ; k+=4)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+
+				p->time = cl.time;
+				p->color = 7 + (rand()&7);
+
+				p->alpha = 1.0;
+				p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+				
+				p->org[0] = org[0] + i + (rand()&3);
+				p->org[1] = org[1] + j + (rand()&3);
+				p->org[2] = org[2] + k + (rand()&3);
+	
+				dir[0] = j*8;
+				dir[1] = i*8;
+				dir[2] = k*8;
+	
+				VectorNormalize (dir);						
+				vel = 50 + (rand()&63);
+				VectorScale (dir, vel, p->vel);
+
+				p->accel[0] = p->accel[1] = 0;
+				p->accel[2] = -PARTICLE_GRAVITY;
+			}
+}
+
+
+/*
+===============
+CL_AddParticles
+===============
+*/
+void CL_AddParticles (void)
+{
+	cparticle_t		*p, *next;
+	float			alpha;
+	float			time, time2;
+	vec3_t			org;
+	int				color;
+	cparticle_t		*active, *tail;
+
+	active = NULL;
+	tail = NULL;
+
+	for (p=active_particles ; p ; p=next)
+	{
+		next = p->next;
+
+		// PMM - added INSTANT_PARTICLE handling for heat beam
+		if (p->alphavel != INSTANT_PARTICLE)
+		{
+			time = (cl.time - p->time)*0.001;
+			alpha = p->alpha + time*p->alphavel;
+			if (alpha <= 0)
+			{	// faded out
+				p->next = free_particles;
+				free_particles = p;
+				continue;
+			}
+		}
+		else
+		{
+			alpha = p->alpha;
+		}
+
+		p->next = NULL;
+		if (!tail)
+			active = tail = p;
+		else
+		{
+			tail->next = p;
+			tail = p;
+		}
+
+		if (alpha > 1.0)
+			alpha = 1;
+		color = p->color;
+
+		time2 = time*time;
+
+		org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
+		org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
+		org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
+
+		V_AddParticle (org, color, alpha);
+		// PMM
+		if (p->alphavel == INSTANT_PARTICLE)
+		{
+			p->alphavel = 0.0;
+			p->alpha = 0.0;
+		}
+	}
+
+	active_particles = active;
+}
+
+
+/*
+==============
+CL_EntityEvent
+
+An entity has just been parsed that has an event value
+
+the female events are there for backwards compatability
+==============
+*/
+extern struct sfx_s	*cl_sfx_footsteps[4];
+
+void CL_EntityEvent (entity_state_t *ent)
+{
+	switch (ent->event)
+	{
+	case EV_ITEM_RESPAWN:
+		S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
+		CL_ItemRespawnParticles (ent->origin);
+		break;
+	case EV_PLAYER_TELEPORT:
+		S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
+		CL_TeleportParticles (ent->origin);
+		break;
+	case EV_FOOTSTEP:
+		if (cl_footsteps->value)
+			S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
+		break;
+	case EV_FALLSHORT:
+		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
+		break;
+	case EV_FALL:
+		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
+		break;
+	case EV_FALLFAR:
+		S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
+		break;
+	}
+}
+
+
+/*
+==============
+CL_ClearEffects
+
+==============
+*/
+void CL_ClearEffects (void)
+{
+	CL_ClearParticles ();
+	CL_ClearDlights ();
+	CL_ClearLightStyles ();
+}
--- /dev/null
+++ b/client/cl_input.c
@@ -1,0 +1,542 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+
+cvar_t	*cl_nodelta;
+
+extern	unsigned	sys_frame_time;
+unsigned	frame_msec;
+unsigned	old_sys_frame_time;
+
+/*
+===============================================================================
+
+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
+
+
+Key_Event (int key, qboolean down, unsigned time);
+
+  +mlook src time
+
+===============================================================================
+*/
+
+
+kbutton_t	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_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
+	{
+		Com_Printf ("Three keys down for a button!\n");
+		return;
+	}
+	
+	if (b->state & 1)
+		return;		// still down
+
+	// save timestamp
+	c = Cmd_Argv(2);
+	b->downtime = atoi(c);
+	if (!b->downtime)
+		b->downtime = sys_frame_time - 100;
+
+	b->state |= 1 + 2;	// down + impulse down
+}
+
+void KeyUp (kbutton_t *b)
+{
+	int		k;
+	char	*c;
+	unsigned	uptime;
+
+	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)
+
+	// save timestamp
+	c = Cmd_Argv(2);
+	uptime = atoi(c);
+	if (uptime)
+		b->msec += uptime - b->downtime;
+	else
+		b->msec += 10;
+
+	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_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_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
+
+/*
+===============
+CL_KeyState
+
+Returns the fraction of the frame that the key was down
+===============
+*/
+float CL_KeyState (kbutton_t *key)
+{
+	float		val;
+	int			msec;
+
+	key->state &= 1;		// clear impulses
+
+	msec = key->msec;
+	key->msec = 0;
+
+	if (key->state)
+	{	// still down
+		msec += sys_frame_time - key->downtime;
+		key->downtime = sys_frame_time;
+	}
+
+#if 0
+	if (msec)
+	{
+		Com_Printf ("%i ", msec);
+	}
+#endif
+
+	val = (float)msec / frame_msec;
+	if (val < 0)
+		val = 0;
+	if (val > 1)
+		val = 1;
+
+	return val;
+}
+
+
+
+
+//==========================================================================
+
+cvar_t	*cl_upspeed;
+cvar_t	*cl_forwardspeed;
+cvar_t	*cl_sidespeed;
+
+cvar_t	*cl_yawspeed;
+cvar_t	*cl_pitchspeed;
+
+cvar_t	*cl_run;
+
+cvar_t	*cl_anglespeedkey;
+
+
+/*
+================
+CL_AdjustAngles
+
+Moves the local angle positions
+================
+*/
+void CL_AdjustAngles (void)
+{
+	float	speed;
+	float	up, down;
+	
+	if (in_speed.state & 1)
+		speed = cls.frametime * cl_anglespeedkey->value;
+	else
+		speed = cls.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);
+	}
+	if (in_klook.state & 1)
+	{
+		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;
+}
+
+/*
+================
+CL_BaseMove
+
+Send the intended movement message to the server
+================
+*/
+void CL_BaseMove (usercmd_t *cmd)
+{	
+	CL_AdjustAngles ();
+	
+	memset (cmd, 0, sizeof(*cmd));
+	
+	VectorCopy (cl.viewangles, cmd->angles);
+	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_forwardspeed->value * CL_KeyState (&in_back);
+	}	
+
+//
+// adjust for speed key / running
+//
+	if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
+	{
+		cmd->forwardmove *= 2;
+		cmd->sidemove *= 2;
+		cmd->upmove *= 2;
+	}	
+}
+
+void CL_ClampPitch (void)
+{
+	float	pitch;
+
+	pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+	if (pitch > 180)
+		pitch -= 360;
+	if (cl.viewangles[PITCH] + pitch > 89)
+		cl.viewangles[PITCH] = 89 - pitch;
+	if (cl.viewangles[PITCH] + pitch < -89)
+		cl.viewangles[PITCH] = -89 - pitch;
+}
+
+/*
+==============
+CL_FinishMove
+==============
+*/
+void CL_FinishMove (usercmd_t *cmd)
+{
+	int		ms;
+	int		i;
+
+//
+// figure button bits
+//	
+	if ( in_attack.state & 3 )
+		cmd->buttons |= BUTTON_ATTACK;
+	in_attack.state &= ~2;
+	
+	if (in_use.state & 3)
+		cmd->buttons |= BUTTON_USE;
+	in_use.state &= ~2;
+
+	if (anykeydown && cls.key_dest == key_game)
+		cmd->buttons |= BUTTON_ANY;
+
+	// send milliseconds of time to apply the move
+	ms = cls.frametime * 1000;
+	if (ms > 250)
+		ms = 100;		// time was unreasonable
+	cmd->msec = ms;
+
+	CL_ClampPitch ();
+	for (i=0 ; i<3 ; i++)
+		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
+
+	cmd->impulse = in_impulse;
+	in_impulse = 0;
+
+// send the ambient light level at the player's current position
+	cmd->lightlevel = (byte)cl_lightlevel->value;
+}
+
+/*
+=================
+CL_CreateCmd
+=================
+*/
+usercmd_t CL_CreateCmd (void)
+{
+	usercmd_t	cmd;
+
+	frame_msec = sys_frame_time - old_sys_frame_time;
+	if (frame_msec < 1)
+		frame_msec = 1;
+	if (frame_msec > 200)
+		frame_msec = 200;
+	
+	// get basic movement from keyboard
+	CL_BaseMove (&cmd);
+
+	// allow mice or other external controllers to add to the move
+	IN_Move (&cmd);
+
+	CL_FinishMove (&cmd);
+
+	old_sys_frame_time = sys_frame_time;
+
+//cmd.impulse = cls.framecount;
+
+	return cmd;
+}
+
+
+void IN_CenterView (void)
+{
+	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+}
+
+/*
+============
+CL_InitInput
+============
+*/
+void CL_InitInput (void)
+{
+	Cmd_AddCommand ("centerview",IN_CenterView);
+
+	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 ("impulse", IN_Impulse);
+	Cmd_AddCommand ("+klook", IN_KLookDown);
+	Cmd_AddCommand ("-klook", IN_KLookUp);
+
+	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
+}
+
+
+
+/*
+=================
+CL_SendCmd
+=================
+*/
+void CL_SendCmd (void)
+{
+	sizebuf_t	buf;
+	byte		data[128];
+	int			i;
+	usercmd_t	*cmd, *oldcmd;
+	usercmd_t	nullcmd;
+	int			checksumIndex;
+
+	// build a command even if not connected
+
+	// save this command off for prediction
+	i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	cl.cmd_time[i] = cls.realtime;	// for netgraph ping calculation
+
+	*cmd = CL_CreateCmd ();
+
+	cl.cmd = *cmd;
+
+	if (cls.state == ca_disconnected || cls.state == ca_connecting)
+		return;
+
+	if ( cls.state == ca_connected)
+	{
+		if (cls.netchan.message.cursize	|| curtime - cls.netchan.last_sent > 1000 )
+			Netchan_Transmit (&cls.netchan, 0, buf.data);	
+		return;
+	}
+
+	// send a userinfo update if needed
+	if (userinfo_modified)
+	{
+		CL_FixUpGender();
+		userinfo_modified = false;
+		MSG_WriteByte (&cls.netchan.message, clc_userinfo);
+		MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
+	}
+
+	SZ_Init (&buf, data, sizeof(data));
+
+	if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop 
+		&& cls.realtime - cl.cinematictime > 1000)
+	{	// skip the rest of the cinematic
+		SCR_FinishCinematic ();
+	}
+
+	// begin a client move command
+	MSG_WriteByte (&buf, clc_move);
+
+	// save the position for a checksum byte
+	checksumIndex = buf.cursize;
+	MSG_WriteByte (&buf, 0);
+
+	// let the server know what the last frame we
+	// got was, so the next message can be delta compressed
+	if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
+		MSG_WriteLong (&buf, -1);	// no compression
+	else
+		MSG_WriteLong (&buf, cl.frame.serverframe);
+
+	// send this and the previous cmds in the message, so
+	// if the last packet was dropped, it can be recovered
+	i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	memset (&nullcmd, 0, sizeof(nullcmd));
+	MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
+	oldcmd = cmd;
+
+	i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+	oldcmd = cmd;
+
+	i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
+	cmd = &cl.cmds[i];
+	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,
+		cls.netchan.outgoing_sequence);
+
+	//
+	// deliver the message
+	//
+	Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);	
+}
+
+
--- /dev/null
+++ b/client/cl_inv.c
@@ -1,0 +1,142 @@
+/*
+Copyright (C) 1997-2001 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_inv.c -- client inventory screen
+
+#include "client.h"
+
+/*
+================
+CL_ParseInventory
+================
+*/
+void CL_ParseInventory (void)
+{
+	int		i;
+
+	for (i=0 ; i<MAX_ITEMS ; i++)
+		cl.inventory[i] = MSG_ReadShort (&net_message);
+}
+
+
+/*
+================
+Inv_DrawString
+================
+*/
+void Inv_DrawString (int x, int y, char *string)
+{
+	while (*string)
+	{
+		re.DrawChar (x, y, *string);
+		x+=8;
+		string++;
+	}
+}
+
+void SetStringHighBit (char *s)
+{
+	while (*s)
+		*s++ |= 128;
+}
+
+/*
+================
+CL_DrawInventory
+================
+*/
+#define	DISPLAY_ITEMS	17
+
+void CL_DrawInventory (void)
+{
+	int		i, j;
+	int		num, selected_num, item;
+	int		index[MAX_ITEMS];
+	char	string[1024];
+	int		x, y;
+	char	binding[1024];
+	char	*bind;
+	int		selected;
+	int		top;
+
+	selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
+
+	num = 0;
+	selected_num = 0;
+	for (i=0 ; i<MAX_ITEMS ; i++)
+	{
+		if (i==selected)
+			selected_num = num;
+		if (cl.inventory[i])
+		{
+			index[num] = i;
+			num++;
+		}
+	}
+
+	// determine scroll point
+	top = selected_num - DISPLAY_ITEMS/2;
+	if (num - top < DISPLAY_ITEMS)
+		top = num - DISPLAY_ITEMS;
+	if (top < 0)
+		top = 0;
+
+	x = (viddef.width-256)/2;
+	y = (viddef.height-240)/2;
+
+	// repaint everything next frame
+	SCR_DirtyScreen ();
+
+	re.DrawPic (x, y+8, "inventory");
+
+	y += 24;
+	x += 24;
+	Inv_DrawString (x, y, "hotkey ### item");
+	Inv_DrawString (x, y+8, "------ --- ----");
+	y += 16;
+	for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
+	{
+		item = index[i];
+		// search for a binding
+		Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
+		bind = "";
+		for (j=0 ; j<256 ; j++)
+			if (keybindings[j] && !Q_stricmp (keybindings[j], binding))
+			{
+				bind = Key_KeynumToString(j);
+				break;
+			}
+
+		Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
+			cl.configstrings[CS_ITEMS+item] );
+		if (item != selected)
+			SetStringHighBit (string);
+		else	// draw a blinky cursor by the selected item
+		{
+			if ( (int)(cls.realtime*10) & 1)
+				re.DrawChar (x-8, y, 15);
+		}
+		Inv_DrawString (x, y, string);
+		y += 8;
+	}
+
+
+}
+
+
--- /dev/null
+++ b/client/cl_main.c
@@ -1,0 +1,1844 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+
+cvar_t	*freelook;
+
+cvar_t	*adr0;
+cvar_t	*adr1;
+cvar_t	*adr2;
+cvar_t	*adr3;
+cvar_t	*adr4;
+cvar_t	*adr5;
+cvar_t	*adr6;
+cvar_t	*adr7;
+cvar_t	*adr8;
+
+cvar_t	*cl_stereo_separation;
+cvar_t	*cl_stereo;
+
+cvar_t	*rcon_client_password;
+cvar_t	*rcon_address;
+
+cvar_t	*cl_noskins;
+cvar_t	*cl_autoskins;
+cvar_t	*cl_footsteps;
+cvar_t	*cl_timeout;
+cvar_t	*cl_predict;
+//cvar_t	*cl_minfps;
+cvar_t	*cl_maxfps;
+cvar_t	*cl_gun;
+
+cvar_t	*cl_add_particles;
+cvar_t	*cl_add_lights;
+cvar_t	*cl_add_entities;
+cvar_t	*cl_add_blend;
+
+cvar_t	*cl_shownet;
+cvar_t	*cl_showmiss;
+cvar_t	*cl_showclamp;
+
+cvar_t	*cl_paused;
+cvar_t	*cl_timedemo;
+
+cvar_t	*lookspring;
+cvar_t	*lookstrafe;
+cvar_t	*sensitivity;
+
+cvar_t	*m_pitch;
+cvar_t	*m_yaw;
+cvar_t	*m_forward;
+cvar_t	*m_side;
+
+cvar_t	*cl_lightlevel;
+
+//
+// userinfo
+//
+cvar_t	*info_password;
+cvar_t	*info_spectator;
+cvar_t	*name;
+cvar_t	*skin;
+cvar_t	*rate;
+cvar_t	*fov;
+cvar_t	*msg;
+cvar_t	*hand;
+cvar_t	*gender;
+cvar_t	*gender_auto;
+
+cvar_t	*cl_vwep;
+
+client_static_t	cls;
+client_state_t	cl;
+
+centity_t		cl_entities[MAX_EDICTS];
+
+entity_state_t	cl_parse_entities[MAX_PARSE_ENTITIES];
+
+extern	cvar_t *allow_download;
+extern	cvar_t *allow_download_players;
+extern	cvar_t *allow_download_models;
+extern	cvar_t *allow_download_sounds;
+extern	cvar_t *allow_download_maps;
+
+//======================================================================
+
+
+/*
+====================
+CL_WriteDemoMessage
+
+Dumps the current net message, prefixed by the length
+====================
+*/
+void CL_WriteDemoMessage (void)
+{
+	int		len, swlen;
+
+	// the first eight bytes are just packet sequencing stuff
+	len = net_message.cursize-8;
+	swlen = LittleLong(len);
+	fwrite (&swlen, 4, 1, cls.demofile);
+	fwrite (net_message.data+8,	len, 1, cls.demofile);
+}
+
+
+/*
+====================
+CL_Stop_f
+
+stop recording a demo
+====================
+*/
+void CL_Stop_f (void)
+{
+	int		len;
+
+	if (!cls.demorecording)
+	{
+		Com_Printf ("Not recording a demo.\n");
+		return;
+	}
+
+// finish up
+	len = -1;
+	fwrite (&len, 4, 1, cls.demofile);
+	fclose (cls.demofile);
+	cls.demofile = NULL;
+	cls.demorecording = false;
+	Com_Printf ("Stopped demo.\n");
+}
+
+/*
+====================
+CL_Record_f
+
+record <demoname>
+
+Begins recording a demo from the current position
+====================
+*/
+void CL_Record_f (void)
+{
+	char	name[MAX_OSPATH];
+	char	buf_data[MAX_MSGLEN];
+	sizebuf_t	buf;
+	int		i;
+	int		len;
+	entity_state_t	*ent;
+	entity_state_t	nullstate;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("record <demoname>\n");
+		return;
+	}
+
+	if (cls.demorecording)
+	{
+		Com_Printf ("Already recording.\n");
+		return;
+	}
+
+	if (cls.state != ca_active)
+	{
+		Com_Printf ("You must be in a level to record.\n");
+		return;
+	}
+
+	//
+	// open the demo file
+	//
+	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
+
+	Com_Printf ("recording to %s.\n", name);
+	FS_CreatePath (name);
+	cls.demofile = fopen (name, "wb");
+	if (!cls.demofile)
+	{
+		Com_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+	cls.demorecording = true;
+
+	// don't start saving messages until a non-delta compressed message is received
+	cls.demowaiting = true;
+
+	//
+	// write out messages to hold the startup information
+	//
+	SZ_Init (&buf, buf_data, sizeof(buf_data));
+
+	// send the serverdata
+	MSG_WriteByte (&buf, svc_serverdata);
+	MSG_WriteLong (&buf, PROTOCOL_VERSION);
+	MSG_WriteLong (&buf, 0x10000 + cl.servercount);
+	MSG_WriteByte (&buf, 1);	// demos are always attract loops
+	MSG_WriteString (&buf, cl.gamedir);
+	MSG_WriteShort (&buf, cl.playernum);
+
+	MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
+
+	// configstrings
+	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+	{
+		if (cl.configstrings[i][0])
+		{
+			if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
+			{	// write it out
+				len = LittleLong (buf.cursize);
+				fwrite (&len, 4, 1, cls.demofile);
+				fwrite (buf.data, buf.cursize, 1, cls.demofile);
+				buf.cursize = 0;
+			}
+
+			MSG_WriteByte (&buf, svc_configstring);
+			MSG_WriteShort (&buf, i);
+			MSG_WriteString (&buf, cl.configstrings[i]);
+		}
+
+	}
+
+	// baselines
+	memset (&nullstate, 0, sizeof(nullstate));
+	for (i=0; i<MAX_EDICTS ; i++)
+	{
+		ent = &cl_entities[i].baseline;
+		if (!ent->modelindex)
+			continue;
+
+		if (buf.cursize + 64 > buf.maxsize)
+		{	// write it out
+			len = LittleLong (buf.cursize);
+			fwrite (&len, 4, 1, cls.demofile);
+			fwrite (buf.data, buf.cursize, 1, cls.demofile);
+			buf.cursize = 0;
+		}
+
+		MSG_WriteByte (&buf, svc_spawnbaseline);		
+		MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
+	}
+
+	MSG_WriteByte (&buf, svc_stufftext);
+	MSG_WriteString (&buf, "precache\n");
+
+	// write it to the demo file
+
+	len = LittleLong (buf.cursize);
+	fwrite (&len, 4, 1, cls.demofile);
+	fwrite (buf.data, buf.cursize, 1, cls.demofile);
+
+	// the rest of the demo file will be individual frames
+}
+
+//======================================================================
+
+/*
+===================
+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)
+{
+	char	*cmd;
+
+	cmd = Cmd_Argv(0);
+	if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
+	{
+		Com_Printf ("Unknown command \"%s\"\n", cmd);
+		return;
+	}
+
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	SZ_Print (&cls.netchan.message, cmd);
+	if (Cmd_Argc() > 1)
+	{
+		SZ_Print (&cls.netchan.message, " ");
+		SZ_Print (&cls.netchan.message, Cmd_Args());
+	}
+}
+
+void CL_Setenv_f( void )
+{
+	int argc = Cmd_Argc();
+
+	if ( argc > 2 )
+	{
+		char buffer[1000];
+		int i;
+
+		strcpy( buffer, Cmd_Argv(1) );
+		strcat( buffer, "=" );
+
+		for ( i = 2; i < argc; i++ )
+		{
+			strcat( buffer, Cmd_Argv( i ) );
+			strcat( buffer, " " );
+		}
+
+		putenv( buffer );
+	}
+	else if ( argc == 2 )
+	{
+		char *env = getenv( Cmd_Argv(1) );
+
+		if ( env )
+		{
+			Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
+		}
+		else
+		{
+			Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
+		}
+	}
+}
+
+
+/*
+==================
+CL_ForwardToServer_f
+==================
+*/
+void CL_ForwardToServer_f (void)
+{
+	if (cls.state != ca_connected && cls.state != ca_active)
+	{
+		Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
+		return;
+	}
+	
+	// don't forward the first argument
+	if (Cmd_Argc() > 1)
+	{
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		SZ_Print (&cls.netchan.message, Cmd_Args());
+	}
+}
+
+
+/*
+==================
+CL_Pause_f
+==================
+*/
+void CL_Pause_f (void)
+{
+	// never pause in multiplayer
+	if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
+	{
+		Cvar_SetValue ("paused", 0);
+		return;
+	}
+
+	Cvar_SetValue ("paused", !cl_paused->value);
+}
+
+/*
+==================
+CL_Quit_f
+==================
+*/
+void CL_Quit_f (void)
+{
+	CL_Disconnect ();
+	Com_Quit ();
+}
+
+/*
+================
+CL_Drop
+
+Called after an ERR_DROP was thrown
+================
+*/
+void CL_Drop (void)
+{
+	if (cls.state == ca_uninitialized)
+		return;
+	if (cls.state == ca_disconnected)
+		return;
+
+	CL_Disconnect ();
+
+	// drop loading plaque unless this is the initial game start
+	if (cls.disable_servercount != -1)
+		SCR_EndLoadingPlaque ();	// get rid of loading plaque
+}
+
+
+/*
+=======================
+CL_SendConnectPacket
+
+We have gotten a challenge from the server, so try and
+connect.
+======================
+*/
+void CL_SendConnectPacket (void)
+{
+	netadr_t	adr;
+	int		port;
+
+	if (!NET_StringToAdr (cls.servername, &adr))
+	{
+		Com_Printf ("Bad server address\n");
+		cls.connect_time = 0;
+		return;
+	}
+	if (adr.port == 0)
+		adr.port = BigShort (PORT_SERVER);
+
+	port = Cvar_VariableValue ("qport");
+	userinfo_modified = false;
+
+	Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
+		PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
+}
+
+/*
+=================
+CL_CheckForResend
+
+Resend a connect message if the last one has timed out
+=================
+*/
+void CL_CheckForResend (void)
+{
+	netadr_t	adr;
+
+	// if the local server is running and we aren't
+	// then connect
+	if (cls.state == ca_disconnected && Com_ServerState() )
+	{
+		cls.state = ca_connecting;
+		strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
+		// we don't need a challenge on the localhost
+		CL_SendConnectPacket ();
+		return;
+//		cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
+	}
+
+	// resend if we haven't gotten a reply yet
+	if (cls.state != ca_connecting)
+		return;
+
+	if (cls.realtime - cls.connect_time < 3000)
+		return;
+
+	if (!NET_StringToAdr (cls.servername, &adr))
+	{
+		Com_Printf ("Bad server address\n");
+		cls.state = ca_disconnected;
+		return;
+	}
+	if (adr.port == 0)
+		adr.port = BigShort (PORT_SERVER);
+
+	cls.connect_time = cls.realtime;	// for retransmit requests
+
+	Com_Printf ("Connecting to %s...\n", cls.servername);
+
+	Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
+}
+
+
+/*
+================
+CL_Connect_f
+
+================
+*/
+void CL_Connect_f (void)
+{
+	char	*server;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("usage: connect <server>\n");
+		return;	
+	}
+	
+	if (Com_ServerState ())
+	{	// if running a local server, kill it and reissue
+		SV_Shutdown (va("Server quit\n", msg), false);
+	}
+	else
+	{
+		CL_Disconnect ();
+	}
+
+	server = Cmd_Argv (1);
+
+	NET_Config (true);		// allow remote
+
+	CL_Disconnect ();
+
+	cls.state = ca_connecting;
+	strncpy (cls.servername, server, sizeof(cls.servername)-1);
+	cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
+}
+
+
+/*
+=====================
+CL_Rcon_f
+
+  Send the rest of the command line over as
+  an unconnected command.
+=====================
+*/
+void CL_Rcon_f (void)
+{
+	char	message[1024];
+	int		i;
+	netadr_t	to;
+
+	if (!rcon_client_password->string)
+	{
+		Com_Printf ("You must set 'rcon_password' before\n"
+					"issuing an rcon command.\n");
+		return;
+	}
+
+	message[0] = (char)255;
+	message[1] = (char)255;
+	message[2] = (char)255;
+	message[3] = (char)255;
+	message[4] = 0;
+
+	NET_Config (true);		// allow remote
+
+	strcat (message, "rcon ");
+
+	strcat (message, rcon_client_password->string);
+	strcat (message, " ");
+
+	for (i=1 ; i<Cmd_Argc() ; i++)
+	{
+		strcat (message, Cmd_Argv(i));
+		strcat (message, " ");
+	}
+
+	if (cls.state >= ca_connected)
+		to = cls.netchan.remote_address;
+	else
+	{
+		if (!strlen(rcon_address->string))
+		{
+			Com_Printf ("You must either be connected,\n"
+						"or set the 'rcon_address' cvar\n"
+						"to issue rcon commands\n");
+
+			return;
+		}
+		NET_StringToAdr (rcon_address->string, &to);
+		if (to.port == 0)
+			to.port = BigShort (PORT_SERVER);
+	}
+	
+	NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
+}
+
+
+/*
+=====================
+CL_ClearState
+
+=====================
+*/
+void CL_ClearState (void)
+{
+	S_StopAllSounds ();
+	CL_ClearEffects ();
+	CL_ClearTEnts ();
+
+// wipe the entire cl structure
+	memset (&cl, 0, sizeof(cl));
+	memset (&cl_entities, 0, sizeof(cl_entities));
+
+	SZ_Clear (&cls.netchan.message);
+
+}
+
+/*
+=====================
+CL_Disconnect
+
+Goes from a connected state to full screen console state
+Sends a disconnect message to the server
+This is also called on Com_Error, so it shouldn't cause any errors
+=====================
+*/
+void CL_Disconnect (void)
+{
+	byte	final[32];
+
+	if (cls.state == ca_disconnected)
+		return;
+
+	if (cl_timedemo && cl_timedemo->value)
+	{
+		int	time;
+		
+		time = Sys_Milliseconds () - cl.timedemo_start;
+		if (time > 0)
+			Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
+			time/1000.0, cl.timedemo_frames*1000.0 / time);
+	}
+
+	VectorClear (cl.refdef.blend);
+	re.CinematicSetPalette(NULL);
+
+	M_ForceMenuOff ();
+
+	cls.connect_time = 0;
+
+	SCR_StopCinematic ();
+
+	if (cls.demorecording)
+		CL_Stop_f ();
+
+	// send a disconnect message to the server
+	final[0] = clc_stringcmd;
+	strcpy ((char *)final+1, "disconnect");
+	Netchan_Transmit (&cls.netchan, strlen(final), final);
+	Netchan_Transmit (&cls.netchan, strlen(final), final);
+	Netchan_Transmit (&cls.netchan, strlen(final), final);
+
+	CL_ClearState ();
+
+	// stop download
+	if (cls.download) {
+		fclose(cls.download);
+		cls.download = NULL;
+	}
+
+	cls.state = ca_disconnected;
+}
+
+void CL_Disconnect_f (void)
+{
+	Com_Error (ERR_DROP, "Disconnected from server");
+}
+
+
+/*
+====================
+CL_Packet_f
+
+packet <destination> <contents>
+
+Contents allows \n escape character
+====================
+*/
+void CL_Packet_f (void)
+{
+	char	send[2048];
+	int		i, l;
+	char	*in, *out;
+	netadr_t	adr;
+
+	if (Cmd_Argc() != 3)
+	{
+		Com_Printf ("packet <destination> <contents>\n");
+		return;
+	}
+
+	NET_Config (true);		// allow remote
+
+	if (!NET_StringToAdr (Cmd_Argv(1), &adr))
+	{
+		Com_Printf ("Bad address\n");
+		return;
+	}
+	if (!adr.port)
+		adr.port = BigShort (PORT_SERVER);
+
+	in = Cmd_Argv(2);
+	out = send+4;
+	send[0] = send[1] = send[2] = send[3] = (char)0xff;
+
+	l = strlen (in);
+	for (i=0 ; i<l ; i++)
+	{
+		if (in[i] == '\\' && in[i+1] == 'n')
+		{
+			*out++ = '\n';
+			i++;
+		}
+		else
+			*out++ = in[i];
+	}
+	*out = 0;
+
+	NET_SendPacket (NS_CLIENT, out-send, send, adr);
+}
+
+/*
+=================
+CL_Changing_f
+
+Just sent as a hint to the client that they should
+drop to full console
+=================
+*/
+void CL_Changing_f (void)
+{
+	//ZOID
+	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
+	if (cls.download)
+		return;
+
+	SCR_BeginLoadingPlaque ();
+	cls.state = ca_connected;	// not active anymore, but not disconnected
+	Com_Printf ("\nChanging map...\n");
+}
+
+
+/*
+=================
+CL_Reconnect_f
+
+The server is changing levels
+=================
+*/
+void CL_Reconnect_f (void)
+{
+	//ZOID
+	//if we are downloading, we don't change!  This so we don't suddenly stop downloading a map
+	if (cls.download)
+		return;
+
+	S_StopAllSounds ();
+	if (cls.state == ca_connected) {
+		Com_Printf ("reconnecting...\n");
+		cls.state = ca_connected;
+		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message, "new");		
+		return;
+	}
+
+	if (*cls.servername) {
+		if (cls.state >= ca_connected) {
+			CL_Disconnect();
+			cls.connect_time = cls.realtime - 1500;
+		} else
+			cls.connect_time = -99999; // fire immediately
+
+		cls.state = ca_connecting;
+		Com_Printf ("reconnecting...\n");
+	}
+}
+
+/*
+=================
+CL_ParseStatusMessage
+
+Handle a reply from a ping
+=================
+*/
+void CL_ParseStatusMessage (void)
+{
+	char	*s;
+
+	s = MSG_ReadString(&net_message);
+
+	Com_Printf ("%s\n", s);
+	M_AddToServerList (net_from, s);
+}
+
+
+/*
+=================
+CL_PingServers_f
+=================
+*/
+void CL_PingServers_f (void)
+{
+	int			i;
+	netadr_t	adr;
+	char		name[32];
+	char		*adrstring;
+	cvar_t		*noudp;
+	cvar_t		*noipx;
+
+	NET_Config (true);		// allow remote
+
+	// send a broadcast packet
+	Com_Printf ("pinging broadcast...\n");
+
+	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
+	if (!noudp->value)
+	{
+		adr.type = NA_BROADCAST;
+		adr.port = BigShort(PORT_SERVER);
+		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+	}
+
+	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
+	if (!noipx->value)
+	{
+		adr.type = NA_BROADCAST_IPX;
+		adr.port = BigShort(PORT_SERVER);
+		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+	}
+
+	// send a packet to each address book entry
+	for (i=0 ; i<16 ; i++)
+	{
+		Com_sprintf (name, sizeof(name), "adr%i", i);
+		adrstring = Cvar_VariableString (name);
+		if (!adrstring || !adrstring[0])
+			continue;
+
+		Com_Printf ("pinging %s...\n", adrstring);
+		if (!NET_StringToAdr (adrstring, &adr))
+		{
+			Com_Printf ("Bad address: %s\n", adrstring);
+			continue;
+		}
+		if (!adr.port)
+			adr.port = BigShort(PORT_SERVER);
+		Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+	}
+}
+
+
+/*
+=================
+CL_Skins_f
+
+Load or download any custom player skins and models
+=================
+*/
+void CL_Skins_f (void)
+{
+	int		i;
+
+	for (i=0 ; i<MAX_CLIENTS ; i++)
+	{
+		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+			continue;
+		Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]); 
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();	// pump message loop
+		CL_ParseClientinfo (i);
+	}
+}
+
+
+/*
+=================
+CL_ConnectionlessPacket
+
+Responses to broadcasts, etc
+=================
+*/
+void CL_ConnectionlessPacket (void)
+{
+	char	*s;
+	char	*c;
+	
+	MSG_BeginReading (&net_message);
+	MSG_ReadLong (&net_message);	// skip the -1
+
+	s = MSG_ReadStringLine (&net_message);
+
+	Cmd_TokenizeString (s, false);
+
+	c = Cmd_Argv(0);
+
+	Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
+
+	// server connection
+	if (!strcmp(c, "client_connect"))
+	{
+		if (cls.state == ca_connected)
+		{
+			Com_Printf ("Dup connect received.  Ignored.\n");
+			return;
+		}
+		Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
+		MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message, "new");	
+		cls.state = ca_connected;
+		return;
+	}
+
+	// server responding to a status broadcast
+	if (!strcmp(c, "info"))
+	{
+		CL_ParseStatusMessage ();
+		return;
+	}
+
+	// remote command from gui front end
+	if (!strcmp(c, "cmd"))
+	{
+		if (!NET_IsLocalAddress(net_from))
+		{
+			Com_Printf ("Command packet from remote host.  Ignored.\n");
+			return;
+		}
+		Sys_AppActivate ();
+		s = MSG_ReadString (&net_message);
+		Cbuf_AddText (s);
+		Cbuf_AddText ("\n");
+		return;
+	}
+	// print command from somewhere
+	if (!strcmp(c, "print"))
+	{
+		s = MSG_ReadString (&net_message);
+		Com_Printf ("%s", s);
+		return;
+	}
+
+	// ping from somewhere
+	if (!strcmp(c, "ping"))
+	{
+		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
+		return;
+	}
+
+	// challenge from the server we are connecting to
+	if (!strcmp(c, "challenge"))
+	{
+		cls.challenge = atoi(Cmd_Argv(1));
+		CL_SendConnectPacket ();
+		return;
+	}
+
+	// echo request from server
+	if (!strcmp(c, "echo"))
+	{
+		Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
+		return;
+	}
+
+	Com_Printf ("Unknown command.\n");
+}
+
+
+/*
+=================
+CL_DumpPackets
+
+A vain attempt to help bad TCP stacks that cause problems
+when they overflow
+=================
+*/
+void CL_DumpPackets (void)
+{
+	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+	{
+		Com_Printf ("dumnping a packet\n");
+	}
+}
+
+/*
+=================
+CL_ReadPackets
+=================
+*/
+void CL_ReadPackets (void)
+{
+	while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+	{
+//	Com_Printf ("packet\n");
+		//
+		// remote command packet
+		//
+		if (*(int *)net_message.data == -1)
+		{
+			CL_ConnectionlessPacket ();
+			continue;
+		}
+
+		if (cls.state == ca_disconnected || cls.state == ca_connecting)
+			continue;		// dump it if not connected
+
+		if (net_message.cursize < 8)
+		{
+			Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
+			continue;
+		}
+
+		//
+		// packet from server
+		//
+		if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
+		{
+			Com_DPrintf ("%s:sequenced packet without connection\n"
+				,NET_AdrToString(net_from));
+			continue;
+		}
+		if (!Netchan_Process(&cls.netchan, &net_message))
+			continue;		// wasn't accepted for some reason
+		CL_ParseServerMessage ();
+	}
+
+	//
+	// check timeout
+	//
+	if (cls.state >= ca_connected
+	 && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
+	{
+		if (++cl.timeoutcount > 5)	// timeoutcount saves debugger
+		{
+			Com_Printf ("\nServer connection timed out.\n");
+			CL_Disconnect ();
+			return;
+		}
+	}
+	else
+		cl.timeoutcount = 0;
+	
+}
+
+
+//=============================================================================
+
+/*
+==============
+CL_FixUpGender_f
+==============
+*/
+void CL_FixUpGender(void)
+{
+	char *p;
+	char sk[80];
+
+	if (gender_auto->value) {
+
+		if (gender->modified) {
+			// was set directly, don't override the user
+			gender->modified = false;
+			return;
+		}
+
+		strncpy(sk, skin->string, sizeof(sk) - 1);
+		if ((p = strchr(sk, '/')) != NULL)
+			*p = 0;
+		if (Q_stricmp(sk, "male") == 0 || Q_stricmp(sk, "cyborg") == 0)
+			Cvar_Set ("gender", "male");
+		else if (Q_stricmp(sk, "female") == 0 || Q_stricmp(sk, "crackhor") == 0)
+			Cvar_Set ("gender", "female");
+		else
+			Cvar_Set ("gender", "none");
+		gender->modified = false;
+	}
+}
+
+/*
+==============
+CL_Userinfo_f
+==============
+*/
+void CL_Userinfo_f (void)
+{
+	Com_Printf ("User info settings:\n");
+	Info_Print (Cvar_Userinfo());
+}
+
+/*
+=================
+CL_Snd_Restart_f
+
+Restart the sound subsystem so it can pick up
+new parameters and flush all sounds
+=================
+*/
+void CL_Snd_Restart_f (void)
+{
+	S_Shutdown ();
+	S_Init ();
+	CL_RegisterSounds ();
+}
+
+int precache_check; // for autodownload of precache items
+int precache_spawncount;
+int precache_tex;
+int precache_model_skin;
+
+byte *precache_model; // used for skin checking in alias models
+
+#define PLAYER_MULT 5
+
+// ENV_CNT is map load, ENV_CNT+1 is first env map
+#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
+#define TEXTURE_CNT (ENV_CNT+13)
+
+static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+
+void CL_RequestNextDownload (void)
+{
+	unsigned	map_checksum;		// for detecting cheater maps
+	char fn[MAX_OSPATH];
+	dmdl_t *pheader;
+
+	if (cls.state != ca_connected)
+		return;
+
+	if (!allow_download->value && precache_check < ENV_CNT)
+		precache_check = ENV_CNT;
+
+//ZOID
+	if (precache_check == CS_MODELS) { // confirm map
+		precache_check = CS_MODELS+2; // 0 isn't used
+		if (allow_download_maps->value)
+			if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
+				return; // started a download
+	}
+	if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
+		if (allow_download_models->value) {
+			while (precache_check < CS_MODELS+MAX_MODELS &&
+				cl.configstrings[precache_check][0]) {
+				if (cl.configstrings[precache_check][0] == '*' ||
+					cl.configstrings[precache_check][0] == '#') {
+					precache_check++;
+					continue;
+				}
+				if (precache_model_skin == 0) {
+					if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
+						precache_model_skin = 1;
+						return; // started a download
+					}
+					precache_model_skin = 1;
+				}
+
+				// checking for skins in the model
+				if (!precache_model) {
+
+					FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
+					if (!precache_model) {
+						precache_model_skin = 0;
+						precache_check++;
+						continue; // couldn't load it
+					}
+					if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
+						// not an alias model
+						FS_FreeFile(precache_model);
+						precache_model = 0;
+						precache_model_skin = 0;
+						precache_check++;
+						continue;
+					}
+					pheader = (dmdl_t *)precache_model;
+					if (LittleLong (pheader->version) != ALIAS_VERSION) {
+						precache_check++;
+						precache_model_skin = 0;
+						continue; // couldn't load it
+					}
+				}
+
+				pheader = (dmdl_t *)precache_model;
+
+				while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
+					if (!CL_CheckOrDownloadFile((char *)precache_model +
+						LittleLong(pheader->ofs_skins) + 
+						(precache_model_skin - 1)*MAX_SKINNAME)) {
+						precache_model_skin++;
+						return; // started a download
+					}
+					precache_model_skin++;
+				}
+				if (precache_model) { 
+					FS_FreeFile(precache_model);
+					precache_model = 0;
+				}
+				precache_model_skin = 0;
+				precache_check++;
+			}
+		}
+		precache_check = CS_SOUNDS;
+	}
+	if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) { 
+		if (allow_download_sounds->value) {
+			if (precache_check == CS_SOUNDS)
+				precache_check++; // zero is blank
+			while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
+				cl.configstrings[precache_check][0]) {
+				if (cl.configstrings[precache_check][0] == '*') {
+					precache_check++;
+					continue;
+				}
+				Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
+				if (!CL_CheckOrDownloadFile(fn))
+					return; // started a download
+			}
+		}
+		precache_check = CS_IMAGES;
+	}
+	if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
+		if (precache_check == CS_IMAGES)
+			precache_check++; // zero is blank
+		while (precache_check < CS_IMAGES+MAX_IMAGES &&
+			cl.configstrings[precache_check][0]) {
+			Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
+			if (!CL_CheckOrDownloadFile(fn))
+				return; // started a download
+		}
+		precache_check = CS_PLAYERSKINS;
+	}
+	// skins are special, since a player has three things to download:
+	// model, weapon model and skin
+	// so precache_check is now *3
+	if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+		if (allow_download_players->value) {
+			while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+				int i, n;
+				char model[MAX_QPATH], skin[MAX_QPATH], *p;
+
+				i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
+				n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
+
+				if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
+					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+					continue;
+				}
+
+				if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
+					p++;
+				else
+					p = cl.configstrings[CS_PLAYERSKINS+i];
+				strcpy(model, p);
+				p = strchr(model, '/');
+				if (!p)
+					p = strchr(model, '\\');
+				if (p) {
+					*p++ = 0;
+					strcpy(skin, p);
+				} else
+					*skin = 0;
+
+				switch (n) {
+				case 0: // model
+					Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
+						return; // started a download
+					}
+					n++;
+					/*FALL THROUGH*/
+
+				case 1: // weapon model
+					Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
+						return; // started a download
+					}
+					n++;
+					/*FALL THROUGH*/
+
+				case 2: // weapon skin
+					Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
+						return; // started a download
+					}
+					n++;
+					/*FALL THROUGH*/
+
+				case 3: // skin
+					Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
+						return; // started a download
+					}
+					n++;
+					/*FALL THROUGH*/
+
+				case 4: // skin_i
+					Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
+					if (!CL_CheckOrDownloadFile(fn)) {
+						precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
+						return; // started a download
+					}
+					// move on to next model
+					precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+				}
+			}
+		}
+		// precache phase completed
+		precache_check = ENV_CNT;
+	}
+
+	if (precache_check == ENV_CNT) {
+		precache_check = ENV_CNT + 1;
+
+		CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+
+		if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
+			Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
+				map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
+			return;
+		}
+	}
+
+	if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
+		if (allow_download->value && allow_download_maps->value) {
+			while (precache_check < TEXTURE_CNT) {
+				int n = precache_check++ - ENV_CNT - 1;
+
+				if (n & 1)
+					Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx", 
+						cl.configstrings[CS_SKY], env_suf[n/2]);
+				else
+					Com_sprintf(fn, sizeof(fn), "env/%s%s.tga", 
+						cl.configstrings[CS_SKY], env_suf[n/2]);
+				if (!CL_CheckOrDownloadFile(fn))
+					return; // started a download
+			}
+		}
+		precache_check = TEXTURE_CNT;
+	}
+
+	if (precache_check == TEXTURE_CNT) {
+		precache_check = TEXTURE_CNT+1;
+		precache_tex = 0;
+	}
+
+	// confirm existance of textures, download any that don't exist
+	if (precache_check == TEXTURE_CNT+1) {
+		// from qcommon/cmodel.c
+		extern int			numtexinfo;
+		extern mapsurface_t	map_surfaces[];
+
+		if (allow_download->value && allow_download_maps->value) {
+			while (precache_tex < numtexinfo) {
+				char fn[MAX_OSPATH];
+
+				sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
+				if (!CL_CheckOrDownloadFile(fn))
+					return; // started a download
+			}
+		}
+		precache_check = TEXTURE_CNT+999;
+	}
+
+//ZOID
+	CL_RegisterSounds ();
+	CL_PrepRefresh ();
+
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
+}
+
+/*
+=================
+CL_Precache_f
+
+The server will send this command right
+before allowing the client into the server
+=================
+*/
+void CL_Precache_f (void)
+{
+	//Yet another hack to let old demos work
+	//the old precache sequence
+	if (Cmd_Argc() < 2) {
+		unsigned	map_checksum;		// for detecting cheater maps
+
+		CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+		CL_RegisterSounds ();
+		CL_PrepRefresh ();
+		return;
+	}
+
+	precache_check = CS_MODELS;
+	precache_spawncount = atoi(Cmd_Argv(1));
+	precache_model = 0;
+	precache_model_skin = 0;
+
+	CL_RequestNextDownload();
+}
+
+
+/*
+=================
+CL_InitLocal
+=================
+*/
+void CL_InitLocal (void)
+{
+	cls.state = ca_disconnected;
+	cls.realtime = Sys_Milliseconds ();
+
+	CL_InitInput ();
+
+	adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
+	adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
+	adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
+	adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
+	adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
+	adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
+	adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
+	adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
+	adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
+
+//
+// register our variables
+//
+	cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
+	cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
+
+	cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
+	cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
+	cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
+	cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
+	cl_gun = Cvar_Get ("cl_gun", "1", 0);
+	cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
+	cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
+	cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
+	cl_predict = Cvar_Get ("cl_predict", "1", 0);
+//	cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
+	cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
+
+	cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
+	cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
+	cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
+	cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
+	cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
+	cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
+
+	cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
+	freelook = Cvar_Get( "freelook", "0", CVAR_ARCHIVE );
+	lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE);
+	lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE);
+	sensitivity = Cvar_Get ("sensitivity", "3", CVAR_ARCHIVE);
+
+	m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
+	m_yaw = Cvar_Get ("m_yaw", "0.022", 0);
+	m_forward = Cvar_Get ("m_forward", "1", 0);
+	m_side = Cvar_Get ("m_side", "1", 0);
+
+	cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
+	cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
+	cl_showclamp = Cvar_Get ("showclamp", "0", 0);
+	cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
+	cl_paused = Cvar_Get ("paused", "0", 0);
+	cl_timedemo = Cvar_Get ("timedemo", "0", 0);
+
+	rcon_client_password = Cvar_Get ("rcon_password", "", 0);
+	rcon_address = Cvar_Get ("rcon_address", "", 0);
+
+	cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
+
+	//
+	// userinfo
+	//
+	info_password = Cvar_Get ("password", "", CVAR_USERINFO);
+	info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
+	name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
+	skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
+	rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE);	// FIXME
+	msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+	hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+	fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
+	gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
+	gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
+	gender->modified = false; // clear this so we know when user sets it manually
+
+	cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
+
+
+	//
+	// register our commands
+	//
+	Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
+	Cmd_AddCommand ("pause", CL_Pause_f);
+	Cmd_AddCommand ("pingservers", CL_PingServers_f);
+	Cmd_AddCommand ("skins", CL_Skins_f);
+
+	Cmd_AddCommand ("userinfo", CL_Userinfo_f);
+	Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
+
+	Cmd_AddCommand ("changing", CL_Changing_f);
+	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
+	Cmd_AddCommand ("record", CL_Record_f);
+	Cmd_AddCommand ("stop", CL_Stop_f);
+
+	Cmd_AddCommand ("quit", CL_Quit_f);
+
+	Cmd_AddCommand ("connect", CL_Connect_f);
+	Cmd_AddCommand ("reconnect", CL_Reconnect_f);
+
+	Cmd_AddCommand ("rcon", CL_Rcon_f);
+
+// 	Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
+
+	Cmd_AddCommand ("setenv", CL_Setenv_f );
+
+	Cmd_AddCommand ("precache", CL_Precache_f);
+
+	Cmd_AddCommand ("download", CL_Download_f);
+
+	//
+	// forward to server commands
+	//
+	// the only thing this does is allow command completion
+	// to work -- all unknown commands are automatically
+	// forwarded to the server
+	Cmd_AddCommand ("wave", NULL);
+	Cmd_AddCommand ("inven", NULL);
+	Cmd_AddCommand ("kill", NULL);
+	Cmd_AddCommand ("use", NULL);
+	Cmd_AddCommand ("drop", NULL);
+	Cmd_AddCommand ("say", NULL);
+	Cmd_AddCommand ("say_team", NULL);
+	Cmd_AddCommand ("info", NULL);
+	Cmd_AddCommand ("prog", NULL);
+	Cmd_AddCommand ("give", NULL);
+	Cmd_AddCommand ("god", NULL);
+	Cmd_AddCommand ("notarget", NULL);
+	Cmd_AddCommand ("noclip", NULL);
+	Cmd_AddCommand ("invuse", NULL);
+	Cmd_AddCommand ("invprev", NULL);
+	Cmd_AddCommand ("invnext", NULL);
+	Cmd_AddCommand ("invdrop", NULL);
+	Cmd_AddCommand ("weapnext", NULL);
+	Cmd_AddCommand ("weapprev", NULL);
+}
+
+
+
+/*
+===============
+CL_WriteConfiguration
+
+Writes key bindings and archived cvars to config.cfg
+===============
+*/
+void CL_WriteConfiguration (void)
+{
+	FILE	*f;
+	char	path[MAX_QPATH];
+
+	if (cls.state == ca_uninitialized)
+		return;
+
+	Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
+	f = fopen (path, "w");
+	if (!f)
+	{
+		Com_Printf ("Couldn't write config.cfg.\n");
+		return;
+	}
+
+	fprintf (f, "// generated by quake, do not modify\n");
+	Key_WriteBindings (f);
+	fclose (f);
+
+	Cvar_WriteVariables (path);
+}
+
+
+/*
+==================
+CL_FixCvarCheats
+
+==================
+*/
+
+typedef struct
+{
+	char	*name;
+	char	*value;
+	cvar_t	*var;
+} cheatvar_t;
+
+cheatvar_t	cheatvars[] = {
+	{"timescale", "1"},
+	{"timedemo", "0"},
+	{"r_drawworld", "1"},
+	{"cl_testlights", "0"},
+	{"r_fullbright", "0"},
+	{"r_drawflat", "0"},
+	{"paused", "0"},
+	{"fixedtime", "0"},
+	{"sw_draworder", "0"},
+	{"gl_lightmap", "0"},
+	{"gl_saturatelighting", "0"},
+	{NULL, NULL}
+};
+
+int		numcheatvars;
+
+void CL_FixCvarCheats (void)
+{
+	int			i;
+	cheatvar_t	*var;
+
+	if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1") 
+		|| !cl.configstrings[CS_MAXCLIENTS][0] )
+		return;		// single player can cheat
+
+	// find all the cvars if we haven't done it yet
+	if (!numcheatvars)
+	{
+		while (cheatvars[numcheatvars].name)
+		{
+			cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
+					cheatvars[numcheatvars].value, 0);
+			numcheatvars++;
+		}
+	}
+
+	// make sure they are all set to the proper values
+	for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
+	{
+		if ( strcmp (var->var->string, var->value) )
+		{
+			Cvar_Set (var->name, var->value);
+		}
+	}
+}
+
+//============================================================================
+
+/*
+==================
+CL_SendCommand
+
+==================
+*/
+void CL_SendCommand (void)
+{
+	// get new key events
+	Sys_SendKeyEvents ();
+
+	// allow mice or other external controllers to add commands
+	IN_Commands ();
+
+	// process console commands
+	Cbuf_Execute ();
+
+	// fix any cheating cvars
+	CL_FixCvarCheats ();
+
+	// send intentions now
+	CL_SendCmd ();
+
+	// resend a connection request if necessary
+	CL_CheckForResend ();
+}
+
+
+/*
+==================
+CL_Frame
+
+==================
+*/
+void CL_Frame (int msec)
+{
+	static int	extratime;
+	static int  lasttimecalled;
+
+	if (dedicated->value)
+		return;
+
+	extratime += msec;
+
+	if (!cl_timedemo->value)
+	{
+		if (cls.state == ca_connected && extratime < 100)
+			return;			// don't flood packets out while connecting
+		if (extratime < 1000/cl_maxfps->value)
+			return;			// framerate is too high
+	}
+
+	// let the mouse activate or deactivate
+	IN_Frame ();
+
+	// decide the simulation time
+	cls.frametime = extratime/1000.0;
+	cl.time += extratime;
+	cls.realtime = curtime;
+
+	extratime = 0;
+#if 0
+	if (cls.frametime > (1.0 / cl_minfps->value))
+		cls.frametime = (1.0 / cl_minfps->value);
+#else
+	if (cls.frametime > (1.0 / 5))
+		cls.frametime = (1.0 / 5);
+#endif
+
+	// if in the debugger last frame, don't timeout
+	if (msec > 5000)
+		cls.netchan.last_received = Sys_Milliseconds ();
+
+	// fetch results from server
+	CL_ReadPackets ();
+
+	// send a new command message to the server
+	CL_SendCommand ();
+
+	// predict all unacknowledged movements
+	CL_PredictMovement ();
+
+	// allow rendering DLL change
+	VID_CheckChanges ();
+	if (!cl.refresh_prepped && cls.state == ca_active)
+		CL_PrepRefresh ();
+
+	// update the screen
+	if (host_speeds->value)
+		time_before_ref = Sys_Milliseconds ();
+	SCR_UpdateScreen ();
+	if (host_speeds->value)
+		time_after_ref = Sys_Milliseconds ();
+
+	// update audio
+	S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
+	
+	CDAudio_Update();
+
+	// advance local effects for next frame
+	CL_RunDLights ();
+	CL_RunLightStyles ();
+	SCR_RunCinematic ();
+	SCR_RunConsole ();
+
+	cls.framecount++;
+
+	if ( log_stats->value )
+	{
+		if ( cls.state == ca_active )
+		{
+			if ( !lasttimecalled )
+			{
+				lasttimecalled = Sys_Milliseconds();
+				if ( log_stats_file )
+					fprintf( log_stats_file, "0\n" );
+			}
+			else
+			{
+				int now = Sys_Milliseconds();
+
+				if ( log_stats_file )
+					fprintf( log_stats_file, "%d\n", now - lasttimecalled );
+				lasttimecalled = now;
+			}
+		}
+	}
+}
+
+
+//============================================================================
+
+/*
+====================
+CL_Init
+====================
+*/
+void CL_Init (void)
+{
+	if (dedicated->value)
+		return;		// nothing running on the client
+
+	// all archived variables will now be loaded
+
+	Con_Init ();	
+#if defined __linux__ || defined __sgi
+	S_Init ();	
+	VID_Init ();
+#else
+	VID_Init ();
+	S_Init ();	// sound must be initialized after window is created
+#endif
+	
+	V_Init ();
+	
+	net_message.data = net_message_buffer;
+	net_message.maxsize = sizeof(net_message_buffer);
+
+	M_Init ();	
+	
+	SCR_Init ();
+	cls.disable_screen = true;	// don't draw yet
+
+	CDAudio_Init ();
+	CL_InitLocal ();
+	IN_Init ();
+
+//	Cbuf_AddText ("exec autoexec.cfg\n");
+	FS_ExecAutoexec ();
+	Cbuf_Execute ();
+
+}
+
+
+/*
+===============
+CL_Shutdown
+
+FIXME: this is a callback from Sys_Quit and Com_Error.  It would be better
+to run quit through here before the final handoff to the sys code.
+===============
+*/
+void CL_Shutdown(void)
+{
+	static qboolean isdown = false;
+	
+	if (isdown)
+	{
+		printf ("recursive shutdown\n");
+		return;
+	}
+	isdown = true;
+
+	CL_WriteConfiguration (); 
+
+	CDAudio_Shutdown ();
+	S_Shutdown();
+	IN_Shutdown ();
+	VID_Shutdown();
+}
+
+
--- /dev/null
+++ b/client/cl_newfx.c
@@ -1,0 +1,1323 @@
+/*
+Copyright (C) 1997-2001 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_newfx.c -- MORE entity effects parsing and management
+
+#include "client.h"
+
+extern cparticle_t	*active_particles, *free_particles;
+extern cparticle_t	particles[MAX_PARTICLES];
+extern int			cl_numparticles;
+extern cvar_t		*vid_ref;
+
+extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
+
+
+/*
+======
+vectoangles2 - this is duplicated in the game DLL, but I need it here.
+======
+*/
+void vectoangles2 (vec3_t value1, vec3_t angles)
+{
+	float	forward;
+	float	yaw, pitch;
+	
+	if (value1[1] == 0 && value1[0] == 0)
+	{
+		yaw = 0;
+		if (value1[2] > 0)
+			pitch = 90;
+		else
+			pitch = 270;
+	}
+	else
+	{
+	// PMM - fixed to correct for pitch of 0
+		if (value1[0])
+			yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
+		else if (value1[1] > 0)
+			yaw = 90;
+		else
+			yaw = 270;
+
+		if (yaw < 0)
+			yaw += 360;
+
+		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
+		pitch = (atan2(value1[2], forward) * 180 / M_PI);
+		if (pitch < 0)
+			pitch += 360;
+	}
+
+	angles[PITCH] = -pitch;
+	angles[YAW] = yaw;
+	angles[ROLL] = 0;
+}
+
+//=============
+//=============
+void CL_Flashlight (int ent, vec3_t pos)
+{
+	cdlight_t	*dl;
+
+	dl = CL_AllocDlight (ent);
+	VectorCopy (pos,  dl->origin);
+	dl->radius = 400;
+	dl->minlight = 250;
+	dl->die = cl.time + 100;
+	dl->color[0] = 1;
+	dl->color[1] = 1;
+	dl->color[2] = 1;
+}
+
+/*
+======
+CL_ColorFlash - flash of light
+======
+*/
+void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
+{
+	cdlight_t	*dl;
+
+	if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
+	{
+		intensity = -intensity;
+		r = -r;
+		g = -g;
+		b = -b;
+	}
+
+	dl = CL_AllocDlight (ent);
+	VectorCopy (pos,  dl->origin);
+	dl->radius = intensity;
+	dl->minlight = 250;
+	dl->die = cl.time + 100;
+	dl->color[0] = r;
+	dl->color[1] = g;
+	dl->color[2] = b;
+}
+
+
+/*
+======
+CL_DebugTrail
+======
+*/
+void CL_DebugTrail (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+//	int			j;
+	cparticle_t	*p;
+	float		dec;
+	vec3_t		right, up;
+//	int			i;
+//	float		d, c, s;
+//	vec3_t		dir;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	MakeNormalVectors (vec, right, up);
+
+//	VectorScale(vec, RT2_SKIP, vec);
+
+//	dec = 1.0;
+//	dec = 0.75;
+	dec = 3;
+	VectorScale (vec, dec, vec);
+	VectorCopy (start, move);
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		VectorClear (p->accel);
+		VectorClear (p->vel);
+		p->alpha = 1.0;
+		p->alphavel = -0.1;
+//		p->alphavel = 0;
+		p->color = 0x74 + (rand()&7);
+		VectorCopy (move, p->org);
+/*
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*2;
+			p->vel[j] = crand()*3;
+			p->accel[j] = 0;
+		}
+*/
+		VectorAdd (move, vec, move);
+	}
+
+}
+
+/*
+===============
+CL_SmokeTrail
+===============
+*/
+void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	VectorScale (vec, spacing, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= spacing;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+frand()*0.5);
+		p->color = colorStart + (rand() % colorRun);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*3;
+			p->accel[j] = 0;
+		}
+		p->vel[2] = 20 + crand()*5;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+void CL_ForceWall (vec3_t start, vec3_t end, int color)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	VectorScale (vec, 4, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= 4;
+
+		if (!free_particles)
+			return;
+		
+		if (frand() > 0.3)
+		{
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			VectorClear (p->accel);
+			
+			p->time = cl.time;
+
+			p->alpha = 1.0;
+			p->alphavel =  -1.0 / (3.0+frand()*0.5);
+			p->color = color;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + crand()*3;
+				p->accel[j] = 0;
+			}
+			p->vel[0] = 0;
+			p->vel[1] = 0;
+			p->vel[2] = -40 - (crand()*10);
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+void CL_FlameEffects (centity_t *ent, vec3_t origin)
+{
+	int			n, count;
+	int			j;
+	cparticle_t	*p;
+
+	count = rand() & 0xF;
+
+	for(n=0;n<count;n++)
+	{
+		if (!free_particles)
+			return;
+			
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		VectorClear (p->accel);
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+frand()*0.2);
+		p->color = 226 + (rand() % 4);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = origin[j] + crand()*5;
+			p->vel[j] = crand()*5;
+		}
+		p->vel[2] = crand() * -10;
+		p->accel[2] = -PARTICLE_GRAVITY;
+	}
+
+	count = rand() & 0x7;
+
+	for(n=0;n<count;n++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+frand()*0.5);
+		p->color = 0 + (rand() % 4);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = origin[j] + crand()*3;
+		}
+		p->vel[2] = 20 + crand()*5;
+	}
+
+}
+
+
+/*
+===============
+CL_GenericParticleEffect
+===============
+*/
+void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		if (numcolors > 1)
+			p->color = color + (rand() & numcolors);
+		else
+			p->color = color;
+
+		d = rand() & dirspread;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = crand()*20;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+//		VectorCopy (accel, p->accel);
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*alphavel);
+//		p->alphavel = alphavel;
+	}
+}
+
+/*
+===============
+CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
+
+===============
+*/
+void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			i, j;
+	cparticle_t	*p;
+	float		dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = dist;
+	VectorScale (vec, dec, vec);
+
+	for (i=0 ; i<len ; i+=dec)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		VectorClear (p->accel);
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (1+frand()*0.1);
+		p->color = 4 + (rand()&7);
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*2;
+			p->vel[j] = crand()*10;
+		}
+		p->org[2] -= 4;
+//		p->vel[2] += 6;
+		p->vel[2] += 20;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+//#define CORKSCREW		1
+//#define DOUBLE_SCREW	1
+#define	RINGS		1
+//#define	SPRAY		1
+
+#ifdef CORKSCREW
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j,k;
+	cparticle_t	*p;
+	vec3_t		right, up;
+	int			i;
+	float		d, c, s;
+	vec3_t		dir;
+	float		ltime;
+	float		step = 5.0;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+//	MakeNormalVectors (vec, right, up);
+	VectorCopy (cl.v_right, right);
+	VectorCopy (cl.v_up, up);
+	VectorMA (move, -1, right, move);
+	VectorMA (move, -1, up, move);
+
+	VectorScale (vec, step, vec);
+	ltime = (float) cl.time/1000.0;
+
+//	for (i=0 ; i<len ; i++)
+	for (i=0 ; i<len ; i+=step)
+	{
+		d = i * 0.1 - fmod(ltime,16.0)*M_PI;
+		c = cos(d)/1.75;
+		s = sin(d)/1.75;
+#ifdef DOUBLE_SCREW		
+		for (k=-1; k<2; k+=2)
+		{
+#else
+		k=1;
+#endif
+			if (!free_particles)
+				return;
+
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			p->time = cl.time;
+			VectorClear (p->accel);
+
+			p->alpha = 0.5;
+	//		p->alphavel = -1.0 / (1+frand()*0.2);
+			// only last one frame!
+			p->alphavel = INSTANT_PARTICLE;
+	//		p->color = 0x74 + (rand()&7);
+//			p->color = 223 - (rand()&7);
+			p->color = 223;
+//			p->color = 240;
+
+			// trim it so it looks like it's starting at the origin
+			if (i < 10)
+			{
+				VectorScale (right, c*(i/10.0)*k, dir);
+				VectorMA (dir, s*(i/10.0)*k, up, dir);
+			}
+			else
+			{
+				VectorScale (right, c*k, dir);
+				VectorMA (dir, s*k, up, dir);
+			}
+			
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + dir[j]*3;
+	//			p->vel[j] = dir[j]*6;
+				p->vel[j] = 0;
+			}
+#ifdef DOUBLE_SCREW
+		}
+#endif
+		VectorAdd (move, vec, move);
+	}
+}
+#endif
+#ifdef RINGS
+//void CL_Heatbeam (vec3_t start, vec3_t end)
+void CL_Heatbeam (vec3_t start, vec3_t forward)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	vec3_t		right, up;
+	int			i;
+	float		c, s;
+	vec3_t		dir;
+	float		ltime;
+	float		step = 32.0, rstep;
+	float		start_pt;
+	float		rot;
+	float		variance;
+	vec3_t		end;
+
+	VectorMA (start, 4096, forward, end);
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	// FIXME - pmm - these might end up using old values?
+//	MakeNormalVectors (vec, right, up);
+	VectorCopy (cl.v_right, right);
+	VectorCopy (cl.v_up, up);
+	if (vidref_val == VIDREF_GL)
+	{ // GL mode
+		VectorMA (move, -0.5, right, move);
+		VectorMA (move, -0.5, up, move);
+	}
+	// otherwise assume SOFT
+
+	ltime = (float) cl.time/1000.0;
+	start_pt = fmod(ltime*96.0,step);
+	VectorMA (move, start_pt, vec, move);
+
+	VectorScale (vec, step, vec);
+
+//	Com_Printf ("%f\n", ltime);
+	rstep = M_PI/10.0;
+	for (i=start_pt ; i<len ; i+=step)
+	{
+		if (i>step*5) // don't bother after the 5th ring
+			break;
+
+		for (rot = 0; rot < M_PI*2; rot += rstep)
+		{
+
+			if (!free_particles)
+				return;
+
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			p->time = cl.time;
+			VectorClear (p->accel);
+//			rot+= fmod(ltime, 12.0)*M_PI;
+//			c = cos(rot)/2.0;
+//			s = sin(rot)/2.0;
+//			variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
+			variance = 0.5;
+			c = cos(rot)*variance;
+			s = sin(rot)*variance;
+			
+			// trim it so it looks like it's starting at the origin
+			if (i < 10)
+			{
+				VectorScale (right, c*(i/10.0), dir);
+				VectorMA (dir, s*(i/10.0), up, dir);
+			}
+			else
+			{
+				VectorScale (right, c, dir);
+				VectorMA (dir, s, up, dir);
+			}
+		
+			p->alpha = 0.5;
+	//		p->alphavel = -1.0 / (1+frand()*0.2);
+			p->alphavel = -1000.0;
+	//		p->color = 0x74 + (rand()&7);
+			p->color = 223 - (rand()&7);
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + dir[j]*3;
+	//			p->vel[j] = dir[j]*6;
+				p->vel[j] = 0;
+			}
+		}
+		VectorAdd (move, vec, move);
+	}
+}
+#endif
+#ifdef SPRAY
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	vec3_t		forward, right, up;
+	int			i;
+	float		d, c, s;
+	vec3_t		dir;
+	float		ltime;
+	float		step = 32.0, rstep;
+	float		start_pt;
+	float		rot;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+//	MakeNormalVectors (vec, right, up);
+	VectorCopy (cl.v_forward, forward);
+	VectorCopy (cl.v_right, right);
+	VectorCopy (cl.v_up, up);
+	VectorMA (move, -0.5, right, move);
+	VectorMA (move, -0.5, up, move);
+
+	for (i=0; i<8; i++)
+	{
+		if (!free_particles)
+			return;
+
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		p->time = cl.time;
+		VectorClear (p->accel);
+		
+		d = crand()*M_PI;
+		c = cos(d)*30;
+		s = sin(d)*30;
+
+		p->alpha = 1.0;
+		p->alphavel = -5.0 / (1+frand());
+		p->color = 223 - (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j];
+		}
+		VectorScale (vec, 450, p->vel);
+		VectorMA (p->vel, c, right, p->vel);
+		VectorMA (p->vel, s, up, p->vel);
+	}
+/*
+
+	ltime = (float) cl.time/1000.0;
+	start_pt = fmod(ltime*16.0,step);
+	VectorMA (move, start_pt, vec, move);
+
+	VectorScale (vec, step, vec);
+
+//	Com_Printf ("%f\n", ltime);
+	rstep = M_PI/12.0;
+	for (i=start_pt ; i<len ; i+=step)
+	{
+		if (i>step*5) // don't bother after the 5th ring
+			break;
+
+		for (rot = 0; rot < M_PI*2; rot += rstep)
+		{
+			if (!free_particles)
+				return;
+
+			p = free_particles;
+			free_particles = p->next;
+			p->next = active_particles;
+			active_particles = p;
+			
+			p->time = cl.time;
+			VectorClear (p->accel);
+//			rot+= fmod(ltime, 12.0)*M_PI;
+//			c = cos(rot)/2.0;
+//			s = sin(rot)/2.0;
+			c = cos(rot)/1.5;
+			s = sin(rot)/1.5;
+			
+			// trim it so it looks like it's starting at the origin
+			if (i < 10)
+			{
+				VectorScale (right, c*(i/10.0), dir);
+				VectorMA (dir, s*(i/10.0), up, dir);
+			}
+			else
+			{
+				VectorScale (right, c, dir);
+				VectorMA (dir, s, up, dir);
+			}
+		
+			p->alpha = 0.5;
+	//		p->alphavel = -1.0 / (1+frand()*0.2);
+			p->alphavel = -1000.0;
+	//		p->color = 0x74 + (rand()&7);
+			p->color = 223 - (rand()&7);
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = move[j] + dir[j]*3;
+	//			p->vel[j] = dir[j]*6;
+				p->vel[j] = 0;
+			}
+		}
+		VectorAdd (move, vec, move);
+	}
+*/
+}
+#endif
+
+/*
+===============
+CL_ParticleSteamEffect
+
+Puffs with velocity along direction, with some randomness thrown in
+===============
+*/
+void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	vec3_t		r, u;
+
+//	vectoangles2 (dir, angle_dir);
+//	AngleVectors (angle_dir, f, r, u);
+
+	MakeNormalVectors (dir, r, u);
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + magnitude*0.1*crand();
+//			p->vel[j] = dir[j]*magnitude;
+		}
+		VectorScale (dir, magnitude, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, r, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, u, p->vel);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY/2;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+void CL_ParticleSteamEffect2 (cl_sustain_t *self)
+//vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	vec3_t		r, u;
+	vec3_t		dir;
+
+//	vectoangles2 (dir, angle_dir);
+//	AngleVectors (angle_dir, f, r, u);
+
+	VectorCopy (self->dir, dir);
+	MakeNormalVectors (dir, r, u);
+
+	for (i=0 ; i<self->count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = self->color + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = self->org[j] + self->magnitude*0.1*crand();
+//			p->vel[j] = dir[j]*magnitude;
+		}
+		VectorScale (dir, self->magnitude, p->vel);
+		d = crand()*self->magnitude/3;
+		VectorMA (p->vel, d, r, p->vel);
+		d = crand()*self->magnitude/3;
+		VectorMA (p->vel, d, u, p->vel);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY/2;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+	self->nextthink += self->thinkinterval;
+}
+
+/*
+===============
+CL_TrackerTrail
+===============
+*/
+void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	vec3_t		forward,right,up,angle_dir;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+	float		dist;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	VectorCopy(vec, forward);
+	vectoangles2 (forward, angle_dir);
+	AngleVectors (angle_dir, forward, right, up);
+
+	dec = 3;
+	VectorScale (vec, 3, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -2.0;
+		p->color = particleColor;
+		dist = DotProduct(move, forward);
+		VectorMA(move, 8 * cos(dist), up, p->org);
+		for (j=0 ; j<3 ; j++)
+		{
+//			p->org[j] = move[j] + crand();
+			p->vel[j] = 0;
+			p->accel[j] = 0;
+		}
+		p->vel[2] = 5;
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+void CL_Tracker_Shell(vec3_t origin)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+
+	for(i=0;i<300;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = 0;
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(origin, 40, dir, p->org);
+	}
+}
+
+void CL_MonsterPlasma_Shell(vec3_t origin)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+
+	for(i=0;i<40;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = 0xe0;
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(origin, 10, dir, p->org);
+//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+	}
+}
+
+void CL_Widowbeamout (cl_sustain_t *self)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+	static int colortable[4] = {2*8,13*8,21*8,18*8};
+	float			ratio;
+
+	ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
+
+	for(i=0;i<300;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = colortable[rand()&3];
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(self->org, (45.0 * ratio), dir, p->org);
+//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+	}
+}
+
+void CL_Nukeblast (cl_sustain_t *self)
+{
+	vec3_t			dir;
+	int				i;
+	cparticle_t		*p;
+	static int colortable[4] = {110, 112, 114, 116};
+	float			ratio;
+
+	ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
+
+	for(i=0;i<700;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = INSTANT_PARTICLE;
+		p->color = colortable[rand()&3];
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+	
+		VectorMA(self->org, (200.0 * ratio), dir, p->org);
+//		VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+	}
+}
+
+void CL_WidowSplash (vec3_t org)
+{
+	static int colortable[4] = {2*8,13*8,21*8,18*8};
+	int			i;
+	cparticle_t	*p;
+	vec3_t		dir;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = colortable[rand()&3];
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+		VectorMA(org, 45.0, dir, p->org);
+		VectorMA(vec3_origin, 40.0, dir, p->vel);
+
+		p->accel[0] = p->accel[1] = 0;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.8 / (0.5 + frand()*0.3);
+	}
+
+}
+
+void CL_Tracker_Explode(vec3_t	origin)
+{
+	vec3_t			dir, backdir;
+	int				i;
+	cparticle_t		*p;
+
+	for(i=0;i<300;i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0;
+		p->color = 0;
+
+		dir[0] = crand();
+		dir[1] = crand();
+		dir[2] = crand();
+		VectorNormalize(dir);
+		VectorScale(dir, -1, backdir);
+	
+		VectorMA(origin, 64, dir, p->org);
+		VectorScale(backdir, 64, p->vel);
+	}
+	
+}
+
+/*
+===============
+CL_TagTrail
+
+===============
+*/
+void CL_TagTrail (vec3_t start, vec3_t end, float color)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	while (len >= 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.8+frand()*0.2);
+		p->color = color;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand()*16;
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
+
+/*
+===============
+CL_ColorExplosionParticles
+===============
+*/
+void CL_ColorExplosionParticles (vec3_t org, int color, int run)
+{
+	int			i, j;
+	cparticle_t	*p;
+
+	for (i=0 ; i<128 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand() % run);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%256)-128;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -0.4 / (0.6 + frand()*0.2);
+	}
+}
+
+/*
+===============
+CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
+===============
+*/
+void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	vec3_t		r, u;
+
+	MakeNormalVectors (dir, r, u);
+
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + magnitude*0.1*crand();
+//			p->vel[j] = dir[j]*magnitude;
+		}
+		VectorScale (dir, magnitude, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, r, p->vel);
+		d = crand()*magnitude/3;
+		VectorMA (p->vel, d, u, p->vel);
+
+		p->accel[0] = p->accel[1] = p->accel[2] = 0;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+/*
+===============
+CL_BlasterParticles2
+
+Wall impact puffs (Green)
+===============
+*/
+void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
+{
+	int			i, j;
+	cparticle_t	*p;
+	float		d;
+	int			count;
+
+	count = 40;
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->time = cl.time;
+		p->color = color + (rand()&7);
+
+		d = rand()&15;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+			p->vel[j] = dir[j] * 30 + crand()*40;
+		}
+
+		p->accel[0] = p->accel[1] = 0;
+		p->accel[2] = -PARTICLE_GRAVITY;
+		p->alpha = 1.0;
+
+		p->alphavel = -1.0 / (0.5 + frand()*0.3);
+	}
+}
+
+/*
+===============
+CL_BlasterTrail2
+
+Green!
+===============
+*/
+void CL_BlasterTrail2 (vec3_t start, vec3_t end)
+{
+	vec3_t		move;
+	vec3_t		vec;
+	float		len;
+	int			j;
+	cparticle_t	*p;
+	int			dec;
+
+	VectorCopy (start, move);
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+
+	dec = 5;
+	VectorScale (vec, 5, vec);
+
+	// FIXME: this is a really silly way to have a loop
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		VectorClear (p->accel);
+		
+		p->time = cl.time;
+
+		p->alpha = 1.0;
+		p->alphavel = -1.0 / (0.3+frand()*0.2);
+		p->color = 0xd0;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = move[j] + crand();
+			p->vel[j] = crand()*5;
+			p->accel[j] = 0;
+		}
+
+		VectorAdd (move, vec, move);
+	}
+}
--- /dev/null
+++ b/client/cl_parse.c
@@ -1,0 +1,806 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+
+char *svc_strings[256] =
+{
+	"svc_bad",
+
+	"svc_muzzleflash",
+	"svc_muzzlflash2",
+	"svc_temp_entity",
+	"svc_layout",
+	"svc_inventory",
+
+	"svc_nop",
+	"svc_disconnect",
+	"svc_reconnect",
+	"svc_sound",
+	"svc_print",
+	"svc_stufftext",
+	"svc_serverdata",
+	"svc_configstring",
+	"svc_spawnbaseline",	
+	"svc_centerprint",
+	"svc_download",
+	"svc_playerinfo",
+	"svc_packetentities",
+	"svc_deltapacketentities",
+	"svc_frame"
+};
+
+//=============================================================================
+
+void CL_DownloadFileName(char *dest, int destlen, char *fn)
+{
+	if (strncmp(fn, "players", 7) == 0)
+		Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
+	else
+		Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
+}
+
+/*
+===============
+CL_CheckOrDownloadFile
+
+Returns true if the file exists, otherwise it attempts
+to start a download from the server.
+===============
+*/
+qboolean	CL_CheckOrDownloadFile (char *filename)
+{
+	FILE *fp;
+	char	name[MAX_OSPATH];
+
+	if (strstr (filename, ".."))
+	{
+		Com_Printf ("Refusing to download a path with ..\n");
+		return true;
+	}
+
+	if (FS_LoadFile (filename, NULL) != -1)
+	{	// it exists, no need to download
+		return true;
+	}
+
+	strcpy (cls.downloadname, filename);
+
+	// download to a temp name, and only rename
+	// to the real name when done, so if interrupted
+	// a runt file wont be left
+	COM_StripExtension (cls.downloadname, cls.downloadtempname);
+	strcat (cls.downloadtempname, ".tmp");
+
+//ZOID
+	// check to see if we already have a tmp for this file, if so, try to resume
+	// open the file if not opened yet
+	CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+//	FS_CreatePath (name);
+
+	fp = fopen (name, "r+b");
+	if (fp) { // it exists
+		int len;
+		fseek(fp, 0, SEEK_END);
+		len = ftell(fp);
+
+		cls.download = fp;
+
+		// give the server an offset to start the download
+		Com_Printf ("Resuming %s\n", cls.downloadname);
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message,
+			va("download %s %i", cls.downloadname, len));
+	} else {
+		Com_Printf ("Downloading %s\n", cls.downloadname);
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		MSG_WriteString (&cls.netchan.message,
+			va("download %s", cls.downloadname));
+	}
+
+	cls.downloadnumber++;
+
+	return false;
+}
+
+/*
+===============
+CL_Download_f
+
+Request a download from the server
+===============
+*/
+void	CL_Download_f (void)
+{
+	char filename[MAX_OSPATH];
+
+	if (Cmd_Argc() != 2) {
+		Com_Printf("Usage: download <filename>\n");
+		return;
+	}
+
+	Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
+
+	if (strstr (filename, ".."))
+	{
+		Com_Printf ("Refusing to download a path with ..\n");
+		return;
+	}
+
+	if (FS_LoadFile (filename, NULL) != -1)
+	{	// it exists, no need to download
+		Com_Printf("File already exists.\n");
+		return;
+	}
+
+	strcpy (cls.downloadname, filename);
+	Com_Printf ("Downloading %s\n", cls.downloadname);
+
+	// download to a temp name, and only rename
+	// to the real name when done, so if interrupted
+	// a runt file wont be left
+	COM_StripExtension (cls.downloadname, cls.downloadtempname);
+	strcat (cls.downloadtempname, ".tmp");
+
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	MSG_WriteString (&cls.netchan.message,
+		va("download %s", cls.downloadname));
+
+	cls.downloadnumber++;
+}
+
+/*
+======================
+CL_RegisterSounds
+======================
+*/
+void CL_RegisterSounds (void)
+{
+	int		i;
+
+	S_BeginRegistration ();
+	CL_RegisterTEntSounds ();
+	for (i=1 ; i<MAX_SOUNDS ; i++)
+	{
+		if (!cl.configstrings[CS_SOUNDS+i][0])
+			break;
+		cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
+		Sys_SendKeyEvents ();	// pump message loop
+	}
+	S_EndRegistration ();
+}
+
+
+/*
+=====================
+CL_ParseDownload
+
+A download message has been received from the server
+=====================
+*/
+void CL_ParseDownload (void)
+{
+	int		size, percent;
+	char	name[MAX_OSPATH];
+	int		r;
+
+	// read the data
+	size = MSG_ReadShort (&net_message);
+	percent = MSG_ReadByte (&net_message);
+	if (size == -1)
+	{
+		Com_Printf ("Server does not have this file.\n");
+		if (cls.download)
+		{
+			// if here, we tried to resume a file but the server said no
+			fclose (cls.download);
+			cls.download = NULL;
+		}
+		CL_RequestNextDownload ();
+		return;
+	}
+
+	// open the file if not opened yet
+	if (!cls.download)
+	{
+		CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+		FS_CreatePath (name);
+
+		cls.download = fopen (name, "wb");
+		if (!cls.download)
+		{
+			net_message.readcount += size;
+			Com_Printf ("Failed to open %s\n", cls.downloadtempname);
+			CL_RequestNextDownload ();
+			return;
+		}
+	}
+
+	fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
+	net_message.readcount += size;
+
+	if (percent != 100)
+	{
+		// request next block
+// change display routines by zoid
+#if 0
+		Com_Printf (".");
+		if (10*(percent/10) != cls.downloadpercent)
+		{
+			cls.downloadpercent = 10*(percent/10);
+			Com_Printf ("%i%%", cls.downloadpercent);
+		}
+#endif
+		cls.downloadpercent = percent;
+
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		SZ_Print (&cls.netchan.message, "nextdl");
+	}
+	else
+	{
+		char	oldn[MAX_OSPATH];
+		char	newn[MAX_OSPATH];
+
+//		Com_Printf ("100%%\n");
+
+		fclose (cls.download);
+
+		// rename the temp file to it's final name
+		CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
+		CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
+		r = rename (oldn, newn);
+		if (r)
+			Com_Printf ("failed to rename.\n");
+
+		cls.download = NULL;
+		cls.downloadpercent = 0;
+
+		// get another file if needed
+
+		CL_RequestNextDownload ();
+	}
+}
+
+
+/*
+=====================================================================
+
+  SERVER CONNECTING MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseServerData
+==================
+*/
+void CL_ParseServerData (void)
+{
+	extern cvar_t	*fs_gamedirvar;
+	char	*str;
+	int		i;
+	
+	Com_DPrintf ("Serverdata packet received.\n");
+//
+// wipe the client_state_t struct
+//
+	CL_ClearState ();
+	cls.state = ca_connected;
+
+// parse protocol version number
+	i = MSG_ReadLong (&net_message);
+	cls.serverProtocol = i;
+
+	// BIG HACK to let demos from release work with the 3.0x patch!!!
+	if (Com_ServerState() && PROTOCOL_VERSION == 34)
+	{
+	}
+	else if (i != PROTOCOL_VERSION)
+		Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
+
+	cl.servercount = MSG_ReadLong (&net_message);
+	cl.attractloop = MSG_ReadByte (&net_message);
+
+	// game directory
+	str = MSG_ReadString (&net_message);
+	strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
+
+	// set gamedir
+	if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
+		Cvar_Set("game", str);
+
+	// parse player entity number
+	cl.playernum = MSG_ReadShort (&net_message);
+
+	// get the full level name
+	str = MSG_ReadString (&net_message);
+
+	if (cl.playernum == -1)
+	{	// playing a cinematic or showing a pic, not a level
+		SCR_PlayCinematic (str);
+	}
+	else
+	{
+		// seperate the printfs so the server message can have a color
+		Com_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\n");
+		Com_Printf ("%c%s\n", 2, str);
+
+		// need to prep refresh at next oportunity
+		cl.refresh_prepped = false;
+	}
+}
+
+/*
+==================
+CL_ParseBaseline
+==================
+*/
+void CL_ParseBaseline (void)
+{
+	entity_state_t	*es;
+	int				bits;
+	int				newnum;
+	entity_state_t	nullstate;
+
+	memset (&nullstate, 0, sizeof(nullstate));
+
+	newnum = CL_ParseEntityBits (&bits);
+	es = &cl_entities[newnum].baseline;
+	CL_ParseDelta (&nullstate, es, newnum, bits);
+}
+
+
+/*
+================
+CL_LoadClientinfo
+
+================
+*/
+void CL_LoadClientinfo (clientinfo_t *ci, char *s)
+{
+	int i;
+	char		*t;
+	char		model_name[MAX_QPATH];
+	char		skin_name[MAX_QPATH];
+	char		model_filename[MAX_QPATH];
+	char		skin_filename[MAX_QPATH];
+	char		weapon_filename[MAX_QPATH];
+
+	strncpy(ci->cinfo, s, sizeof(ci->cinfo));
+	ci->cinfo[sizeof(ci->cinfo)-1] = 0;
+
+	// isolate the player's name
+	strncpy(ci->name, s, sizeof(ci->name));
+	ci->name[sizeof(ci->name)-1] = 0;
+	t = strstr (s, "\\");
+	if (t)
+	{
+		ci->name[t-s] = 0;
+		s = t+1;
+	}
+
+	if (cl_noskins->value || *s == 0)
+	{
+		Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+		Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
+		Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
+		Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
+		ci->model = re.RegisterModel (model_filename);
+		memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
+		ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
+		ci->skin = re.RegisterSkin (skin_filename);
+		ci->icon = re.RegisterPic (ci->iconname);
+	}
+	else
+	{
+		// isolate the model name
+		strcpy (model_name, s);
+		t = strstr(model_name, "/");
+		if (!t)
+			t = strstr(model_name, "\\");
+		if (!t)
+			t = model_name;
+		*t = 0;
+
+		// isolate the skin name
+		strcpy (skin_name, s + strlen(model_name) + 1);
+
+		// model file
+		Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
+		ci->model = re.RegisterModel (model_filename);
+		if (!ci->model)
+		{
+			strcpy(model_name, "male");
+			Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+			ci->model = re.RegisterModel (model_filename);
+		}
+
+		// skin file
+		Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+		ci->skin = re.RegisterSkin (skin_filename);
+
+		// if we don't have the skin and the model wasn't male,
+		// see if the male has it (this is for CTF's skins)
+ 		if (!ci->skin && Q_stricmp(model_name, "male"))
+		{
+			// change model to male
+			strcpy(model_name, "male");
+			Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+			ci->model = re.RegisterModel (model_filename);
+
+			// see if the skin exists for the male model
+			Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+			ci->skin = re.RegisterSkin (skin_filename);
+		}
+
+		// if we still don't have a skin, it means that the male model didn't have
+		// it, so default to grunt
+		if (!ci->skin) {
+			// see if the skin exists for the male model
+			Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
+			ci->skin = re.RegisterSkin (skin_filename);
+		}
+
+		// weapon file
+		for (i = 0; i < num_cl_weaponmodels; i++) {
+			Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
+			ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+			if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
+				// try male
+				Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
+				ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+			}
+			if (!cl_vwep->value)
+				break; // only one when vwep is off
+		}
+
+		// icon file
+		Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
+		ci->icon = re.RegisterPic (ci->iconname);
+	}
+
+	// must have loaded all data types to be valud
+	if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
+	{
+		ci->skin = NULL;
+		ci->icon = NULL;
+		ci->model = NULL;
+		ci->weaponmodel[0] = NULL;
+		return;
+	}
+}
+
+/*
+================
+CL_ParseClientinfo
+
+Load the skin, icon, and model for a client
+================
+*/
+void CL_ParseClientinfo (int player)
+{
+	char			*s;
+	clientinfo_t	*ci;
+
+	s = cl.configstrings[player+CS_PLAYERSKINS];
+
+	ci = &cl.clientinfo[player];
+
+	CL_LoadClientinfo (ci, s);
+}
+
+
+/*
+================
+CL_ParseConfigString
+================
+*/
+void CL_ParseConfigString (void)
+{
+	int		i;
+	char	*s;
+
+	i = MSG_ReadShort (&net_message);
+	if (i < 0 || i >= MAX_CONFIGSTRINGS)
+		Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
+	s = MSG_ReadString(&net_message);
+	strcpy (cl.configstrings[i], s);
+
+	// do something apropriate 
+
+	if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
+		CL_SetLightstyle (i - CS_LIGHTS);
+	else if (i == CS_CDTRACK)
+	{
+		if (cl.refresh_prepped)
+			CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+	}
+	else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
+	{
+		if (cl.refresh_prepped)
+		{
+			cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
+			if (cl.configstrings[i][0] == '*')
+				cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
+			else
+				cl.model_clip[i-CS_MODELS] = NULL;
+		}
+	}
+	else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
+	{
+		if (cl.refresh_prepped)
+			cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
+	}
+	else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
+	{
+		if (cl.refresh_prepped)
+			cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
+	}
+	else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
+	{
+		if (cl.refresh_prepped)
+			CL_ParseClientinfo (i-CS_PLAYERSKINS);
+	}
+}
+
+
+/*
+=====================================================================
+
+ACTION MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseStartSoundPacket
+==================
+*/
+void CL_ParseStartSoundPacket(void)
+{
+    vec3_t  pos_v;
+	float	*pos;
+    int 	channel, ent;
+    int 	sound_num;
+    float 	volume;
+    float 	attenuation;  
+	int		flags;
+	float	ofs;
+
+	flags = MSG_ReadByte (&net_message);
+	sound_num = MSG_ReadByte (&net_message);
+
+    if (flags & SND_VOLUME)
+		volume = MSG_ReadByte (&net_message) / 255.0;
+	else
+		volume = DEFAULT_SOUND_PACKET_VOLUME;
+	
+    if (flags & SND_ATTENUATION)
+		attenuation = MSG_ReadByte (&net_message) / 64.0;
+	else
+		attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;	
+
+    if (flags & SND_OFFSET)
+		ofs = MSG_ReadByte (&net_message) / 1000.0;
+	else
+		ofs = 0;
+
+	if (flags & SND_ENT)
+	{	// entity reletive
+		channel = MSG_ReadShort(&net_message); 
+		ent = channel>>3;
+		if (ent > MAX_EDICTS)
+			Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
+
+		channel &= 7;
+	}
+	else
+	{
+		ent = 0;
+		channel = 0;
+	}
+
+	if (flags & SND_POS)
+	{	// positioned in space
+		MSG_ReadPos (&net_message, pos_v);
+ 
+		pos = pos_v;
+	}
+	else	// use entity number
+		pos = NULL;
+
+	if (!cl.sound_precache[sound_num])
+		return;
+
+	S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
+}       
+
+
+void SHOWNET(char *s)
+{
+	if (cl_shownet->value>=2)
+		Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
+}
+
+/*
+=====================
+CL_ParseServerMessage
+=====================
+*/
+void CL_ParseServerMessage (void)
+{
+	int			cmd;
+	char		*s;
+	int			i;
+
+//
+// if recording demos, copy the message out
+//
+	if (cl_shownet->value == 1)
+		Com_Printf ("%i ",net_message.cursize);
+	else if (cl_shownet->value >= 2)
+		Com_Printf ("------------------\n");
+
+
+//
+// parse the message
+//
+	while (1)
+	{
+		if (net_message.readcount > net_message.cursize)
+		{
+			Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
+			break;
+		}
+
+		cmd = MSG_ReadByte (&net_message);
+
+		if (cmd == -1)
+		{
+			SHOWNET("END OF MESSAGE");
+			break;
+		}
+
+		if (cl_shownet->value>=2)
+		{
+			if (!svc_strings[cmd])
+				Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
+			else
+				SHOWNET(svc_strings[cmd]);
+		}
+	
+	// other commands
+		switch (cmd)
+		{
+		default:
+			Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
+			break;
+			
+		case svc_nop:
+//			Com_Printf ("svc_nop\n");
+			break;
+			
+		case svc_disconnect:
+			Com_Error (ERR_DISCONNECT,"Server disconnected\n");
+			break;
+
+		case svc_reconnect:
+			Com_Printf ("Server disconnected, reconnecting\n");
+			if (cls.download) {
+				//ZOID, close download
+				fclose (cls.download);
+				cls.download = NULL;
+			}
+			cls.state = ca_connecting;
+			cls.connect_time = -99999;	// CL_CheckForResend() will fire immediately
+			break;
+
+		case svc_print:
+			i = MSG_ReadByte (&net_message);
+			if (i == PRINT_CHAT)
+			{
+				S_StartLocalSound ("misc/talk.wav");
+				con.ormask = 128;
+			}
+			Com_Printf ("%s", MSG_ReadString (&net_message));
+			con.ormask = 0;
+			break;
+			
+		case svc_centerprint:
+			SCR_CenterPrint (MSG_ReadString (&net_message));
+			break;
+			
+		case svc_stufftext:
+			s = MSG_ReadString (&net_message);
+			Com_DPrintf ("stufftext: %s\n", s);
+			Cbuf_AddText (s);
+			break;
+			
+		case svc_serverdata:
+			Cbuf_Execute ();		// make sure any stuffed commands are done
+			CL_ParseServerData ();
+			break;
+			
+		case svc_configstring:
+			CL_ParseConfigString ();
+			break;
+			
+		case svc_sound:
+			CL_ParseStartSoundPacket();
+			break;
+			
+		case svc_spawnbaseline:
+			CL_ParseBaseline ();
+			break;
+
+		case svc_temp_entity:
+			CL_ParseTEnt ();
+			break;
+
+		case svc_muzzleflash:
+			CL_ParseMuzzleFlash ();
+			break;
+
+		case svc_muzzleflash2:
+			CL_ParseMuzzleFlash2 ();
+			break;
+
+		case svc_download:
+			CL_ParseDownload ();
+			break;
+
+		case svc_frame:
+			CL_ParseFrame ();
+			break;
+
+		case svc_inventory:
+			CL_ParseInventory ();
+			break;
+
+		case svc_layout:
+			s = MSG_ReadString (&net_message);
+			strncpy (cl.layout, s, sizeof(cl.layout)-1);
+			break;
+
+		case svc_playerinfo:
+		case svc_packetentities:
+		case svc_deltapacketentities:
+			Com_Error (ERR_DROP, "Out of place frame data");
+			break;
+		}
+	}
+
+	CL_AddNetgraph ();
+
+	//
+	// we don't know if it is ok to save a demo message until
+	// after we have parsed the frame
+	//
+	if (cls.demorecording && !cls.demowaiting)
+		CL_WriteDemoMessage ();
+
+}
+
+
--- /dev/null
+++ b/client/cl_pred.c
@@ -1,0 +1,278 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+
+
+/*
+===================
+CL_CheckPredictionError
+===================
+*/
+void CL_CheckPredictionError (void)
+{
+	int		frame;
+	int		delta[3];
+	int		i;
+	int		len;
+
+	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+		return;
+
+	// calculate the last usercmd_t we sent that the server has processed
+	frame = cls.netchan.incoming_acknowledged;
+	frame &= (CMD_BACKUP-1);
+
+	// compare what the server returned with what we had predicted it to be
+	VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
+
+	// save the prediction error for interpolation
+	len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
+	if (len > 640)	// 80 world units
+	{	// a teleport or something
+		VectorClear (cl.prediction_error);
+	}
+	else
+	{
+		if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
+			Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe, 
+			delta[0] + delta[1] + delta[2]);
+
+		VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
+
+		// save for error itnerpolation
+		for (i=0 ; i<3 ; i++)
+			cl.prediction_error[i] = delta[i]*0.125;
+	}
+}
+
+
+/*
+====================
+CL_ClipMoveToEntities
+
+====================
+*/
+void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
+{
+	int			i, x, zd, zu;
+	trace_t		trace;
+	int			headnode;
+	float		*angles;
+	entity_state_t	*ent;
+	int			num;
+	cmodel_t		*cmodel;
+	vec3_t		bmins, bmaxs;
+
+	for (i=0 ; i<cl.frame.num_entities ; i++)
+	{
+		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+		ent = &cl_parse_entities[num];
+
+		if (!ent->solid)
+			continue;
+
+		if (ent->number == cl.playernum+1)
+			continue;
+
+		if (ent->solid == 31)
+		{	// special value for bmodel
+			cmodel = cl.model_clip[ent->modelindex];
+			if (!cmodel)
+				continue;
+			headnode = cmodel->headnode;
+			angles = ent->angles;
+		}
+		else
+		{	// encoded bbox
+			x = 8*(ent->solid & 31);
+			zd = 8*((ent->solid>>5) & 31);
+			zu = 8*((ent->solid>>10) & 63) - 32;
+
+			bmins[0] = bmins[1] = -x;
+			bmaxs[0] = bmaxs[1] = x;
+			bmins[2] = -zd;
+			bmaxs[2] = zu;
+
+			headnode = CM_HeadnodeForBox (bmins, bmaxs);
+			angles = vec3_origin;	// boxes don't rotate
+		}
+
+		if (tr->allsolid)
+			return;
+
+		trace = CM_TransformedBoxTrace (start, end,
+			mins, maxs, headnode,  MASK_PLAYERSOLID,
+			ent->origin, angles);
+
+		if (trace.allsolid || trace.startsolid ||
+		trace.fraction < tr->fraction)
+		{
+			trace.ent = (struct edict_s *)ent;
+		 	if (tr->startsolid)
+			{
+				*tr = trace;
+				tr->startsolid = true;
+			}
+			else
+				*tr = trace;
+		}
+		else if (trace.startsolid)
+			tr->startsolid = true;
+	}
+}
+
+
+/*
+================
+CL_PMTrace
+================
+*/
+trace_t		CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+	trace_t	t;
+
+	// check against world
+	t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
+	if (t.fraction < 1.0)
+		t.ent = (struct edict_s *)1;
+
+	// check all other solid models
+	CL_ClipMoveToEntities (start, mins, maxs, end, &t);
+
+	return t;
+}
+
+int		CL_PMpointcontents (vec3_t point)
+{
+	int			i;
+	entity_state_t	*ent;
+	int			num;
+	cmodel_t		*cmodel;
+	int			contents;
+
+	contents = CM_PointContents (point, 0);
+
+	for (i=0 ; i<cl.frame.num_entities ; i++)
+	{
+		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+		ent = &cl_parse_entities[num];
+
+		if (ent->solid != 31) // special value for bmodel
+			continue;
+
+		cmodel = cl.model_clip[ent->modelindex];
+		if (!cmodel)
+			continue;
+
+		contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
+	}
+
+	return contents;
+}
+
+
+/*
+=================
+CL_PredictMovement
+
+Sets cl.predicted_origin and cl.predicted_angles
+=================
+*/
+void CL_PredictMovement (void)
+{
+	int			ack, current;
+	int			frame;
+	int			oldframe;
+	usercmd_t	*cmd;
+	pmove_t		pm;
+	int			i;
+	int			step;
+	int			oldz;
+
+	if (cls.state != ca_active)
+		return;
+
+	if (cl_paused->value)
+		return;
+
+	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+	{	// just set angles
+		for (i=0 ; i<3 ; i++)
+		{
+			cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
+		}
+		return;
+	}
+
+	ack = cls.netchan.incoming_acknowledged;
+	current = cls.netchan.outgoing_sequence;
+
+	// if we are too far out of date, just freeze
+	if (current - ack >= CMD_BACKUP)
+	{
+		if (cl_showmiss->value)
+			Com_Printf ("exceeded CMD_BACKUP\n");
+		return;	
+	}
+
+	// copy current state to pmove
+	memset (&pm, 0, sizeof(pm));
+	pm.trace = CL_PMTrace;
+	pm.pointcontents = CL_PMpointcontents;
+
+	pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
+
+	pm.s = cl.frame.playerstate.pmove;
+
+//	SCR_DebugGraph (current - ack - 1, 0);
+
+	frame = 0;
+
+	// run frames
+	while (++ack < current)
+	{
+		frame = ack & (CMD_BACKUP-1);
+		cmd = &cl.cmds[frame];
+
+		pm.cmd = *cmd;
+		Pmove (&pm);
+
+		// save for debug checking
+		VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
+	}
+
+	oldframe = (ack-2) & (CMD_BACKUP-1);
+	oldz = cl.predicted_origins[oldframe][2];
+	step = pm.s.origin[2] - oldz;
+	if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
+	{
+		cl.predicted_step = step * 0.125;
+		cl.predicted_step_time = cls.realtime - cls.frametime * 500;
+	}
+
+
+	// copy results out for rendering
+	cl.predicted_origin[0] = pm.s.origin[0]*0.125;
+	cl.predicted_origin[1] = pm.s.origin[1]*0.125;
+	cl.predicted_origin[2] = pm.s.origin[2]*0.125;
+
+	VectorCopy (pm.viewangles, cl.predicted_angles);
+}
--- /dev/null
+++ b/client/cl_scrn.c
@@ -1,0 +1,1401 @@
+/*
+Copyright (C) 1997-2001 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_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+/*
+
+  full screen console
+  put up loading plaque
+  blanked background with loading plaque
+  blanked background with menu
+  cinematics
+  full screen image for quit and victory
+
+  end of unit intermissions
+
+  */
+
+#include "client.h"
+
+float		scr_con_current;	// aproaches scr_conlines at scr_conspeed
+float		scr_conlines;		// 0.0 to 1.0 lines of console to display
+
+qboolean	scr_initialized;		// ready to draw
+
+int			scr_draw_loading;
+
+vrect_t		scr_vrect;		// position of render window on screen
+
+
+cvar_t		*scr_viewsize;
+cvar_t		*scr_conspeed;
+cvar_t		*scr_centertime;
+cvar_t		*scr_showturtle;
+cvar_t		*scr_showpause;
+cvar_t		*scr_printspeed;
+
+cvar_t		*scr_netgraph;
+cvar_t		*scr_timegraph;
+cvar_t		*scr_debuggraph;
+cvar_t		*scr_graphheight;
+cvar_t		*scr_graphscale;
+cvar_t		*scr_graphshift;
+cvar_t		*scr_drawall;
+
+typedef struct
+{
+	int		x1, y1, x2, y2;
+} dirty_t;
+
+dirty_t		scr_dirty, scr_old_dirty[2];
+
+char		crosshair_pic[MAX_QPATH];
+int			crosshair_width, crosshair_height;
+
+void SCR_TimeRefresh_f (void);
+void SCR_Loading_f (void);
+
+
+/*
+===============================================================================
+
+BAR GRAPHS
+
+===============================================================================
+*/
+
+/*
+==============
+CL_AddNetgraph
+
+A new packet was just parsed
+==============
+*/
+void CL_AddNetgraph (void)
+{
+	int		i;
+	int		in;
+	int		ping;
+
+	// if using the debuggraph for something else, don't
+	// add the net lines
+	if (scr_debuggraph->value || scr_timegraph->value)
+		return;
+
+	for (i=0 ; i<cls.netchan.dropped ; i++)
+		SCR_DebugGraph (30, 0x40);
+
+	for (i=0 ; i<cl.surpressCount ; i++)
+		SCR_DebugGraph (30, 0xdf);
+
+	// see what the latency was on this packet
+	in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
+	ping = cls.realtime - cl.cmd_time[in];
+	ping /= 30;
+	if (ping > 30)
+		ping = 30;
+	SCR_DebugGraph (ping, 0xd0);
+}
+
+
+typedef struct
+{
+	float	value;
+	int		color;
+} graphsamp_t;
+
+static	int			current;
+static	graphsamp_t	values[1024];
+
+/*
+==============
+SCR_DebugGraph
+==============
+*/
+void SCR_DebugGraph (float value, int color)
+{
+	values[current&1023].value = value;
+	values[current&1023].color = color;
+	current++;
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph (void)
+{
+	int		a, x, y, w, i, h;
+	float	v;
+	int		color;
+
+	//
+	// draw the graph
+	//
+	w = scr_vrect.width;
+
+	x = scr_vrect.x;
+	y = scr_vrect.y+scr_vrect.height;
+	re.DrawFill (x, y-scr_graphheight->value,
+		w, scr_graphheight->value, 8);
+
+	for (a=0 ; a<w ; a++)
+	{
+		i = (current-1-a+1024) & 1023;
+		v = values[i].value;
+		color = values[i].color;
+		v = v*scr_graphscale->value + scr_graphshift->value;
+		
+		if (v < 0)
+			v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
+		h = (int)v % (int)scr_graphheight->value;
+		re.DrawFill (x+w-1-a, y - h, 1,	h, color);
+	}
+}
+
+/*
+===============================================================================
+
+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_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)
+{
+	char	*s;
+	char	line[64];
+	int		i, j, l;
+
+	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;
+	s = str;
+	while (*s)
+	{
+		if (*s == '\n')
+			scr_center_lines++;
+		s++;
+	}
+
+	// echo it to the console
+	Com_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\n");
+
+	s = str;
+	do	
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (s[l] == '\n' || !s[l])
+				break;
+		for (i=0 ; i<(40-l)/2 ; i++)
+			line[i] = ' ';
+
+		for (j=0 ; j<l ; j++)
+		{
+			line[i++] = s[j];
+		}
+
+		line[i] = '\n';
+		line[i+1] = 0;
+
+		Com_Printf ("%s", line);
+
+		while (*s && *s != '\n')
+			s++;
+
+		if (!*s)
+			break;
+		s++;		// skip the \n
+	} while (1);
+	Com_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\n");
+	Con_ClearNotify ();
+}
+
+
+void SCR_DrawCenterString (void)
+{
+	char	*start;
+	int		l;
+	int		j;
+	int		x, y;
+	int		remaining;
+
+// the finale prints the characters one at a time
+	remaining = 9999;
+
+	scr_erase_center = 0;
+	start = scr_centerstring;
+
+	if (scr_center_lines <= 4)
+		y = viddef.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 = (viddef.width - l*8)/2;
+		SCR_AddDirtyPoint (x, y);
+		for (j=0 ; j<l ; j++, x+=8)
+		{
+			re.DrawChar (x, y, start[j]);	
+			if (!remaining--)
+				return;
+		}
+		SCR_AddDirtyPoint (x, y+8);
+			
+		y += 8;
+
+		while (*start && *start != '\n')
+			start++;
+
+		if (!*start)
+			break;
+		start++;		// skip the \n
+	} while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+	scr_centertime_off -= cls.frametime;
+	
+	if (scr_centertime_off <= 0)
+		return;
+
+	SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+=================
+SCR_CalcVrect
+
+Sets scr_vrect, the coordinates of the rendered window
+=================
+*/
+static void SCR_CalcVrect (void)
+{
+	int		size;
+
+	// bound viewsize
+	if (scr_viewsize->value < 40)
+		Cvar_Set ("viewsize","40");
+	if (scr_viewsize->value > 100)
+		Cvar_Set ("viewsize","100");
+
+	size = scr_viewsize->value;
+
+	scr_vrect.width = viddef.width*size/100;
+	scr_vrect.width &= ~7;
+
+	scr_vrect.height = viddef.height*size/100;
+	scr_vrect.height &= ~1;
+
+	scr_vrect.x = (viddef.width - scr_vrect.width)/2;
+	scr_vrect.y = (viddef.height - scr_vrect.height)/2;
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize->value+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize->value-10);
+}
+
+/*
+=================
+SCR_Sky_f
+
+Set a specific sky and rotation speed
+=================
+*/
+void SCR_Sky_f (void)
+{
+	float	rotate;
+	vec3_t	axis;
+
+	if (Cmd_Argc() < 2)
+	{
+		Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
+		return;
+	}
+	if (Cmd_Argc() > 2)
+		rotate = atof(Cmd_Argv(2));
+	else
+		rotate = 0;
+	if (Cmd_Argc() == 6)
+	{
+		axis[0] = atof(Cmd_Argv(3));
+		axis[1] = atof(Cmd_Argv(4));
+		axis[2] = atof(Cmd_Argv(5));
+	}
+	else
+	{
+		axis[0] = 0;
+		axis[1] = 0;
+		axis[2] = 1;
+	}
+
+	re.SetSky (Cmd_Argv(1), rotate, axis);
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+	scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+	scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
+	scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
+	scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
+	scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
+	scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
+	scr_netgraph = Cvar_Get ("netgraph", "0", 0);
+	scr_timegraph = Cvar_Get ("timegraph", "0", 0);
+	scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
+	scr_graphheight = Cvar_Get ("graphheight", "32", 0);
+	scr_graphscale = Cvar_Get ("graphscale", "1", 0);
+	scr_graphshift = Cvar_Get ("graphshift", "0", 0);
+	scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
+
+//
+// register our commands
+//
+	Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
+	Cmd_AddCommand ("loading",SCR_Loading_f);
+	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+	Cmd_AddCommand ("sky",SCR_Sky_f);
+
+	scr_initialized = true;
+}
+
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 
+		< CMD_BACKUP-1)
+		return;
+
+	re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
+}
+
+/*
+==============
+SCR_DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+	int		w, h;
+
+	if (!scr_showpause->value)		// turn off for screenshots
+		return;
+
+	if (!cl_paused->value)
+		return;
+
+	re.DrawGetPicSize (&w, &h, "pause");
+	re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");
+}
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+	int		w, h;
+		
+	if (!scr_draw_loading)
+		return;
+
+	scr_draw_loading = false;
+	re.DrawGetPicSize (&w, &h, "loading");
+	re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
+}
+
+//=============================================================================
+
+/*
+==================
+SCR_RunConsole
+
+Scroll it up or down
+==================
+*/
+void SCR_RunConsole (void)
+{
+// decide on the height of the console
+	if (cls.key_dest == key_console)
+		scr_conlines = 0.5;		// half screen
+	else
+		scr_conlines = 0;				// none visible
+	
+	if (scr_conlines < scr_con_current)
+	{
+		scr_con_current -= scr_conspeed->value*cls.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*cls.frametime;
+		if (scr_conlines < scr_con_current)
+			scr_con_current = scr_conlines;
+	}
+
+}
+
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+	Con_CheckResize ();
+	
+	if (cls.state == ca_disconnected || cls.state == ca_connecting)
+	{	// forced full screen console
+		Con_DrawConsole (1.0);
+		return;
+	}
+
+	if (cls.state != ca_active || !cl.refresh_prepped)
+	{	// connected, but can't render
+		Con_DrawConsole (0.5);
+		re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
+		return;
+	}
+
+	if (scr_con_current)
+	{
+		Con_DrawConsole (scr_con_current);
+	}
+	else
+	{
+		if (cls.key_dest == key_game || cls.key_dest == key_message)
+			Con_DrawNotify ();	// only draw notify in game
+	}
+}
+
+//=============================================================================
+
+/*
+================
+SCR_BeginLoadingPlaque
+================
+*/
+void SCR_BeginLoadingPlaque (void)
+{
+	S_StopAllSounds ();
+	cl.sound_prepped = false;		// don't play ambients
+	CDAudio_Stop ();
+	if (cls.disable_screen)
+		return;
+	if (developer->value)
+		return;
+	if (cls.state == ca_disconnected)
+		return;	// if at console, don't bring up the plaque
+	if (cls.key_dest == key_console)
+		return;
+	if (cl.cinematictime > 0)
+		scr_draw_loading = 2;	// clear to balack first
+	else
+		scr_draw_loading = 1;
+	SCR_UpdateScreen ();
+	cls.disable_screen = Sys_Milliseconds ();
+	cls.disable_servercount = cl.servercount;
+}
+
+/*
+================
+SCR_EndLoadingPlaque
+================
+*/
+void SCR_EndLoadingPlaque (void)
+{
+	cls.disable_screen = 0;
+	Con_ClearNotify ();
+}
+
+/*
+================
+SCR_Loading_f
+================
+*/
+void SCR_Loading_f (void)
+{
+	SCR_BeginLoadingPlaque ();
+}
+
+/*
+================
+SCR_TimeRefresh_f
+================
+*/
+int entitycmpfnc( const entity_t *a, const entity_t *b )
+{
+	/*
+	** all other models are sorted by model then skin
+	*/
+	if ( a->model == b->model )
+	{
+		return ( ( int ) a->skin - ( int ) b->skin );
+	}
+	else
+	{
+		return ( ( int ) a->model - ( int ) b->model );
+	}
+}
+
+void SCR_TimeRefresh_f (void)
+{
+	int		i;
+	int		start, stop;
+	float	time;
+
+	if ( cls.state != ca_active )
+		return;
+
+	start = Sys_Milliseconds ();
+
+	if (Cmd_Argc() == 2)
+	{	// run without page flipping
+		re.BeginFrame( 0 );
+		for (i=0 ; i<128 ; i++)
+		{
+			cl.refdef.viewangles[1] = i/128.0*360.0;
+			re.RenderFrame (&cl.refdef);
+		}
+		re.EndFrame();
+	}
+	else
+	{
+		for (i=0 ; i<128 ; i++)
+		{
+			cl.refdef.viewangles[1] = i/128.0*360.0;
+
+			re.BeginFrame( 0 );
+			re.RenderFrame (&cl.refdef);
+			re.EndFrame();
+		}
+	}
+
+	stop = Sys_Milliseconds ();
+	time = (stop-start)/1000.0;
+	Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+/*
+=================
+SCR_AddDirtyPoint
+=================
+*/
+void SCR_AddDirtyPoint (int x, int y)
+{
+	if (x < scr_dirty.x1)
+		scr_dirty.x1 = x;
+	if (x > scr_dirty.x2)
+		scr_dirty.x2 = x;
+	if (y < scr_dirty.y1)
+		scr_dirty.y1 = y;
+	if (y > scr_dirty.y2)
+		scr_dirty.y2 = y;
+}
+
+void SCR_DirtyScreen (void)
+{
+	SCR_AddDirtyPoint (0, 0);
+	SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
+}
+
+/*
+==============
+SCR_TileClear
+
+Clear any parts of the tiled background that were drawn on last frame
+==============
+*/
+void SCR_TileClear (void)
+{
+	int		i;
+	int		top, bottom, left, right;
+	dirty_t	clear;
+
+	if (scr_drawall->value)
+		SCR_DirtyScreen ();	// for power vr or broken page flippers...
+
+	if (scr_con_current == 1.0)
+		return;		// full screen console
+	if (scr_viewsize->value == 100)
+		return;		// full screen rendering
+	if (cl.cinematictime > 0)
+		return;		// full screen cinematic
+
+	// erase rect will be the union of the past three frames
+	// so tripple buffering works properly
+	clear = scr_dirty;
+	for (i=0 ; i<2 ; i++)
+	{
+		if (scr_old_dirty[i].x1 < clear.x1)
+			clear.x1 = scr_old_dirty[i].x1;
+		if (scr_old_dirty[i].x2 > clear.x2)
+			clear.x2 = scr_old_dirty[i].x2;
+		if (scr_old_dirty[i].y1 < clear.y1)
+			clear.y1 = scr_old_dirty[i].y1;
+		if (scr_old_dirty[i].y2 > clear.y2)
+			clear.y2 = scr_old_dirty[i].y2;
+	}
+
+	scr_old_dirty[1] = scr_old_dirty[0];
+	scr_old_dirty[0] = scr_dirty;
+
+	scr_dirty.x1 = 9999;
+	scr_dirty.x2 = -9999;
+	scr_dirty.y1 = 9999;
+	scr_dirty.y2 = -9999;
+
+	// don't bother with anything convered by the console)
+	top = scr_con_current*viddef.height;
+	if (top >= clear.y1)
+		clear.y1 = top;
+
+	if (clear.y2 <= clear.y1)
+		return;		// nothing disturbed
+
+	top = scr_vrect.y;
+	bottom = top + scr_vrect.height-1;
+	left = scr_vrect.x;
+	right = left + scr_vrect.width-1;
+
+	if (clear.y1 < top)
+	{	// clear above view screen
+		i = clear.y2 < top-1 ? clear.y2 : top-1;
+		re.DrawTileClear (clear.x1 , clear.y1,
+			clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
+		clear.y1 = top;
+	}
+	if (clear.y2 > bottom)
+	{	// clear below view screen
+		i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
+		re.DrawTileClear (clear.x1, i,
+			clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
+		clear.y2 = bottom;
+	}
+	if (clear.x1 < left)
+	{	// clear left of view screen
+		i = clear.x2 < left-1 ? clear.x2 : left-1;
+		re.DrawTileClear (clear.x1, clear.y1,
+			i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
+		clear.x1 = left;
+	}
+	if (clear.x2 > right)
+	{	// clear left of view screen
+		i = clear.x1 > right+1 ? clear.x1 : right+1;
+		re.DrawTileClear (i, clear.y1,
+			clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
+		clear.x2 = right;
+	}
+
+}
+
+
+//===============================================================
+
+
+#define STAT_MINUS		10	// num frame for '-' stats digit
+char		*sb_nums[2][11] = 
+{
+	{"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+	"num_6", "num_7", "num_8", "num_9", "num_minus"},
+	{"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+	"anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
+};
+
+#define	ICON_WIDTH	24
+#define	ICON_HEIGHT	24
+#define	CHAR_WIDTH	16
+#define	ICON_SPACE	8
+
+
+
+/*
+================
+SizeHUDString
+
+Allow embedded \n in the string
+================
+*/
+void SizeHUDString (char *string, int *w, int *h)
+{
+	int		lines, width, current;
+
+	lines = 1;
+	width = 0;
+
+	current = 0;
+	while (*string)
+	{
+		if (*string == '\n')
+		{
+			lines++;
+			current = 0;
+		}
+		else
+		{
+			current++;
+			if (current > width)
+				width = current;
+		}
+		string++;
+	}
+
+	*w = width * 8;
+	*h = lines * 8;
+}
+
+void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
+{
+	int		margin;
+	char	line[1024];
+	int		width;
+	int		i;
+
+	margin = x;
+
+	while (*string)
+	{
+		// scan out one line of text from the string
+		width = 0;
+		while (*string && *string != '\n')
+			line[width++] = *string++;
+		line[width] = 0;
+
+		if (centerwidth)
+			x = margin + (centerwidth - width*8)/2;
+		else
+			x = margin;
+		for (i=0 ; i<width ; i++)
+		{
+			re.DrawChar (x, y, line[i]^xor);
+			x += 8;
+		}
+		if (*string)
+		{
+			string++;	// skip the \n
+			x = margin;
+			y += 8;
+		}
+	}
+}
+
+
+/*
+==============
+SCR_DrawField
+==============
+*/
+void SCR_DrawField (int x, int y, int color, int width, int value)
+{
+	char	num[16], *ptr;
+	int		l;
+	int		frame;
+
+	if (width < 1)
+		return;
+
+	// draw number string
+	if (width > 5)
+		width = 5;
+
+	SCR_AddDirtyPoint (x, y);
+	SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
+
+	Com_sprintf (num, sizeof(num), "%i", value);
+	l = strlen(num);
+	if (l > width)
+		l = width;
+	x += 2 + CHAR_WIDTH*(width - l);
+
+	ptr = num;
+	while (*ptr && l)
+	{
+		if (*ptr == '-')
+			frame = STAT_MINUS;
+		else
+			frame = *ptr -'0';
+
+		re.DrawPic (x,y,sb_nums[color][frame]);
+		x += CHAR_WIDTH;
+		ptr++;
+		l--;
+	}
+}
+
+
+/*
+===============
+SCR_TouchPics
+
+Allows rendering code to cache all needed sbar graphics
+===============
+*/
+void SCR_TouchPics (void)
+{
+	int		i, j;
+
+	for (i=0 ; i<2 ; i++)
+		for (j=0 ; j<11 ; j++)
+			re.RegisterPic (sb_nums[i][j]);
+
+	if (crosshair->value)
+	{
+		if (crosshair->value > 3 || crosshair->value < 0)
+			crosshair->value = 3;
+
+		Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
+		re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
+		if (!crosshair_width)
+			crosshair_pic[0] = 0;
+	}
+}
+
+/*
+================
+SCR_ExecuteLayoutString 
+
+================
+*/
+void SCR_ExecuteLayoutString (char *s)
+{
+	int		x, y;
+	int		value;
+	char	*token;
+	int		width;
+	int		index;
+	clientinfo_t	*ci;
+
+	if (cls.state != ca_active || !cl.refresh_prepped)
+		return;
+
+	if (!s[0])
+		return;
+
+	x = 0;
+	y = 0;
+	width = 3;
+
+	while (s)
+	{
+		token = COM_Parse (&s);
+		if (!strcmp(token, "xl"))
+		{
+			token = COM_Parse (&s);
+			x = atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "xr"))
+		{
+			token = COM_Parse (&s);
+			x = viddef.width + atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "xv"))
+		{
+			token = COM_Parse (&s);
+			x = viddef.width/2 - 160 + atoi(token);
+			continue;
+		}
+
+		if (!strcmp(token, "yt"))
+		{
+			token = COM_Parse (&s);
+			y = atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "yb"))
+		{
+			token = COM_Parse (&s);
+			y = viddef.height + atoi(token);
+			continue;
+		}
+		if (!strcmp(token, "yv"))
+		{
+			token = COM_Parse (&s);
+			y = viddef.height/2 - 120 + atoi(token);
+			continue;
+		}
+
+		if (!strcmp(token, "pic"))
+		{	// draw a pic from a stat number
+			token = COM_Parse (&s);
+			value = cl.frame.playerstate.stats[atoi(token)];
+			if (value >= MAX_IMAGES)
+				Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
+			if (cl.configstrings[CS_IMAGES+value])
+			{
+				SCR_AddDirtyPoint (x, y);
+				SCR_AddDirtyPoint (x+23, y+23);
+				re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
+			}
+			continue;
+		}
+
+		if (!strcmp(token, "client"))
+		{	// draw a deathmatch client block
+			int		score, ping, time;
+
+			token = COM_Parse (&s);
+			x = viddef.width/2 - 160 + atoi(token);
+			token = COM_Parse (&s);
+			y = viddef.height/2 - 120 + atoi(token);
+			SCR_AddDirtyPoint (x, y);
+			SCR_AddDirtyPoint (x+159, y+31);
+
+			token = COM_Parse (&s);
+			value = atoi(token);
+			if (value >= MAX_CLIENTS || value < 0)
+				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+			ci = &cl.clientinfo[value];
+
+			token = COM_Parse (&s);
+			score = atoi(token);
+
+			token = COM_Parse (&s);
+			ping = atoi(token);
+
+			token = COM_Parse (&s);
+			time = atoi(token);
+
+			DrawAltString (x+32, y, ci->name);
+			DrawString (x+32, y+8,  "Score: ");
+			DrawAltString (x+32+7*8, y+8,  va("%i", score));
+			DrawString (x+32, y+16, va("Ping:  %i", ping));
+			DrawString (x+32, y+24, va("Time:  %i", time));
+
+			if (!ci->icon)
+				ci = &cl.baseclientinfo;
+			re.DrawPic (x, y, ci->iconname);
+			continue;
+		}
+
+		if (!strcmp(token, "ctf"))
+		{	// draw a ctf client block
+			int		score, ping;
+			char	block[80];
+
+			token = COM_Parse (&s);
+			x = viddef.width/2 - 160 + atoi(token);
+			token = COM_Parse (&s);
+			y = viddef.height/2 - 120 + atoi(token);
+			SCR_AddDirtyPoint (x, y);
+			SCR_AddDirtyPoint (x+159, y+31);
+
+			token = COM_Parse (&s);
+			value = atoi(token);
+			if (value >= MAX_CLIENTS || value < 0)
+				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+			ci = &cl.clientinfo[value];
+
+			token = COM_Parse (&s);
+			score = atoi(token);
+
+			token = COM_Parse (&s);
+			ping = atoi(token);
+			if (ping > 999)
+				ping = 999;
+
+			sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
+
+			if (value == cl.playernum)
+				DrawAltString (x, y, block);
+			else
+				DrawString (x, y, block);
+			continue;
+		}
+
+		if (!strcmp(token, "picn"))
+		{	// draw a pic from a name
+			token = COM_Parse (&s);
+			SCR_AddDirtyPoint (x, y);
+			SCR_AddDirtyPoint (x+23, y+23);
+			re.DrawPic (x, y, token);
+			continue;
+		}
+
+		if (!strcmp(token, "num"))
+		{	// draw a number
+			token = COM_Parse (&s);
+			width = atoi(token);
+			token = COM_Parse (&s);
+			value = cl.frame.playerstate.stats[atoi(token)];
+			SCR_DrawField (x, y, 0, width, value);
+			continue;
+		}
+
+		if (!strcmp(token, "hnum"))
+		{	// health number
+			int		color;
+
+			width = 3;
+			value = cl.frame.playerstate.stats[STAT_HEALTH];
+			if (value > 25)
+				color = 0;	// green
+			else if (value > 0)
+				color = (cl.frame.serverframe>>2) & 1;		// flash
+			else
+				color = 1;
+
+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
+				re.DrawPic (x, y, "field_3");
+
+			SCR_DrawField (x, y, color, width, value);
+			continue;
+		}
+
+		if (!strcmp(token, "anum"))
+		{	// ammo number
+			int		color;
+
+			width = 3;
+			value = cl.frame.playerstate.stats[STAT_AMMO];
+			if (value > 5)
+				color = 0;	// green
+			else if (value >= 0)
+				color = (cl.frame.serverframe>>2) & 1;		// flash
+			else
+				continue;	// negative number = don't show
+
+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
+				re.DrawPic (x, y, "field_3");
+
+			SCR_DrawField (x, y, color, width, value);
+			continue;
+		}
+
+		if (!strcmp(token, "rnum"))
+		{	// armor number
+			int		color;
+
+			width = 3;
+			value = cl.frame.playerstate.stats[STAT_ARMOR];
+			if (value < 1)
+				continue;
+
+			color = 0;	// green
+
+			if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
+				re.DrawPic (x, y, "field_3");
+
+			SCR_DrawField (x, y, color, width, value);
+			continue;
+		}
+
+
+		if (!strcmp(token, "stat_string"))
+		{
+			token = COM_Parse (&s);
+			index = atoi(token);
+			if (index < 0 || index >= MAX_CONFIGSTRINGS)
+				Com_Error (ERR_DROP, "Bad stat_string index");
+			index = cl.frame.playerstate.stats[index];
+			if (index < 0 || index >= MAX_CONFIGSTRINGS)
+				Com_Error (ERR_DROP, "Bad stat_string index");
+			DrawString (x, y, cl.configstrings[index]);
+			continue;
+		}
+
+		if (!strcmp(token, "cstring"))
+		{
+			token = COM_Parse (&s);
+			DrawHUDString (token, x, y, 320, 0);
+			continue;
+		}
+
+		if (!strcmp(token, "string"))
+		{
+			token = COM_Parse (&s);
+			DrawString (x, y, token);
+			continue;
+		}
+
+		if (!strcmp(token, "cstring2"))
+		{
+			token = COM_Parse (&s);
+			DrawHUDString (token, x, y, 320,0x80);
+			continue;
+		}
+
+		if (!strcmp(token, "string2"))
+		{
+			token = COM_Parse (&s);
+			DrawAltString (x, y, token);
+			continue;
+		}
+
+		if (!strcmp(token, "if"))
+		{	// draw a number
+			token = COM_Parse (&s);
+			value = cl.frame.playerstate.stats[atoi(token)];
+			if (!value)
+			{	// skip to endif
+				while (s && strcmp(token, "endif") )
+				{
+					token = COM_Parse (&s);
+				}
+			}
+
+			continue;
+		}
+
+
+	}
+}
+
+
+/*
+================
+SCR_DrawStats
+
+The status bar is a small layout program that
+is based on the stats array
+================
+*/
+void SCR_DrawStats (void)
+{
+	SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
+}
+
+
+/*
+================
+SCR_DrawLayout
+
+================
+*/
+#define	STAT_LAYOUTS		13
+
+void SCR_DrawLayout (void)
+{
+	if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
+		return;
+	SCR_ExecuteLayoutString (cl.layout);
+}
+
+//=======================================================
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+	int numframes;
+	int i;
+	float separation[2] = { 0, 0 };
+
+	// if the screen is disabled (loading plaque is up, or vid mode changing)
+	// do nothing at all
+	if (cls.disable_screen)
+	{
+		if (Sys_Milliseconds() - cls.disable_screen > 120000)
+		{
+			cls.disable_screen = 0;
+			Com_Printf ("Loading plaque timed out.\n");
+		}
+		return;
+	}
+
+	if (!scr_initialized || !con.initialized)
+		return;				// not initialized yet
+
+	/*
+	** range check cl_camera_separation so we don't inadvertently fry someone's
+	** brain
+	*/
+	if ( cl_stereo_separation->value > 1.0 )
+		Cvar_SetValue( "cl_stereo_separation", 1.0 );
+	else if ( cl_stereo_separation->value < 0 )
+		Cvar_SetValue( "cl_stereo_separation", 0.0 );
+
+	if ( cl_stereo->value )
+	{
+		numframes = 2;
+		separation[0] = -cl_stereo_separation->value / 2;
+		separation[1] =  cl_stereo_separation->value / 2;
+	}		
+	else
+	{
+		separation[0] = 0;
+		separation[1] = 0;
+		numframes = 1;
+	}
+
+	for ( i = 0; i < numframes; i++ )
+	{
+		re.BeginFrame( separation[i] );
+
+		if (scr_draw_loading == 2)
+		{	//  loading plaque over black screen
+			int		w, h;
+
+			re.CinematicSetPalette(NULL);
+			scr_draw_loading = false;
+			re.DrawGetPicSize (&w, &h, "loading");
+			re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
+//			re.EndFrame();
+//			return;
+		} 
+		// if a cinematic is supposed to be running, handle menus
+		// and console specially
+		else if (cl.cinematictime > 0)
+		{
+			if (cls.key_dest == key_menu)
+			{
+				if (cl.cinematicpalette_active)
+				{
+					re.CinematicSetPalette(NULL);
+					cl.cinematicpalette_active = false;
+				}
+				M_Draw ();
+//				re.EndFrame();
+//				return;
+			}
+			else if (cls.key_dest == key_console)
+			{
+				if (cl.cinematicpalette_active)
+				{
+					re.CinematicSetPalette(NULL);
+					cl.cinematicpalette_active = false;
+				}
+				SCR_DrawConsole ();
+//				re.EndFrame();
+//				return;
+			}
+			else
+			{
+				SCR_DrawCinematic();
+//				re.EndFrame();
+//				return;
+			}
+		}
+		else 
+		{
+
+			// make sure the game palette is active
+			if (cl.cinematicpalette_active)
+			{
+				re.CinematicSetPalette(NULL);
+				cl.cinematicpalette_active = false;
+			}
+
+			// do 3D refresh drawing, and then update the screen
+			SCR_CalcVrect ();
+
+			// clear any dirty part of the background
+			SCR_TileClear ();
+
+			V_RenderView ( separation[i] );
+
+			SCR_DrawStats ();
+			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
+				SCR_DrawLayout ();
+			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
+				CL_DrawInventory ();
+
+			SCR_DrawNet ();
+			SCR_CheckDrawCenterString ();
+
+			if (scr_timegraph->value)
+				SCR_DebugGraph (cls.frametime*300, 0);
+
+			if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
+				SCR_DrawDebugGraph ();
+
+			SCR_DrawPause ();
+
+			SCR_DrawConsole ();
+
+			M_Draw ();
+
+			SCR_DrawLoading ();
+		}
+	}
+	re.EndFrame();
+}
--- /dev/null
+++ b/client/cl_tent.c
@@ -1,0 +1,1745 @@
+/*
+Copyright (C) 1997-2001 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_tent.c -- client side temporary entities
+
+#include "client.h"
+
+typedef enum
+{
+	ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
+} exptype_t;
+
+typedef struct
+{
+	exptype_t	type;
+	entity_t	ent;
+
+	int			frames;
+	float		light;
+	vec3_t		lightcolor;
+	float		start;
+	int			baseframe;
+} explosion_t;
+
+
+
+#define	MAX_EXPLOSIONS	32
+explosion_t	cl_explosions[MAX_EXPLOSIONS];
+
+
+#define	MAX_BEAMS	32
+typedef struct
+{
+	int		entity;
+	int		dest_entity;
+	struct model_s	*model;
+	int		endtime;
+	vec3_t	offset;
+	vec3_t	start, end;
+} beam_t;
+beam_t		cl_beams[MAX_BEAMS];
+//PMM - added this for player-linked beams.  Currently only used by the plasma beam
+beam_t		cl_playerbeams[MAX_BEAMS];
+
+
+#define	MAX_LASERS	32
+typedef struct
+{
+	entity_t	ent;
+	int			endtime;
+} laser_t;
+laser_t		cl_lasers[MAX_LASERS];
+
+//ROGUE
+cl_sustain_t	cl_sustains[MAX_SUSTAINS];
+//ROGUE
+
+//PGM
+extern void CL_TeleportParticles (vec3_t org);
+//PGM
+
+void CL_BlasterParticles (vec3_t org, vec3_t dir);
+void CL_ExplosionParticles (vec3_t org);
+void CL_BFGExplosionParticles (vec3_t org);
+// RAFAEL
+void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
+
+struct sfx_s	*cl_sfx_ric1;
+struct sfx_s	*cl_sfx_ric2;
+struct sfx_s	*cl_sfx_ric3;
+struct sfx_s	*cl_sfx_lashit;
+struct sfx_s	*cl_sfx_spark5;
+struct sfx_s	*cl_sfx_spark6;
+struct sfx_s	*cl_sfx_spark7;
+struct sfx_s	*cl_sfx_railg;
+struct sfx_s	*cl_sfx_rockexp;
+struct sfx_s	*cl_sfx_grenexp;
+struct sfx_s	*cl_sfx_watrexp;
+// RAFAEL
+struct sfx_s	*cl_sfx_plasexp;
+struct sfx_s	*cl_sfx_footsteps[4];
+
+struct model_s	*cl_mod_explode;
+struct model_s	*cl_mod_smoke;
+struct model_s	*cl_mod_flash;
+struct model_s	*cl_mod_parasite_segment;
+struct model_s	*cl_mod_grapple_cable;
+struct model_s	*cl_mod_parasite_tip;
+struct model_s	*cl_mod_explo4;
+struct model_s	*cl_mod_bfg_explo;
+struct model_s	*cl_mod_powerscreen;
+// RAFAEL
+struct model_s	*cl_mod_plasmaexplo;
+
+//ROGUE
+struct sfx_s	*cl_sfx_lightning;
+struct sfx_s	*cl_sfx_disrexp;
+struct model_s	*cl_mod_lightning;
+struct model_s	*cl_mod_heatbeam;
+struct model_s	*cl_mod_monster_heatbeam;
+struct model_s	*cl_mod_explo4_big;
+
+//ROGUE
+/*
+=================
+CL_RegisterTEntSounds
+=================
+*/
+void CL_RegisterTEntSounds (void)
+{
+	int		i;
+	char	name[MAX_QPATH];
+
+	// PMM - version stuff
+//	Com_Printf ("%s\n", ROGUE_VERSION_STRING);
+	// PMM
+	cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
+	cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
+	cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
+	cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
+	cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
+	cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
+	cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
+	cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
+	cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
+	cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
+	cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
+	// RAFAEL
+	// cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
+	S_RegisterSound ("player/land1.wav");
+
+	S_RegisterSound ("player/fall2.wav");
+	S_RegisterSound ("player/fall1.wav");
+
+	for (i=0 ; i<4 ; i++)
+	{
+		Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
+		cl_sfx_footsteps[i] = S_RegisterSound (name);
+	}
+
+//PGM
+	cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
+	cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
+	// version stuff
+	sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
+	if (name[0] == 'w')
+		name[0] = 'W';
+//PGM
+}	
+
+/*
+=================
+CL_RegisterTEntModels
+=================
+*/
+void CL_RegisterTEntModels (void)
+{
+	cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
+	cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
+	cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
+	cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
+	cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
+	cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
+	cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
+	cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
+	cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
+
+re.RegisterModel ("models/objects/laser/tris.md2");
+re.RegisterModel ("models/objects/grenade2/tris.md2");
+re.RegisterModel ("models/weapons/v_machn/tris.md2");
+re.RegisterModel ("models/weapons/v_handgr/tris.md2");
+re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone/tris.md2");
+re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
+// RAFAEL
+// re.RegisterModel ("models/objects/blaser/tris.md2");
+
+re.RegisterPic ("w_machinegun");
+re.RegisterPic ("a_bullets");
+re.RegisterPic ("i_health");
+re.RegisterPic ("a_grenades");
+
+//ROGUE
+	cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
+	cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
+	cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
+	cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
+//ROGUE
+}	
+
+/*
+=================
+CL_ClearTEnts
+=================
+*/
+void CL_ClearTEnts (void)
+{
+	memset (cl_beams, 0, sizeof(cl_beams));
+	memset (cl_explosions, 0, sizeof(cl_explosions));
+	memset (cl_lasers, 0, sizeof(cl_lasers));
+
+//ROGUE
+	memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
+	memset (cl_sustains, 0, sizeof(cl_sustains));
+//ROGUE
+}
+
+/*
+=================
+CL_AllocExplosion
+=================
+*/
+explosion_t *CL_AllocExplosion (void)
+{
+	int		i;
+	int		time;
+	int		index;
+	
+	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+	{
+		if (cl_explosions[i].type == ex_free)
+		{
+			memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
+			return &cl_explosions[i];
+		}
+	}
+// find the oldest explosion
+	time = cl.time;
+	index = 0;
+
+	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+		if (cl_explosions[i].start < time)
+		{
+			time = cl_explosions[i].start;
+			index = i;
+		}
+	memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
+	return &cl_explosions[index];
+}
+
+/*
+=================
+CL_SmokeAndFlash
+=================
+*/
+void CL_SmokeAndFlash(vec3_t origin)
+{
+	explosion_t	*ex;
+
+	ex = CL_AllocExplosion ();
+	VectorCopy (origin, ex->ent.origin);
+	ex->type = ex_misc;
+	ex->frames = 4;
+	ex->ent.flags = RF_TRANSLUCENT;
+	ex->start = cl.frame.servertime - 100;
+	ex->ent.model = cl_mod_smoke;
+
+	ex = CL_AllocExplosion ();
+	VectorCopy (origin, ex->ent.origin);
+	ex->type = ex_flash;
+	ex->ent.flags = RF_FULLBRIGHT;
+	ex->frames = 2;
+	ex->start = cl.frame.servertime - 100;
+	ex->ent.model = cl_mod_flash;
+}
+
+/*
+=================
+CL_ParseParticles
+=================
+*/
+void CL_ParseParticles (void)
+{
+	int		color, count;
+	vec3_t	pos, dir;
+
+	MSG_ReadPos (&net_message, pos);
+	MSG_ReadDir (&net_message, dir);
+
+	color = MSG_ReadByte (&net_message);
+
+	count = MSG_ReadByte (&net_message);
+
+	CL_ParticleEffect (pos, dir, color, count);
+}
+
+/*
+=================
+CL_ParseBeam
+=================
+*/
+int CL_ParseBeam (struct model_s *model)
+{
+	int		ent;
+	vec3_t	start, end;
+	beam_t	*b;
+	int		i;
+	
+	ent = MSG_ReadShort (&net_message);
+	
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+
+// override any beam with the same entity
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+		if (b->entity == ent)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return ent;
+		}
+
+// find a free beam
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return ent;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return ent;
+}
+
+/*
+=================
+CL_ParseBeam2
+=================
+*/
+int CL_ParseBeam2 (struct model_s *model)
+{
+	int		ent;
+	vec3_t	start, end, offset;
+	beam_t	*b;
+	int		i;
+	
+	ent = MSG_ReadShort (&net_message);
+	
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+	MSG_ReadPos (&net_message, offset);
+
+//	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+		if (b->entity == ent)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+
+// find a free beam
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;	
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return ent;
+}
+
+// ROGUE
+/*
+=================
+CL_ParsePlayerBeam
+  - adds to the cl_playerbeam array instead of the cl_beams array
+=================
+*/
+int CL_ParsePlayerBeam (struct model_s *model)
+{
+	int		ent;
+	vec3_t	start, end, offset;
+	beam_t	*b;
+	int		i;
+	
+	ent = MSG_ReadShort (&net_message);
+	
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+	// PMM - network optimization
+	if (model == cl_mod_heatbeam)
+		VectorSet(offset, 2, 7, -3);
+	else if (model == cl_mod_monster_heatbeam)
+	{
+		model = cl_mod_heatbeam;
+		VectorSet(offset, 0, 0, 0);
+	}
+	else
+		MSG_ReadPos (&net_message, offset);
+
+//	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+// PMM - For player beams, we only want one per player (entity) so..
+	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (b->entity == ent)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+	}
+
+// find a free beam
+	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+			b->entity = ent;
+			b->model = model;
+			b->endtime = cl.time + 100;		// PMM - this needs to be 100 to prevent multiple heatbeams
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorCopy (offset, b->offset);
+			return ent;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return ent;
+}
+//rogue
+
+/*
+=================
+CL_ParseLightning
+=================
+*/
+int CL_ParseLightning (struct model_s *model)
+{
+	int		srcEnt, destEnt;
+	vec3_t	start, end;
+	beam_t	*b;
+	int		i;
+	
+	srcEnt = MSG_ReadShort (&net_message);
+	destEnt = MSG_ReadShort (&net_message);
+
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+
+// override any beam with the same source AND destination entities
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+		if (b->entity == srcEnt && b->dest_entity == destEnt)
+		{
+//			Com_Printf("%d: OVERRIDE  %d -> %d\n", cl.time, srcEnt, destEnt);
+			b->entity = srcEnt;
+			b->dest_entity = destEnt;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return srcEnt;
+		}
+
+// find a free beam
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+		{
+//			Com_Printf("%d: NORMAL  %d -> %d\n", cl.time, srcEnt, destEnt);
+			b->entity = srcEnt;
+			b->dest_entity = destEnt;
+			b->model = model;
+			b->endtime = cl.time + 200;
+			VectorCopy (start, b->start);
+			VectorCopy (end, b->end);
+			VectorClear (b->offset);
+			return srcEnt;
+		}
+	}
+	Com_Printf ("beam list overflow!\n");	
+	return srcEnt;
+}
+
+/*
+=================
+CL_ParseLaser
+=================
+*/
+void CL_ParseLaser (int colors)
+{
+	vec3_t	start;
+	vec3_t	end;
+	laser_t	*l;
+	int		i;
+
+	MSG_ReadPos (&net_message, start);
+	MSG_ReadPos (&net_message, end);
+
+	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+	{
+		if (l->endtime < cl.time)
+		{
+			l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
+			VectorCopy (start, l->ent.origin);
+			VectorCopy (end, l->ent.oldorigin);
+			l->ent.alpha = 0.30;
+			l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
+			l->ent.model = NULL;
+			l->ent.frame = 4;
+			l->endtime = cl.time + 100;
+			return;
+		}
+	}
+}
+
+//=============
+//ROGUE
+void CL_ParseSteam (void)
+{
+	vec3_t	pos, dir;
+	int		id, i;
+	int		r;
+	int		cnt;
+	int		color;
+	int		magnitude;
+	cl_sustain_t	*s, *free_sustain;
+
+	id = MSG_ReadShort (&net_message);		// an id of -1 is an instant effect
+	if (id != -1) // sustains
+	{
+//			Com_Printf ("Sustain effect id %d\n", id);
+		free_sustain = NULL;
+		for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+		{
+			if (s->id == 0)
+			{
+				free_sustain = s;
+				break;
+			}
+		}
+		if (free_sustain)
+		{
+			s->id = id;
+			s->count = MSG_ReadByte (&net_message);
+			MSG_ReadPos (&net_message, s->org);
+			MSG_ReadDir (&net_message, s->dir);
+			r = MSG_ReadByte (&net_message);
+			s->color = r & 0xff;
+			s->magnitude = MSG_ReadShort (&net_message);
+			s->endtime = cl.time + MSG_ReadLong (&net_message);
+			s->think = CL_ParticleSteamEffect2;
+			s->thinkinterval = 100;
+			s->nextthink = cl.time;
+		}
+		else
+		{
+//				Com_Printf ("No free sustains!\n");
+			// FIXME - read the stuff anyway
+			cnt = MSG_ReadByte (&net_message);
+			MSG_ReadPos (&net_message, pos);
+			MSG_ReadDir (&net_message, dir);
+			r = MSG_ReadByte (&net_message);
+			magnitude = MSG_ReadShort (&net_message);
+			magnitude = MSG_ReadLong (&net_message); // really interval
+		}
+	}
+	else // instant
+	{
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		r = MSG_ReadByte (&net_message);
+		magnitude = MSG_ReadShort (&net_message);
+		color = r & 0xff;
+		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+//		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+	}
+}
+
+void CL_ParseWidow (void)
+{
+	vec3_t	pos;
+	int		id, i;
+	cl_sustain_t	*s, *free_sustain;
+
+	id = MSG_ReadShort (&net_message);
+
+	free_sustain = NULL;
+	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+	{
+		if (s->id == 0)
+		{
+			free_sustain = s;
+			break;
+		}
+	}
+	if (free_sustain)
+	{
+		s->id = id;
+		MSG_ReadPos (&net_message, s->org);
+		s->endtime = cl.time + 2100;
+		s->think = CL_Widowbeamout;
+		s->thinkinterval = 1;
+		s->nextthink = cl.time;
+	}
+	else // no free sustains
+	{
+		// FIXME - read the stuff anyway
+		MSG_ReadPos (&net_message, pos);
+	}
+}
+
+void CL_ParseNuke (void)
+{
+	vec3_t	pos;
+	int		i;
+	cl_sustain_t	*s, *free_sustain;
+
+	free_sustain = NULL;
+	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+	{
+		if (s->id == 0)
+		{
+			free_sustain = s;
+			break;
+		}
+	}
+	if (free_sustain)
+	{
+		s->id = 21000;
+		MSG_ReadPos (&net_message, s->org);
+		s->endtime = cl.time + 1000;
+		s->think = CL_Nukeblast;
+		s->thinkinterval = 1;
+		s->nextthink = cl.time;
+	}
+	else // no free sustains
+	{
+		// FIXME - read the stuff anyway
+		MSG_ReadPos (&net_message, pos);
+	}
+}
+
+//ROGUE
+//=============
+
+
+/*
+=================
+CL_ParseTEnt
+=================
+*/
+static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
+
+void CL_ParseTEnt (void)
+{
+	int		type;
+	vec3_t	pos, pos2, dir;
+	explosion_t	*ex;
+	int		cnt;
+	int		color;
+	int		r;
+	int		ent;
+	int		magnitude;
+
+	type = MSG_ReadByte (&net_message);
+
+	switch (type)
+	{
+	case TE_BLOOD:			// bullet hitting flesh
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect (pos, dir, 0xe8, 60);
+		break;
+
+	case TE_GUNSHOT:			// bullet hitting wall
+	case TE_SPARKS:
+	case TE_BULLET_SPARKS:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		if (type == TE_GUNSHOT)
+			CL_ParticleEffect (pos, dir, 0, 40);
+		else
+			CL_ParticleEffect (pos, dir, 0xe0, 6);
+
+		if (type != TE_SPARKS)
+		{
+			CL_SmokeAndFlash(pos);
+			
+			// impact sound
+			cnt = rand()&15;
+			if (cnt == 1)
+				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
+			else if (cnt == 2)
+				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
+			else if (cnt == 3)
+				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
+		}
+
+		break;
+		
+	case TE_SCREEN_SPARKS:
+	case TE_SHIELD_SPARKS:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		if (type == TE_SCREEN_SPARKS)
+			CL_ParticleEffect (pos, dir, 0xd0, 40);
+		else
+			CL_ParticleEffect (pos, dir, 0xb0, 40);
+		//FIXME : replace or remove this sound
+		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+		
+	case TE_SHOTGUN:			// bullet hitting wall
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect (pos, dir, 0, 20);
+		CL_SmokeAndFlash(pos);
+		break;
+
+	case TE_SPLASH:			// bullet hitting water
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		r = MSG_ReadByte (&net_message);
+		if (r > 6)
+			color = 0x00;
+		else
+			color = splash_color[r];
+		CL_ParticleEffect (pos, dir, color, cnt);
+
+		if (r == SPLASH_SPARKS)
+		{
+			r = rand() & 3;
+			if (r == 0)
+				S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
+			else if (r == 1)
+				S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
+			else
+				S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
+		}
+		break;
+
+	case TE_LASER_SPARKS:
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		color = MSG_ReadByte (&net_message);
+		CL_ParticleEffect2 (pos, dir, color, cnt);
+		break;
+
+	// RAFAEL
+	case TE_BLUEHYPERBLASTER:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, dir);
+		CL_BlasterParticles (pos, dir);
+		break;
+
+	case TE_BLASTER:			// blaster hitting wall
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_BlasterParticles (pos, dir);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+	// PMM - fixed to correct for pitch of 0
+		if (dir[0])
+			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+		else if (dir[1] > 0)
+			ex->ent.angles[1] = 90;
+		else if (dir[1] < 0)
+			ex->ent.angles[1] = 270;
+		else
+			ex->ent.angles[1] = 0;
+
+		ex->type = ex_misc;
+		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 150;
+		ex->lightcolor[0] = 1;
+		ex->lightcolor[1] = 1;
+		ex->ent.model = cl_mod_explode;
+		ex->frames = 4;
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+		
+	case TE_RAILTRAIL:			// railgun effect
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_RailTrail (pos, pos2);
+		S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_EXPLOSION2:
+	case TE_GRENADE_EXPLOSION:
+	case TE_GRENADE_EXPLOSION_WATER:
+		MSG_ReadPos (&net_message, pos);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.model = cl_mod_explo4;
+		ex->frames = 19;
+		ex->baseframe = 30;
+		ex->ent.angles[1] = rand() % 360;
+		CL_ExplosionParticles (pos);
+		if (type == TE_GRENADE_EXPLOSION_WATER)
+			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+		else
+			S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
+		break;
+
+	// RAFAEL
+	case TE_PLASMA_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0; 
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.angles[1] = rand() % 360;
+		ex->ent.model = cl_mod_explo4;
+		if (frand() < 0.5)
+			ex->baseframe = 15;
+		ex->frames = 15;
+		CL_ExplosionParticles (pos);
+		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+		break;
+	
+	case TE_EXPLOSION1:
+	case TE_EXPLOSION1_BIG:						// PMM
+	case TE_ROCKET_EXPLOSION:
+	case TE_ROCKET_EXPLOSION_WATER:
+	case TE_EXPLOSION1_NP:						// PMM
+		MSG_ReadPos (&net_message, pos);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.angles[1] = rand() % 360;
+		if (type != TE_EXPLOSION1_BIG)				// PMM
+			ex->ent.model = cl_mod_explo4;			// PMM
+		else
+			ex->ent.model = cl_mod_explo4_big;
+		if (frand() < 0.5)
+			ex->baseframe = 15;
+		ex->frames = 15;
+		if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))		// PMM
+			CL_ExplosionParticles (pos);									// PMM
+		if (type == TE_ROCKET_EXPLOSION_WATER)
+			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+		else
+			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_BFG_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 0.0;
+		ex->lightcolor[1] = 1.0;
+		ex->lightcolor[2] = 0.0;
+		ex->ent.model = cl_mod_bfg_explo;
+		ex->ent.flags |= RF_TRANSLUCENT;
+		ex->ent.alpha = 0.30;
+		ex->frames = 4;
+		break;
+
+	case TE_BFG_BIGEXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		CL_BFGExplosionParticles (pos);
+		break;
+
+	case TE_BFG_LASER:
+		CL_ParseLaser (0xd0d1d2d3);
+		break;
+
+	case TE_BUBBLETRAIL:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_BubbleTrail (pos, pos2);
+		break;
+
+	case TE_PARASITE_ATTACK:
+	case TE_MEDIC_CABLE_ATTACK:
+		ent = CL_ParseBeam (cl_mod_parasite_segment);
+		break;
+
+	case TE_BOSSTPORT:			// boss teleporting to station
+		MSG_ReadPos (&net_message, pos);
+		CL_BigTeleportParticles (pos);
+		S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
+		break;
+
+	case TE_GRAPPLE_CABLE:
+		ent = CL_ParseBeam2 (cl_mod_grapple_cable);
+		break;
+
+	// RAFAEL
+	case TE_WELDING_SPARKS:
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		color = MSG_ReadByte (&net_message);
+		CL_ParticleEffect2 (pos, dir, color, cnt);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_flash;
+		// note to self
+		// we need a better no draw flag
+		ex->ent.flags = RF_BEAM;
+		ex->start = cl.frame.servertime - 0.1;
+		ex->light = 100 + (rand()%75);
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 1.0;
+		ex->lightcolor[2] = 0.3;
+		ex->ent.model = cl_mod_flash;
+		ex->frames = 2;
+		break;
+
+	case TE_GREENBLOOD:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect2 (pos, dir, 0xdf, 30);
+		break;
+
+	// RAFAEL
+	case TE_TUNNEL_SPARKS:
+		cnt = MSG_ReadByte (&net_message);
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		color = MSG_ReadByte (&net_message);
+		CL_ParticleEffect3 (pos, dir, color, cnt);
+		break;
+
+//=============
+//PGM
+		// PMM -following code integrated for flechette (different color)
+	case TE_BLASTER2:			// green blaster hitting wall
+	case TE_FLECHETTE:			// flechette
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		
+		// PMM
+		if (type == TE_BLASTER2)
+			CL_BlasterParticles2 (pos, dir, 0xd0);
+		else
+			CL_BlasterParticles2 (pos, dir, 0x6f); // 75
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+	// PMM - fixed to correct for pitch of 0
+		if (dir[0])
+			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+		else if (dir[1] > 0)
+			ex->ent.angles[1] = 90;
+		else if (dir[1] < 0)
+			ex->ent.angles[1] = 270;
+		else
+			ex->ent.angles[1] = 0;
+
+		ex->type = ex_misc;
+		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+
+		// PMM
+		if (type == TE_BLASTER2)
+			ex->ent.skinnum = 1;
+		else // flechette
+			ex->ent.skinnum = 2;
+
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 150;
+		// PMM
+		if (type == TE_BLASTER2)
+			ex->lightcolor[1] = 1;
+		else // flechette
+		{
+			ex->lightcolor[0] = 0.19;
+			ex->lightcolor[1] = 0.41;
+			ex->lightcolor[2] = 0.75;
+		}
+		ex->ent.model = cl_mod_explode;
+		ex->frames = 4;
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+
+	case TE_LIGHTNING:
+		ent = CL_ParseLightning (cl_mod_lightning);
+		S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_DEBUGTRAIL:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_DebugTrail (pos, pos2);
+		break;
+
+	case TE_PLAIN_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+
+		ex = CL_AllocExplosion ();
+		VectorCopy (pos, ex->ent.origin);
+		ex->type = ex_poly;
+		ex->ent.flags = RF_FULLBRIGHT;
+		ex->start = cl.frame.servertime - 100;
+		ex->light = 350;
+		ex->lightcolor[0] = 1.0;
+		ex->lightcolor[1] = 0.5;
+		ex->lightcolor[2] = 0.5;
+		ex->ent.angles[1] = rand() % 360;
+		ex->ent.model = cl_mod_explo4;
+		if (frand() < 0.5)
+			ex->baseframe = 15;
+		ex->frames = 15;
+		if (type == TE_ROCKET_EXPLOSION_WATER)
+			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+		else
+			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_FLASHLIGHT:
+		MSG_ReadPos(&net_message, pos);
+		ent = MSG_ReadShort(&net_message);
+		CL_Flashlight(ent, pos);
+		break;
+
+	case TE_FORCEWALL:
+		MSG_ReadPos(&net_message, pos);
+		MSG_ReadPos(&net_message, pos2);
+		color = MSG_ReadByte (&net_message);
+		CL_ForceWall(pos, pos2, color);
+		break;
+
+	case TE_HEATBEAM:
+		ent = CL_ParsePlayerBeam (cl_mod_heatbeam);
+		break;
+
+	case TE_MONSTER_HEATBEAM:
+		ent = CL_ParsePlayerBeam (cl_mod_monster_heatbeam);
+		break;
+
+	case TE_HEATBEAM_SPARKS:
+//		cnt = MSG_ReadByte (&net_message);
+		cnt = 50;
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+//		r = MSG_ReadByte (&net_message);
+//		magnitude = MSG_ReadShort (&net_message);
+		r = 8;
+		magnitude = 60;
+		color = r & 0xff;
+		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+	
+	case TE_HEATBEAM_STEAM:
+//		cnt = MSG_ReadByte (&net_message);
+		cnt = 20;
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+//		r = MSG_ReadByte (&net_message);
+//		magnitude = MSG_ReadShort (&net_message);
+//		color = r & 0xff;
+		color = 0xe0;
+		magnitude = 60;
+		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_STEAM:
+		CL_ParseSteam();
+		break;
+
+	case TE_BUBBLETRAIL2:
+//		cnt = MSG_ReadByte (&net_message);
+		cnt = 8;
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadPos (&net_message, pos2);
+		CL_BubbleTrail2 (pos, pos2, cnt);
+		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_MOREBLOOD:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+		CL_ParticleEffect (pos, dir, 0xe8, 250);
+		break;
+
+	case TE_CHAINFIST_SMOKE:
+		dir[0]=0; dir[1]=0; dir[2]=1;
+		MSG_ReadPos(&net_message, pos);
+		CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
+		break;
+
+	case TE_ELECTRIC_SPARKS:
+		MSG_ReadPos (&net_message, pos);
+		MSG_ReadDir (&net_message, dir);
+//		CL_ParticleEffect (pos, dir, 109, 40);
+		CL_ParticleEffect (pos, dir, 0x75, 40);
+		//FIXME : replace or remove this sound
+		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_TRACKER_EXPLOSION:
+		MSG_ReadPos (&net_message, pos);
+		CL_ColorFlash (pos, 0, 150, -1, -1, -1);
+		CL_ColorExplosionParticles (pos, 0, 1);
+//		CL_Tracker_Explode (pos);
+		S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
+		break;
+
+	case TE_TELEPORT_EFFECT:
+	case TE_DBALL_GOAL:
+		MSG_ReadPos (&net_message, pos);
+		CL_TeleportParticles (pos);
+		break;
+
+	case TE_WIDOWBEAMOUT:
+		CL_ParseWidow ();
+		break;
+
+	case TE_NUKEBLAST:
+		CL_ParseNuke ();
+		break;
+
+	case TE_WIDOWSPLASH:
+		MSG_ReadPos (&net_message, pos);
+		CL_WidowSplash (pos);
+		break;
+//PGM
+//==============
+
+	default:
+		Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
+	}
+}
+
+/*
+=================
+CL_AddBeams
+=================
+*/
+void CL_AddBeams (void)
+{
+	int			i,j;
+	beam_t		*b;
+	vec3_t		dist, org;
+	float		d;
+	entity_t	ent;
+	float		yaw, pitch;
+	float		forward;
+	float		len, steps;
+	float		model_length;
+	
+// update beams
+	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+	{
+		if (!b->model || b->endtime < cl.time)
+			continue;
+
+		// if coming from the player, update the start position
+		if (b->entity == cl.playernum+1)	// entity 0 is the world
+		{
+			VectorCopy (cl.refdef.vieworg, b->start);
+			b->start[2] -= 22;	// adjust for view height
+		}
+		VectorAdd (b->start, b->offset, org);
+
+	// calculate pitch and yaw
+		VectorSubtract (b->end, org, dist);
+
+		if (dist[1] == 0 && dist[0] == 0)
+		{
+			yaw = 0;
+			if (dist[2] > 0)
+				pitch = 90;
+			else
+				pitch = 270;
+		}
+		else
+		{
+	// PMM - fixed to correct for pitch of 0
+			if (dist[0])
+				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+			else if (dist[1] > 0)
+				yaw = 90;
+			else
+				yaw = 270;
+			if (yaw < 0)
+				yaw += 360;
+	
+			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+			if (pitch < 0)
+				pitch += 360.0;
+		}
+
+	// add new entities for the beams
+		d = VectorNormalize(dist);
+
+		memset (&ent, 0, sizeof(ent));
+		if (b->model == cl_mod_lightning)
+		{
+			model_length = 35.0;
+			d-= 20.0;  // correction so it doesn't end in middle of tesla
+		}
+		else
+		{
+			model_length = 30.0;
+		}
+		steps = ceil(d/model_length);
+		len = (d-model_length)/(steps-1);
+
+		// PMM - special case for lightning model .. if the real length is shorter than the model,
+		// flip it around & draw it from the end to the start.  This prevents the model from going
+		// through the tesla mine (instead it goes through the target)
+		if ((b->model == cl_mod_lightning) && (d <= model_length))
+		{
+//			Com_Printf ("special case\n");
+			VectorCopy (b->end, ent.origin);
+			// offset to push beam outside of tesla model (negative because dist is from end to start
+			// for this beam)
+//			for (j=0 ; j<3 ; j++)
+//				ent.origin[j] -= dist[j]*10.0;
+			ent.model = b->model;
+			ent.flags = RF_FULLBRIGHT;
+			ent.angles[0] = pitch;
+			ent.angles[1] = yaw;
+			ent.angles[2] = rand()%360;
+			V_AddEntity (&ent);			
+			return;
+		}
+		while (d > 0)
+		{
+			VectorCopy (org, ent.origin);
+			ent.model = b->model;
+			if (b->model == cl_mod_lightning)
+			{
+				ent.flags = RF_FULLBRIGHT;
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = rand()%360;
+			}
+			else
+			{
+				ent.angles[0] = pitch;
+				ent.angles[1] = yaw;
+				ent.angles[2] = rand()%360;
+			}
+			
+//			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+			V_AddEntity (&ent);
+
+			for (j=0 ; j<3 ; j++)
+				org[j] += dist[j]*len;
+			d -= model_length;
+		}
+	}
+}
+
+
+/*
+//				Com_Printf ("Endpoint:  %f %f %f\n", b->end[0], b->end[1], b->end[2]);
+//				Com_Printf ("Pred View Angles:  %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
+//				Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
+//				VectorCopy (cl.predicted_origin, b->start);
+//				b->start[2] += 22;	// adjust for view height
+//				if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
+//					b->start[2] = cl.refdef.vieworg[2];
+//				}
+
+//				Com_Printf ("Time:  %d %d %f\n", cl.time, cls.realtime, cls.frametime);
+*/
+
+extern cvar_t *hand;
+
+/*
+=================
+ROGUE - draw player locked beams
+CL_AddPlayerBeams
+=================
+*/
+void CL_AddPlayerBeams (void)
+{
+	int			i,j;
+	beam_t		*b;
+	vec3_t		dist, org;
+	float		d;
+	entity_t	ent;
+	float		yaw, pitch;
+	float		forward;
+	float		len, steps;
+	int			framenum;
+	float		model_length;
+	
+	float		hand_multiplier;
+	frame_t		*oldframe;
+	player_state_t	*ps, *ops;
+
+//PMM
+	if (hand)
+	{
+		if (hand->value == 2)
+			hand_multiplier = 0;
+		else if (hand->value == 1)
+			hand_multiplier = -1;
+		else
+			hand_multiplier = 1;
+	}
+	else 
+	{
+		hand_multiplier = 1;
+	}
+//PMM
+
+// update beams
+	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+	{
+		vec3_t		f,r,u;
+		if (!b->model || b->endtime < cl.time)
+			continue;
+
+		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+		{
+
+			// if coming from the player, update the start position
+			if (b->entity == cl.playernum+1)	// entity 0 is the world
+			{	
+				// set up gun position
+				// code straight out of CL_AddViewWeapon
+				ps = &cl.frame.playerstate;
+				j = (cl.frame.serverframe - 1) & UPDATE_MASK;
+				oldframe = &cl.frames[j];
+				if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+					oldframe = &cl.frame;		// previous frame was dropped or involid
+				ops = &oldframe->playerstate;
+				for (j=0 ; j<3 ; j++)
+				{
+					b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
+						+ cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
+				}
+				VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
+				VectorMA (     org, b->offset[1], cl.v_forward, org);
+				VectorMA (     org, b->offset[2], cl.v_up, org);
+				if ((hand) && (hand->value == 2)) {
+					VectorMA (org, -1, cl.v_up, org);
+				}
+				// FIXME - take these out when final
+				VectorCopy (cl.v_right, r);
+				VectorCopy (cl.v_forward, f);
+				VectorCopy (cl.v_up, u);
+
+			}
+			else
+				VectorCopy (b->start, org);
+		}
+		else
+		{
+			// if coming from the player, update the start position
+			if (b->entity == cl.playernum+1)	// entity 0 is the world
+			{
+				VectorCopy (cl.refdef.vieworg, b->start);
+				b->start[2] -= 22;	// adjust for view height
+			}
+			VectorAdd (b->start, b->offset, org);
+		}
+
+	// calculate pitch and yaw
+		VectorSubtract (b->end, org, dist);
+
+//PMM
+		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
+		{
+			vec_t len;
+
+			len = VectorLength (dist);
+			VectorScale (f, len, dist);
+			VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
+			VectorMA (dist, b->offset[1], f, dist);
+			VectorMA (dist, b->offset[2], u, dist);
+			if ((hand) && (hand->value == 2)) {
+				VectorMA (org, -1, cl.v_up, org);
+			}
+		}
+//PMM
+
+		if (dist[1] == 0 && dist[0] == 0)
+		{
+			yaw = 0;
+			if (dist[2] > 0)
+				pitch = 90;
+			else
+				pitch = 270;
+		}
+		else
+		{
+	// PMM - fixed to correct for pitch of 0
+			if (dist[0])
+				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+			else if (dist[1] > 0)
+				yaw = 90;
+			else
+				yaw = 270;
+			if (yaw < 0)
+				yaw += 360;
+	
+			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+			if (pitch < 0)
+				pitch += 360.0;
+		}
+		
+		if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+		{
+			if (b->entity != cl.playernum+1)
+			{
+				framenum = 2;
+//				Com_Printf ("Third person\n");
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = 0;
+//				Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
+				AngleVectors(ent.angles, f, r, u);
+					
+				// if it's a non-origin offset, it's a player, so use the hardcoded player offset
+				if (!VectorCompare (b->offset, vec3_origin))
+				{
+					VectorMA (org, -(b->offset[0])+1, r, org);
+					VectorMA (org, -(b->offset[1]), f, org);
+					VectorMA (org, -(b->offset[2])-10, u, org);
+				}
+				else
+				{
+					// if it's a monster, do the particle effect
+					CL_MonsterPlasma_Shell(b->start);
+				}
+			}
+			else
+			{
+				framenum = 1;
+			}
+		}
+
+		// if it's the heatbeam, draw the particle effect
+		if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
+		{
+			CL_Heatbeam (org, dist);
+		}
+
+	// add new entities for the beams
+		d = VectorNormalize(dist);
+
+		memset (&ent, 0, sizeof(ent));
+		if (b->model == cl_mod_heatbeam)
+		{
+			model_length = 32.0;
+		}
+		else if (b->model == cl_mod_lightning)
+		{
+			model_length = 35.0;
+			d-= 20.0;  // correction so it doesn't end in middle of tesla
+		}
+		else
+		{
+			model_length = 30.0;
+		}
+		steps = ceil(d/model_length);
+		len = (d-model_length)/(steps-1);
+
+		// PMM - special case for lightning model .. if the real length is shorter than the model,
+		// flip it around & draw it from the end to the start.  This prevents the model from going
+		// through the tesla mine (instead it goes through the target)
+		if ((b->model == cl_mod_lightning) && (d <= model_length))
+		{
+//			Com_Printf ("special case\n");
+			VectorCopy (b->end, ent.origin);
+			// offset to push beam outside of tesla model (negative because dist is from end to start
+			// for this beam)
+//			for (j=0 ; j<3 ; j++)
+//				ent.origin[j] -= dist[j]*10.0;
+			ent.model = b->model;
+			ent.flags = RF_FULLBRIGHT;
+			ent.angles[0] = pitch;
+			ent.angles[1] = yaw;
+			ent.angles[2] = rand()%360;
+			V_AddEntity (&ent);			
+			return;
+		}
+		while (d > 0)
+		{
+			VectorCopy (org, ent.origin);
+			ent.model = b->model;
+			if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+			{
+//				ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+//				ent.alpha = 0.3;
+				ent.flags = RF_FULLBRIGHT;
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = (cl.time) % 360;
+//				ent.angles[2] = rand()%360;
+				ent.frame = framenum;
+			}
+			else if (b->model == cl_mod_lightning)
+			{
+				ent.flags = RF_FULLBRIGHT;
+				ent.angles[0] = -pitch;
+				ent.angles[1] = yaw + 180.0;
+				ent.angles[2] = rand()%360;
+			}
+			else
+			{
+				ent.angles[0] = pitch;
+				ent.angles[1] = yaw;
+				ent.angles[2] = rand()%360;
+			}
+			
+//			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+			V_AddEntity (&ent);
+
+			for (j=0 ; j<3 ; j++)
+				org[j] += dist[j]*len;
+			d -= model_length;
+		}
+	}
+}
+
+/*
+=================
+CL_AddExplosions
+=================
+*/
+void CL_AddExplosions (void)
+{
+	entity_t	*ent;
+	int			i;
+	explosion_t	*ex;
+	float		frac;
+	int			f;
+
+	memset (&ent, 0, sizeof(ent));
+
+	for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
+	{
+		if (ex->type == ex_free)
+			continue;
+		frac = (cl.time - ex->start)/100.0;
+		f = floor(frac);
+
+		ent = &ex->ent;
+
+		switch (ex->type)
+		{
+		case ex_mflash:
+			if (f >= ex->frames-1)
+				ex->type = ex_free;
+			break;
+		case ex_misc:
+			if (f >= ex->frames-1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+			ent->alpha = 1.0 - frac/(ex->frames-1);
+			break;
+		case ex_flash:
+			if (f >= 1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+			ent->alpha = 1.0;
+			break;
+		case ex_poly:
+			if (f >= ex->frames-1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+
+			ent->alpha = (16.0 - (float)f)/16.0;
+
+			if (f < 10)
+			{
+				ent->skinnum = (f>>1);
+				if (ent->skinnum < 0)
+					ent->skinnum = 0;
+			}
+			else
+			{
+				ent->flags |= RF_TRANSLUCENT;
+				if (f < 13)
+					ent->skinnum = 5;
+				else
+					ent->skinnum = 6;
+			}
+			break;
+		case ex_poly2:
+			if (f >= ex->frames-1)
+			{
+				ex->type = ex_free;
+				break;
+			}
+
+			ent->alpha = (5.0 - (float)f)/5.0;
+			ent->skinnum = 0;
+			ent->flags |= RF_TRANSLUCENT;
+			break;
+		}
+
+		if (ex->type == ex_free)
+			continue;
+		if (ex->light)
+		{
+			V_AddLight (ent->origin, ex->light*ent->alpha,
+				ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
+		}
+
+		VectorCopy (ent->origin, ent->oldorigin);
+
+		if (f < 0)
+			f = 0;
+		ent->frame = ex->baseframe + f + 1;
+		ent->oldframe = ex->baseframe + f;
+		ent->backlerp = 1.0 - cl.lerpfrac;
+
+		V_AddEntity (ent);
+	}
+}
+
+
+/*
+=================
+CL_AddLasers
+=================
+*/
+void CL_AddLasers (void)
+{
+	laser_t		*l;
+	int			i;
+
+	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+	{
+		if (l->endtime >= cl.time)
+			V_AddEntity (&l->ent);
+	}
+}
+
+/* PMM - CL_Sustains */
+void CL_ProcessSustain ()
+{
+	cl_sustain_t	*s;
+	int				i;
+
+	for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
+	{
+		if (s->id)
+			if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
+			{
+//				Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
+				s->think (s);
+			}
+			else if (s->endtime < cl.time)
+				s->id = 0;
+	}
+}
+
+/*
+=================
+CL_AddTEnts
+=================
+*/
+void CL_AddTEnts (void)
+{
+	CL_AddBeams ();
+	// PMM - draw plasma beams
+	CL_AddPlayerBeams ();
+	CL_AddExplosions ();
+	CL_AddLasers ();
+	// PMM - set up sustain
+	CL_ProcessSustain();
+}
--- /dev/null
+++ b/client/cl_view.c
@@ -1,0 +1,584 @@
+/*
+Copyright (C) 1997-2001 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_view.c -- player rendering positioning
+
+#include "client.h"
+
+//=============
+//
+// development tools for weapons
+//
+int			gun_frame;
+struct model_s	*gun_model;
+
+//=============
+
+cvar_t		*crosshair;
+cvar_t		*cl_testparticles;
+cvar_t		*cl_testentities;
+cvar_t		*cl_testlights;
+cvar_t		*cl_testblend;
+
+cvar_t		*cl_stats;
+
+
+int			r_numdlights;
+dlight_t	r_dlights[MAX_DLIGHTS];
+
+int			r_numentities;
+entity_t	r_entities[MAX_ENTITIES];
+
+int			r_numparticles;
+particle_t	r_particles[MAX_PARTICLES];
+
+lightstyle_t	r_lightstyles[MAX_LIGHTSTYLES];
+
+char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+int num_cl_weaponmodels;
+
+/*
+====================
+V_ClearScene
+
+Specifies the model that will be used as the world
+====================
+*/
+void V_ClearScene (void)
+{
+	r_numdlights = 0;
+	r_numentities = 0;
+	r_numparticles = 0;
+}
+
+
+/*
+=====================
+V_AddEntity
+
+=====================
+*/
+void V_AddEntity (entity_t *ent)
+{
+	if (r_numentities >= MAX_ENTITIES)
+		return;
+	r_entities[r_numentities++] = *ent;
+}
+
+
+/*
+=====================
+V_AddParticle
+
+=====================
+*/
+void V_AddParticle (vec3_t org, int color, float alpha)
+{
+	particle_t	*p;
+
+	if (r_numparticles >= MAX_PARTICLES)
+		return;
+	p = &r_particles[r_numparticles++];
+	VectorCopy (org, p->origin);
+	p->color = color;
+	p->alpha = alpha;
+}
+
+/*
+=====================
+V_AddLight
+
+=====================
+*/
+void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
+{
+	dlight_t	*dl;
+
+	if (r_numdlights >= MAX_DLIGHTS)
+		return;
+	dl = &r_dlights[r_numdlights++];
+	VectorCopy (org, dl->origin);
+	dl->intensity = intensity;
+	dl->color[0] = r;
+	dl->color[1] = g;
+	dl->color[2] = b;
+}
+
+
+/*
+=====================
+V_AddLightStyle
+
+=====================
+*/
+void V_AddLightStyle (int style, float r, float g, float b)
+{
+	lightstyle_t	*ls;
+
+	if (style < 0 || style > MAX_LIGHTSTYLES)
+		Com_Error (ERR_DROP, "Bad light style %i", style);
+	ls = &r_lightstyles[style];
+
+	ls->white = r+g+b;
+	ls->rgb[0] = r;
+	ls->rgb[1] = g;
+	ls->rgb[2] = b;
+}
+
+/*
+================
+V_TestParticles
+
+If cl_testparticles is set, create 4096 particles in the view
+================
+*/
+void V_TestParticles (void)
+{
+	particle_t	*p;
+	int			i, j;
+	float		d, r, u;
+
+	r_numparticles = MAX_PARTICLES;
+	for (i=0 ; i<r_numparticles ; i++)
+	{
+		d = i*0.25;
+		r = 4*((i&7)-3.5);
+		u = 4*(((i>>3)&7)-3.5);
+		p = &r_particles[i];
+
+		for (j=0 ; j<3 ; j++)
+			p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
+			cl.v_right[j]*r + cl.v_up[j]*u;
+
+		p->color = 8;
+		p->alpha = cl_testparticles->value;
+	}
+}
+
+/*
+================
+V_TestEntities
+
+If cl_testentities is set, create 32 player models
+================
+*/
+void V_TestEntities (void)
+{
+	int			i, j;
+	float		f, r;
+	entity_t	*ent;
+
+	r_numentities = 32;
+	memset (r_entities, 0, sizeof(r_entities));
+
+	for (i=0 ; i<r_numentities ; i++)
+	{
+		ent = &r_entities[i];
+
+		r = 64 * ( (i%4) - 1.5 );
+		f = 64 * (i/4) + 128;
+
+		for (j=0 ; j<3 ; j++)
+			ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+			cl.v_right[j]*r;
+
+		ent->model = cl.baseclientinfo.model;
+		ent->skin = cl.baseclientinfo.skin;
+	}
+}
+
+/*
+================
+V_TestLights
+
+If cl_testlights is set, create 32 lights models
+================
+*/
+void V_TestLights (void)
+{
+	int			i, j;
+	float		f, r;
+	dlight_t	*dl;
+
+	r_numdlights = 32;
+	memset (r_dlights, 0, sizeof(r_dlights));
+
+	for (i=0 ; i<r_numdlights ; i++)
+	{
+		dl = &r_dlights[i];
+
+		r = 64 * ( (i%4) - 1.5 );
+		f = 64 * (i/4) + 128;
+
+		for (j=0 ; j<3 ; j++)
+			dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+			cl.v_right[j]*r;
+		dl->color[0] = ((i%6)+1) & 1;
+		dl->color[1] = (((i%6)+1) & 2)>>1;
+		dl->color[2] = (((i%6)+1) & 4)>>2;
+		dl->intensity = 200;
+	}
+}
+
+//===================================================================
+
+/*
+=================
+CL_PrepRefresh
+
+Call before entering a new level, or after changing dlls
+=================
+*/
+void CL_PrepRefresh (void)
+{
+	char		mapname[32];
+	int			i;
+	char		name[MAX_QPATH];
+	float		rotate;
+	vec3_t		axis;
+
+	if (!cl.configstrings[CS_MODELS+1][0])
+		return;		// no map loaded
+
+	SCR_AddDirtyPoint (0, 0);
+	SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
+
+	// let the render dll load the map
+	strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5);	// skip "maps/"
+	mapname[strlen(mapname)-4] = 0;		// cut off ".bsp"
+
+	// register models, pics, and skins
+	Com_Printf ("Map: %s\r", mapname); 
+	SCR_UpdateScreen ();
+	re.BeginRegistration (mapname);
+	Com_Printf ("                                     \r");
+
+	// precache status bar pics
+	Com_Printf ("pics\r"); 
+	SCR_UpdateScreen ();
+	SCR_TouchPics ();
+	Com_Printf ("                                     \r");
+
+	CL_RegisterTEntModels ();
+
+	num_cl_weaponmodels = 1;
+	strcpy(cl_weaponmodels[0], "weapon.md2");
+
+	for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
+	{
+		strcpy (name, cl.configstrings[CS_MODELS+i]);
+		name[37] = 0;	// never go beyond one line
+		if (name[0] != '*')
+			Com_Printf ("%s\r", name); 
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();	// pump message loop
+		if (name[0] == '#')
+		{
+			// special player weapon model
+			if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
+			{
+				strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
+					sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
+				num_cl_weaponmodels++;
+			}
+		} 
+		else
+		{
+			cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
+			if (name[0] == '*')
+				cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
+			else
+				cl.model_clip[i] = NULL;
+		}
+		if (name[0] != '*')
+			Com_Printf ("                                     \r");
+	}
+
+	Com_Printf ("images\r", i); 
+	SCR_UpdateScreen ();
+	for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
+	{
+		cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
+		Sys_SendKeyEvents ();	// pump message loop
+	}
+	
+	Com_Printf ("                                     \r");
+	for (i=0 ; i<MAX_CLIENTS ; i++)
+	{
+		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+			continue;
+		Com_Printf ("client %i\r", i); 
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();	// pump message loop
+		CL_ParseClientinfo (i);
+		Com_Printf ("                                     \r");
+	}
+
+	CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
+
+	// set sky textures and speed
+	Com_Printf ("sky\r", i); 
+	SCR_UpdateScreen ();
+	rotate = atof (cl.configstrings[CS_SKYROTATE]);
+	sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f", 
+		&axis[0], &axis[1], &axis[2]);
+	re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
+	Com_Printf ("                                     \r");
+
+	// the renderer can now free unneeded stuff
+	re.EndRegistration ();
+
+	// clear any lines of console text
+	Con_ClearNotify ();
+
+	SCR_UpdateScreen ();
+	cl.refresh_prepped = true;
+	cl.force_refdef = true;	// make sure we have a valid refdef
+
+	// start the cd track
+	CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+}
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
+{
+	float	a;
+	float	x;
+
+	if (fov_x < 1 || fov_x > 179)
+		Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
+
+	x = width/tan(fov_x/360*M_PI);
+
+	a = atan (height/x);
+
+	a = a*360/M_PI;
+
+	return a;
+}
+
+//============================================================================
+
+// gun frame debugging functions
+void V_Gun_Next_f (void)
+{
+	gun_frame++;
+	Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Prev_f (void)
+{
+	gun_frame--;
+	if (gun_frame < 0)
+		gun_frame = 0;
+	Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Model_f (void)
+{
+	char	name[MAX_QPATH];
+
+	if (Cmd_Argc() != 2)
+	{
+		gun_model = NULL;
+		return;
+	}
+	Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
+	gun_model = re.RegisterModel (name);
+}
+
+//============================================================================
+
+
+/*
+=================
+SCR_DrawCrosshair
+=================
+*/
+void SCR_DrawCrosshair (void)
+{
+	if (!crosshair->value)
+		return;
+
+	if (crosshair->modified)
+	{
+		crosshair->modified = false;
+		SCR_TouchPics ();
+	}
+
+	if (!crosshair_pic[0])
+		return;
+
+	re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
+	, scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
+}
+
+/*
+==================
+V_RenderView
+
+==================
+*/
+void V_RenderView( float stereo_separation )
+{
+	extern int entitycmpfnc( const entity_t *, const entity_t * );
+
+	if (cls.state != ca_active)
+		return;
+
+	if (!cl.refresh_prepped)
+		return;			// still loading
+
+	if (cl_timedemo->value)
+	{
+		if (!cl.timedemo_start)
+			cl.timedemo_start = Sys_Milliseconds ();
+		cl.timedemo_frames++;
+	}
+
+	// an invalid frame will just use the exact previous refdef
+	// we can't use the old frame if the video mode has changed, though...
+	if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
+	{
+		cl.force_refdef = false;
+
+		V_ClearScene ();
+
+		// build a refresh entity list and calc cl.sim*
+		// this also calls CL_CalcViewValues which loads
+		// v_forward, etc.
+		CL_AddEntities ();
+
+		if (cl_testparticles->value)
+			V_TestParticles ();
+		if (cl_testentities->value)
+			V_TestEntities ();
+		if (cl_testlights->value)
+			V_TestLights ();
+		if (cl_testblend->value)
+		{
+			cl.refdef.blend[0] = 1;
+			cl.refdef.blend[1] = 0.5;
+			cl.refdef.blend[2] = 0.25;
+			cl.refdef.blend[3] = 0.5;
+		}
+
+		// offset vieworg appropriately if we're doing stereo separation
+		if ( stereo_separation != 0 )
+		{
+			vec3_t tmp;
+
+			VectorScale( cl.v_right, stereo_separation, tmp );
+			VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
+		}
+
+		// 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/8 pixel, so add 1/16 in each axis
+		cl.refdef.vieworg[0] += 1.0/16;
+		cl.refdef.vieworg[1] += 1.0/16;
+		cl.refdef.vieworg[2] += 1.0/16;
+
+		cl.refdef.x = scr_vrect.x;
+		cl.refdef.y = scr_vrect.y;
+		cl.refdef.width = scr_vrect.width;
+		cl.refdef.height = scr_vrect.height;
+		cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
+		cl.refdef.time = cl.time*0.001;
+
+		cl.refdef.areabits = cl.frame.areabits;
+
+		if (!cl_add_entities->value)
+			r_numentities = 0;
+		if (!cl_add_particles->value)
+			r_numparticles = 0;
+		if (!cl_add_lights->value)
+			r_numdlights = 0;
+		if (!cl_add_blend->value)
+		{
+			VectorClear (cl.refdef.blend);
+		}
+
+		cl.refdef.num_entities = r_numentities;
+		cl.refdef.entities = r_entities;
+		cl.refdef.num_particles = r_numparticles;
+		cl.refdef.particles = r_particles;
+		cl.refdef.num_dlights = r_numdlights;
+		cl.refdef.dlights = r_dlights;
+		cl.refdef.lightstyles = r_lightstyles;
+
+		cl.refdef.rdflags = cl.frame.playerstate.rdflags;
+
+		// sort entities for better cache locality
+        qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
+	}
+
+	re.RenderFrame (&cl.refdef);
+	if (cl_stats->value)
+		Com_Printf ("ent:%i  lt:%i  part:%i\n", r_numentities, r_numdlights, r_numparticles);
+	if ( log_stats->value && ( log_stats_file != 0 ) )
+		fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
+
+
+	SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
+	SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
+		scr_vrect.y+scr_vrect.height-1);
+
+	SCR_DrawCrosshair ();
+}
+
+
+/*
+=============
+V_Viewpos_f
+=============
+*/
+void V_Viewpos_f (void)
+{
+	Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
+		(int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2], 
+		(int)cl.refdef.viewangles[YAW]);
+}
+
+/*
+=============
+V_Init
+=============
+*/
+void V_Init (void)
+{
+	Cmd_AddCommand ("gun_next", V_Gun_Next_f);
+	Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
+	Cmd_AddCommand ("gun_model", V_Gun_Model_f);
+
+	Cmd_AddCommand ("viewpos", V_Viewpos_f);
+
+	crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
+
+	cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
+	cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
+	cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
+	cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
+
+	cl_stats = Cvar_Get ("cl_stats", "0", 0);
+}
--- /dev/null
+++ b/client/client.h
@@ -1,0 +1,584 @@
+/*
+Copyright (C) 1997-2001 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 -- primary header for client
+
+//define	PARANOID			// speed sapping error checking
+
+#include <math.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ref.h"
+
+#include "vid.h"
+#include "screen.h"
+#include "sound.h"
+#include "input.h"
+#include "keys.h"
+#include "console.h"
+#include "cdaudio.h"
+
+//=============================================================================
+
+typedef struct
+{
+	qboolean		valid;			// cleared if delta parsing was invalid
+	int				serverframe;
+	int				servertime;		// server time the message is valid for (in msec)
+	int				deltaframe;
+	byte			areabits[MAX_MAP_AREAS/8];		// portalarea visibility bits
+	player_state_t	playerstate;
+	int				num_entities;
+	int				parse_entities;	// non-masked index into cl_parse_entities array
+} frame_t;
+
+typedef struct
+{
+	entity_state_t	baseline;		// delta from this if not from a previous frame
+	entity_state_t	current;
+	entity_state_t	prev;			// will always be valid, but might just be a copy of current
+
+	int			serverframe;		// if not current, this ent isn't in the frame
+
+	int			trailcount;			// for diminishing grenade trails
+	vec3_t		lerp_origin;		// for trails (variable hz)
+
+	int			fly_stoptime;
+} centity_t;
+
+#define MAX_CLIENTWEAPONMODELS		20		// PGM -- upped from 16 to fit the chainfist vwep
+
+typedef struct
+{
+	char	name[MAX_QPATH];
+	char	cinfo[MAX_QPATH];
+	struct image_s	*skin;
+	struct image_s	*icon;
+	char	iconname[MAX_QPATH];
+	struct model_s	*model;
+	struct model_s	*weaponmodel[MAX_CLIENTWEAPONMODELS];
+} clientinfo_t;
+
+extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+extern int num_cl_weaponmodels;
+
+#define	CMD_BACKUP		64	// allow a lot of command backups for very fast systems
+
+//
+// the client_state_t structure is wiped completely at every
+// server map change
+//
+typedef struct
+{
+	int			timeoutcount;
+
+	int			timedemo_frames;
+	int			timedemo_start;
+
+	qboolean	refresh_prepped;	// false if on new level or new ref dll
+	qboolean	sound_prepped;		// ambient sounds can start
+	qboolean	force_refdef;		// vid has changed, so we can't use a paused refdef
+
+	int			parse_entities;		// index (not anded off) into cl_parse_entities[]
+
+	usercmd_t	cmd;
+	usercmd_t	cmds[CMD_BACKUP];	// each mesage will send several old cmds
+	int			cmd_time[CMD_BACKUP];	// time sent, for calculating pings
+	short		predicted_origins[CMD_BACKUP][3];	// for debug comparing against server
+
+	float		predicted_step;				// for stair up smoothing
+	unsigned	predicted_step_time;
+
+	vec3_t		predicted_origin;	// generated by CL_PredictMovement
+	vec3_t		predicted_angles;
+	vec3_t		prediction_error;
+
+	frame_t		frame;				// received from server
+	int			surpressCount;		// number of messages rate supressed
+	frame_t		frames[UPDATE_BACKUP];
+
+	// the client maintains its own idea of view angles, which are
+	// sent to the server each frame.  It is cleared to 0 upon entering each level.
+	// the server sends a delta each frame which is added to the locally
+	// tracked view angles to account for standing on rotating objects,
+	// and teleport direction changes
+	vec3_t		viewangles;
+
+	int			time;			// this is the time value that the client
+								// is rendering at.  always <= cls.realtime
+	float		lerpfrac;		// between oldframe and frame
+
+	refdef_t	refdef;
+
+	vec3_t		v_forward, v_right, v_up;	// set when refdef.angles is set
+
+	//
+	// transient data from server
+	//
+	char		layout[1024];		// general 2D overlay
+	int			inventory[MAX_ITEMS];
+
+	//
+	// non-gameserver infornamtion
+	// FIXME: move this cinematic stuff into the cin_t structure
+	FILE		*cinematic_file;
+	int			cinematictime;		// cls.realtime for first cinematic frame
+	int			cinematicframe;
+	char		cinematicpalette[768];
+	qboolean	cinematicpalette_active;
+
+	//
+	// server state information
+	//
+	qboolean	attractloop;		// running the attract loop, any key will menu
+	int			servercount;	// server identification for prespawns
+	char		gamedir[MAX_QPATH];
+	int			playernum;
+
+	char		configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+
+	//
+	// locally derived information from server state
+	//
+	struct model_s	*model_draw[MAX_MODELS];
+	struct cmodel_s	*model_clip[MAX_MODELS];
+
+	struct sfx_s	*sound_precache[MAX_SOUNDS];
+	struct image_s	*image_precache[MAX_IMAGES];
+
+	clientinfo_t	clientinfo[MAX_CLIENTS];
+	clientinfo_t	baseclientinfo;
+} client_state_t;
+
+extern	client_state_t	cl;
+
+/*
+==================================================================
+
+the client_static_t structure is persistant through an arbitrary number
+of server connections
+
+==================================================================
+*/
+
+typedef enum {
+	ca_uninitialized,
+	ca_disconnected, 	// not talking to a server
+	ca_connecting,		// sending request packets to the server
+	ca_connected,		// netchan_t established, waiting for svc_serverdata
+	ca_active			// game views should be displayed
+} connstate_t;
+
+typedef enum {
+	dl_none,
+	dl_model,
+	dl_sound,
+	dl_skin,
+	dl_single
+} dltype_t;		// download type
+
+typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
+
+typedef struct
+{
+	connstate_t	state;
+	keydest_t	key_dest;
+
+	int			framecount;
+	int			realtime;			// always increasing, no clamping, etc
+	float		frametime;			// seconds since last frame
+
+// screen rendering information
+	float		disable_screen;		// showing loading plaque between levels
+									// or changing rendering dlls
+									// if time gets > 30 seconds ahead, break it
+	int			disable_servercount;	// when we receive a frame and cl.servercount
+									// > cls.disable_servercount, clear disable_screen
+
+// connection information
+	char		servername[MAX_OSPATH];	// name of server from original connect
+	float		connect_time;		// for connection retransmits
+
+	int			quakePort;			// a 16 bit value that allows quake servers
+									// to work around address translating routers
+	netchan_t	netchan;
+	int			serverProtocol;		// in case we are doing some kind of version hack
+
+	int			challenge;			// from the server to use for connecting
+
+	FILE		*download;			// file transfer from server
+	char		downloadtempname[MAX_OSPATH];
+	char		downloadname[MAX_OSPATH];
+	int			downloadnumber;
+	dltype_t	downloadtype;
+	int			downloadpercent;
+
+// demo recording info must be here, so it isn't cleared on level change
+	qboolean	demorecording;
+	qboolean	demowaiting;	// don't record until a non-delta message is received
+	FILE		*demofile;
+} client_static_t;
+
+extern client_static_t	cls;
+
+//=============================================================================
+
+//
+// cvars
+//
+extern	cvar_t	*cl_stereo_separation;
+extern	cvar_t	*cl_stereo;
+
+extern	cvar_t	*cl_gun;
+extern	cvar_t	*cl_add_blend;
+extern	cvar_t	*cl_add_lights;
+extern	cvar_t	*cl_add_particles;
+extern	cvar_t	*cl_add_entities;
+extern	cvar_t	*cl_predict;
+extern	cvar_t	*cl_footsteps;
+extern	cvar_t	*cl_noskins;
+extern	cvar_t	*cl_autoskins;
+
+extern	cvar_t	*cl_upspeed;
+extern	cvar_t	*cl_forwardspeed;
+extern	cvar_t	*cl_sidespeed;
+
+extern	cvar_t	*cl_yawspeed;
+extern	cvar_t	*cl_pitchspeed;
+
+extern	cvar_t	*cl_run;
+
+extern	cvar_t	*cl_anglespeedkey;
+
+extern	cvar_t	*cl_shownet;
+extern	cvar_t	*cl_showmiss;
+extern	cvar_t	*cl_showclamp;
+
+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;
+
+extern	cvar_t	*freelook;
+
+extern	cvar_t	*cl_lightlevel;	// FIXME HACK
+
+extern	cvar_t	*cl_paused;
+extern	cvar_t	*cl_timedemo;
+
+extern	cvar_t	*cl_vwep;
+
+typedef struct
+{
+	int		key;				// so entities can reuse same entry
+	vec3_t	color;
+	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
+} cdlight_t;
+
+extern	centity_t	cl_entities[MAX_EDICTS];
+extern	cdlight_t	cl_dlights[MAX_DLIGHTS];
+
+// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
+// entities, so that when a delta compressed message arives from the server
+// it can be un-deltad from the original 
+#define	MAX_PARSE_ENTITIES	1024
+extern	entity_state_t	cl_parse_entities[MAX_PARSE_ENTITIES];
+
+//=============================================================================
+
+extern	netadr_t	net_from;
+extern	sizebuf_t	net_message;
+
+void DrawString (int x, int y, char *s);
+void DrawAltString (int x, int y, char *s);	// toggle high bit
+qboolean	CL_CheckOrDownloadFile (char *filename);
+
+void CL_AddNetgraph (void);
+
+//ROGUE
+typedef struct cl_sustain
+{
+	int			id;
+	int			type;
+	int			endtime;
+	int			nextthink;
+	int			thinkinterval;
+	vec3_t		org;
+	vec3_t		dir;
+	int			color;
+	int			count;
+	int			magnitude;
+	void		(*think)(struct cl_sustain *self);
+} cl_sustain_t;
+
+#define MAX_SUSTAINS		32
+void CL_ParticleSteamEffect2(cl_sustain_t *self);
+
+void CL_TeleporterParticles (entity_state_t *ent);
+void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count);
+void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count);
+
+// RAFAEL
+void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count);
+
+
+//=================================================
+
+// ========
+// PGM
+typedef struct particle_s
+{
+	struct particle_s	*next;
+
+	float		time;
+
+	vec3_t		org;
+	vec3_t		vel;
+	vec3_t		accel;
+	float		color;
+	float		colorvel;
+	float		alpha;
+	float		alphavel;
+} cparticle_t;
+
+
+#define	PARTICLE_GRAVITY	40
+#define BLASTER_PARTICLE_COLOR		0xe0
+// PMM
+#define INSTANT_PARTICLE	-10000.0
+// PGM
+// ========
+
+void CL_ClearEffects (void);
+void CL_ClearTEnts (void);
+void CL_BlasterTrail (vec3_t start, vec3_t end);
+void CL_QuadTrail (vec3_t start, vec3_t end);
+void CL_RailTrail (vec3_t start, vec3_t end);
+void CL_BubbleTrail (vec3_t start, vec3_t end);
+void CL_FlagTrail (vec3_t start, vec3_t end, float color);
+
+// RAFAEL
+void CL_IonripperTrail (vec3_t start, vec3_t end);
+
+// ========
+// PGM
+void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color);
+void CL_BlasterTrail2 (vec3_t start, vec3_t end);
+void CL_DebugTrail (vec3_t start, vec3_t end);
+void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing);
+void CL_Flashlight (int ent, vec3_t pos);
+void CL_ForceWall (vec3_t start, vec3_t end, int color);
+void CL_FlameEffects (centity_t *ent, vec3_t origin);
+void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel);
+void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
+void CL_Heatbeam (vec3_t start, vec3_t end);
+void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
+void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor);
+void CL_Tracker_Explode(vec3_t origin);
+void CL_TagTrail (vec3_t start, vec3_t end, float color);
+void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b);
+void CL_Tracker_Shell(vec3_t origin);
+void CL_MonsterPlasma_Shell(vec3_t origin);
+void CL_ColorExplosionParticles (vec3_t org, int color, int run);
+void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
+void CL_Widowbeamout (cl_sustain_t *self);
+void CL_Nukeblast (cl_sustain_t *self);
+void CL_WidowSplash (vec3_t org);
+// PGM
+// ========
+
+int CL_ParseEntityBits (unsigned *bits);
+void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits);
+void CL_ParseFrame (void);
+
+void CL_ParseTEnt (void);
+void CL_ParseConfigString (void);
+void CL_ParseMuzzleFlash (void);
+void CL_ParseMuzzleFlash2 (void);
+void SmokeAndFlash(vec3_t origin);
+
+void CL_SetLightstyle (int i);
+
+void CL_RunParticles (void);
+void CL_RunDLights (void);
+void CL_RunLightStyles (void);
+
+void CL_AddEntities (void);
+void CL_AddDLights (void);
+void CL_AddTEnts (void);
+void CL_AddLightStyles (void);
+
+//=================================================
+
+void CL_PrepRefresh (void);
+void CL_RegisterSounds (void);
+
+void CL_Quit_f (void);
+
+void IN_Accumulate (void);
+
+void CL_ParseLayout (void);
+
+
+//
+// cl_main
+//
+extern	refexport_t	re;		// interface to refresh .dll
+
+void CL_Init (void);
+
+void CL_FixUpGender(void);
+void CL_Disconnect (void);
+void CL_Disconnect_f (void);
+void CL_GetChallengePacket (void);
+void CL_PingServers_f (void);
+void CL_Snd_Restart_f (void);
+void CL_RequestNextDownload (void);
+
+//
+// cl_input
+//
+typedef struct
+{
+	int			down[2];		// key nums holding it down
+	unsigned	downtime;		// msec timestamp
+	unsigned	msec;			// msec down this frame
+	int			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_ClearState (void);
+
+void CL_ReadPackets (void);
+
+int  CL_ReadFromServer (void);
+void CL_WriteToServer (usercmd_t *cmd);
+void CL_BaseMove (usercmd_t *cmd);
+
+void IN_CenterView (void);
+
+float CL_KeyState (kbutton_t *key);
+char *Key_KeynumToString (int keynum);
+
+//
+// cl_demo.c
+//
+void CL_WriteDemoMessage (void);
+void CL_Stop_f (void);
+void CL_Record_f (void);
+
+//
+// cl_parse.c
+//
+extern	char *svc_strings[256];
+
+void CL_ParseServerMessage (void);
+void CL_LoadClientinfo (clientinfo_t *ci, char *s);
+void SHOWNET(char *s);
+void CL_ParseClientinfo (int player);
+void CL_Download_f (void);
+
+//
+// cl_view.c
+//
+extern	int			gun_frame;
+extern	struct model_s	*gun_model;
+
+void V_Init (void);
+void V_RenderView( float stereo_separation );
+void V_AddEntity (entity_t *ent);
+void V_AddParticle (vec3_t org, int color, float alpha);
+void V_AddLight (vec3_t org, float intensity, float r, float g, float b);
+void V_AddLightStyle (int style, float r, float g, float b);
+
+//
+// cl_tent.c
+//
+void CL_RegisterTEntSounds (void);
+void CL_RegisterTEntModels (void);
+void CL_SmokeAndFlash(vec3_t origin);
+
+
+//
+// cl_pred.c
+//
+void CL_InitPrediction (void);
+void CL_PredictMove (void);
+void CL_CheckPredictionError (void);
+
+//
+// cl_fx.c
+//
+cdlight_t *CL_AllocDlight (int key);
+void CL_BigTeleportParticles (vec3_t org);
+void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old);
+void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
+void CL_FlyEffect (centity_t *ent, vec3_t origin);
+void CL_BfgParticles (entity_t *ent);
+void CL_AddParticles (void);
+void CL_EntityEvent (entity_state_t *ent);
+// RAFAEL
+void CL_TrapParticles (entity_t *ent);
+
+//
+// menus
+//
+void M_Init (void);
+void M_Keydown (int key);
+void M_Draw (void);
+void M_Menu_Main_f (void);
+void M_ForceMenuOff (void);
+void M_AddToServerList (netadr_t adr, char *info);
+
+//
+// cl_inv.c
+//
+void CL_ParseInventory (void);
+void CL_KeyInventory (int key);
+void CL_DrawInventory (void);
+
+//
+// cl_pred.c
+//
+void CL_PredictMovement (void);
+
+#if id386
+void x86_TimerStart( void );
+void x86_TimerStop( void );
+void x86_TimerInit( unsigned long smallest, unsigned longest );
+unsigned long *x86_TimerGetHistogram( void );
+#endif
--- /dev/null
+++ b/client/console.c
@@ -1,0 +1,682 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+
+console_t	con;
+
+cvar_t		*con_notifytime;
+
+
+#define		MAXCMDLINE	256
+extern	char	key_lines[32][MAXCMDLINE];
+extern	int		edit_line;
+extern	int		key_linepos;
+		
+
+void DrawString (int x, int y, char *s)
+{
+	while (*s)
+	{
+		re.DrawChar (x, y, *s);
+		x+=8;
+		s++;
+	}
+}
+
+void DrawAltString (int x, int y, char *s)
+{
+	while (*s)
+	{
+		re.DrawChar (x, y, *s ^ 0x80);
+		x+=8;
+		s++;
+	}
+}
+
+
+void Key_ClearTyping (void)
+{
+	key_lines[edit_line][1] = 0;	// clear any typing
+	key_linepos = 1;
+}
+
+/*
+================
+Con_ToggleConsole_f
+================
+*/
+void Con_ToggleConsole_f (void)
+{
+	SCR_EndLoadingPlaque ();	// get rid of loading plaque
+
+	if (cl.attractloop)
+	{
+		Cbuf_AddText ("killserver\n");
+		return;
+	}
+
+	if (cls.state == ca_disconnected)
+	{	// start the demo loop again
+		Cbuf_AddText ("d1\n");
+		return;
+	}
+
+	Key_ClearTyping ();
+	Con_ClearNotify ();
+
+	if (cls.key_dest == key_console)
+	{
+		M_ForceMenuOff ();
+		Cvar_Set ("paused", "0");
+	}
+	else
+	{
+		M_ForceMenuOff ();
+		cls.key_dest = key_console;	
+
+		if (Cvar_VariableValue ("maxclients") == 1 
+			&& Com_ServerState ())
+			Cvar_Set ("paused", "1");
+	}
+}
+
+/*
+================
+Con_ToggleChat_f
+================
+*/
+void Con_ToggleChat_f (void)
+{
+	Key_ClearTyping ();
+
+	if (cls.key_dest == key_console)
+	{
+		if (cls.state == ca_active)
+		{
+			M_ForceMenuOff ();
+			cls.key_dest = key_game;
+		}
+	}
+	else
+		cls.key_dest = key_console;
+	
+	Con_ClearNotify ();
+}
+
+/*
+================
+Con_Clear_f
+================
+*/
+void Con_Clear_f (void)
+{
+	memset (con.text, ' ', CON_TEXTSIZE);
+}
+
+						
+/*
+================
+Con_Dump_f
+
+Save the console contents out to a file
+================
+*/
+void Con_Dump_f (void)
+{
+	int		l, x;
+	char	*line;
+	FILE	*f;
+	char	buffer[1024];
+	char	name[MAX_OSPATH];
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("usage: condump <filename>\n");
+		return;
+	}
+
+	Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
+
+	Com_Printf ("Dumped console text to %s.\n", name);
+	FS_CreatePath (name);
+	f = fopen (name, "w");
+	if (!f)
+	{
+		Com_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+
+	// skip empty lines
+	for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
+	{
+		line = con.text + (l%con.totallines)*con.linewidth;
+		for (x=0 ; x<con.linewidth ; x++)
+			if (line[x] != ' ')
+				break;
+		if (x != con.linewidth)
+			break;
+	}
+
+	// write the remaining lines
+	buffer[con.linewidth] = 0;
+	for ( ; l <= con.current ; l++)
+	{
+		line = con.text + (l%con.totallines)*con.linewidth;
+		strncpy (buffer, line, con.linewidth);
+		for (x=con.linewidth-1 ; x>=0 ; x--)
+		{
+			if (buffer[x] == ' ')
+				buffer[x] = 0;
+			else
+				break;
+		}
+		for (x=0; buffer[x]; x++)
+			buffer[x] &= 0x7f;
+
+		fprintf (f, "%s\n", buffer);
+	}
+
+	fclose (f);
+}
+
+						
+/*
+================
+Con_ClearNotify
+================
+*/
+void Con_ClearNotify (void)
+{
+	int		i;
+	
+	for (i=0 ; i<NUM_CON_TIMES ; i++)
+		con.times[i] = 0;
+}
+
+						
+/*
+================
+Con_MessageMode_f
+================
+*/
+void Con_MessageMode_f (void)
+{
+	chat_team = false;
+	cls.key_dest = key_message;
+}
+
+/*
+================
+Con_MessageMode2_f
+================
+*/
+void Con_MessageMode2_f (void)
+{
+	chat_team = true;
+	cls.key_dest = key_message;
+}
+
+/*
+================
+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 = (viddef.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;
+		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;
+
+		memcpy (tbuf, con.text, CON_TEXTSIZE);
+		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.current = con.totallines - 1;
+	con.display = con.current;
+}
+
+
+/*
+================
+Con_Init
+================
+*/
+void Con_Init (void)
+{
+	con.linewidth = -1;
+
+	Con_CheckResize ();
+	
+	Com_Printf ("Console initialized.\n");
+
+//
+// register our commands
+//
+	con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
+
+	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+	Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
+	Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+	Cmd_AddCommand ("clear", Con_Clear_f);
+	Cmd_AddCommand ("condump", Con_Dump_f);
+	con.initialized = true;
+}
+
+
+/*
+===============
+Con_Linefeed
+===============
+*/
+void Con_Linefeed (void)
+{
+	con.x = 0;
+	if (con.display == con.current)
+		con.display++;
+	con.current++;
+	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 text will appear at the top of the game window
+================
+*/
+void Con_Print (char *txt)
+{
+	int		y;
+	int		c, l;
+	static int	cr;
+	int		mask;
+
+	if (!con.initialized)
+		return;
+
+	if (txt[0] == 1 || 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] = cls.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.ormask;
+			con.x++;
+			if (con.x >= con.linewidth)
+				con.x = 0;
+			break;
+		}
+		
+	}
+}
+
+
+/*
+==============
+Con_CenteredPrint
+==============
+*/
+void Con_CenteredPrint (char *text)
+{
+	int		l;
+	char	buffer[1024];
+
+	l = strlen(text);
+	l = (con.linewidth-l)/2;
+	if (l < 0)
+		l = 0;
+	memset (buffer, ' ', l);
+	strcpy (buffer+l, text);
+	strcat (buffer, "\n");
+	Con_Print (buffer);
+}
+
+/*
+==============================================================================
+
+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 (cls.key_dest == key_menu)
+		return;
+	if (cls.key_dest != key_console && cls.state == ca_active)
+		return;		// don't draw anything (always draw if not active)
+
+	text = key_lines[edit_line];
+	
+// add the cursor frame
+	text[key_linepos] = 10+((int)(cls.realtime>>8)&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++)
+		re.DrawChar ( (i+1)<<3, con.vislines - 22, 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;
+	int		time;
+	char	*s;
+	int		skip;
+
+	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 = cls.realtime - time;
+		if (time > con_notifytime->value*1000)
+			continue;
+		text = con.text + (i % con.totallines)*con.linewidth;
+		
+		for (x = 0 ; x < con.linewidth ; x++)
+			re.DrawChar ( (x+1)<<3, v, text[x]);
+
+		v += 8;
+	}
+
+
+	if (cls.key_dest == key_message)
+	{
+		if (chat_team)
+		{
+			DrawString (8, v, "say_team:");
+			skip = 11;
+		}
+		else
+		{
+			DrawString (8, v, "say:");
+			skip = 5;
+		}
+
+		s = chat_buffer;
+		if (chat_bufferlen > (viddef.width>>3)-(skip+1))
+			s += chat_bufferlen - ((viddef.width>>3)-(skip+1));
+		x = 0;
+		while(s[x])
+		{
+			re.DrawChar ( (x+skip)<<3, v, s[x]);
+			x++;
+		}
+		re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
+		v += 8;
+	}
+	
+	if (v)
+	{
+		SCR_AddDirtyPoint (0,0);
+		SCR_AddDirtyPoint (viddef.width-1, v);
+	}
+}
+
+/*
+================
+Con_DrawConsole
+
+Draws the console with the solid background
+================
+*/
+void Con_DrawConsole (float frac)
+{
+	int				i, j, x, y, n;
+	int				rows;
+	char			*text;
+	int				row;
+	int				lines;
+	char			version[64];
+	char			dlbar[1024];
+
+	lines = viddef.height * frac;
+	if (lines <= 0)
+		return;
+
+	if (lines > viddef.height)
+		lines = viddef.height;
+
+// draw the background
+	re.DrawStretchPic (0, -viddef.height+lines, viddef.width, viddef.height, "conback");
+	SCR_AddDirtyPoint (0,0);
+	SCR_AddDirtyPoint (viddef.width-1,lines-1);
+
+	Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
+	for (x=0 ; x<5 ; x++)
+		re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version[x] );
+
+// draw the text
+	con.vislines = lines;
+	
+#if 0
+	rows = (lines-8)>>3;		// rows of text to draw
+
+	y = lines - 24;
+#else
+	rows = (lines-22)>>3;		// rows of text to draw
+
+	y = lines - 30;
+#endif
+
+// draw from the bottom up
+	if (con.display != con.current)
+	{
+	// draw arrows to show the buffer is backscrolled
+		for (x=0 ; x<con.linewidth ; x+=4)
+			re.DrawChar ( (x+1)<<3, y, '^');
+	
+		y -= 8;
+		rows--;
+	}
+	
+	row = con.display;
+	for (i=0 ; i<rows ; i++, y-=8, row--)
+	{
+		if (row < 0)
+			break;
+		if (con.current - row >= con.totallines)
+			break;		// past scrollback wrap point
+			
+		text = con.text + (row % con.totallines)*con.linewidth;
+
+		for (x=0 ; x<con.linewidth ; x++)
+			re.DrawChar ( (x+1)<<3, y, text[x]);
+	}
+
+//ZOID
+	// draw the download bar
+	// figure out width
+	if (cls.download) {
+		if ((text = strrchr(cls.downloadname, '/')) != NULL)
+			text++;
+		else
+			text = cls.downloadname;
+
+		x = con.linewidth - ((con.linewidth * 7) / 40);
+		y = x - strlen(text) - 8;
+		i = con.linewidth/3;
+		if (strlen(text) > i) {
+			y = x - i - 11;
+			strncpy(dlbar, text, i);
+			dlbar[i] = 0;
+			strcat(dlbar, "...");
+		} else
+			strcpy(dlbar, text);
+		strcat(dlbar, ": ");
+		i = strlen(dlbar);
+		dlbar[i++] = '\x80';
+		// where's the dot go?
+		if (cls.downloadpercent == 0)
+			n = 0;
+		else
+			n = y * cls.downloadpercent / 100;
+			
+		for (j = 0; j < y; j++)
+			if (j == n)
+				dlbar[i++] = '\x83';
+			else
+				dlbar[i++] = '\x81';
+		dlbar[i++] = '\x82';
+		dlbar[i] = 0;
+
+		sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
+
+		// draw it
+		y = con.vislines-12;
+		for (i = 0; i < strlen(dlbar); i++)
+			re.DrawChar ( (i+1)<<3, y, dlbar[i]);
+	}
+//ZOID
+
+// draw the input prompt, user text, and cursor if desired
+	Con_DrawInput ();
+}
+
+
--- /dev/null
+++ b/client/console.h
@@ -1,0 +1,62 @@
+/*
+Copyright (C) 1997-2001 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
+//
+
+#define	NUM_CON_TIMES 4
+
+#define		CON_TEXTSIZE	32768
+typedef struct
+{
+	qboolean	initialized;
+
+	char	text[CON_TEXTSIZE];
+	int		current;		// line where next message will be printed
+	int		x;				// offset in current line for next print
+	int		display;		// bottom of console displays this line
+
+	int		ormask;			// high bit mask for colored characters
+
+	int 	linewidth;		// characters across screen
+	int		totallines;		// total lines in console scrollback
+
+	float	cursorspeed;
+
+	int		vislines;
+
+	float	times[NUM_CON_TIMES];	// cls.realtime time the line was generated
+								// for transparent notify lines
+} console_t;
+
+extern	console_t	con;
+
+void Con_DrawCharacter (int cx, int line, int num);
+
+void Con_CheckResize (void);
+void Con_Init (void);
+void Con_DrawConsole (float frac);
+void Con_Print (char *txt);
+void Con_CenteredPrint (char *text);
+void Con_Clear_f (void);
+void Con_DrawNotify (void);
+void Con_ClearNotify (void);
+void Con_ToggleConsole_f (void);
--- /dev/null
+++ b/client/input.h
@@ -1,0 +1,34 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// input.h -- external (non-keyboard) input devices
+
+void IN_Init (void);
+
+void IN_Shutdown (void);
+
+void IN_Commands (void);
+// oportunity for devices to stick commands on the script buffer
+
+void IN_Frame (void);
+
+void IN_Move (usercmd_t *cmd);
+// add additional movement on top of the keyboard move cmd
+
+void IN_Activate (qboolean active);
--- /dev/null
+++ b/client/keys.c
@@ -1,0 +1,943 @@
+/*
+Copyright (C) 1997-2001 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 "client.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	anykeydown;
+
+int		edit_line=0;
+int		history_line=0;
+
+int		key_waiting;
+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},
+
+	{"KP_HOME",			K_KP_HOME },
+	{"KP_UPARROW",		K_KP_UPARROW },
+	{"KP_PGUP",			K_KP_PGUP },
+	{"KP_LEFTARROW",	K_KP_LEFTARROW },
+	{"KP_5",			K_KP_5 },
+	{"KP_RIGHTARROW",	K_KP_RIGHTARROW },
+	{"KP_END",			K_KP_END },
+	{"KP_DOWNARROW",	K_KP_DOWNARROW },
+	{"KP_PGDN",			K_KP_PGDN },
+	{"KP_ENTER",		K_KP_ENTER },
+	{"KP_INS",			K_KP_INS },
+	{"KP_DEL",			K_KP_DEL },
+	{"KP_SLASH",		K_KP_SLASH },
+	{"KP_MINUS",		K_KP_MINUS },
+	{"KP_PLUS",			K_KP_PLUS },
+
+	{"MWHEELUP", K_MWHEELUP },
+	{"MWHEELDOWN", K_MWHEELDOWN },
+
+	{"PAUSE", K_PAUSE},
+
+	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands
+
+	{NULL,0}
+};
+
+/*
+==============================================================================
+
+			LINE TYPING INTO THE CONSOLE
+
+==============================================================================
+*/
+
+void CompleteCommand (void)
+{
+	char	*cmd, *s;
+
+	s = key_lines[edit_line]+1;
+	if (*s == '\\' || *s == '/')
+		s++;
+
+	cmd = Cmd_CompleteCommand (s);
+	if (!cmd)
+		cmd = Cvar_CompleteVariable (s);
+	if (cmd)
+	{
+		key_lines[edit_line][1] = '/';
+		strcpy (key_lines[edit_line]+2, cmd);
+		key_linepos = strlen(cmd)+2;
+		key_lines[edit_line][key_linepos] = ' ';
+		key_linepos++;
+		key_lines[edit_line][key_linepos] = 0;
+		return;
+	}
+}
+
+/*
+====================
+Key_Console
+
+Interactive line editing and console scrollback
+====================
+*/
+void Key_Console (int key)
+{
+
+	switch ( key )
+	{
+	case K_KP_SLASH:
+		key = '/';
+		break;
+	case K_KP_MINUS:
+		key = '-';
+		break;
+	case K_KP_PLUS:
+		key = '+';
+		break;
+	case K_KP_HOME:
+		key = '7';
+		break;
+	case K_KP_UPARROW:
+		key = '8';
+		break;
+	case K_KP_PGUP:
+		key = '9';
+		break;
+	case K_KP_LEFTARROW:
+		key = '4';
+		break;
+	case K_KP_5:
+		key = '5';
+		break;
+	case K_KP_RIGHTARROW:
+		key = '6';
+		break;
+	case K_KP_END:
+		key = '1';
+		break;
+	case K_KP_DOWNARROW:
+		key = '2';
+		break;
+	case K_KP_PGDN:
+		key = '3';
+		break;
+	case K_KP_INS:
+		key = '0';
+		break;
+	case K_KP_DEL:
+		key = '.';
+		break;
+	}
+
+	if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
+		 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
+	{
+		char *cbd;
+		
+		if ( ( cbd = Sys_GetClipboardData() ) != 0 )
+		{
+			int i;
+
+			strtok( cbd, "\n\r\b" );
+
+			i = strlen( cbd );
+			if ( i + key_linepos >= MAXCMDLINE)
+				i= MAXCMDLINE - key_linepos;
+
+			if ( i > 0 )
+			{
+				cbd[i]=0;
+				strcat( key_lines[edit_line], cbd );
+				key_linepos += i;
+			}
+			free( cbd );
+		}
+
+		return;
+	}
+
+	if ( key == 'l' ) 
+	{
+		if ( keydown[K_CTRL] )
+		{
+			Cbuf_AddText ("clear\n");
+			return;
+		}
+	}
+
+	if ( key == K_ENTER || key == K_KP_ENTER )
+	{	// backslash text are commands, else chat
+		if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
+			Cbuf_AddText (key_lines[edit_line]+2);	// skip the >
+		else
+			Cbuf_AddText (key_lines[edit_line]+1);	// valid command
+
+		Cbuf_AddText ("\n");
+		Com_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
+		CompleteCommand ();
+		return;
+	}
+	
+	if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
+	{
+		if (key_linepos > 1)
+			key_linepos--;
+		return;
+	}
+
+	if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
+		 ( ( key == 'p' ) && keydown[K_CTRL] ) )
+	{
+		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;
+		strcpy(key_lines[edit_line], key_lines[history_line]);
+		key_linepos = strlen(key_lines[edit_line]);
+		return;
+	}
+
+	if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
+		 ( ( key == 'n' ) && keydown[K_CTRL] ) )
+	{
+		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
+		{
+			strcpy(key_lines[edit_line], key_lines[history_line]);
+			key_linepos = strlen(key_lines[edit_line]);
+		}
+		return;
+	}
+
+	if (key == K_PGUP || key == K_KP_PGUP )
+	{
+		con.display -= 2;
+		return;
+	}
+
+	if (key == K_PGDN || key == K_KP_PGDN ) 
+	{
+		con.display += 2;
+		if (con.display > con.current)
+			con.display = con.current;
+		return;
+	}
+
+	if (key == K_HOME || key == K_KP_HOME )
+	{
+		con.display = con.current - con.totallines + 10;
+		return;
+	}
+
+	if (key == K_END || key == K_KP_END )
+	{
+		con.display = con.current;
+		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;
+	}
+
+}
+
+//============================================================================
+
+qboolean	chat_team;
+char		chat_buffer[MAXCMDLINE];
+int			chat_bufferlen = 0;
+
+void Key_Message (int key)
+{
+
+	if ( key == K_ENTER || key == K_KP_ENTER )
+	{
+		if (chat_team)
+			Cbuf_AddText ("say_team \"");
+		else
+			Cbuf_AddText ("say \"");
+		Cbuf_AddText(chat_buffer);
+		Cbuf_AddText("\"\n");
+
+		cls.key_dest = key_game;
+		chat_bufferlen = 0;
+		chat_buffer[0] = 0;
+		return;
+	}
+
+	if (key == K_ESCAPE)
+	{
+		cls.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 == sizeof(chat_buffer)-1)
+		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 = strlen (binding);	
+	new = Z_Malloc (l+1);
+	strcpy (new, binding);
+	new[l] = 0;
+	keybindings[keynum] = new;	
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+void Key_Unbind_f (void)
+{
+	int		b;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("unbind <key> : remove commands from a key\n");
+		return;
+	}
+	
+	b = Key_StringToKeynum (Cmd_Argv(1));
+	if (b==-1)
+	{
+		Com_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)
+	{
+		Com_Printf ("bind <key> [command] : attach a command to a key\n");
+		return;
+	}
+	b = Key_StringToKeynum (Cmd_Argv(1));
+	if (b==-1)
+	{
+		Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+		return;
+	}
+
+	if (c == 2)
+	{
+		if (keybindings[b])
+			Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
+		else
+			Com_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++)
+	{
+		strcat (cmd, Cmd_Argv(i));
+		if (i != (c-1))
+			strcat (cmd, " ");
+	}
+
+	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] && keybindings[i][0])
+			fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+============
+Key_Bindlist_f
+
+============
+*/
+void Key_Bindlist_f (void)
+{
+	int		i;
+
+	for (i=0 ; i<256 ; i++)
+		if (keybindings[i] && keybindings[i][0])
+			Com_Printf ("%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_KP_ENTER] = true;
+	consolekeys[K_TAB] = true;
+	consolekeys[K_LEFTARROW] = true;
+	consolekeys[K_KP_LEFTARROW] = true;
+	consolekeys[K_RIGHTARROW] = true;
+	consolekeys[K_KP_RIGHTARROW] = true;
+	consolekeys[K_UPARROW] = true;
+	consolekeys[K_KP_UPARROW] = true;
+	consolekeys[K_DOWNARROW] = true;
+	consolekeys[K_KP_DOWNARROW] = true;
+	consolekeys[K_BACKSPACE] = true;
+	consolekeys[K_HOME] = true;
+	consolekeys[K_KP_HOME] = true;
+	consolekeys[K_END] = true;
+	consolekeys[K_KP_END] = true;
+	consolekeys[K_PGUP] = true;
+	consolekeys[K_KP_PGUP] = true;
+	consolekeys[K_PGDN] = true;
+	consolekeys[K_KP_PGDN] = true;
+	consolekeys[K_SHIFT] = true;
+	consolekeys[K_INS] = true;
+	consolekeys[K_KP_INS] = true;
+	consolekeys[K_KP_DEL] = true;
+	consolekeys[K_KP_SLASH] = true;
+	consolekeys[K_KP_PLUS] = true;
+	consolekeys[K_KP_MINUS] = true;
+	consolekeys[K_KP_5] = 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);
+	Cmd_AddCommand ("bindlist",Key_Bindlist_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, unsigned time)
+{
+	char	*kb;
+	char	cmd[1024];
+
+	// hack for modal presses
+	if (key_waiting == -1)
+	{
+		if (down)
+			key_waiting = key;
+		return;
+	}
+
+	// update auto-repeat status
+	if (down)
+	{
+		key_repeats[key]++;
+		if (key != K_BACKSPACE 
+			&& key != K_PAUSE 
+			&& key != K_PGUP 
+			&& key != K_KP_PGUP 
+			&& key != K_PGDN
+			&& key != K_KP_PGDN
+			&& key_repeats[key] > 1)
+			return;	// ignore most autorepeats
+			
+		if (key >= 200 && !keybindings[key])
+			Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
+	}
+	else
+	{
+		key_repeats[key] = 0;
+	}
+
+	if (key == K_SHIFT)
+		shift_down = down;
+
+	// console key is hardcoded, so the user can never unbind it
+	if (key == '`' || key == '~')
+	{
+		if (!down)
+			return;
+		Con_ToggleConsole_f ();
+		return;
+	}
+
+	// any key during the attract mode will bring up the menu
+	if (cl.attractloop && cls.key_dest != key_menu)
+		key = K_ESCAPE;
+
+	// menu key is hardcoded, so the user can never unbind it
+	if (key == K_ESCAPE)
+	{
+		if (!down)
+			return;
+
+		if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
+		{	// put away help computer / inventory
+			Cbuf_AddText ("cmd putaway\n");
+			return;
+		}
+		switch (cls.key_dest)
+		{
+		case key_message:
+			Key_Message (key);
+			break;
+		case key_menu:
+			M_Keydown (key);
+			break;
+		case key_game:
+		case key_console:
+			M_Menu_Main_f ();
+			break;
+		default:
+			Com_Error (ERR_FATAL, "Bad cls.key_dest");
+		}
+		return;
+	}
+
+	// track if any key is down for BUTTON_ANY
+	keydown[key] = down;
+	if (down)
+	{
+		if (key_repeats[key] == 1)
+			anykeydown++;
+	}
+	else
+	{
+		anykeydown--;
+		if (anykeydown < 0)
+			anykeydown = 0;
+	}
+
+//
+// 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] == '+')
+		{
+			Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+			Cbuf_AddText (cmd);
+		}
+		if (keyshift[key] != key)
+		{
+			kb = keybindings[keyshift[key]];
+			if (kb && kb[0] == '+')
+			{
+				Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+				Cbuf_AddText (cmd);
+			}
+		}
+		return;
+	}
+
+//
+// if not a consolekey, send to the interpreter no matter what mode is
+//
+	if ( (cls.key_dest == key_menu && menubound[key])
+	|| (cls.key_dest == key_console && !consolekeys[key])
+	|| (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
+	{
+		kb = keybindings[key];
+		if (kb)
+		{
+			if (kb[0] == '+')
+			{	// button commands add keynum and time as a parm
+				Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
+				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 (cls.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:
+		Com_Error (ERR_FATAL, "Bad cls.key_dest");
+	}
+}
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates (void)
+{
+	int		i;
+
+	anykeydown = false;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		if ( keydown[i] || key_repeats[i] )
+			Key_Event( i, false, 0 );
+		keydown[i] = 0;
+		key_repeats[i] = 0;
+	}
+}
+
+
+/*
+===================
+Key_GetKey
+===================
+*/
+int Key_GetKey (void)
+{
+	key_waiting = -1;
+
+	while (key_waiting == -1)
+		Sys_SendKeyEvents ();
+
+	return key_waiting;
+}
+
--- /dev/null
+++ b/client/keys.h
@@ -1,0 +1,146 @@
+/*
+Copyright (C) 1997-2001 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_KP_HOME		160
+#define K_KP_UPARROW	161
+#define K_KP_PGUP		162
+#define	K_KP_LEFTARROW	163
+#define K_KP_5			164
+#define K_KP_RIGHTARROW	165
+#define K_KP_END		166
+#define K_KP_DOWNARROW	167
+#define K_KP_PGDN		168
+#define	K_KP_ENTER		169
+#define K_KP_INS   		170
+#define	K_KP_DEL		171
+#define K_KP_SLASH		172
+#define K_KP_MINUS		173
+#define K_KP_PLUS		174
+
+#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
+
+#define K_MWHEELDOWN	239
+#define K_MWHEELUP		240
+
+extern char		*keybindings[256];
+extern	int		key_repeats[256];
+
+extern	int	anykeydown;
+extern char chat_buffer[];
+extern	int chat_bufferlen;
+extern	qboolean	chat_team;
+
+void Key_Event (int key, qboolean down, unsigned time);
+void Key_Init (void);
+void Key_WriteBindings (FILE *f);
+void Key_SetBinding (int keynum, char *binding);
+void Key_ClearStates (void);
+int Key_GetKey (void);
+
--- /dev/null
+++ b/client/menu.c
@@ -1,0 +1,4016 @@
+/*
+Copyright (C) 1997-2001 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 <ctype.h>
+#ifdef _WIN32
+#include <io.h>
+#endif
+#include "client.h"
+#include "../client/qmenu.h"
+
+static int	m_main_cursor;
+
+#define NUM_CURSOR_FRAMES 15
+
+static char *menu_in_sound		= "misc/menu1.wav";
+static char *menu_move_sound	= "misc/menu2.wav";
+static char *menu_out_sound		= "misc/menu3.wav";
+
+void M_Menu_Main_f (void);
+	void M_Menu_Game_f (void);
+		void M_Menu_LoadGame_f (void);
+		void M_Menu_SaveGame_f (void);
+		void M_Menu_PlayerConfig_f (void);
+			void M_Menu_DownloadOptions_f (void);
+		void M_Menu_Credits_f( void );
+	void M_Menu_Multiplayer_f( void );
+		void M_Menu_JoinServer_f (void);
+			void M_Menu_AddressBook_f( void );
+		void M_Menu_StartServer_f (void);
+			void M_Menu_DMOptions_f (void);
+	void M_Menu_Video_f (void);
+	void M_Menu_Options_f (void);
+		void M_Menu_Keys_f (void);
+	void M_Menu_Quit_f (void);
+
+	void M_Menu_Credits( void );
+
+qboolean	m_entersound;		// play after drawing a frame, so caching
+								// won't disrupt the sound
+
+void	(*m_drawfunc) (void);
+const char *(*m_keyfunc) (int key);
+
+//=============================================================================
+/* Support Routines */
+
+#define	MAX_MENU_DEPTH	8
+
+
+typedef struct
+{
+	void	(*draw) (void);
+	const char *(*key) (int k);
+} menulayer_t;
+
+menulayer_t	m_layers[MAX_MENU_DEPTH];
+int		m_menudepth;
+
+static void M_Banner( char *name )
+{
+	int w, h;
+
+	re.DrawGetPicSize (&w, &h, name );
+	re.DrawPic( viddef.width / 2 - w / 2, viddef.height / 2 - 110, name );
+}
+
+void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
+{
+	int		i;
+
+	if (Cvar_VariableValue ("maxclients") == 1 
+		&& Com_ServerState ())
+		Cvar_Set ("paused", "1");
+
+	// if this menu is already present, drop back to that level
+	// to avoid stacking menus by hotkeys
+	for (i=0 ; i<m_menudepth ; i++)
+		if (m_layers[i].draw == draw &&
+			m_layers[i].key == key)
+		{
+			m_menudepth = i;
+		}
+
+	if (i == m_menudepth)
+	{
+		if (m_menudepth >= MAX_MENU_DEPTH)
+			Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
+		m_layers[m_menudepth].draw = m_drawfunc;
+		m_layers[m_menudepth].key = m_keyfunc;
+		m_menudepth++;
+	}
+
+	m_drawfunc = draw;
+	m_keyfunc = key;
+
+	m_entersound = true;
+
+	cls.key_dest = key_menu;
+}
+
+void M_ForceMenuOff (void)
+{
+	m_drawfunc = 0;
+	m_keyfunc = 0;
+	cls.key_dest = key_game;
+	m_menudepth = 0;
+	Key_ClearStates ();
+	Cvar_Set ("paused", "0");
+}
+
+void M_PopMenu (void)
+{
+	S_StartLocalSound( menu_out_sound );
+	if (m_menudepth < 1)
+		Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
+	m_menudepth--;
+
+	m_drawfunc = m_layers[m_menudepth].draw;
+	m_keyfunc = m_layers[m_menudepth].key;
+
+	if (!m_menudepth)
+		M_ForceMenuOff ();
+}
+
+
+const char *Default_MenuKey( menuframework_s *m, int key )
+{
+	const char *sound = NULL;
+	menucommon_s *item;
+
+	if ( m )
+	{
+		if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
+		{
+			if ( item->type == MTYPE_FIELD )
+			{
+				if ( Field_Key( ( menufield_s * ) item, key ) )
+					return NULL;
+			}
+		}
+	}
+
+	switch ( key )
+	{
+	case K_ESCAPE:
+		M_PopMenu();
+		return menu_out_sound;
+	case K_KP_UPARROW:
+	case K_UPARROW:
+		if ( m )
+		{
+			m->cursor--;
+			Menu_AdjustCursor( m, -1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_TAB:
+		if ( m )
+		{
+			m->cursor++;
+			Menu_AdjustCursor( m, 1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_KP_DOWNARROW:
+	case K_DOWNARROW:
+		if ( m )
+		{
+			m->cursor++;
+			Menu_AdjustCursor( m, 1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_KP_LEFTARROW:
+	case K_LEFTARROW:
+		if ( m )
+		{
+			Menu_SlideItem( m, -1 );
+			sound = menu_move_sound;
+		}
+		break;
+	case K_KP_RIGHTARROW:
+	case K_RIGHTARROW:
+		if ( m )
+		{
+			Menu_SlideItem( m, 1 );
+			sound = menu_move_sound;
+		}
+		break;
+
+	case K_MOUSE1:
+	case K_MOUSE2:
+	case K_MOUSE3:
+	case K_JOY1:
+	case K_JOY2:
+	case K_JOY3:
+	case K_JOY4:
+	case K_AUX1:
+	case K_AUX2:
+	case K_AUX3:
+	case K_AUX4:
+	case K_AUX5:
+	case K_AUX6:
+	case K_AUX7:
+	case K_AUX8:
+	case K_AUX9:
+	case K_AUX10:
+	case K_AUX11:
+	case K_AUX12:
+	case K_AUX13:
+	case K_AUX14:
+	case K_AUX15:
+	case K_AUX16:
+	case K_AUX17:
+	case K_AUX18:
+	case K_AUX19:
+	case K_AUX20:
+	case K_AUX21:
+	case K_AUX22:
+	case K_AUX23:
+	case K_AUX24:
+	case K_AUX25:
+	case K_AUX26:
+	case K_AUX27:
+	case K_AUX28:
+	case K_AUX29:
+	case K_AUX30:
+	case K_AUX31:
+	case K_AUX32:
+		
+	case K_KP_ENTER:
+	case K_ENTER:
+		if ( m )
+			Menu_SelectItem( m );
+		sound = menu_move_sound;
+		break;
+	}
+
+	return sound;
+}
+
+//=============================================================================
+
+/*
+================
+M_DrawCharacter
+
+Draws one solid graphics character
+cx and cy are in 320*240 coordinates, and will be centered on
+higher res screens.
+================
+*/
+void M_DrawCharacter (int cx, int cy, int num)
+{
+	re.DrawChar ( cx + ((viddef.width - 320)>>1), cy + ((viddef.height - 240)>>1), 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_DrawPic (int x, int y, char *pic)
+{
+	re.DrawPic (x + ((viddef.width - 320)>>1), y + ((viddef.height - 240)>>1), pic);
+}
+
+
+/*
+=============
+M_DrawCursor
+
+Draws an animating cursor with the point at
+x,y.  The pic will extend to the left of x,
+and both above and below y.
+=============
+*/
+void M_DrawCursor( int x, int y, int f )
+{
+	char	cursorname[80];
+	static qboolean cached;
+
+	if ( !cached )
+	{
+		int i;
+
+		for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
+		{
+			Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
+
+			re.RegisterPic( cursorname );
+		}
+		cached = true;
+	}
+
+	Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
+	re.DrawPic( x, y, cursorname );
+}
+
+void M_DrawTextBox (int x, int y, int width, int lines)
+{
+	int		cx, cy;
+	int		n;
+
+	// draw left side
+	cx = x;
+	cy = y;
+	M_DrawCharacter (cx, cy, 1);
+	for (n = 0; n < lines; n++)
+	{
+		cy += 8;
+		M_DrawCharacter (cx, cy, 4);
+	}
+	M_DrawCharacter (cx, cy+8, 7);
+
+	// draw middle
+	cx += 8;
+	while (width > 0)
+	{
+		cy = y;
+		M_DrawCharacter (cx, cy, 2);
+		for (n = 0; n < lines; n++)
+		{
+			cy += 8;
+			M_DrawCharacter (cx, cy, 5);
+		}
+		M_DrawCharacter (cx, cy+8, 8);
+		width -= 1;
+		cx += 8;
+	}
+
+	// draw right side
+	cy = y;
+	M_DrawCharacter (cx, cy, 3);
+	for (n = 0; n < lines; n++)
+	{
+		cy += 8;
+		M_DrawCharacter (cx, cy, 6);
+	}
+	M_DrawCharacter (cx, cy+8, 9);
+}
+
+		
+/*
+=======================================================================
+
+MAIN MENU
+
+=======================================================================
+*/
+#define	MAIN_ITEMS	5
+
+
+void M_Main_Draw (void)
+{
+	int i;
+	int w, h;
+	int ystart;
+	int	xoffset;
+	int widest = -1;
+	int totalheight = 0;
+	char litname[80];
+	char *names[] =
+	{
+		"m_main_game",
+		"m_main_multiplayer",
+		"m_main_options",
+		"m_main_video",
+		"m_main_quit",
+		0
+	};
+
+	for ( i = 0; names[i] != 0; i++ )
+	{
+		re.DrawGetPicSize( &w, &h, names[i] );
+
+		if ( w > widest )
+			widest = w;
+		totalheight += ( h + 12 );
+	}
+
+	ystart = ( viddef.height / 2 - 110 );
+	xoffset = ( viddef.width - widest + 70 ) / 2;
+
+	for ( i = 0; names[i] != 0; i++ )
+	{
+		if ( i != m_main_cursor )
+			re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
+	}
+	strcpy( litname, names[m_main_cursor] );
+	strcat( litname, "_sel" );
+	re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
+
+	M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
+
+	re.DrawGetPicSize( &w, &h, "m_main_plaque" );
+	re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
+
+	re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
+}
+
+
+const char *M_Main_Key (int key)
+{
+	const char *sound = menu_move_sound;
+
+	switch (key)
+	{
+	case K_ESCAPE:
+		M_PopMenu ();
+		break;
+
+	case K_KP_DOWNARROW:
+	case K_DOWNARROW:
+		if (++m_main_cursor >= MAIN_ITEMS)
+			m_main_cursor = 0;
+		return sound;
+
+	case K_KP_UPARROW:
+	case K_UPARROW:
+		if (--m_main_cursor < 0)
+			m_main_cursor = MAIN_ITEMS - 1;
+		return sound;
+
+	case K_KP_ENTER:
+	case K_ENTER:
+		m_entersound = true;
+
+		switch (m_main_cursor)
+		{
+		case 0:
+			M_Menu_Game_f ();
+			break;
+
+		case 1:
+			M_Menu_Multiplayer_f();
+			break;
+
+		case 2:
+			M_Menu_Options_f ();
+			break;
+
+		case 3:
+			M_Menu_Video_f ();
+			break;
+
+		case 4:
+			M_Menu_Quit_f ();
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+
+void M_Menu_Main_f (void)
+{
+	M_PushMenu (M_Main_Draw, M_Main_Key);
+}
+
+/*
+=======================================================================
+
+MULTIPLAYER MENU
+
+=======================================================================
+*/
+static menuframework_s	s_multiplayer_menu;
+static menuaction_s		s_join_network_server_action;
+static menuaction_s		s_start_network_server_action;
+static menuaction_s		s_player_setup_action;
+
+static void Multiplayer_MenuDraw (void)
+{
+	M_Banner( "m_banner_multiplayer" );
+
+	Menu_AdjustCursor( &s_multiplayer_menu, 1 );
+	Menu_Draw( &s_multiplayer_menu );
+}
+
+static void PlayerSetupFunc( void *unused )
+{
+	M_Menu_PlayerConfig_f();
+}
+
+static void JoinNetworkServerFunc( void *unused )
+{
+	M_Menu_JoinServer_f();
+}
+
+static void StartNetworkServerFunc( void *unused )
+{
+	M_Menu_StartServer_f ();
+}
+
+void Multiplayer_MenuInit( void )
+{
+	s_multiplayer_menu.x = viddef.width * 0.50 - 64;
+	s_multiplayer_menu.nitems = 0;
+
+	s_join_network_server_action.generic.type	= MTYPE_ACTION;
+	s_join_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_join_network_server_action.generic.x		= 0;
+	s_join_network_server_action.generic.y		= 0;
+	s_join_network_server_action.generic.name	= " join network server";
+	s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
+
+	s_start_network_server_action.generic.type	= MTYPE_ACTION;
+	s_start_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_start_network_server_action.generic.x		= 0;
+	s_start_network_server_action.generic.y		= 10;
+	s_start_network_server_action.generic.name	= " start network server";
+	s_start_network_server_action.generic.callback = StartNetworkServerFunc;
+
+	s_player_setup_action.generic.type	= MTYPE_ACTION;
+	s_player_setup_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_player_setup_action.generic.x		= 0;
+	s_player_setup_action.generic.y		= 20;
+	s_player_setup_action.generic.name	= " player setup";
+	s_player_setup_action.generic.callback = PlayerSetupFunc;
+
+	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
+	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
+	Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
+
+	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+
+	Menu_Center( &s_multiplayer_menu );
+}
+
+const char *Multiplayer_MenuKey( int key )
+{
+	return Default_MenuKey( &s_multiplayer_menu, key );
+}
+
+void M_Menu_Multiplayer_f( void )
+{
+	Multiplayer_MenuInit();
+	M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
+}
+
+/*
+=======================================================================
+
+KEYS MENU
+
+=======================================================================
+*/
+char *bindnames[][2] =
+{
+{"+attack", 		"attack"},
+{"weapnext", 		"next weapon"},
+{"+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",			"up / jump"},
+{"+movedown",		"down / crouch"},
+
+{"inven",			"inventory"},
+{"invuse",			"use item"},
+{"invdrop",			"drop item"},
+{"invprev",			"prev item"},
+{"invnext",			"next item"},
+
+{"cmd help", 		"help computer" }, 
+{ 0, 0 }
+};
+
+int				keys_cursor;
+static int		bind_grab;
+
+static menuframework_s	s_keys_menu;
+static menuaction_s		s_keys_attack_action;
+static menuaction_s		s_keys_change_weapon_action;
+static menuaction_s		s_keys_walk_forward_action;
+static menuaction_s		s_keys_backpedal_action;
+static menuaction_s		s_keys_turn_left_action;
+static menuaction_s		s_keys_turn_right_action;
+static menuaction_s		s_keys_run_action;
+static menuaction_s		s_keys_step_left_action;
+static menuaction_s		s_keys_step_right_action;
+static menuaction_s		s_keys_sidestep_action;
+static menuaction_s		s_keys_look_up_action;
+static menuaction_s		s_keys_look_down_action;
+static menuaction_s		s_keys_center_view_action;
+static menuaction_s		s_keys_mouse_look_action;
+static menuaction_s		s_keys_keyboard_look_action;
+static menuaction_s		s_keys_move_up_action;
+static menuaction_s		s_keys_move_down_action;
+static menuaction_s		s_keys_inventory_action;
+static menuaction_s		s_keys_inv_use_action;
+static menuaction_s		s_keys_inv_drop_action;
+static menuaction_s		s_keys_inv_prev_action;
+static menuaction_s		s_keys_inv_next_action;
+
+static menuaction_s		s_keys_help_computer_action;
+
+static 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, "");
+	}
+}
+
+static 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;
+		}
+	}
+}
+
+static void KeyCursorDrawFunc( menuframework_s *menu )
+{
+	if ( bind_grab )
+		re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
+	else
+		re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
+}
+
+static void DrawKeyBindingFunc( void *self )
+{
+	int keys[2];
+	menuaction_s *a = ( menuaction_s * ) self;
+
+	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
+		
+	if (keys[0] == -1)
+	{
+		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
+	}
+	else
+	{
+		int x;
+		const char *name;
+
+		name = Key_KeynumToString (keys[0]);
+
+		Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
+
+		x = strlen(name) * 8;
+
+		if (keys[1] != -1)
+		{
+			Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
+			Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
+		}
+	}
+}
+
+static void KeyBindingFunc( void *self )
+{
+	menuaction_s *a = ( menuaction_s * ) self;
+	int keys[2];
+
+	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
+
+	if (keys[1] != -1)
+		M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
+
+	bind_grab = true;
+
+	Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
+}
+
+static void Keys_MenuInit( void )
+{
+	int y = 0;
+	int i = 0;
+
+	s_keys_menu.x = viddef.width * 0.50;
+	s_keys_menu.nitems = 0;
+	s_keys_menu.cursordraw = KeyCursorDrawFunc;
+
+	s_keys_attack_action.generic.type	= MTYPE_ACTION;
+	s_keys_attack_action.generic.flags  = QMF_GRAYED;
+	s_keys_attack_action.generic.x		= 0;
+	s_keys_attack_action.generic.y		= y;
+	s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_attack_action.generic.localdata[0] = i;
+	s_keys_attack_action.generic.name	= bindnames[s_keys_attack_action.generic.localdata[0]][1];
+
+	s_keys_change_weapon_action.generic.type	= MTYPE_ACTION;
+	s_keys_change_weapon_action.generic.flags  = QMF_GRAYED;
+	s_keys_change_weapon_action.generic.x		= 0;
+	s_keys_change_weapon_action.generic.y		= y += 9;
+	s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_change_weapon_action.generic.localdata[0] = ++i;
+	s_keys_change_weapon_action.generic.name	= bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
+
+	s_keys_walk_forward_action.generic.type	= MTYPE_ACTION;
+	s_keys_walk_forward_action.generic.flags  = QMF_GRAYED;
+	s_keys_walk_forward_action.generic.x		= 0;
+	s_keys_walk_forward_action.generic.y		= y += 9;
+	s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_walk_forward_action.generic.localdata[0] = ++i;
+	s_keys_walk_forward_action.generic.name	= bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
+
+	s_keys_backpedal_action.generic.type	= MTYPE_ACTION;
+	s_keys_backpedal_action.generic.flags  = QMF_GRAYED;
+	s_keys_backpedal_action.generic.x		= 0;
+	s_keys_backpedal_action.generic.y		= y += 9;
+	s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_backpedal_action.generic.localdata[0] = ++i;
+	s_keys_backpedal_action.generic.name	= bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
+
+	s_keys_turn_left_action.generic.type	= MTYPE_ACTION;
+	s_keys_turn_left_action.generic.flags  = QMF_GRAYED;
+	s_keys_turn_left_action.generic.x		= 0;
+	s_keys_turn_left_action.generic.y		= y += 9;
+	s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_turn_left_action.generic.localdata[0] = ++i;
+	s_keys_turn_left_action.generic.name	= bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
+
+	s_keys_turn_right_action.generic.type	= MTYPE_ACTION;
+	s_keys_turn_right_action.generic.flags  = QMF_GRAYED;
+	s_keys_turn_right_action.generic.x		= 0;
+	s_keys_turn_right_action.generic.y		= y += 9;
+	s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_turn_right_action.generic.localdata[0] = ++i;
+	s_keys_turn_right_action.generic.name	= bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
+
+	s_keys_run_action.generic.type	= MTYPE_ACTION;
+	s_keys_run_action.generic.flags  = QMF_GRAYED;
+	s_keys_run_action.generic.x		= 0;
+	s_keys_run_action.generic.y		= y += 9;
+	s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_run_action.generic.localdata[0] = ++i;
+	s_keys_run_action.generic.name	= bindnames[s_keys_run_action.generic.localdata[0]][1];
+
+	s_keys_step_left_action.generic.type	= MTYPE_ACTION;
+	s_keys_step_left_action.generic.flags  = QMF_GRAYED;
+	s_keys_step_left_action.generic.x		= 0;
+	s_keys_step_left_action.generic.y		= y += 9;
+	s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_step_left_action.generic.localdata[0] = ++i;
+	s_keys_step_left_action.generic.name	= bindnames[s_keys_step_left_action.generic.localdata[0]][1];
+
+	s_keys_step_right_action.generic.type	= MTYPE_ACTION;
+	s_keys_step_right_action.generic.flags  = QMF_GRAYED;
+	s_keys_step_right_action.generic.x		= 0;
+	s_keys_step_right_action.generic.y		= y += 9;
+	s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_step_right_action.generic.localdata[0] = ++i;
+	s_keys_step_right_action.generic.name	= bindnames[s_keys_step_right_action.generic.localdata[0]][1];
+
+	s_keys_sidestep_action.generic.type	= MTYPE_ACTION;
+	s_keys_sidestep_action.generic.flags  = QMF_GRAYED;
+	s_keys_sidestep_action.generic.x		= 0;
+	s_keys_sidestep_action.generic.y		= y += 9;
+	s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_sidestep_action.generic.localdata[0] = ++i;
+	s_keys_sidestep_action.generic.name	= bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
+
+	s_keys_look_up_action.generic.type	= MTYPE_ACTION;
+	s_keys_look_up_action.generic.flags  = QMF_GRAYED;
+	s_keys_look_up_action.generic.x		= 0;
+	s_keys_look_up_action.generic.y		= y += 9;
+	s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_look_up_action.generic.localdata[0] = ++i;
+	s_keys_look_up_action.generic.name	= bindnames[s_keys_look_up_action.generic.localdata[0]][1];
+
+	s_keys_look_down_action.generic.type	= MTYPE_ACTION;
+	s_keys_look_down_action.generic.flags  = QMF_GRAYED;
+	s_keys_look_down_action.generic.x		= 0;
+	s_keys_look_down_action.generic.y		= y += 9;
+	s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_look_down_action.generic.localdata[0] = ++i;
+	s_keys_look_down_action.generic.name	= bindnames[s_keys_look_down_action.generic.localdata[0]][1];
+
+	s_keys_center_view_action.generic.type	= MTYPE_ACTION;
+	s_keys_center_view_action.generic.flags  = QMF_GRAYED;
+	s_keys_center_view_action.generic.x		= 0;
+	s_keys_center_view_action.generic.y		= y += 9;
+	s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_center_view_action.generic.localdata[0] = ++i;
+	s_keys_center_view_action.generic.name	= bindnames[s_keys_center_view_action.generic.localdata[0]][1];
+
+	s_keys_mouse_look_action.generic.type	= MTYPE_ACTION;
+	s_keys_mouse_look_action.generic.flags  = QMF_GRAYED;
+	s_keys_mouse_look_action.generic.x		= 0;
+	s_keys_mouse_look_action.generic.y		= y += 9;
+	s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_mouse_look_action.generic.localdata[0] = ++i;
+	s_keys_mouse_look_action.generic.name	= bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
+
+	s_keys_keyboard_look_action.generic.type	= MTYPE_ACTION;
+	s_keys_keyboard_look_action.generic.flags  = QMF_GRAYED;
+	s_keys_keyboard_look_action.generic.x		= 0;
+	s_keys_keyboard_look_action.generic.y		= y += 9;
+	s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_keyboard_look_action.generic.localdata[0] = ++i;
+	s_keys_keyboard_look_action.generic.name	= bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
+
+	s_keys_move_up_action.generic.type	= MTYPE_ACTION;
+	s_keys_move_up_action.generic.flags  = QMF_GRAYED;
+	s_keys_move_up_action.generic.x		= 0;
+	s_keys_move_up_action.generic.y		= y += 9;
+	s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_move_up_action.generic.localdata[0] = ++i;
+	s_keys_move_up_action.generic.name	= bindnames[s_keys_move_up_action.generic.localdata[0]][1];
+
+	s_keys_move_down_action.generic.type	= MTYPE_ACTION;
+	s_keys_move_down_action.generic.flags  = QMF_GRAYED;
+	s_keys_move_down_action.generic.x		= 0;
+	s_keys_move_down_action.generic.y		= y += 9;
+	s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_move_down_action.generic.localdata[0] = ++i;
+	s_keys_move_down_action.generic.name	= bindnames[s_keys_move_down_action.generic.localdata[0]][1];
+
+	s_keys_inventory_action.generic.type	= MTYPE_ACTION;
+	s_keys_inventory_action.generic.flags  = QMF_GRAYED;
+	s_keys_inventory_action.generic.x		= 0;
+	s_keys_inventory_action.generic.y		= y += 9;
+	s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inventory_action.generic.localdata[0] = ++i;
+	s_keys_inventory_action.generic.name	= bindnames[s_keys_inventory_action.generic.localdata[0]][1];
+
+	s_keys_inv_use_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_use_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_use_action.generic.x		= 0;
+	s_keys_inv_use_action.generic.y		= y += 9;
+	s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_use_action.generic.localdata[0] = ++i;
+	s_keys_inv_use_action.generic.name	= bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
+
+	s_keys_inv_drop_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_drop_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_drop_action.generic.x		= 0;
+	s_keys_inv_drop_action.generic.y		= y += 9;
+	s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_drop_action.generic.localdata[0] = ++i;
+	s_keys_inv_drop_action.generic.name	= bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
+
+	s_keys_inv_prev_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_prev_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_prev_action.generic.x		= 0;
+	s_keys_inv_prev_action.generic.y		= y += 9;
+	s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_prev_action.generic.localdata[0] = ++i;
+	s_keys_inv_prev_action.generic.name	= bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
+
+	s_keys_inv_next_action.generic.type	= MTYPE_ACTION;
+	s_keys_inv_next_action.generic.flags  = QMF_GRAYED;
+	s_keys_inv_next_action.generic.x		= 0;
+	s_keys_inv_next_action.generic.y		= y += 9;
+	s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_inv_next_action.generic.localdata[0] = ++i;
+	s_keys_inv_next_action.generic.name	= bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
+
+	s_keys_help_computer_action.generic.type	= MTYPE_ACTION;
+	s_keys_help_computer_action.generic.flags  = QMF_GRAYED;
+	s_keys_help_computer_action.generic.x		= 0;
+	s_keys_help_computer_action.generic.y		= y += 9;
+	s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
+	s_keys_help_computer_action.generic.localdata[0] = ++i;
+	s_keys_help_computer_action.generic.name	= bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
+
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
+
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
+
+	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
+	
+	Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+	Menu_Center( &s_keys_menu );
+}
+
+static void Keys_MenuDraw (void)
+{
+	Menu_AdjustCursor( &s_keys_menu, 1 );
+	Menu_Draw( &s_keys_menu );
+}
+
+static const char *Keys_MenuKey( int key )
+{
+	menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );
+
+	if ( bind_grab )
+	{	
+		if ( key != K_ESCAPE && key != '`' )
+		{
+			char cmd[1024];
+
+			Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
+			Cbuf_InsertText (cmd);
+		}
+		
+		Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+		bind_grab = false;
+		return menu_out_sound;
+	}
+
+	switch ( key )
+	{
+	case K_KP_ENTER:
+	case K_ENTER:
+		KeyBindingFunc( item );
+		return menu_in_sound;
+	case K_BACKSPACE:		// delete bindings
+	case K_DEL:				// delete bindings
+	case K_KP_DEL:
+		M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
+		return menu_out_sound;
+	default:
+		return Default_MenuKey( &s_keys_menu, key );
+	}
+}
+
+void M_Menu_Keys_f (void)
+{
+	Keys_MenuInit();
+	M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+CONTROLS MENU
+
+=======================================================================
+*/
+static cvar_t *win_noalttab;
+extern cvar_t *in_joystick;
+
+static menuframework_s	s_options_menu;
+static menuaction_s		s_options_defaults_action;
+static menuaction_s		s_options_customize_options_action;
+static menuslider_s		s_options_sensitivity_slider;
+static menulist_s		s_options_freelook_box;
+static menulist_s		s_options_noalttab_box;
+static menulist_s		s_options_alwaysrun_box;
+static menulist_s		s_options_invertmouse_box;
+static menulist_s		s_options_lookspring_box;
+static menulist_s		s_options_lookstrafe_box;
+static menulist_s		s_options_crosshair_box;
+static menuslider_s		s_options_sfxvolume_slider;
+static menulist_s		s_options_joystick_box;
+static menulist_s		s_options_cdvolume_box;
+static menulist_s		s_options_quality_list;
+static menulist_s		s_options_compatibility_list;
+static menulist_s		s_options_console_action;
+
+static void CrosshairFunc( void *unused )
+{
+	Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
+}
+
+static void JoystickFunc( void *unused )
+{
+	Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
+}
+
+static void CustomizeControlsFunc( void *unused )
+{
+	M_Menu_Keys_f();
+}
+
+static void AlwaysRunFunc( void *unused )
+{
+	Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
+}
+
+static void FreeLookFunc( void *unused )
+{
+	Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
+}
+
+static void MouseSpeedFunc( void *unused )
+{
+	Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
+}
+
+static void NoAltTabFunc( void *unused )
+{
+	Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
+}
+
+static float ClampCvar( float min, float max, float value )
+{
+	if ( value < min ) return min;
+	if ( value > max ) return max;
+	return value;
+}
+
+static void ControlsSetMenuItemValues( void )
+{
+	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
+	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
+	s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
+	s_options_sensitivity_slider.curvalue	= ( sensitivity->value ) * 2;
+
+	Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
+	s_options_alwaysrun_box.curvalue		= cl_run->value;
+
+	s_options_invertmouse_box.curvalue		= m_pitch->value < 0;
+
+	Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
+	s_options_lookspring_box.curvalue		= lookspring->value;
+
+	Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
+	s_options_lookstrafe_box.curvalue		= lookstrafe->value;
+
+	Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
+	s_options_freelook_box.curvalue			= freelook->value;
+
+	Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
+	s_options_crosshair_box.curvalue		= crosshair->value;
+
+	Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
+	s_options_joystick_box.curvalue		= in_joystick->value;
+
+	s_options_noalttab_box.curvalue			= win_noalttab->value;
+}
+
+static void ControlsResetDefaultsFunc( void *unused )
+{
+	Cbuf_AddText ("exec default.cfg\n");
+	Cbuf_Execute();
+
+	ControlsSetMenuItemValues();
+}
+
+static void InvertMouseFunc( void *unused )
+{
+	if ( s_options_invertmouse_box.curvalue == 0 )
+	{
+		Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
+	}
+	else
+	{
+		Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
+	}
+}
+
+static void LookspringFunc( void *unused )
+{
+	Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
+}
+
+static void LookstrafeFunc( void *unused )
+{
+	Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
+}
+
+static void UpdateVolumeFunc( void *unused )
+{
+	Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
+}
+
+static void UpdateCDVolumeFunc( void *unused )
+{
+	Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
+}
+
+static void ConsoleFunc( void *unused )
+{
+	/*
+	** the proper way to do this is probably to have ToggleConsole_f accept a parameter
+	*/
+	extern void Key_ClearTyping( void );
+
+	if ( cl.attractloop )
+	{
+		Cbuf_AddText ("killserver\n");
+		return;
+	}
+
+	Key_ClearTyping ();
+	Con_ClearNotify ();
+
+	M_ForceMenuOff ();
+	cls.key_dest = key_console;
+}
+
+static void UpdateSoundQualityFunc( void *unused )
+{
+	if ( s_options_quality_list.curvalue )
+	{
+		Cvar_SetValue( "s_khz", 22 );
+		Cvar_SetValue( "s_loadas8bit", false );
+	}
+	else
+	{
+		Cvar_SetValue( "s_khz", 11 );
+		Cvar_SetValue( "s_loadas8bit", true );
+	}
+	
+	Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
+
+	M_DrawTextBox( 8, 120 - 48, 36, 3 );
+	M_Print( 16 + 16, 120 - 48 + 8,  "Restarting the sound system. This" );
+	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+	// the text box won't show up unless we do a buffer swap
+	re.EndFrame();
+
+	CL_Snd_Restart_f();
+}
+
+void Options_MenuInit( void )
+{
+	static const char *cd_music_items[] =
+	{
+		"disabled",
+		"enabled",
+		0
+	};
+	static const char *quality_items[] =
+	{
+		"low", "high", 0
+	};
+
+	static const char *compatibility_items[] =
+	{
+		"max compatibility", "max performance", 0
+	};
+
+	static const char *yesno_names[] =
+	{
+		"no",
+		"yes",
+		0
+	};
+
+	static const char *crosshair_names[] =
+	{
+		"none",
+		"cross",
+		"dot",
+		"angle",
+		0
+	};
+
+	win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
+
+	/*
+	** configure controls menu and menu items
+	*/
+	s_options_menu.x = viddef.width / 2;
+	s_options_menu.y = viddef.height / 2 - 58;
+	s_options_menu.nitems = 0;
+
+	s_options_sfxvolume_slider.generic.type	= MTYPE_SLIDER;
+	s_options_sfxvolume_slider.generic.x	= 0;
+	s_options_sfxvolume_slider.generic.y	= 0;
+	s_options_sfxvolume_slider.generic.name	= "effects volume";
+	s_options_sfxvolume_slider.generic.callback	= UpdateVolumeFunc;
+	s_options_sfxvolume_slider.minvalue		= 0;
+	s_options_sfxvolume_slider.maxvalue		= 10;
+	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
+
+	s_options_cdvolume_box.generic.type	= MTYPE_SPINCONTROL;
+	s_options_cdvolume_box.generic.x		= 0;
+	s_options_cdvolume_box.generic.y		= 10;
+	s_options_cdvolume_box.generic.name	= "CD music";
+	s_options_cdvolume_box.generic.callback	= UpdateCDVolumeFunc;
+	s_options_cdvolume_box.itemnames		= cd_music_items;
+	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
+
+	s_options_quality_list.generic.type	= MTYPE_SPINCONTROL;
+	s_options_quality_list.generic.x		= 0;
+	s_options_quality_list.generic.y		= 20;;
+	s_options_quality_list.generic.name		= "sound quality";
+	s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
+	s_options_quality_list.itemnames		= quality_items;
+	s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
+
+	s_options_compatibility_list.generic.type	= MTYPE_SPINCONTROL;
+	s_options_compatibility_list.generic.x		= 0;
+	s_options_compatibility_list.generic.y		= 30;
+	s_options_compatibility_list.generic.name	= "sound compatibility";
+	s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
+	s_options_compatibility_list.itemnames		= compatibility_items;
+	s_options_compatibility_list.curvalue		= Cvar_VariableValue( "s_primary" );
+
+	s_options_sensitivity_slider.generic.type	= MTYPE_SLIDER;
+	s_options_sensitivity_slider.generic.x		= 0;
+	s_options_sensitivity_slider.generic.y		= 50;
+	s_options_sensitivity_slider.generic.name	= "mouse speed";
+	s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
+	s_options_sensitivity_slider.minvalue		= 2;
+	s_options_sensitivity_slider.maxvalue		= 22;
+
+	s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_alwaysrun_box.generic.x	= 0;
+	s_options_alwaysrun_box.generic.y	= 60;
+	s_options_alwaysrun_box.generic.name	= "always run";
+	s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
+	s_options_alwaysrun_box.itemnames = yesno_names;
+
+	s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_invertmouse_box.generic.x	= 0;
+	s_options_invertmouse_box.generic.y	= 70;
+	s_options_invertmouse_box.generic.name	= "invert mouse";
+	s_options_invertmouse_box.generic.callback = InvertMouseFunc;
+	s_options_invertmouse_box.itemnames = yesno_names;
+
+	s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_lookspring_box.generic.x	= 0;
+	s_options_lookspring_box.generic.y	= 80;
+	s_options_lookspring_box.generic.name	= "lookspring";
+	s_options_lookspring_box.generic.callback = LookspringFunc;
+	s_options_lookspring_box.itemnames = yesno_names;
+
+	s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_lookstrafe_box.generic.x	= 0;
+	s_options_lookstrafe_box.generic.y	= 90;
+	s_options_lookstrafe_box.generic.name	= "lookstrafe";
+	s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
+	s_options_lookstrafe_box.itemnames = yesno_names;
+
+	s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_freelook_box.generic.x	= 0;
+	s_options_freelook_box.generic.y	= 100;
+	s_options_freelook_box.generic.name	= "free look";
+	s_options_freelook_box.generic.callback = FreeLookFunc;
+	s_options_freelook_box.itemnames = yesno_names;
+
+	s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_crosshair_box.generic.x	= 0;
+	s_options_crosshair_box.generic.y	= 110;
+	s_options_crosshair_box.generic.name	= "crosshair";
+	s_options_crosshair_box.generic.callback = CrosshairFunc;
+	s_options_crosshair_box.itemnames = crosshair_names;
+/*
+	s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_noalttab_box.generic.x	= 0;
+	s_options_noalttab_box.generic.y	= 110;
+	s_options_noalttab_box.generic.name	= "disable alt-tab";
+	s_options_noalttab_box.generic.callback = NoAltTabFunc;
+	s_options_noalttab_box.itemnames = yesno_names;
+*/
+	s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
+	s_options_joystick_box.generic.x	= 0;
+	s_options_joystick_box.generic.y	= 120;
+	s_options_joystick_box.generic.name	= "use joystick";
+	s_options_joystick_box.generic.callback = JoystickFunc;
+	s_options_joystick_box.itemnames = yesno_names;
+
+	s_options_customize_options_action.generic.type	= MTYPE_ACTION;
+	s_options_customize_options_action.generic.x		= 0;
+	s_options_customize_options_action.generic.y		= 140;
+	s_options_customize_options_action.generic.name	= "customize controls";
+	s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
+
+	s_options_defaults_action.generic.type	= MTYPE_ACTION;
+	s_options_defaults_action.generic.x		= 0;
+	s_options_defaults_action.generic.y		= 150;
+	s_options_defaults_action.generic.name	= "reset defaults";
+	s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
+
+	s_options_console_action.generic.type	= MTYPE_ACTION;
+	s_options_console_action.generic.x		= 0;
+	s_options_console_action.generic.y		= 160;
+	s_options_console_action.generic.name	= "go to console";
+	s_options_console_action.generic.callback = ConsoleFunc;
+
+	ControlsSetMenuItemValues();
+
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
+	Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
+}
+
+void Options_MenuDraw (void)
+{
+	M_Banner( "m_banner_options" );
+	Menu_AdjustCursor( &s_options_menu, 1 );
+	Menu_Draw( &s_options_menu );
+}
+
+const char *Options_MenuKey( int key )
+{
+	return Default_MenuKey( &s_options_menu, key );
+}
+
+void M_Menu_Options_f (void)
+{
+	Options_MenuInit();
+	M_PushMenu ( Options_MenuDraw, Options_MenuKey );
+}
+
+/*
+=======================================================================
+
+VIDEO MENU
+
+=======================================================================
+*/
+
+void M_Menu_Video_f (void)
+{
+	VID_MenuInit();
+	M_PushMenu( VID_MenuDraw, VID_MenuKey );
+}
+
+/*
+=============================================================================
+
+END GAME MENU
+
+=============================================================================
+*/
+static int credits_start_time;
+static const char **credits;
+static char *creditsIndex[256];
+static char *creditsBuffer;
+static const char *idcredits[] =
+{
+	"+QUAKE II BY ID SOFTWARE",
+	"",
+	"+PROGRAMMING",
+	"John Carmack",
+	"John Cash",
+	"Brian Hook",
+	"",
+	"+ART",
+	"Adrian Carmack",
+	"Kevin Cloud",
+	"Paul Steed",
+	"",
+	"+LEVEL DESIGN",
+	"Tim Willits",
+	"American McGee",
+	"Christian Antkow",
+	"Paul Jaquays",
+	"Brandon James",
+	"",
+	"+BIZ",
+	"Todd Hollenshead",
+	"Barrett (Bear) Alexander",
+	"Donna Jackson",
+	"",
+	"",
+	"+SPECIAL THANKS",
+	"Ben Donges for beta testing",
+	"",
+	"",
+	"",
+	"",
+	"",
+	"",
+	"+ADDITIONAL SUPPORT",
+	"",
+	"+LINUX PORT AND CTF",
+	"Dave \"Zoid\" Kirsch",
+	"",
+	"+CINEMATIC SEQUENCES",
+	"Ending Cinematic by Blur Studio - ",
+	"Venice, CA",
+	"",
+	"Environment models for Introduction",
+	"Cinematic by Karl Dolgener",
+	"",
+	"Assistance with environment design",
+	"by Cliff Iwai",
+	"",
+	"+SOUND EFFECTS AND MUSIC",
+	"Sound Design by Soundelux Media Labs.",
+	"Music Composed and Produced by",
+	"Soundelux Media Labs.  Special thanks",
+	"to Bill Brown, Tom Ozanich, Brian",
+	"Celano, Jeff Eisner, and The Soundelux",
+	"Players.",
+	"",
+	"\"Level Music\" by Sonic Mayhem",
+	"www.sonicmayhem.com",
+	"",
+	"\"Quake II Theme Song\"",
+	"(C) 1997 Rob Zombie. All Rights",
+	"Reserved.",
+	"",
+	"Track 10 (\"Climb\") by Jer Sypult",
+	"",
+	"Voice of computers by",
+	"Carly Staehlin-Taylor",
+	"",
+	"+THANKS TO ACTIVISION",
+	"+IN PARTICULAR:",
+	"",
+	"John Tam",
+	"Steve Rosenthal",
+	"Marty Stratton",
+	"Henk Hartong",
+	"",
+	"Quake II(tm) (C)1997 Id Software, Inc.",
+	"All Rights Reserved.  Distributed by",
+	"Activision, Inc. under license.",
+	"Quake II(tm), the Id Software name,",
+	"the \"Q II\"(tm) logo and id(tm)",
+	"logo are trademarks of Id Software,",
+	"Inc. Activision(R) is a registered",
+	"trademark of Activision, Inc. All",
+	"other trademarks and trade names are",
+	"properties of their respective owners.",
+	0
+};
+
+static const char *xatcredits[] =
+{
+	"+QUAKE II MISSION PACK: THE RECKONING",
+	"+BY",
+	"+XATRIX ENTERTAINMENT, INC.",
+	"",
+	"+DESIGN AND DIRECTION",
+	"Drew Markham",
+	"",
+	"+PRODUCED BY",
+	"Greg Goodrich",
+	"",
+	"+PROGRAMMING",
+	"Rafael Paiz",
+	"",
+	"+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
+	"Alex Mayberry",
+	"",
+	"+LEVEL DESIGN",
+	"Mal Blackwell",
+	"Dan Koppel",
+	"",
+	"+ART DIRECTION",
+	"Michael \"Maxx\" Kaufman",
+	"",
+	"+COMPUTER GRAPHICS SUPERVISOR AND",
+	"+CHARACTER ANIMATION DIRECTION",
+	"Barry Dempsey",
+	"",
+	"+SENIOR ANIMATOR AND MODELER",
+	"Jason Hoover",
+	"",
+	"+CHARACTER ANIMATION AND",
+	"+MOTION CAPTURE SPECIALIST",
+	"Amit Doron",
+	"",
+	"+ART",
+	"Claire Praderie-Markham",
+	"Viktor Antonov",
+	"Corky Lehmkuhl",
+	"",
+	"+INTRODUCTION ANIMATION",
+	"Dominique Drozdz",
+	"",
+	"+ADDITIONAL LEVEL DESIGN",
+	"Aaron Barber",
+	"Rhett Baldwin",
+	"",
+	"+3D CHARACTER ANIMATION TOOLS",
+	"Gerry Tyra, SA Technology",
+	"",
+	"+ADDITIONAL EDITOR TOOL PROGRAMMING",
+	"Robert Duffy",
+	"",
+	"+ADDITIONAL PROGRAMMING",
+	"Ryan Feltrin",
+	"",
+	"+PRODUCTION COORDINATOR",
+	"Victoria Sylvester",
+	"",
+	"+SOUND DESIGN",
+	"Gary Bradfield",
+	"",
+	"+MUSIC BY",
+	"Sonic Mayhem",
+	"",
+	"",
+	"",
+	"+SPECIAL THANKS",
+	"+TO",
+	"+OUR FRIENDS AT ID SOFTWARE",
+	"",
+	"John Carmack",
+	"John Cash",
+	"Brian Hook",
+	"Adrian Carmack",
+	"Kevin Cloud",
+	"Paul Steed",
+	"Tim Willits",
+	"Christian Antkow",
+	"Paul Jaquays",
+	"Brandon James",
+	"Todd Hollenshead",
+	"Barrett (Bear) Alexander",
+	"Dave \"Zoid\" Kirsch",
+	"Donna Jackson",
+	"",
+	"",
+	"",
+	"+THANKS TO ACTIVISION",
+	"+IN PARTICULAR:",
+	"",
+	"Marty Stratton",
+	"Henk \"The Original Ripper\" Hartong",
+	"Kevin Kraff",
+	"Jamey Gottlieb",
+	"Chris Hepburn",
+	"",
+	"+AND THE GAME TESTERS",
+	"",
+	"Tim Vanlaw",
+	"Doug Jacobs",
+	"Steven Rosenthal",
+	"David Baker",
+	"Chris Campbell",
+	"Aaron Casillas",
+	"Steve Elwell",
+	"Derek Johnstone",
+	"Igor Krinitskiy",
+	"Samantha Lee",
+	"Michael Spann",
+	"Chris Toft",
+	"Juan Valdes",
+	"",
+	"+THANKS TO INTERGRAPH COMPUTER SYTEMS",
+	"+IN PARTICULAR:",
+	"",
+	"Michael T. Nicolaou",
+	"",
+	"",
+	"Quake II Mission Pack: The Reckoning",
+	"(tm) (C)1998 Id Software, Inc. All",
+	"Rights Reserved. Developed by Xatrix",
+	"Entertainment, Inc. for Id Software,",
+	"Inc. Distributed by Activision Inc.",
+	"under license. Quake(R) is a",
+	"registered trademark of Id Software,",
+	"Inc. Quake II Mission Pack: The",
+	"Reckoning(tm), Quake II(tm), the Id",
+	"Software name, the \"Q II\"(tm) logo",
+	"and id(tm) logo are trademarks of Id",
+	"Software, Inc. Activision(R) is a",
+	"registered trademark of Activision,",
+	"Inc. Xatrix(R) is a registered",
+	"trademark of Xatrix Entertainment,",
+	"Inc. All other trademarks and trade",
+	"names are properties of their",
+	"respective owners.",
+	0
+};
+
+static const char *roguecredits[] =
+{
+	"+QUAKE II MISSION PACK 2: GROUND ZERO",
+	"+BY",
+	"+ROGUE ENTERTAINMENT, INC.",
+	"",
+	"+PRODUCED BY",
+	"Jim Molinets",
+	"",
+	"+PROGRAMMING",
+	"Peter Mack",
+	"Patrick Magruder",
+	"",
+	"+LEVEL DESIGN",
+	"Jim Molinets",
+	"Cameron Lamprecht",
+	"Berenger Fish",
+	"Robert Selitto",
+	"Steve Tietze",
+	"Steve Thoms",
+	"",
+	"+ART DIRECTION",
+	"Rich Fleider",
+	"",
+	"+ART",
+	"Rich Fleider",
+	"Steve Maines",
+	"Won Choi",
+	"",
+	"+ANIMATION SEQUENCES",
+	"Creat Studios",
+	"Steve Maines",
+	"",
+	"+ADDITIONAL LEVEL DESIGN",
+	"Rich Fleider",
+	"Steve Maines",
+	"Peter Mack",
+	"",
+	"+SOUND",
+	"James Grunke",
+	"",
+	"+GROUND ZERO THEME",
+	"+AND",
+	"+MUSIC BY",
+	"Sonic Mayhem",
+	"",
+	"+VWEP MODELS",
+	"Brent \"Hentai\" Dill",
+	"",
+	"",
+	"",
+	"+SPECIAL THANKS",
+	"+TO",
+	"+OUR FRIENDS AT ID SOFTWARE",
+	"",
+	"John Carmack",
+	"John Cash",
+	"Brian Hook",
+	"Adrian Carmack",
+	"Kevin Cloud",
+	"Paul Steed",
+	"Tim Willits",
+	"Christian Antkow",
+	"Paul Jaquays",
+	"Brandon James",
+	"Todd Hollenshead",
+	"Barrett (Bear) Alexander",
+	"Katherine Anna Kang",
+	"Donna Jackson",
+	"Dave \"Zoid\" Kirsch",
+	"",
+	"",
+	"",
+	"+THANKS TO ACTIVISION",
+	"+IN PARTICULAR:",
+	"",
+	"Marty Stratton",
+	"Henk Hartong",
+	"Mitch Lasky",
+	"Steve Rosenthal",
+	"Steve Elwell",
+	"",
+	"+AND THE GAME TESTERS",
+	"",
+	"The Ranger Clan",
+	"Dave \"Zoid\" Kirsch",
+	"Nihilistic Software",
+	"Robert Duffy",
+	"",
+	"And Countless Others",
+	"",
+	"",
+	"",
+	"Quake II Mission Pack 2: Ground Zero",
+	"(tm) (C)1998 Id Software, Inc. All",
+	"Rights Reserved. Developed by Rogue",
+	"Entertainment, Inc. for Id Software,",
+	"Inc. Distributed by Activision Inc.",
+	"under license. Quake(R) is a",
+	"registered trademark of Id Software,",
+	"Inc. Quake II Mission Pack 2: Ground",
+	"Zero(tm), Quake II(tm), the Id",
+	"Software name, the \"Q II\"(tm) logo",
+	"and id(tm) logo are trademarks of Id",
+	"Software, Inc. Activision(R) is a",
+	"registered trademark of Activision,",
+	"Inc. Rogue(R) is a registered",
+	"trademark of Rogue Entertainment,",
+	"Inc. All other trademarks and trade",
+	"names are properties of their",
+	"respective owners.",
+	0
+};
+
+
+void M_Credits_MenuDraw( void )
+{
+	int i, y;
+
+	/*
+	** draw the credits
+	*/
+	for ( i = 0, y = viddef.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < viddef.height; y += 10, i++ )
+	{
+		int j, stringoffset = 0;
+		int bold = false;
+
+		if ( y <= -8 )
+			continue;
+
+		if ( credits[i][0] == '+' )
+		{
+			bold = true;
+			stringoffset = 1;
+		}
+		else
+		{
+			bold = false;
+			stringoffset = 0;
+		}
+
+		for ( j = 0; credits[i][j+stringoffset]; j++ )
+		{
+			int x;
+
+			x = ( viddef.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
+
+			if ( bold )
+				re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
+			else
+				re.DrawChar( x, y, credits[i][j+stringoffset] );
+		}
+	}
+
+	if ( y < 0 )
+		credits_start_time = cls.realtime;
+}
+
+const char *M_Credits_Key( int key )
+{
+	switch (key)
+	{
+	case K_ESCAPE:
+		if (creditsBuffer)
+			FS_FreeFile (creditsBuffer);
+		M_PopMenu ();
+		break;
+	}
+
+	return menu_out_sound;
+
+}
+
+extern int Developer_searchpath (int who);
+
+void M_Menu_Credits_f( void )
+{
+	int		n;
+	int		count;
+	char	*p;
+	int		isdeveloper = 0;
+
+	creditsBuffer = NULL;
+	count = FS_LoadFile ("credits", &creditsBuffer);
+	if (count != -1)
+	{
+		p = creditsBuffer;
+		for (n = 0; n < 255; n++)
+		{
+			creditsIndex[n] = p;
+			while (*p != '\r' && *p != '\n')
+			{
+				p++;
+				if (--count == 0)
+					break;
+			}
+			if (*p == '\r')
+			{
+				*p++ = 0;
+				if (--count == 0)
+					break;
+			}
+			*p++ = 0;
+			if (--count == 0)
+				break;
+		}
+		creditsIndex[++n] = 0;
+		credits = creditsIndex;
+	}
+	else
+	{
+		isdeveloper = Developer_searchpath (1);
+		
+		if (isdeveloper == 1)			// xatrix
+			credits = xatcredits;
+		else if (isdeveloper == 2)		// ROGUE
+			credits = roguecredits;
+		else
+		{
+			credits = idcredits;	
+		}
+
+	}
+
+	credits_start_time = cls.realtime;
+	M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
+}
+
+/*
+=============================================================================
+
+GAME MENU
+
+=============================================================================
+*/
+
+static int		m_game_cursor;
+
+static menuframework_s	s_game_menu;
+static menuaction_s		s_easy_game_action;
+static menuaction_s		s_medium_game_action;
+static menuaction_s		s_hard_game_action;
+static menuaction_s		s_load_game_action;
+static menuaction_s		s_save_game_action;
+static menuaction_s		s_credits_action;
+static menuseparator_s	s_blankline;
+
+static void StartGame( void )
+{
+	// disable updates and start the cinematic going
+	cl.servercount = -1;
+	M_ForceMenuOff ();
+	Cvar_SetValue( "deathmatch", 0 );
+	Cvar_SetValue( "coop", 0 );
+
+	Cvar_SetValue( "gamerules", 0 );		//PGM
+
+	Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
+	cls.key_dest = key_game;
+}
+
+static void EasyGameFunc( void *data )
+{
+	Cvar_ForceSet( "skill", "0" );
+	StartGame();
+}
+
+static void MediumGameFunc( void *data )
+{
+	Cvar_ForceSet( "skill", "1" );
+	StartGame();
+}
+
+static void HardGameFunc( void *data )
+{
+	Cvar_ForceSet( "skill", "2" );
+	StartGame();
+}
+
+static void LoadGameFunc( void *unused )
+{
+	M_Menu_LoadGame_f ();
+}
+
+static void SaveGameFunc( void *unused )
+{
+	M_Menu_SaveGame_f();
+}
+
+static void CreditsFunc( void *unused )
+{
+	M_Menu_Credits_f();
+}
+
+void Game_MenuInit( void )
+{
+	static const char *difficulty_names[] =
+	{
+		"easy",
+		"medium",
+		"hard",
+		0
+	};
+
+	s_game_menu.x = viddef.width * 0.50;
+	s_game_menu.nitems = 0;
+
+	s_easy_game_action.generic.type	= MTYPE_ACTION;
+	s_easy_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_easy_game_action.generic.x		= 0;
+	s_easy_game_action.generic.y		= 0;
+	s_easy_game_action.generic.name	= "easy";
+	s_easy_game_action.generic.callback = EasyGameFunc;
+
+	s_medium_game_action.generic.type	= MTYPE_ACTION;
+	s_medium_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_medium_game_action.generic.x		= 0;
+	s_medium_game_action.generic.y		= 10;
+	s_medium_game_action.generic.name	= "medium";
+	s_medium_game_action.generic.callback = MediumGameFunc;
+
+	s_hard_game_action.generic.type	= MTYPE_ACTION;
+	s_hard_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_hard_game_action.generic.x		= 0;
+	s_hard_game_action.generic.y		= 20;
+	s_hard_game_action.generic.name	= "hard";
+	s_hard_game_action.generic.callback = HardGameFunc;
+
+	s_blankline.generic.type = MTYPE_SEPARATOR;
+
+	s_load_game_action.generic.type	= MTYPE_ACTION;
+	s_load_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_load_game_action.generic.x		= 0;
+	s_load_game_action.generic.y		= 40;
+	s_load_game_action.generic.name	= "load game";
+	s_load_game_action.generic.callback = LoadGameFunc;
+
+	s_save_game_action.generic.type	= MTYPE_ACTION;
+	s_save_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_save_game_action.generic.x		= 0;
+	s_save_game_action.generic.y		= 50;
+	s_save_game_action.generic.name	= "save game";
+	s_save_game_action.generic.callback = SaveGameFunc;
+
+	s_credits_action.generic.type	= MTYPE_ACTION;
+	s_credits_action.generic.flags  = QMF_LEFT_JUSTIFY;
+	s_credits_action.generic.x		= 0;
+	s_credits_action.generic.y		= 60;
+	s_credits_action.generic.name	= "credits";
+	s_credits_action.generic.callback = CreditsFunc;
+
+	Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+	Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
+
+	Menu_Center( &s_game_menu );
+}
+
+void Game_MenuDraw( void )
+{
+	M_Banner( "m_banner_game" );
+	Menu_AdjustCursor( &s_game_menu, 1 );
+	Menu_Draw( &s_game_menu );
+}
+
+const char *Game_MenuKey( int key )
+{
+	return Default_MenuKey( &s_game_menu, key );
+}
+
+void M_Menu_Game_f (void)
+{
+	Game_MenuInit();
+	M_PushMenu( Game_MenuDraw, Game_MenuKey );
+	m_game_cursor = 1;
+}
+
+/*
+=============================================================================
+
+LOADGAME MENU
+
+=============================================================================
+*/
+
+#define	MAX_SAVEGAMES	15
+
+static menuframework_s	s_savegame_menu;
+
+static menuframework_s	s_loadgame_menu;
+static menuaction_s		s_loadgame_actions[MAX_SAVEGAMES];
+
+char		m_savestrings[MAX_SAVEGAMES][32];
+qboolean	m_savevalid[MAX_SAVEGAMES];
+
+void Create_Savestrings (void)
+{
+	int		i;
+	FILE	*f;
+	char	name[MAX_OSPATH];
+
+	for (i=0 ; i<MAX_SAVEGAMES ; i++)
+	{
+		Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
+		f = fopen (name, "rb");
+		if (!f)
+		{
+			strcpy (m_savestrings[i], "<EMPTY>");
+			m_savevalid[i] = false;
+		}
+		else
+		{
+			FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
+			fclose (f);
+			m_savevalid[i] = true;
+		}
+	}
+}
+
+void LoadGameCallback( void *self )
+{
+	menuaction_s *a = ( menuaction_s * ) self;
+
+	if ( m_savevalid[ a->generic.localdata[0] ] )
+		Cbuf_AddText (va("load save%i\n",  a->generic.localdata[0] ) );
+	M_ForceMenuOff ();
+}
+
+void LoadGame_MenuInit( void )
+{
+	int i;
+
+	s_loadgame_menu.x = viddef.width / 2 - 120;
+	s_loadgame_menu.y = viddef.height / 2 - 58;
+	s_loadgame_menu.nitems = 0;
+
+	Create_Savestrings();
+
+	for ( i = 0; i < MAX_SAVEGAMES; i++ )
+	{
+		s_loadgame_actions[i].generic.name			= m_savestrings[i];
+		s_loadgame_actions[i].generic.flags			= QMF_LEFT_JUSTIFY;
+		s_loadgame_actions[i].generic.localdata[0]	= i;
+		s_loadgame_actions[i].generic.callback		= LoadGameCallback;
+
+		s_loadgame_actions[i].generic.x = 0;
+		s_loadgame_actions[i].generic.y = ( i ) * 10;
+		if (i>0)	// separate from autosave
+			s_loadgame_actions[i].generic.y += 10;
+
+		s_loadgame_actions[i].generic.type = MTYPE_ACTION;
+
+		Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
+	}
+}
+
+void LoadGame_MenuDraw( void )
+{
+	M_Banner( "m_banner_load_game" );
+//	Menu_AdjustCursor( &s_loadgame_menu, 1 );
+	Menu_Draw( &s_loadgame_menu );
+}
+
+const char *LoadGame_MenuKey( int key )
+{
+	if ( key == K_ESCAPE || key == K_ENTER )
+	{
+		s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
+		if ( s_savegame_menu.cursor < 0 )
+			s_savegame_menu.cursor = 0;
+	}
+	return Default_MenuKey( &s_loadgame_menu, key );
+}
+
+void M_Menu_LoadGame_f (void)
+{
+	LoadGame_MenuInit();
+	M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+SAVEGAME MENU
+
+=============================================================================
+*/
+static menuframework_s	s_savegame_menu;
+static menuaction_s		s_savegame_actions[MAX_SAVEGAMES];
+
+void SaveGameCallback( void *self )
+{
+	menuaction_s *a = ( menuaction_s * ) self;
+
+	Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
+	M_ForceMenuOff ();
+}
+
+void SaveGame_MenuDraw( void )
+{
+	M_Banner( "m_banner_save_game" );
+	Menu_AdjustCursor( &s_savegame_menu, 1 );
+	Menu_Draw( &s_savegame_menu );
+}
+
+void SaveGame_MenuInit( void )
+{
+	int i;
+
+	s_savegame_menu.x = viddef.width / 2 - 120;
+	s_savegame_menu.y = viddef.height / 2 - 58;
+	s_savegame_menu.nitems = 0;
+
+	Create_Savestrings();
+
+	// don't include the autosave slot
+	for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
+	{
+		s_savegame_actions[i].generic.name = m_savestrings[i+1];
+		s_savegame_actions[i].generic.localdata[0] = i+1;
+		s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+		s_savegame_actions[i].generic.callback = SaveGameCallback;
+
+		s_savegame_actions[i].generic.x = 0;
+		s_savegame_actions[i].generic.y = ( i ) * 10;
+
+		s_savegame_actions[i].generic.type = MTYPE_ACTION;
+
+		Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
+	}
+}
+
+const char *SaveGame_MenuKey( int key )
+{
+	if ( key == K_ENTER || key == K_ESCAPE )
+	{
+		s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
+		if ( s_loadgame_menu.cursor < 0 )
+			s_loadgame_menu.cursor = 0;
+	}
+	return Default_MenuKey( &s_savegame_menu, key );
+}
+
+void M_Menu_SaveGame_f (void)
+{
+	if (!Com_ServerState())
+		return;		// not playing a game
+
+	SaveGame_MenuInit();
+	M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
+	Create_Savestrings ();
+}
+
+
+/*
+=============================================================================
+
+JOIN SERVER MENU
+
+=============================================================================
+*/
+#define MAX_LOCAL_SERVERS 8
+
+static menuframework_s	s_joinserver_menu;
+static menuseparator_s	s_joinserver_server_title;
+static menuaction_s		s_joinserver_search_action;
+static menuaction_s		s_joinserver_address_book_action;
+static menuaction_s		s_joinserver_server_actions[MAX_LOCAL_SERVERS];
+
+int		m_num_servers;
+#define	NO_SERVER_STRING	"<no server>"
+
+// user readable information
+static char local_server_names[MAX_LOCAL_SERVERS][80];
+
+// network address
+static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
+
+void M_AddToServerList (netadr_t adr, char *info)
+{
+	int		i;
+
+	if (m_num_servers == MAX_LOCAL_SERVERS)
+		return;
+	while ( *info == ' ' )
+		info++;
+
+	// ignore if duplicated
+	for (i=0 ; i<m_num_servers ; i++)
+		if (!strcmp(info, local_server_names[i]))
+			return;
+
+	local_server_netadr[m_num_servers] = adr;
+	strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
+	m_num_servers++;
+}
+
+
+void JoinServerFunc( void *self )
+{
+	char	buffer[128];
+	int		index;
+
+	index = ( menuaction_s * ) self - s_joinserver_server_actions;
+
+	if ( Q_stricmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
+		return;
+
+	if (index >= m_num_servers)
+		return;
+
+	Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
+	Cbuf_AddText (buffer);
+	M_ForceMenuOff ();
+}
+
+void AddressBookFunc( void *self )
+{
+	M_Menu_AddressBook_f();
+}
+
+void NullCursorDraw( void *self )
+{
+}
+
+void SearchLocalGames( void )
+{
+	int		i;
+
+	m_num_servers = 0;
+	for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
+		strcpy (local_server_names[i], NO_SERVER_STRING);
+
+	M_DrawTextBox( 8, 120 - 48, 36, 3 );
+	M_Print( 16 + 16, 120 - 48 + 8,  "Searching for local servers, this" );
+	M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+	M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+	// the text box won't show up unless we do a buffer swap
+	re.EndFrame();
+
+	// send out info packets
+	CL_PingServers_f();
+}
+
+void SearchLocalGamesFunc( void *self )
+{
+	SearchLocalGames();
+}
+
+void JoinServer_MenuInit( void )
+{
+	int i;
+
+	s_joinserver_menu.x = viddef.width * 0.50 - 120;
+	s_joinserver_menu.nitems = 0;
+
+	s_joinserver_address_book_action.generic.type	= MTYPE_ACTION;
+	s_joinserver_address_book_action.generic.name	= "address book";
+	s_joinserver_address_book_action.generic.flags	= QMF_LEFT_JUSTIFY;
+	s_joinserver_address_book_action.generic.x		= 0;
+	s_joinserver_address_book_action.generic.y		= 0;
+	s_joinserver_address_book_action.generic.callback = AddressBookFunc;
+
+	s_joinserver_search_action.generic.type = MTYPE_ACTION;
+	s_joinserver_search_action.generic.name	= "refresh server list";
+	s_joinserver_search_action.generic.flags	= QMF_LEFT_JUSTIFY;
+	s_joinserver_search_action.generic.x	= 0;
+	s_joinserver_search_action.generic.y	= 10;
+	s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
+	s_joinserver_search_action.generic.statusbar = "search for servers";
+
+	s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
+	s_joinserver_server_title.generic.name = "connect to...";
+	s_joinserver_server_title.generic.x    = 80;
+	s_joinserver_server_title.generic.y	   = 30;
+
+	for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
+	{
+		s_joinserver_server_actions[i].generic.type	= MTYPE_ACTION;
+		strcpy (local_server_names[i], NO_SERVER_STRING);
+		s_joinserver_server_actions[i].generic.name	= local_server_names[i];
+		s_joinserver_server_actions[i].generic.flags	= QMF_LEFT_JUSTIFY;
+		s_joinserver_server_actions[i].generic.x		= 0;
+		s_joinserver_server_actions[i].generic.y		= 40 + i*10;
+		s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
+		s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
+	}
+
+	Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
+	Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
+	Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
+
+	for ( i = 0; i < 8; i++ )
+		Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
+
+	Menu_Center( &s_joinserver_menu );
+
+	SearchLocalGames();
+}
+
+void JoinServer_MenuDraw(void)
+{
+	M_Banner( "m_banner_join_server" );
+	Menu_Draw( &s_joinserver_menu );
+}
+
+
+const char *JoinServer_MenuKey( int key )
+{
+	return Default_MenuKey( &s_joinserver_menu, key );
+}
+
+void M_Menu_JoinServer_f (void)
+{
+	JoinServer_MenuInit();
+	M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+START SERVER MENU
+
+=============================================================================
+*/
+static menuframework_s s_startserver_menu;
+static char **mapnames;
+static int	  nummaps;
+
+static menuaction_s	s_startserver_start_action;
+static menuaction_s	s_startserver_dmoptions_action;
+static menufield_s	s_timelimit_field;
+static menufield_s	s_fraglimit_field;
+static menufield_s	s_maxclients_field;
+static menufield_s	s_hostname_field;
+static menulist_s	s_startmap_list;
+static menulist_s	s_rules_box;
+
+void DMOptionsFunc( void *self )
+{
+	if (s_rules_box.curvalue == 1)
+		return;
+	M_Menu_DMOptions_f();
+}
+
+void RulesChangeFunc ( void *self )
+{
+	// DM
+	if (s_rules_box.curvalue == 0)
+	{
+		s_maxclients_field.generic.statusbar = NULL;
+		s_startserver_dmoptions_action.generic.statusbar = NULL;
+	}
+	else if(s_rules_box.curvalue == 1)		// coop				// PGM
+	{
+		s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
+		if (atoi(s_maxclients_field.buffer) > 4)
+			strcpy( s_maxclients_field.buffer, "4" );
+		s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
+	}
+//=====
+//PGM
+	// ROGUE GAMES
+	else if(Developer_searchpath(2) == 2)
+	{
+		if (s_rules_box.curvalue == 2)			// tag	
+		{
+			s_maxclients_field.generic.statusbar = NULL;
+			s_startserver_dmoptions_action.generic.statusbar = NULL;
+		}
+/*
+		else if(s_rules_box.curvalue == 3)		// deathball
+		{
+			s_maxclients_field.generic.statusbar = NULL;
+			s_startserver_dmoptions_action.generic.statusbar = NULL;
+		}
+*/
+	}
+//PGM
+//=====
+}
+
+void StartServerActionFunc( void *self )
+{
+	char	startmap[1024];
+	int		timelimit;
+	int		fraglimit;
+	int		maxclients;
+	char	*spot;
+
+	strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
+
+	maxclients  = atoi( s_maxclients_field.buffer );
+	timelimit	= atoi( s_timelimit_field.buffer );
+	fraglimit	= atoi( s_fraglimit_field.buffer );
+
+	Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
+	Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
+	Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
+	Cvar_Set("hostname", s_hostname_field.buffer );
+//	Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+//	Cvar_SetValue ("coop", s_rules_box.curvalue );
+
+//PGM
+	if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
+	{
+		Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+		Cvar_SetValue ("coop", s_rules_box.curvalue );
+		Cvar_SetValue ("gamerules", 0 );
+	}
+	else
+	{
+		Cvar_SetValue ("deathmatch", 1 );	// deathmatch is always true for rogue games, right?
+		Cvar_SetValue ("coop", 0 );			// FIXME - this might need to depend on which game we're running
+		Cvar_SetValue ("gamerules", s_rules_box.curvalue );
+	}
+//PGM
+
+	spot = NULL;
+	if (s_rules_box.curvalue == 1)		// PGM
+	{
+ 		if(Q_stricmp(startmap, "bunk1") == 0)
+  			spot = "start";
+ 		else if(Q_stricmp(startmap, "mintro") == 0)
+  			spot = "start";
+ 		else if(Q_stricmp(startmap, "fact1") == 0)
+  			spot = "start";
+ 		else if(Q_stricmp(startmap, "power1") == 0)
+  			spot = "pstart";
+ 		else if(Q_stricmp(startmap, "biggun") == 0)
+  			spot = "bstart";
+ 		else if(Q_stricmp(startmap, "hangar1") == 0)
+  			spot = "unitstart";
+ 		else if(Q_stricmp(startmap, "city1") == 0)
+  			spot = "unitstart";
+ 		else if(Q_stricmp(startmap, "boss1") == 0)
+			spot = "bosstart";
+	}
+
+	if (spot)
+	{
+		if (Com_ServerState())
+			Cbuf_AddText ("disconnect\n");
+		Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
+	}
+	else
+	{
+		Cbuf_AddText (va("map %s\n", startmap));
+	}
+
+	M_ForceMenuOff ();
+}
+
+void StartServer_MenuInit( void )
+{
+	static const char *dm_coop_names[] =
+	{
+		"deathmatch",
+		"cooperative",
+		0
+	};
+//=======
+//PGM
+	static const char *dm_coop_names_rogue[] =
+	{
+		"deathmatch",
+		"cooperative",
+		"tag",
+//		"deathball",
+		0
+	};
+//PGM
+//=======
+	char *buffer;
+	char  mapsname[1024];
+	char *s;
+	int length;
+	int i;
+	FILE *fp;
+
+	/*
+	** load the list of map names
+	*/
+	Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
+	if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
+	{
+		if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
+			Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
+	}
+	else
+	{
+#ifdef _WIN32
+		length = filelength( fileno( fp  ) );
+#else
+		fseek(fp, 0, SEEK_END);
+		length = ftell(fp);
+		fseek(fp, 0, SEEK_SET);
+#endif
+		buffer = malloc( length );
+		fread( buffer, length, 1, fp );
+	}
+
+	s = buffer;
+
+	i = 0;
+	while ( i < length )
+	{
+		if ( s[i] == '\r' )
+			nummaps++;
+		i++;
+	}
+
+	if ( nummaps == 0 )
+		Com_Error( ERR_DROP, "no maps in maps.lst\n" );
+
+	mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
+	memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
+
+	s = buffer;
+
+	for ( i = 0; i < nummaps; i++ )
+	{
+    char  shortname[MAX_TOKEN_CHARS];
+    char  longname[MAX_TOKEN_CHARS];
+		char  scratch[200];
+		int		j, l;
+
+		strcpy( shortname, COM_Parse( &s ) );
+		l = strlen(shortname);
+		for (j=0 ; j<l ; j++)
+			shortname[j] = toupper(shortname[j]);
+		strcpy( longname, COM_Parse( &s ) );
+		Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
+
+		mapnames[i] = malloc( strlen( scratch ) + 1 );
+		strcpy( mapnames[i], scratch );
+	}
+	mapnames[nummaps] = 0;
+
+	if ( fp != 0 )
+	{
+		fp = 0;
+		free( buffer );
+	}
+	else
+	{
+		FS_FreeFile( buffer );
+	}
+
+	/*
+	** initialize the menu stuff
+	*/
+	s_startserver_menu.x = viddef.width * 0.50;
+	s_startserver_menu.nitems = 0;
+
+	s_startmap_list.generic.type = MTYPE_SPINCONTROL;
+	s_startmap_list.generic.x	= 0;
+	s_startmap_list.generic.y	= 0;
+	s_startmap_list.generic.name	= "initial map";
+	s_startmap_list.itemnames = mapnames;
+
+	s_rules_box.generic.type = MTYPE_SPINCONTROL;
+	s_rules_box.generic.x	= 0;
+	s_rules_box.generic.y	= 20;
+	s_rules_box.generic.name	= "rules";
+	
+//PGM - rogue games only available with rogue DLL.
+	if(Developer_searchpath(2) == 2)
+		s_rules_box.itemnames = dm_coop_names_rogue;
+	else
+		s_rules_box.itemnames = dm_coop_names;
+//PGM
+
+	if (Cvar_VariableValue("coop"))
+		s_rules_box.curvalue = 1;
+	else
+		s_rules_box.curvalue = 0;
+	s_rules_box.generic.callback = RulesChangeFunc;
+
+	s_timelimit_field.generic.type = MTYPE_FIELD;
+	s_timelimit_field.generic.name = "time limit";
+	s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
+	s_timelimit_field.generic.x	= 0;
+	s_timelimit_field.generic.y	= 36;
+	s_timelimit_field.generic.statusbar = "0 = no limit";
+	s_timelimit_field.length = 3;
+	s_timelimit_field.visible_length = 3;
+	strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
+
+	s_fraglimit_field.generic.type = MTYPE_FIELD;
+	s_fraglimit_field.generic.name = "frag limit";
+	s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
+	s_fraglimit_field.generic.x	= 0;
+	s_fraglimit_field.generic.y	= 54;
+	s_fraglimit_field.generic.statusbar = "0 = no limit";
+	s_fraglimit_field.length = 3;
+	s_fraglimit_field.visible_length = 3;
+	strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
+
+	/*
+	** maxclients determines the maximum number of players that can join
+	** the game.  If maxclients is only "1" then we should default the menu
+	** option to 8 players, otherwise use whatever its current value is. 
+	** Clamping will be done when the server is actually started.
+	*/
+	s_maxclients_field.generic.type = MTYPE_FIELD;
+	s_maxclients_field.generic.name = "max players";
+	s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
+	s_maxclients_field.generic.x	= 0;
+	s_maxclients_field.generic.y	= 72;
+	s_maxclients_field.generic.statusbar = NULL;
+	s_maxclients_field.length = 3;
+	s_maxclients_field.visible_length = 3;
+	if ( Cvar_VariableValue( "maxclients" ) == 1 )
+		strcpy( s_maxclients_field.buffer, "8" );
+	else 
+		strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
+
+	s_hostname_field.generic.type = MTYPE_FIELD;
+	s_hostname_field.generic.name = "hostname";
+	s_hostname_field.generic.flags = 0;
+	s_hostname_field.generic.x	= 0;
+	s_hostname_field.generic.y	= 90;
+	s_hostname_field.generic.statusbar = NULL;
+	s_hostname_field.length = 12;
+	s_hostname_field.visible_length = 12;
+	strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
+
+	s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
+	s_startserver_dmoptions_action.generic.name	= " deathmatch flags";
+	s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
+	s_startserver_dmoptions_action.generic.x	= 24;
+	s_startserver_dmoptions_action.generic.y	= 108;
+	s_startserver_dmoptions_action.generic.statusbar = NULL;
+	s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
+
+	s_startserver_start_action.generic.type = MTYPE_ACTION;
+	s_startserver_start_action.generic.name	= " begin";
+	s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
+	s_startserver_start_action.generic.x	= 24;
+	s_startserver_start_action.generic.y	= 128;
+	s_startserver_start_action.generic.callback = StartServerActionFunc;
+
+	Menu_AddItem( &s_startserver_menu, &s_startmap_list );
+	Menu_AddItem( &s_startserver_menu, &s_rules_box );
+	Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
+	Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
+	Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
+	Menu_AddItem( &s_startserver_menu, &s_hostname_field );
+	Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
+	Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
+
+	Menu_Center( &s_startserver_menu );
+
+	// call this now to set proper inital state
+	RulesChangeFunc ( NULL );
+}
+
+void StartServer_MenuDraw(void)
+{
+	Menu_Draw( &s_startserver_menu );
+}
+
+const char *StartServer_MenuKey( int key )
+{
+	if ( key == K_ESCAPE )
+	{
+		if ( mapnames )
+		{
+			int i;
+
+			for ( i = 0; i < nummaps; i++ )
+				free( mapnames[i] );
+			free( mapnames );
+		}
+		mapnames = 0;
+		nummaps = 0;
+	}
+
+	return Default_MenuKey( &s_startserver_menu, key );
+}
+
+void M_Menu_StartServer_f (void)
+{
+	StartServer_MenuInit();
+	M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
+}
+
+/*
+=============================================================================
+
+DMOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static char dmoptions_statusbar[128];
+
+static menuframework_s s_dmoptions_menu;
+
+static menulist_s	s_friendlyfire_box;
+static menulist_s	s_falls_box;
+static menulist_s	s_weapons_stay_box;
+static menulist_s	s_instant_powerups_box;
+static menulist_s	s_powerups_box;
+static menulist_s	s_health_box;
+static menulist_s	s_spawn_farthest_box;
+static menulist_s	s_teamplay_box;
+static menulist_s	s_samelevel_box;
+static menulist_s	s_force_respawn_box;
+static menulist_s	s_armor_box;
+static menulist_s	s_allow_exit_box;
+static menulist_s	s_infinite_ammo_box;
+static menulist_s	s_fixed_fov_box;
+static menulist_s	s_quad_drop_box;
+
+//ROGUE
+static menulist_s	s_no_mines_box;
+static menulist_s	s_no_nukes_box;
+static menulist_s	s_stack_double_box;
+static menulist_s	s_no_spheres_box;
+//ROGUE
+
+static void DMFlagCallback( void *self )
+{
+	menulist_s *f = ( menulist_s * ) self;
+	int flags;
+	int bit = 0;
+
+	flags = Cvar_VariableValue( "dmflags" );
+
+	if ( f == &s_friendlyfire_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_FRIENDLY_FIRE;
+		else
+			flags |= DF_NO_FRIENDLY_FIRE;
+		goto setvalue;
+	}
+	else if ( f == &s_falls_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_FALLING;
+		else
+			flags |= DF_NO_FALLING;
+		goto setvalue;
+	}
+	else if ( f == &s_weapons_stay_box ) 
+	{
+		bit = DF_WEAPONS_STAY;
+	}
+	else if ( f == &s_instant_powerups_box )
+	{
+		bit = DF_INSTANT_ITEMS;
+	}
+	else if ( f == &s_allow_exit_box )
+	{
+		bit = DF_ALLOW_EXIT;
+	}
+	else if ( f == &s_powerups_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_ITEMS;
+		else
+			flags |= DF_NO_ITEMS;
+		goto setvalue;
+	}
+	else if ( f == &s_health_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_HEALTH;
+		else
+			flags |= DF_NO_HEALTH;
+		goto setvalue;
+	}
+	else if ( f == &s_spawn_farthest_box )
+	{
+		bit = DF_SPAWN_FARTHEST;
+	}
+	else if ( f == &s_teamplay_box )
+	{
+		if ( f->curvalue == 1 )
+		{
+			flags |=  DF_SKINTEAMS;
+			flags &= ~DF_MODELTEAMS;
+		}
+		else if ( f->curvalue == 2 )
+		{
+			flags |=  DF_MODELTEAMS;
+			flags &= ~DF_SKINTEAMS;
+		}
+		else
+		{
+			flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
+		}
+
+		goto setvalue;
+	}
+	else if ( f == &s_samelevel_box )
+	{
+		bit = DF_SAME_LEVEL;
+	}
+	else if ( f == &s_force_respawn_box )
+	{
+		bit = DF_FORCE_RESPAWN;
+	}
+	else if ( f == &s_armor_box )
+	{
+		if ( f->curvalue )
+			flags &= ~DF_NO_ARMOR;
+		else
+			flags |= DF_NO_ARMOR;
+		goto setvalue;
+	}
+	else if ( f == &s_infinite_ammo_box )
+	{
+		bit = DF_INFINITE_AMMO;
+	}
+	else if ( f == &s_fixed_fov_box )
+	{
+		bit = DF_FIXED_FOV;
+	}
+	else if ( f == &s_quad_drop_box )
+	{
+		bit = DF_QUAD_DROP;
+	}
+
+//=======
+//ROGUE
+	else if (Developer_searchpath(2) == 2)
+	{
+		if ( f == &s_no_mines_box)
+		{
+			bit = DF_NO_MINES;
+		}
+		else if ( f == &s_no_nukes_box)
+		{
+			bit = DF_NO_NUKES;
+		}
+		else if ( f == &s_stack_double_box)
+		{
+			bit = DF_NO_STACK_DOUBLE;
+		}
+		else if ( f == &s_no_spheres_box)
+		{
+			bit = DF_NO_SPHERES;
+		}
+	}
+//ROGUE
+//=======
+
+	if ( f )
+	{
+		if ( f->curvalue == 0 )
+			flags &= ~bit;
+		else
+			flags |= bit;
+	}
+
+setvalue:
+	Cvar_SetValue ("dmflags", flags);
+
+	Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
+
+}
+
+void DMOptions_MenuInit( void )
+{
+	static const char *yes_no_names[] =
+	{
+		"no", "yes", 0
+	};
+	static const char *teamplay_names[] = 
+	{
+		"disabled", "by skin", "by model", 0
+	};
+	int dmflags = Cvar_VariableValue( "dmflags" );
+	int y = 0;
+
+	s_dmoptions_menu.x = viddef.width * 0.50;
+	s_dmoptions_menu.nitems = 0;
+
+	s_falls_box.generic.type = MTYPE_SPINCONTROL;
+	s_falls_box.generic.x	= 0;
+	s_falls_box.generic.y	= y;
+	s_falls_box.generic.name	= "falling damage";
+	s_falls_box.generic.callback = DMFlagCallback;
+	s_falls_box.itemnames = yes_no_names;
+	s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
+
+	s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
+	s_weapons_stay_box.generic.x	= 0;
+	s_weapons_stay_box.generic.y	= y += 10;
+	s_weapons_stay_box.generic.name	= "weapons stay";
+	s_weapons_stay_box.generic.callback = DMFlagCallback;
+	s_weapons_stay_box.itemnames = yes_no_names;
+	s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
+
+	s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
+	s_instant_powerups_box.generic.x	= 0;
+	s_instant_powerups_box.generic.y	= y += 10;
+	s_instant_powerups_box.generic.name	= "instant powerups";
+	s_instant_powerups_box.generic.callback = DMFlagCallback;
+	s_instant_powerups_box.itemnames = yes_no_names;
+	s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
+
+	s_powerups_box.generic.type = MTYPE_SPINCONTROL;
+	s_powerups_box.generic.x	= 0;
+	s_powerups_box.generic.y	= y += 10;
+	s_powerups_box.generic.name	= "allow powerups";
+	s_powerups_box.generic.callback = DMFlagCallback;
+	s_powerups_box.itemnames = yes_no_names;
+	s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
+
+	s_health_box.generic.type = MTYPE_SPINCONTROL;
+	s_health_box.generic.x	= 0;
+	s_health_box.generic.y	= y += 10;
+	s_health_box.generic.callback = DMFlagCallback;
+	s_health_box.generic.name	= "allow health";
+	s_health_box.itemnames = yes_no_names;
+	s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
+
+	s_armor_box.generic.type = MTYPE_SPINCONTROL;
+	s_armor_box.generic.x	= 0;
+	s_armor_box.generic.y	= y += 10;
+	s_armor_box.generic.name	= "allow armor";
+	s_armor_box.generic.callback = DMFlagCallback;
+	s_armor_box.itemnames = yes_no_names;
+	s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
+
+	s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
+	s_spawn_farthest_box.generic.x	= 0;
+	s_spawn_farthest_box.generic.y	= y += 10;
+	s_spawn_farthest_box.generic.name	= "spawn farthest";
+	s_spawn_farthest_box.generic.callback = DMFlagCallback;
+	s_spawn_farthest_box.itemnames = yes_no_names;
+	s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
+
+	s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
+	s_samelevel_box.generic.x	= 0;
+	s_samelevel_box.generic.y	= y += 10;
+	s_samelevel_box.generic.name	= "same map";
+	s_samelevel_box.generic.callback = DMFlagCallback;
+	s_samelevel_box.itemnames = yes_no_names;
+	s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
+
+	s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
+	s_force_respawn_box.generic.x	= 0;
+	s_force_respawn_box.generic.y	= y += 10;
+	s_force_respawn_box.generic.name	= "force respawn";
+	s_force_respawn_box.generic.callback = DMFlagCallback;
+	s_force_respawn_box.itemnames = yes_no_names;
+	s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
+
+	s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
+	s_teamplay_box.generic.x	= 0;
+	s_teamplay_box.generic.y	= y += 10;
+	s_teamplay_box.generic.name	= "teamplay";
+	s_teamplay_box.generic.callback = DMFlagCallback;
+	s_teamplay_box.itemnames = teamplay_names;
+
+	s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_exit_box.generic.x	= 0;
+	s_allow_exit_box.generic.y	= y += 10;
+	s_allow_exit_box.generic.name	= "allow exit";
+	s_allow_exit_box.generic.callback = DMFlagCallback;
+	s_allow_exit_box.itemnames = yes_no_names;
+	s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
+
+	s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
+	s_infinite_ammo_box.generic.x	= 0;
+	s_infinite_ammo_box.generic.y	= y += 10;
+	s_infinite_ammo_box.generic.name	= "infinite ammo";
+	s_infinite_ammo_box.generic.callback = DMFlagCallback;
+	s_infinite_ammo_box.itemnames = yes_no_names;
+	s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
+
+	s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
+	s_fixed_fov_box.generic.x	= 0;
+	s_fixed_fov_box.generic.y	= y += 10;
+	s_fixed_fov_box.generic.name	= "fixed FOV";
+	s_fixed_fov_box.generic.callback = DMFlagCallback;
+	s_fixed_fov_box.itemnames = yes_no_names;
+	s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
+
+	s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
+	s_quad_drop_box.generic.x	= 0;
+	s_quad_drop_box.generic.y	= y += 10;
+	s_quad_drop_box.generic.name	= "quad drop";
+	s_quad_drop_box.generic.callback = DMFlagCallback;
+	s_quad_drop_box.itemnames = yes_no_names;
+	s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
+
+	s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
+	s_friendlyfire_box.generic.x	= 0;
+	s_friendlyfire_box.generic.y	= y += 10;
+	s_friendlyfire_box.generic.name	= "friendly fire";
+	s_friendlyfire_box.generic.callback = DMFlagCallback;
+	s_friendlyfire_box.itemnames = yes_no_names;
+	s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
+
+//============
+//ROGUE
+	if(Developer_searchpath(2) == 2)
+	{
+		s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
+		s_no_mines_box.generic.x	= 0;
+		s_no_mines_box.generic.y	= y += 10;
+		s_no_mines_box.generic.name	= "remove mines";
+		s_no_mines_box.generic.callback = DMFlagCallback;
+		s_no_mines_box.itemnames = yes_no_names;
+		s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
+
+		s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
+		s_no_nukes_box.generic.x	= 0;
+		s_no_nukes_box.generic.y	= y += 10;
+		s_no_nukes_box.generic.name	= "remove nukes";
+		s_no_nukes_box.generic.callback = DMFlagCallback;
+		s_no_nukes_box.itemnames = yes_no_names;
+		s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
+
+		s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
+		s_stack_double_box.generic.x	= 0;
+		s_stack_double_box.generic.y	= y += 10;
+		s_stack_double_box.generic.name	= "2x/4x stacking off";
+		s_stack_double_box.generic.callback = DMFlagCallback;
+		s_stack_double_box.itemnames = yes_no_names;
+		s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
+
+		s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
+		s_no_spheres_box.generic.x	= 0;
+		s_no_spheres_box.generic.y	= y += 10;
+		s_no_spheres_box.generic.name	= "remove spheres";
+		s_no_spheres_box.generic.callback = DMFlagCallback;
+		s_no_spheres_box.itemnames = yes_no_names;
+		s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
+
+	}
+//ROGUE
+//============
+
+	Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_health_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
+	Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
+
+//=======
+//ROGUE
+	if(Developer_searchpath(2) == 2)
+	{
+		Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
+		Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
+		Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
+		Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
+	}
+//ROGUE
+//=======
+
+	Menu_Center( &s_dmoptions_menu );
+
+	// set the original dmflags statusbar
+	DMFlagCallback( 0 );
+	Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
+}
+
+void DMOptions_MenuDraw(void)
+{
+	Menu_Draw( &s_dmoptions_menu );
+}
+
+const char *DMOptions_MenuKey( int key )
+{
+	return Default_MenuKey( &s_dmoptions_menu, key );
+}
+
+void M_Menu_DMOptions_f (void)
+{
+	DMOptions_MenuInit();
+	M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
+}
+
+/*
+=============================================================================
+
+DOWNLOADOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static menuframework_s s_downloadoptions_menu;
+
+static menuseparator_s	s_download_title;
+static menulist_s	s_allow_download_box;
+static menulist_s	s_allow_download_maps_box;
+static menulist_s	s_allow_download_models_box;
+static menulist_s	s_allow_download_players_box;
+static menulist_s	s_allow_download_sounds_box;
+
+static void DownloadCallback( void *self )
+{
+	menulist_s *f = ( menulist_s * ) self;
+
+	if (f == &s_allow_download_box)
+	{
+		Cvar_SetValue("allow_download", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_maps_box)
+	{
+		Cvar_SetValue("allow_download_maps", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_models_box)
+	{
+		Cvar_SetValue("allow_download_models", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_players_box)
+	{
+		Cvar_SetValue("allow_download_players", f->curvalue);
+	}
+
+	else if (f == &s_allow_download_sounds_box)
+	{
+		Cvar_SetValue("allow_download_sounds", f->curvalue);
+	}
+}
+
+void DownloadOptions_MenuInit( void )
+{
+	static const char *yes_no_names[] =
+	{
+		"no", "yes", 0
+	};
+	int y = 0;
+
+	s_downloadoptions_menu.x = viddef.width * 0.50;
+	s_downloadoptions_menu.nitems = 0;
+
+	s_download_title.generic.type = MTYPE_SEPARATOR;
+	s_download_title.generic.name = "Download Options";
+	s_download_title.generic.x    = 48;
+	s_download_title.generic.y	 = y;
+
+	s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_box.generic.x	= 0;
+	s_allow_download_box.generic.y	= y += 20;
+	s_allow_download_box.generic.name	= "allow downloading";
+	s_allow_download_box.generic.callback = DownloadCallback;
+	s_allow_download_box.itemnames = yes_no_names;
+	s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
+
+	s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_maps_box.generic.x	= 0;
+	s_allow_download_maps_box.generic.y	= y += 20;
+	s_allow_download_maps_box.generic.name	= "maps";
+	s_allow_download_maps_box.generic.callback = DownloadCallback;
+	s_allow_download_maps_box.itemnames = yes_no_names;
+	s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
+
+	s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_players_box.generic.x	= 0;
+	s_allow_download_players_box.generic.y	= y += 10;
+	s_allow_download_players_box.generic.name	= "player models/skins";
+	s_allow_download_players_box.generic.callback = DownloadCallback;
+	s_allow_download_players_box.itemnames = yes_no_names;
+	s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
+
+	s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_models_box.generic.x	= 0;
+	s_allow_download_models_box.generic.y	= y += 10;
+	s_allow_download_models_box.generic.name	= "models";
+	s_allow_download_models_box.generic.callback = DownloadCallback;
+	s_allow_download_models_box.itemnames = yes_no_names;
+	s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
+
+	s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
+	s_allow_download_sounds_box.generic.x	= 0;
+	s_allow_download_sounds_box.generic.y	= y += 10;
+	s_allow_download_sounds_box.generic.name	= "sounds";
+	s_allow_download_sounds_box.generic.callback = DownloadCallback;
+	s_allow_download_sounds_box.itemnames = yes_no_names;
+	s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
+
+	Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
+	Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
+
+	Menu_Center( &s_downloadoptions_menu );
+
+	// skip over title
+	if (s_downloadoptions_menu.cursor == 0)
+		s_downloadoptions_menu.cursor = 1;
+}
+
+void DownloadOptions_MenuDraw(void)
+{
+	Menu_Draw( &s_downloadoptions_menu );
+}
+
+const char *DownloadOptions_MenuKey( int key )
+{
+	return Default_MenuKey( &s_downloadoptions_menu, key );
+}
+
+void M_Menu_DownloadOptions_f (void)
+{
+	DownloadOptions_MenuInit();
+	M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
+}
+/*
+=============================================================================
+
+ADDRESS BOOK MENU
+
+=============================================================================
+*/
+#define NUM_ADDRESSBOOK_ENTRIES 9
+
+static menuframework_s	s_addressbook_menu;
+static menufield_s		s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
+
+void AddressBook_MenuInit( void )
+{
+	int i;
+
+	s_addressbook_menu.x = viddef.width / 2 - 142;
+	s_addressbook_menu.y = viddef.height / 2 - 58;
+	s_addressbook_menu.nitems = 0;
+
+	for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
+	{
+		cvar_t *adr;
+		char buffer[20];
+
+		Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
+
+		adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
+
+		s_addressbook_fields[i].generic.type = MTYPE_FIELD;
+		s_addressbook_fields[i].generic.name = 0;
+		s_addressbook_fields[i].generic.callback = 0;
+		s_addressbook_fields[i].generic.x		= 0;
+		s_addressbook_fields[i].generic.y		= i * 18 + 0;
+		s_addressbook_fields[i].generic.localdata[0] = i;
+		s_addressbook_fields[i].cursor			= 0;
+		s_addressbook_fields[i].length			= 60;
+		s_addressbook_fields[i].visible_length	= 30;
+
+		strcpy( s_addressbook_fields[i].buffer, adr->string );
+
+		Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
+	}
+}
+
+const char *AddressBook_MenuKey( int key )
+{
+	if ( key == K_ESCAPE )
+	{
+		int index;
+		char buffer[20];
+
+		for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
+		{
+			Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
+			Cvar_Set( buffer, s_addressbook_fields[index].buffer );
+		}
+	}
+	return Default_MenuKey( &s_addressbook_menu, key );
+}
+
+void AddressBook_MenuDraw(void)
+{
+	M_Banner( "m_banner_addressbook" );
+	Menu_Draw( &s_addressbook_menu );
+}
+
+void M_Menu_AddressBook_f(void)
+{
+	AddressBook_MenuInit();
+	M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
+}
+
+/*
+=============================================================================
+
+PLAYER CONFIG MENU
+
+=============================================================================
+*/
+static menuframework_s	s_player_config_menu;
+static menufield_s		s_player_name_field;
+static menulist_s		s_player_model_box;
+static menulist_s		s_player_skin_box;
+static menulist_s		s_player_handedness_box;
+static menulist_s		s_player_rate_box;
+static menuseparator_s	s_player_skin_title;
+static menuseparator_s	s_player_model_title;
+static menuseparator_s	s_player_hand_title;
+static menuseparator_s	s_player_rate_title;
+static menuaction_s		s_player_download_action;
+
+#define MAX_DISPLAYNAME 16
+#define MAX_PLAYERMODELS 1024
+
+typedef struct
+{
+	int		nskins;
+	char	**skindisplaynames;
+	char	displayname[MAX_DISPLAYNAME];
+	char	directory[MAX_QPATH];
+} playermodelinfo_s;
+
+static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
+static char *s_pmnames[MAX_PLAYERMODELS];
+static int s_numplayermodels;
+
+static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
+static const char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
+	"Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
+
+void DownloadOptionsFunc( void *self )
+{
+	M_Menu_DownloadOptions_f();
+}
+
+static void HandednessCallback( void *unused )
+{
+	Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
+}
+
+static void RateCallback( void *unused )
+{
+	if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
+		Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
+}
+
+static void ModelCallback( void *unused )
+{
+	s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
+	s_player_skin_box.curvalue = 0;
+}
+
+static void FreeFileList( char **list, int n )
+{
+	int i;
+
+	for ( i = 0; i < n; i++ )
+	{
+		if ( list[i] )
+		{
+			free( list[i] );
+			list[i] = 0;
+		}
+	}
+	free( list );
+}
+
+static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
+{
+	int i;
+	char scratch[1024];
+
+	strcpy( scratch, skin );
+	*strrchr( scratch, '.' ) = 0;
+	strcat( scratch, "_i.pcx" );
+
+	for ( i = 0; i < npcxfiles; i++ )
+	{
+		if ( strcmp( pcxfiles[i], scratch ) == 0 )
+			return true;
+	}
+
+	return false;
+}
+
+static qboolean PlayerConfig_ScanDirectories( void )
+{
+	char findname[1024];
+	char scratch[1024];
+	int ndirs = 0, npms = 0;
+	char **dirnames;
+	char *path = NULL;
+	int i;
+
+	extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
+
+	s_numplayermodels = 0;
+
+	/*
+	** get a list of directories
+	*/
+	do 
+	{
+		path = FS_NextPath( path );
+		Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
+
+		if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
+			break;
+	} while ( path );
+
+	if ( !dirnames )
+		return false;
+
+	/*
+	** go through the subdirectories
+	*/
+	npms = ndirs;
+	if ( npms > MAX_PLAYERMODELS )
+		npms = MAX_PLAYERMODELS;
+
+	for ( i = 0; i < npms; i++ )
+	{
+		int k, s;
+		char *a, *b, *c;
+		char **pcxnames;
+		char **skinnames;
+		int npcxfiles;
+		int nskins = 0;
+
+		if ( dirnames[i] == 0 )
+			continue;
+
+		// verify the existence of tris.md2
+		strcpy( scratch, dirnames[i] );
+		strcat( scratch, "/tris.md2" );
+		if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) )
+		{
+			free( dirnames[i] );
+			dirnames[i] = 0;
+			Sys_FindClose();
+			continue;
+		}
+		Sys_FindClose();
+
+		// verify the existence of at least one pcx skin
+		strcpy( scratch, dirnames[i] );
+		strcat( scratch, "/*.pcx" );
+		pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
+
+		if ( !pcxnames )
+		{
+			free( dirnames[i] );
+			dirnames[i] = 0;
+			continue;
+		}
+
+		// count valid skins, which consist of a skin with a matching "_i" icon
+		for ( k = 0; k < npcxfiles-1; k++ )
+		{
+			if ( !strstr( pcxnames[k], "_i.pcx" ) )
+			{
+				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+				{
+					nskins++;
+				}
+			}
+		}
+		if ( !nskins )
+			continue;
+
+		skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
+		memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
+
+		// copy the valid skins
+		for ( s = 0, k = 0; k < npcxfiles-1; k++ )
+		{
+			char *a, *b, *c;
+
+			if ( !strstr( pcxnames[k], "_i.pcx" ) )
+			{
+				if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+				{
+					a = strrchr( pcxnames[k], '/' );
+					b = strrchr( pcxnames[k], '\\' );
+
+					if ( a > b )
+						c = a;
+					else
+						c = b;
+
+					strcpy( scratch, c + 1 );
+
+					if ( strrchr( scratch, '.' ) )
+						*strrchr( scratch, '.' ) = 0;
+
+					skinnames[s] = strdup( scratch );
+					s++;
+				}
+			}
+		}
+
+		// at this point we have a valid player model
+		s_pmi[s_numplayermodels].nskins = nskins;
+		s_pmi[s_numplayermodels].skindisplaynames = skinnames;
+
+		// make short name for the model
+		a = strrchr( dirnames[i], '/' );
+		b = strrchr( dirnames[i], '\\' );
+
+		if ( a > b )
+			c = a;
+		else
+			c = b;
+
+		strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
+		strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
+
+		FreeFileList( pcxnames, npcxfiles );
+
+		s_numplayermodels++;
+	}
+	if ( dirnames )
+		FreeFileList( dirnames, ndirs );
+}
+
+static int pmicmpfnc( const void *_a, const void *_b )
+{
+	const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a;
+	const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b;
+
+	/*
+	** sort by male, female, then alphabetical
+	*/
+	if ( strcmp( a->directory, "male" ) == 0 )
+		return -1;
+	else if ( strcmp( b->directory, "male" ) == 0 )
+		return 1;
+
+	if ( strcmp( a->directory, "female" ) == 0 )
+		return -1;
+	else if ( strcmp( b->directory, "female" ) == 0 )
+		return 1;
+
+	return strcmp( a->directory, b->directory );
+}
+
+
+qboolean PlayerConfig_MenuInit( void )
+{
+	extern cvar_t *name;
+	extern cvar_t *team;
+	extern cvar_t *skin;
+	char currentdirectory[1024];
+	char currentskin[1024];
+	int i = 0;
+
+	int currentdirectoryindex = 0;
+	int currentskinindex = 0;
+
+	cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+
+	static const char *handedness[] = { "right", "left", "center", 0 };
+
+	PlayerConfig_ScanDirectories();
+
+	if (s_numplayermodels == 0)
+		return false;
+
+	if ( hand->value < 0 || hand->value > 2 )
+		Cvar_SetValue( "hand", 0 );
+
+	strcpy( currentdirectory, skin->string );
+
+	if ( strchr( currentdirectory, '/' ) )
+	{
+		strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
+		*strchr( currentdirectory, '/' ) = 0;
+	}
+	else if ( strchr( currentdirectory, '\\' ) )
+	{
+		strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
+		*strchr( currentdirectory, '\\' ) = 0;
+	}
+	else
+	{
+		strcpy( currentdirectory, "male" );
+		strcpy( currentskin, "grunt" );
+	}
+
+	qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
+
+	memset( s_pmnames, 0, sizeof( s_pmnames ) );
+	for ( i = 0; i < s_numplayermodels; i++ )
+	{
+		s_pmnames[i] = s_pmi[i].displayname;
+		if ( Q_stricmp( s_pmi[i].directory, currentdirectory ) == 0 )
+		{
+			int j;
+
+			currentdirectoryindex = i;
+
+			for ( j = 0; j < s_pmi[i].nskins; j++ )
+			{
+				if ( Q_stricmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
+				{
+					currentskinindex = j;
+					break;
+				}
+			}
+		}
+	}
+
+	s_player_config_menu.x = viddef.width / 2 - 95; 
+	s_player_config_menu.y = viddef.height / 2 - 97;
+	s_player_config_menu.nitems = 0;
+
+	s_player_name_field.generic.type = MTYPE_FIELD;
+	s_player_name_field.generic.name = "name";
+	s_player_name_field.generic.callback = 0;
+	s_player_name_field.generic.x		= 0;
+	s_player_name_field.generic.y		= 0;
+	s_player_name_field.length	= 20;
+	s_player_name_field.visible_length = 20;
+	strcpy( s_player_name_field.buffer, name->string );
+	s_player_name_field.cursor = strlen( name->string );
+
+	s_player_model_title.generic.type = MTYPE_SEPARATOR;
+	s_player_model_title.generic.name = "model";
+	s_player_model_title.generic.x    = -8;
+	s_player_model_title.generic.y	 = 60;
+
+	s_player_model_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_model_box.generic.x	= -56;
+	s_player_model_box.generic.y	= 70;
+	s_player_model_box.generic.callback = ModelCallback;
+	s_player_model_box.generic.cursor_offset = -48;
+	s_player_model_box.curvalue = currentdirectoryindex;
+	s_player_model_box.itemnames = s_pmnames;
+
+	s_player_skin_title.generic.type = MTYPE_SEPARATOR;
+	s_player_skin_title.generic.name = "skin";
+	s_player_skin_title.generic.x    = -16;
+	s_player_skin_title.generic.y	 = 84;
+
+	s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_skin_box.generic.x	= -56;
+	s_player_skin_box.generic.y	= 94;
+	s_player_skin_box.generic.name	= 0;
+	s_player_skin_box.generic.callback = 0;
+	s_player_skin_box.generic.cursor_offset = -48;
+	s_player_skin_box.curvalue = currentskinindex;
+	s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
+
+	s_player_hand_title.generic.type = MTYPE_SEPARATOR;
+	s_player_hand_title.generic.name = "handedness";
+	s_player_hand_title.generic.x    = 32;
+	s_player_hand_title.generic.y	 = 108;
+
+	s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_handedness_box.generic.x	= -56;
+	s_player_handedness_box.generic.y	= 118;
+	s_player_handedness_box.generic.name	= 0;
+	s_player_handedness_box.generic.cursor_offset = -48;
+	s_player_handedness_box.generic.callback = HandednessCallback;
+	s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
+	s_player_handedness_box.itemnames = handedness;
+
+	for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
+		if (Cvar_VariableValue("rate") == rate_tbl[i])
+			break;
+
+	s_player_rate_title.generic.type = MTYPE_SEPARATOR;
+	s_player_rate_title.generic.name = "connect speed";
+	s_player_rate_title.generic.x    = 56;
+	s_player_rate_title.generic.y	 = 156;
+
+	s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
+	s_player_rate_box.generic.x	= -56;
+	s_player_rate_box.generic.y	= 166;
+	s_player_rate_box.generic.name	= 0;
+	s_player_rate_box.generic.cursor_offset = -48;
+	s_player_rate_box.generic.callback = RateCallback;
+	s_player_rate_box.curvalue = i;
+	s_player_rate_box.itemnames = rate_names;
+
+	s_player_download_action.generic.type = MTYPE_ACTION;
+	s_player_download_action.generic.name	= "download options";
+	s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
+	s_player_download_action.generic.x	= -24;
+	s_player_download_action.generic.y	= 186;
+	s_player_download_action.generic.statusbar = NULL;
+	s_player_download_action.generic.callback = DownloadOptionsFunc;
+
+	Menu_AddItem( &s_player_config_menu, &s_player_name_field );
+	Menu_AddItem( &s_player_config_menu, &s_player_model_title );
+	Menu_AddItem( &s_player_config_menu, &s_player_model_box );
+	if ( s_player_skin_box.itemnames )
+	{
+		Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
+		Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
+	}
+	Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
+	Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
+	Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
+	Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
+	Menu_AddItem( &s_player_config_menu, &s_player_download_action );
+
+	return true;
+}
+
+void PlayerConfig_MenuDraw( void )
+{
+	extern float CalcFov( float fov_x, float w, float h );
+	refdef_t refdef;
+	char scratch[MAX_QPATH];
+
+	memset( &refdef, 0, sizeof( refdef ) );
+
+	refdef.x = viddef.width / 2;
+	refdef.y = viddef.height / 2 - 72;
+	refdef.width = 144;
+	refdef.height = 168;
+	refdef.fov_x = 40;
+	refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
+	refdef.time = cls.realtime*0.001;
+
+	if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
+	{
+		static int yaw;
+		int maxframe = 29;
+		entity_t entity;
+
+		memset( &entity, 0, sizeof( entity ) );
+
+		Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
+		entity.model = re.RegisterModel( scratch );
+		Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+		entity.skin = re.RegisterSkin( scratch );
+		entity.flags = RF_FULLBRIGHT;
+		entity.origin[0] = 80;
+		entity.origin[1] = 0;
+		entity.origin[2] = 0;
+		VectorCopy( entity.origin, entity.oldorigin );
+		entity.frame = 0;
+		entity.oldframe = 0;
+		entity.backlerp = 0.0;
+		entity.angles[1] = yaw++;
+		if ( ++yaw > 360 )
+			yaw -= 360;
+
+		refdef.areabits = 0;
+		refdef.num_entities = 1;
+		refdef.entities = &entity;
+		refdef.lightstyles = 0;
+		refdef.rdflags = RDF_NOWORLDMODEL;
+
+		Menu_Draw( &s_player_config_menu );
+
+		M_DrawTextBox( ( refdef.x ) * ( 320.0F / viddef.width ) - 8, ( viddef.height / 2 ) * ( 240.0F / viddef.height) - 77, refdef.width / 8, refdef.height / 8 );
+		refdef.height += 4;
+
+		re.RenderFrame( &refdef );
+
+		Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx", 
+			s_pmi[s_player_model_box.curvalue].directory,
+			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+		re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
+	}
+}
+
+const char *PlayerConfig_MenuKey (int key)
+{
+	int i;
+
+	if ( key == K_ESCAPE )
+	{
+		char scratch[1024];
+
+		Cvar_Set( "name", s_player_name_field.buffer );
+
+		Com_sprintf( scratch, sizeof( scratch ), "%s/%s", 
+			s_pmi[s_player_model_box.curvalue].directory, 
+			s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+
+		Cvar_Set( "skin", scratch );
+
+		for ( i = 0; i < s_numplayermodels; i++ )
+		{
+			int j;
+
+			for ( j = 0; j < s_pmi[i].nskins; j++ )
+			{
+				if ( s_pmi[i].skindisplaynames[j] )
+					free( s_pmi[i].skindisplaynames[j] );
+				s_pmi[i].skindisplaynames[j] = 0;
+			}
+			free( s_pmi[i].skindisplaynames );
+			s_pmi[i].skindisplaynames = 0;
+			s_pmi[i].nskins = 0;
+		}
+	}
+	return Default_MenuKey( &s_player_config_menu, key );
+}
+
+
+void M_Menu_PlayerConfig_f (void)
+{
+	if (!PlayerConfig_MenuInit())
+	{
+		Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
+		return;
+	}
+	Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+	M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+GALLERY MENU
+
+=======================================================================
+*/
+#if 0
+void M_Menu_Gallery_f( void )
+{
+	extern void Gallery_MenuDraw( void );
+	extern const char *Gallery_MenuKey( int key );
+
+	M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
+}
+#endif
+
+/*
+=======================================================================
+
+QUIT MENU
+
+=======================================================================
+*/
+
+const char *M_Quit_Key (int key)
+{
+	switch (key)
+	{
+	case K_ESCAPE:
+	case 'n':
+	case 'N':
+		M_PopMenu ();
+		break;
+
+	case 'Y':
+	case 'y':
+		cls.key_dest = key_console;
+		CL_Quit_f ();
+		break;
+
+	default:
+		break;
+	}
+
+	return NULL;
+
+}
+
+
+void M_Quit_Draw (void)
+{
+	int		w, h;
+
+	re.DrawGetPicSize (&w, &h, "quit");
+	re.DrawPic ( (viddef.width-w)/2, (viddef.height-h)/2, "quit");
+}
+
+
+void M_Menu_Quit_f (void)
+{
+	M_PushMenu (M_Quit_Draw, M_Quit_Key);
+}
+
+
+
+//=============================================================================
+/* Menu Subsystem */
+
+
+/*
+=================
+M_Init
+=================
+*/
+void M_Init (void)
+{
+	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
+	Cmd_AddCommand ("menu_game", M_Menu_Game_f);
+		Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
+		Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
+		Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
+			Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
+		Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
+			Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
+		Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
+			Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
+		Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
+	Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
+	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
+	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
+		Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
+	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
+}
+
+
+/*
+=================
+M_Draw
+=================
+*/
+void M_Draw (void)
+{
+	if (cls.key_dest != key_menu)
+		return;
+
+	// repaint everything next frame
+	SCR_DirtyScreen ();
+
+	// dim everything behind it down
+	if (cl.cinematictime > 0)
+		re.DrawFill (0,0,viddef.width, viddef.height, 0);
+	else
+		re.DrawFadeScreen ();
+
+	m_drawfunc ();
+
+	// delay playing the enter sound until after the
+	// menu has been drawn, to avoid delay while
+	// caching images
+	if (m_entersound)
+	{
+		S_StartLocalSound( menu_in_sound );
+		m_entersound = false;
+	}
+}
+
+
+/*
+=================
+M_Keydown
+=================
+*/
+void M_Keydown (int key)
+{
+	const char *s;
+
+	if (m_keyfunc)
+		if ( ( s = m_keyfunc( key ) ) != 0 )
+			S_StartLocalSound( ( char * ) s );
+}
+
+
--- /dev/null
+++ b/client/qmenu.c
@@ -1,0 +1,674 @@
+/*
+Copyright (C) 1997-2001 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 <string.h>
+#include <ctype.h>
+
+#include "client.h"
+#include "qmenu.h"
+
+static void	 Action_DoEnter( menuaction_s *a );
+static void	 Action_Draw( menuaction_s *a );
+static void  Menu_DrawStatusBar( const char *string );
+static void	 Menulist_DoEnter( menulist_s *l );
+static void	 MenuList_Draw( menulist_s *l );
+static void	 Separator_Draw( menuseparator_s *s );
+static void	 Slider_DoSlide( menuslider_s *s, int dir );
+static void	 Slider_Draw( menuslider_s *s );
+static void	 SpinControl_DoEnter( menulist_s *s );
+static void	 SpinControl_Draw( menulist_s *s );
+static void	 SpinControl_DoSlide( menulist_s *s, int dir );
+
+#define RCOLUMN_OFFSET  16
+#define LCOLUMN_OFFSET -16
+
+extern refexport_t re;
+extern viddef_t viddef;
+
+#define VID_WIDTH viddef.width
+#define VID_HEIGHT viddef.height
+
+#define Draw_Char re.DrawChar
+#define Draw_Fill re.DrawFill
+
+void Action_DoEnter( menuaction_s *a )
+{
+	if ( a->generic.callback )
+		a->generic.callback( a );
+}
+
+void Action_Draw( menuaction_s *a )
+{
+	if ( a->generic.flags & QMF_LEFT_JUSTIFY )
+	{
+		if ( a->generic.flags & QMF_GRAYED )
+			Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+		else
+			Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+	}
+	else
+	{
+		if ( a->generic.flags & QMF_GRAYED )
+			Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+		else
+			Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+	}
+	if ( a->generic.ownerdraw )
+		a->generic.ownerdraw( a );
+}
+
+qboolean Field_DoEnter( menufield_s *f )
+{
+	if ( f->generic.callback )
+	{
+		f->generic.callback( f );
+		return true;
+	}
+	return false;
+}
+
+void Field_Draw( menufield_s *f )
+{
+	int i;
+	char tempbuffer[128]="";
+
+	if ( f->generic.name )
+		Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name );
+
+	strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length );
+
+	Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 );
+	Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 );
+
+	Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 );
+	Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 );
+
+	for ( i = 0; i < f->visible_length; i++ )
+	{
+		Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 );
+		Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 );
+	}
+
+	Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer );
+
+	if ( Menu_ItemAtCursor( f->generic.parent ) == f )
+	{
+		int offset;
+
+		if ( f->visible_offset )
+			offset = f->visible_length;
+		else
+			offset = f->cursor;
+
+		if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 )
+		{
+			Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
+					   f->generic.y + f->generic.parent->y,
+					   11 );
+		}
+		else
+		{
+			Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
+					   f->generic.y + f->generic.parent->y,
+					   ' ' );
+		}
+	}
+}
+
+qboolean Field_Key( menufield_s *f, int key )
+{
+	extern int keydown[];
+
+	switch ( key )
+	{
+	case K_KP_SLASH:
+		key = '/';
+		break;
+	case K_KP_MINUS:
+		key = '-';
+		break;
+	case K_KP_PLUS:
+		key = '+';
+		break;
+	case K_KP_HOME:
+		key = '7';
+		break;
+	case K_KP_UPARROW:
+		key = '8';
+		break;
+	case K_KP_PGUP:
+		key = '9';
+		break;
+	case K_KP_LEFTARROW:
+		key = '4';
+		break;
+	case K_KP_5:
+		key = '5';
+		break;
+	case K_KP_RIGHTARROW:
+		key = '6';
+		break;
+	case K_KP_END:
+		key = '1';
+		break;
+	case K_KP_DOWNARROW:
+		key = '2';
+		break;
+	case K_KP_PGDN:
+		key = '3';
+		break;
+	case K_KP_INS:
+		key = '0';
+		break;
+	case K_KP_DEL:
+		key = '.';
+		break;
+	}
+
+	if ( key > 127 )
+	{
+		switch ( key )
+		{
+		case K_DEL:
+		default:
+			return false;
+		}
+	}
+
+	/*
+	** support pasting from the clipboard
+	*/
+	if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
+		 ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
+	{
+		char *cbd;
+		
+		if ( ( cbd = Sys_GetClipboardData() ) != 0 )
+		{
+			strtok( cbd, "\n\r\b" );
+
+			strncpy( f->buffer, cbd, f->length - 1 );
+			f->cursor = strlen( f->buffer );
+			f->visible_offset = f->cursor - f->visible_length;
+			if ( f->visible_offset < 0 )
+				f->visible_offset = 0;
+
+			free( cbd );
+		}
+		return true;
+	}
+
+	switch ( key )
+	{
+	case K_KP_LEFTARROW:
+	case K_LEFTARROW:
+	case K_BACKSPACE:
+		if ( f->cursor > 0 )
+		{
+			memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 );
+			f->cursor--;
+
+			if ( f->visible_offset )
+			{
+				f->visible_offset--;
+			}
+		}
+		break;
+
+	case K_KP_DEL:
+	case K_DEL:
+		memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 );
+		break;
+
+	case K_KP_ENTER:
+	case K_ENTER:
+	case K_ESCAPE:
+	case K_TAB:
+		return false;
+
+	case K_SPACE:
+	default:
+		if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) )
+			return false;
+
+		if ( f->cursor < f->length )
+		{
+			f->buffer[f->cursor++] = key;
+			f->buffer[f->cursor] = 0;
+
+			if ( f->cursor > f->visible_length )
+			{
+				f->visible_offset++;
+			}
+		}
+	}
+
+	return true;
+}
+
+void Menu_AddItem( menuframework_s *menu, void *item )
+{
+	if ( menu->nitems == 0 )
+		menu->nslots = 0;
+
+	if ( menu->nitems < MAXMENUITEMS )
+	{
+		menu->items[menu->nitems] = item;
+		( ( menucommon_s * ) menu->items[menu->nitems] )->parent = menu;
+		menu->nitems++;
+	}
+
+	menu->nslots = Menu_TallySlots( menu );
+}
+
+/*
+** Menu_AdjustCursor
+**
+** This function takes the given menu, the direction, and attempts
+** to adjust the menu's cursor so that it's at the next available
+** slot.
+*/
+void Menu_AdjustCursor( menuframework_s *m, int dir )
+{
+	menucommon_s *citem;
+
+	/*
+	** see if it's in a valid spot
+	*/
+	if ( m->cursor >= 0 && m->cursor < m->nitems )
+	{
+		if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 )
+		{
+			if ( citem->type != MTYPE_SEPARATOR )
+				return;
+		}
+	}
+
+	/*
+	** it's not in a valid spot, so crawl in the direction indicated until we
+	** find a valid spot
+	*/
+	if ( dir == 1 )
+	{
+		while ( 1 )
+		{
+			citem = Menu_ItemAtCursor( m );
+			if ( citem )
+				if ( citem->type != MTYPE_SEPARATOR )
+					break;
+			m->cursor += dir;
+			if ( m->cursor >= m->nitems )
+				m->cursor = 0;
+		}
+	}
+	else
+	{
+		while ( 1 )
+		{
+			citem = Menu_ItemAtCursor( m );
+			if ( citem )
+				if ( citem->type != MTYPE_SEPARATOR )
+					break;
+			m->cursor += dir;
+			if ( m->cursor < 0 )
+				m->cursor = m->nitems - 1;
+		}
+	}
+}
+
+void Menu_Center( menuframework_s *menu )
+{
+	int height;
+
+	height = ( ( menucommon_s * ) menu->items[menu->nitems-1])->y;
+	height += 10;
+
+	menu->y = ( VID_HEIGHT - height ) / 2;
+}
+
+void Menu_Draw( menuframework_s *menu )
+{
+	int i;
+	menucommon_s *item;
+
+	/*
+	** draw contents
+	*/
+	for ( i = 0; i < menu->nitems; i++ )
+	{
+		switch ( ( ( menucommon_s * ) menu->items[i] )->type )
+		{
+		case MTYPE_FIELD:
+			Field_Draw( ( menufield_s * ) menu->items[i] );
+			break;
+		case MTYPE_SLIDER:
+			Slider_Draw( ( menuslider_s * ) menu->items[i] );
+			break;
+		case MTYPE_LIST:
+			MenuList_Draw( ( menulist_s * ) menu->items[i] );
+			break;
+		case MTYPE_SPINCONTROL:
+			SpinControl_Draw( ( menulist_s * ) menu->items[i] );
+			break;
+		case MTYPE_ACTION:
+			Action_Draw( ( menuaction_s * ) menu->items[i] );
+			break;
+		case MTYPE_SEPARATOR:
+			Separator_Draw( ( menuseparator_s * ) menu->items[i] );
+			break;
+		}
+	}
+
+	item = Menu_ItemAtCursor( menu );
+
+	if ( item && item->cursordraw )
+	{
+		item->cursordraw( item );
+	}
+	else if ( menu->cursordraw )
+	{
+		menu->cursordraw( menu );
+	}
+	else if ( item && item->type != MTYPE_FIELD )
+	{
+		if ( item->flags & QMF_LEFT_JUSTIFY )
+		{
+			Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
+		}
+		else
+		{
+			Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
+		}
+	}
+
+	if ( item )
+	{
+		if ( item->statusbarfunc )
+			item->statusbarfunc( ( void * ) item );
+		else if ( item->statusbar )
+			Menu_DrawStatusBar( item->statusbar );
+		else
+			Menu_DrawStatusBar( menu->statusbar );
+
+	}
+	else
+	{
+		Menu_DrawStatusBar( menu->statusbar );
+	}
+}
+
+void Menu_DrawStatusBar( const char *string )
+{
+	if ( string )
+	{
+		int l = strlen( string );
+		int maxrow = VID_HEIGHT / 8;
+		int maxcol = VID_WIDTH / 8;
+		int col = maxcol / 2 - l / 2;
+
+		Draw_Fill( 0, VID_HEIGHT-8, VID_WIDTH, 8, 4 );
+		Menu_DrawString( col*8, VID_HEIGHT - 8, string );
+	}
+	else
+	{
+		Draw_Fill( 0, VID_HEIGHT-8, VID_WIDTH, 8, 0 );
+	}
+}
+
+void Menu_DrawString( int x, int y, const char *string )
+{
+	unsigned i;
+
+	for ( i = 0; i < strlen( string ); i++ )
+	{
+		Draw_Char( ( x + i*8 ), y, string[i] );
+	}
+}
+
+void Menu_DrawStringDark( int x, int y, const char *string )
+{
+	unsigned i;
+
+	for ( i = 0; i < strlen( string ); i++ )
+	{
+		Draw_Char( ( x + i*8 ), y, string[i] + 128 );
+	}
+}
+
+void Menu_DrawStringR2L( int x, int y, const char *string )
+{
+	unsigned i;
+
+	for ( i = 0; i < strlen( string ); i++ )
+	{
+		Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] );
+	}
+}
+
+void Menu_DrawStringR2LDark( int x, int y, const char *string )
+{
+	unsigned i;
+
+	for ( i = 0; i < strlen( string ); i++ )
+	{
+		Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 );
+	}
+}
+
+void *Menu_ItemAtCursor( menuframework_s *m )
+{
+	if ( m->cursor < 0 || m->cursor >= m->nitems )
+		return 0;
+
+	return m->items[m->cursor];
+}
+
+qboolean Menu_SelectItem( menuframework_s *s )
+{
+	menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
+
+	if ( item )
+	{
+		switch ( item->type )
+		{
+		case MTYPE_FIELD:
+			return Field_DoEnter( ( menufield_s * ) item ) ;
+		case MTYPE_ACTION:
+			Action_DoEnter( ( menuaction_s * ) item );
+			return true;
+		case MTYPE_LIST:
+//			Menulist_DoEnter( ( menulist_s * ) item );
+			return false;
+		case MTYPE_SPINCONTROL:
+//			SpinControl_DoEnter( ( menulist_s * ) item );
+			return false;
+		}
+	}
+	return false;
+}
+
+void Menu_SetStatusBar( menuframework_s *m, const char *string )
+{
+	m->statusbar = string;
+}
+
+void Menu_SlideItem( menuframework_s *s, int dir )
+{
+	menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
+
+	if ( item )
+	{
+		switch ( item->type )
+		{
+		case MTYPE_SLIDER:
+			Slider_DoSlide( ( menuslider_s * ) item, dir );
+			break;
+		case MTYPE_SPINCONTROL:
+			SpinControl_DoSlide( ( menulist_s * ) item, dir );
+			break;
+		}
+	}
+}
+
+int Menu_TallySlots( menuframework_s *menu )
+{
+	int i;
+	int total = 0;
+
+	for ( i = 0; i < menu->nitems; i++ )
+	{
+		if ( ( ( menucommon_s * ) menu->items[i] )->type == MTYPE_LIST )
+		{
+			int nitems = 0;
+			const char **n = ( ( menulist_s * ) menu->items[i] )->itemnames;
+
+			while (*n)
+				nitems++, n++;
+
+			total += nitems;
+		}
+		else
+		{
+			total++;
+		}
+	}
+
+	return total;
+}
+
+void Menulist_DoEnter( menulist_s *l )
+{
+	int start;
+
+	start = l->generic.y / 10 + 1;
+
+	l->curvalue = l->generic.parent->cursor - start;
+
+	if ( l->generic.callback )
+		l->generic.callback( l );
+}
+
+void MenuList_Draw( menulist_s *l )
+{
+	const char **n;
+	int y = 0;
+
+	Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name );
+
+	n = l->itemnames;
+
+  	Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 );
+	while ( *n )
+	{
+		Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n );
+
+		n++;
+		y += 10;
+	}
+}
+
+void Separator_Draw( menuseparator_s *s )
+{
+	if ( s->generic.name )
+		Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name );
+}
+
+void Slider_DoSlide( menuslider_s *s, int dir )
+{
+	s->curvalue += dir;
+
+	if ( s->curvalue > s->maxvalue )
+		s->curvalue = s->maxvalue;
+	else if ( s->curvalue < s->minvalue )
+		s->curvalue = s->minvalue;
+
+	if ( s->generic.callback )
+		s->generic.callback( s );
+}
+
+#define SLIDER_RANGE 10
+
+void Slider_Draw( menuslider_s *s )
+{
+	int	i;
+
+	Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
+		                s->generic.y + s->generic.parent->y, 
+						s->generic.name );
+
+	s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
+
+	if ( s->range < 0)
+		s->range = 0;
+	if ( s->range > 1)
+		s->range = 1;
+	Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128);
+	for ( i = 0; i < SLIDER_RANGE; i++ )
+		Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129);
+	Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130);
+	Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131);
+}
+
+void SpinControl_DoEnter( menulist_s *s )
+{
+	s->curvalue++;
+	if ( s->itemnames[s->curvalue] == 0 )
+		s->curvalue = 0;
+
+	if ( s->generic.callback )
+		s->generic.callback( s );
+}
+
+void SpinControl_DoSlide( menulist_s *s, int dir )
+{
+	s->curvalue += dir;
+
+	if ( s->curvalue < 0 )
+		s->curvalue = 0;
+	else if ( s->itemnames[s->curvalue] == 0 )
+		s->curvalue--;
+
+	if ( s->generic.callback )
+		s->generic.callback( s );
+}
+
+void SpinControl_Draw( menulist_s *s )
+{
+	char buffer[100];
+
+	if ( s->generic.name )
+	{
+		Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET, 
+							s->generic.y + s->generic.parent->y, 
+							s->generic.name );
+	}
+	if ( !strchr( s->itemnames[s->curvalue], '\n' ) )
+	{
+		Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] );
+	}
+	else
+	{
+		strcpy( buffer, s->itemnames[s->curvalue] );
+		*strchr( buffer, '\n' ) = 0;
+		Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer );
+		strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 );
+		Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer );
+	}
+}
+
--- /dev/null
+++ b/client/qmenu.h
@@ -1,0 +1,140 @@
+/*
+Copyright (C) 1997-2001 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 __QMENU_H__
+#define __QMENU_H__
+
+#define MAXMENUITEMS	64
+
+#define MTYPE_SLIDER		0
+#define MTYPE_LIST			1
+#define MTYPE_ACTION		2
+#define MTYPE_SPINCONTROL	3
+#define MTYPE_SEPARATOR  	4
+#define MTYPE_FIELD			5
+
+#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 QMF_LEFT_JUSTIFY	0x00000001
+#define QMF_GRAYED			0x00000002
+#define QMF_NUMBERSONLY		0x00000004
+
+typedef struct _tag_menuframework
+{
+	int x, y;
+	int	cursor;
+
+	int	nitems;
+	int nslots;
+	void *items[64];
+
+	const char *statusbar;
+
+	void (*cursordraw)( struct _tag_menuframework *m );
+	
+} menuframework_s;
+
+typedef struct
+{
+	int type;
+	const char *name;
+	int x, y;
+	menuframework_s *parent;
+	int cursor_offset;
+	int	localdata[4];
+	unsigned flags;
+
+	const char *statusbar;
+
+	void (*callback)( void *self );
+	void (*statusbarfunc)( void *self );
+	void (*ownerdraw)( void *self );
+	void (*cursordraw)( void *self );
+} menucommon_s;
+
+typedef struct
+{
+	menucommon_s generic;
+
+	char		buffer[80];
+	int			cursor;
+	int			length;
+	int			visible_length;
+	int			visible_offset;
+} menufield_s;
+
+typedef struct 
+{
+	menucommon_s generic;
+
+	float minvalue;
+	float maxvalue;
+	float curvalue;
+
+	float range;
+} menuslider_s;
+
+typedef struct
+{
+	menucommon_s generic;
+
+	int curvalue;
+
+	const char **itemnames;
+} menulist_s;
+
+typedef struct
+{
+	menucommon_s generic;
+} menuaction_s;
+
+typedef struct
+{
+	menucommon_s generic;
+} menuseparator_s;
+
+qboolean Field_Key( menufield_s *field, int key );
+
+void	Menu_AddItem( menuframework_s *menu, void *item );
+void	Menu_AdjustCursor( menuframework_s *menu, int dir );
+void	Menu_Center( menuframework_s *menu );
+void	Menu_Draw( menuframework_s *menu );
+void	*Menu_ItemAtCursor( menuframework_s *m );
+qboolean Menu_SelectItem( menuframework_s *s );
+void	Menu_SetStatusBar( menuframework_s *s, const char *string );
+void	Menu_SlideItem( menuframework_s *s, int dir );
+int		Menu_TallySlots( menuframework_s *menu );
+
+void	 Menu_DrawString( int, int, const char * );
+void	 Menu_DrawStringDark( int, int, const char * );
+void	 Menu_DrawStringR2L( int, int, const char * );
+void	 Menu_DrawStringR2LDark( int, int, const char * );
+
+#endif
--- /dev/null
+++ b/client/ref.h
@@ -1,0 +1,224 @@
+/*
+Copyright (C) 1997-2001 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 "../qcommon/qcommon.h"
+
+#define	MAX_DLIGHTS		32
+#define	MAX_ENTITIES	128
+#define	MAX_PARTICLES	4096
+#define	MAX_LIGHTSTYLES	256
+
+#define POWERSUIT_SCALE		4.0F
+
+#define SHELL_RED_COLOR		0xF2
+#define SHELL_GREEN_COLOR	0xD0
+#define SHELL_BLUE_COLOR	0xF3
+
+#define SHELL_RG_COLOR		0xDC
+//#define SHELL_RB_COLOR		0x86
+#define SHELL_RB_COLOR		0x68
+#define SHELL_BG_COLOR		0x78
+
+//ROGUE
+#define SHELL_DOUBLE_COLOR	0xDF // 223
+#define	SHELL_HALF_DAM_COLOR	0x90
+#define SHELL_CYAN_COLOR	0x72
+//ROGUE
+
+#define SHELL_WHITE_COLOR	0xD7
+
+typedef struct entity_s
+{
+	struct model_s		*model;			// opaque type outside refresh
+	float				angles[3];
+
+	/*
+	** most recent data
+	*/
+	float				origin[3];		// also used as RF_BEAM's "from"
+	int					frame;			// also used as RF_BEAM's diameter
+
+	/*
+	** previous data for lerping
+	*/
+	float				oldorigin[3];	// also used as RF_BEAM's "to"
+	int					oldframe;
+
+	/*
+	** misc
+	*/
+	float	backlerp;				// 0.0 = current, 1.0 = old
+	int		skinnum;				// also used as RF_BEAM's palette index
+
+	int		lightstyle;				// for flashing entities
+	float	alpha;					// ignore if RF_TRANSLUCENT isn't set
+
+	struct image_s	*skin;			// NULL for inline skin
+	int		flags;
+
+} entity_t;
+
+#define ENTITY_FLAGS  68
+
+typedef struct
+{
+	vec3_t	origin;
+	vec3_t	color;
+	float	intensity;
+} dlight_t;
+
+typedef struct
+{
+	vec3_t	origin;
+	int		color;
+	float	alpha;
+} particle_t;
+
+typedef struct
+{
+	float		rgb[3];			// 0.0 - 2.0
+	float		white;			// highest of rgb
+} lightstyle_t;
+
+typedef struct
+{
+	int			x, y, width, height;// in virtual screen coordinates
+	float		fov_x, fov_y;
+	float		vieworg[3];
+	float		viewangles[3];
+	float		blend[4];			// rgba 0-1 full screen blend
+	float		time;				// time is uesed to auto animate
+	int			rdflags;			// RDF_UNDERWATER, etc
+
+	byte		*areabits;			// if not NULL, only areas with set bits will be drawn
+
+	lightstyle_t	*lightstyles;	// [MAX_LIGHTSTYLES]
+
+	int			num_entities;
+	entity_t	*entities;
+
+	int			num_dlights;
+	dlight_t	*dlights;
+
+	int			num_particles;
+	particle_t	*particles;
+} refdef_t;
+
+
+
+#define	API_VERSION		3
+
+//
+// these are the functions exported by the refresh module
+//
+typedef struct
+{
+	// if api_version is different, the dll cannot be used
+	int		api_version;
+
+	// called when the library is loaded
+	qboolean	(*Init) ( void *hinstance, void *wndproc );
+
+	// called before the library is unloaded
+	void	(*Shutdown) (void);
+
+	// All data that will be used in a level should be
+	// registered before rendering any frames to prevent disk hits,
+	// but they can still be registered at a later time
+	// if necessary.
+	//
+	// EndRegistration will free any remaining data that wasn't registered.
+	// Any model_s or skin_s pointers from before the BeginRegistration
+	// are no longer valid after EndRegistration.
+	//
+	// Skins and images need to be differentiated, because skins
+	// are flood filled to eliminate mip map edge errors, and pics have
+	// an implicit "pics/" prepended to the name. (a pic name that starts with a
+	// slash will not use the "pics/" prefix or the ".pcx" postfix)
+	void	(*BeginRegistration) (char *map);
+	struct model_s *(*RegisterModel) (char *name);
+	struct image_s *(*RegisterSkin) (char *name);
+	struct image_s *(*RegisterPic) (char *name);
+	void	(*SetSky) (char *name, float rotate, vec3_t axis);
+	void	(*EndRegistration) (void);
+
+	void	(*RenderFrame) (refdef_t *fd);
+
+	void	(*DrawGetPicSize) (int *w, int *h, char *name);	// will return 0 0 if not found
+	void	(*DrawPic) (int x, int y, char *name);
+	void	(*DrawStretchPic) (int x, int y, int w, int h, char *name);
+	void	(*DrawChar) (int x, int y, int c);
+	void	(*DrawTileClear) (int x, int y, int w, int h, char *name);
+	void	(*DrawFill) (int x, int y, int w, int h, int c);
+	void	(*DrawFadeScreen) (void);
+
+	// Draw images for cinematic rendering (which can have a different palette). Note that calls
+	void	(*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data);
+
+	/*
+	** video mode and refresh state management entry points
+	*/
+	void	(*CinematicSetPalette)( const unsigned char *palette);	// NULL = game palette
+	void	(*BeginFrame)( float camera_separation );
+	void	(*EndFrame) (void);
+
+	void	(*AppActivate)( qboolean activate );
+
+} refexport_t;
+
+//
+// these are the functions imported by the refresh module
+//
+typedef struct
+{
+	void	(*Sys_Error) (int err_level, char *str, ...);
+
+	void	(*Cmd_AddCommand) (char *name, void(*cmd)(void));
+	void	(*Cmd_RemoveCommand) (char *name);
+	int		(*Cmd_Argc) (void);
+	char	*(*Cmd_Argv) (int i);
+	void	(*Cmd_ExecuteText) (int exec_when, char *text);
+
+	void	(*Con_Printf) (int print_level, char *str, ...);
+
+	// files will be memory mapped read only
+	// the returned buffer may be part of a larger pak file,
+	// or a discrete file from anywhere in the quake search path
+	// a -1 return means the file does not exist
+	// NULL can be passed for buf to just determine existance
+	int		(*FS_LoadFile) (char *name, void **buf);
+	void	(*FS_FreeFile) (void *buf);
+
+	// gamedir will be the current directory that generated
+	// files should be stored to, ie: "f:\quake\id1"
+	char	*(*FS_Gamedir) (void);
+
+	cvar_t	*(*Cvar_Get) (char *name, char *value, int flags);
+	cvar_t	*(*Cvar_Set)( char *name, char *value );
+	void	 (*Cvar_SetValue)( char *name, float value );
+
+	qboolean	(*Vid_GetModeInfo)( int *width, int *height, int mode );
+	void		(*Vid_MenuInit)( void );
+	void		(*Vid_NewWindow)( int width, int height );
+} refimport_t;
+
+
+// this is the only function actually exported at the linker level
+typedef	refexport_t	(*GetRefAPI_t) (refimport_t);
--- /dev/null
+++ b/client/screen.h
@@ -1,0 +1,62 @@
+/*
+Copyright (C) 1997-2001 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_CenterPrint (char *str);
+void	SCR_BeginLoadingPlaque (void);
+void	SCR_EndLoadingPlaque (void);
+
+void	SCR_DebugGraph (float value, int color);
+
+void	SCR_TouchPics (void);
+
+void	SCR_RunConsole (void);
+
+extern	float		scr_con_current;
+extern	float		scr_conlines;		// lines of console to display
+
+extern	int			sb_lines;
+
+extern	cvar_t		*scr_viewsize;
+extern	cvar_t		*crosshair;
+
+extern	vrect_t		scr_vrect;		// position of render window
+
+extern	char		crosshair_pic[MAX_QPATH];
+extern	int			crosshair_width, crosshair_height;
+
+void SCR_AddDirtyPoint (int x, int y);
+void SCR_DirtyScreen (void);
+
+//
+// scr_cin.c
+//
+void SCR_PlayCinematic (char *name);
+qboolean SCR_DrawCinematic (void);
+void SCR_RunCinematic (void);
+void SCR_StopCinematic (void);
+void SCR_FinishCinematic (void);
+
--- /dev/null
+++ b/client/snd_dma.c
@@ -1,0 +1,1214 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+#include "snd_loc.h"
+
+void S_Play(void);
+void S_SoundList(void);
+void S_Update_();
+void S_StopAllSounds(void);
+
+
+// =======================================================================
+// Internal sound data & structures
+// =======================================================================
+
+// only begin attenuating sound volumes when outside the FULLVOLUME range
+#define		SOUND_FULLVOLUME	80
+
+#define		SOUND_LOOPATTENUATE	0.003
+
+int			s_registration_sequence;
+
+channel_t   channels[MAX_CHANNELS];
+
+qboolean	snd_initialized = false;
+int			sound_started=0;
+
+dma_t		dma;
+
+vec3_t		listener_origin;
+vec3_t		listener_forward;
+vec3_t		listener_right;
+vec3_t		listener_up;
+
+qboolean	s_registering;
+
+int			soundtime;		// sample PAIRS
+int   		paintedtime; 	// sample PAIRS
+
+// during registration it is possible to have more sounds
+// than could actually be referenced during gameplay,
+// because we don't want to free anything until we are
+// sure we won't need it.
+#define		MAX_SFX		(MAX_SOUNDS*2)
+sfx_t		known_sfx[MAX_SFX];
+int			num_sfx;
+
+#define		MAX_PLAYSOUNDS	128
+playsound_t	s_playsounds[MAX_PLAYSOUNDS];
+playsound_t	s_freeplays;
+playsound_t	s_pendingplays;
+
+int			s_beginofs;
+
+cvar_t		*s_volume;
+cvar_t		*s_testsound;
+cvar_t		*s_loadas8bit;
+cvar_t		*s_khz;
+cvar_t		*s_show;
+cvar_t		*s_mixahead;
+cvar_t		*s_primary;
+
+
+int		s_rawend;
+portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];
+
+
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+
+void S_SoundInfo_f(void)
+{
+	if (!sound_started)
+	{
+		Com_Printf ("sound system not started\n");
+		return;
+	}
+	
+    Com_Printf("%5d stereo\n", dma.channels - 1);
+    Com_Printf("%5d samples\n", dma.samples);
+    Com_Printf("%5d samplepos\n", dma.samplepos);
+    Com_Printf("%5d samplebits\n", dma.samplebits);
+    Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
+    Com_Printf("%5d speed\n", dma.speed);
+    Com_Printf("0x%x dma buffer\n", dma.buffer);
+}
+
+
+
+/*
+================
+S_Init
+================
+*/
+void S_Init (void)
+{
+	cvar_t	*cv;
+
+	Com_Printf("\n------- sound initialization -------\n");
+
+	cv = Cvar_Get ("s_initsound", "1", 0);
+	if (!cv->value)
+		Com_Printf ("not initializing.\n");
+	else
+	{
+		s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
+		s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
+		s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
+		s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
+		s_show = Cvar_Get ("s_show", "0", 0);
+		s_testsound = Cvar_Get ("s_testsound", "0", 0);
+		s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE);	// win32 specific
+
+		Cmd_AddCommand("play", S_Play);
+		Cmd_AddCommand("stopsound", S_StopAllSounds);
+		Cmd_AddCommand("soundlist", S_SoundList);
+		Cmd_AddCommand("soundinfo", S_SoundInfo_f);
+
+		if (!SNDDMA_Init())
+			return;
+
+		S_InitScaletable ();
+
+		sound_started = 1;
+		num_sfx = 0;
+
+		soundtime = 0;
+		paintedtime = 0;
+
+		Com_Printf ("sound sampling rate: %i\n", dma.speed);
+
+		S_StopAllSounds ();
+	}
+
+	Com_Printf("------------------------------------\n");
+}
+
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+void S_Shutdown(void)
+{
+	int		i;
+	sfx_t	*sfx;
+
+	if (!sound_started)
+		return;
+
+	SNDDMA_Shutdown();
+
+	sound_started = 0;
+
+	Cmd_RemoveCommand("play");
+	Cmd_RemoveCommand("stopsound");
+	Cmd_RemoveCommand("soundlist");
+	Cmd_RemoveCommand("soundinfo");
+
+	// free all sounds
+	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+	{
+		if (!sfx->name[0])
+			continue;
+		if (sfx->cache)
+			Z_Free (sfx->cache);
+		memset (sfx, 0, sizeof(*sfx));
+	}
+
+	num_sfx = 0;
+}
+
+
+// =======================================================================
+// Load a sound
+// =======================================================================
+
+/*
+==================
+S_FindName
+
+==================
+*/
+sfx_t *S_FindName (char *name, qboolean create)
+{
+	int		i;
+	sfx_t	*sfx;
+
+	if (!name)
+		Com_Error (ERR_FATAL, "S_FindName: NULL\n");
+	if (!name[0])
+		Com_Error (ERR_FATAL, "S_FindName: empty name\n");
+
+	if (strlen(name) >= MAX_QPATH)
+		Com_Error (ERR_FATAL, "Sound name too long: %s", name);
+
+	// see if already loaded
+	for (i=0 ; i < num_sfx ; i++)
+		if (!strcmp(known_sfx[i].name, name))
+		{
+			return &known_sfx[i];
+		}
+
+	if (!create)
+		return NULL;
+
+	// find a free sfx
+	for (i=0 ; i < num_sfx ; i++)
+		if (!known_sfx[i].name[0])
+//			registration_sequence < s_registration_sequence)
+			break;
+
+	if (i == num_sfx)
+	{
+		if (num_sfx == MAX_SFX)
+			Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
+		num_sfx++;
+	}
+	
+	sfx = &known_sfx[i];
+	memset (sfx, 0, sizeof(*sfx));
+	strcpy (sfx->name, name);
+	sfx->registration_sequence = s_registration_sequence;
+	
+	return sfx;
+}
+
+
+/*
+==================
+S_AliasName
+
+==================
+*/
+sfx_t *S_AliasName (char *aliasname, char *truename)
+{
+	sfx_t	*sfx;
+	char	*s;
+	int		i;
+
+	s = Z_Malloc (MAX_QPATH);
+	strcpy (s, truename);
+
+	// find a free sfx
+	for (i=0 ; i < num_sfx ; i++)
+		if (!known_sfx[i].name[0])
+			break;
+
+	if (i == num_sfx)
+	{
+		if (num_sfx == MAX_SFX)
+			Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
+		num_sfx++;
+	}
+	
+	sfx = &known_sfx[i];
+	memset (sfx, 0, sizeof(*sfx));
+	strcpy (sfx->name, aliasname);
+	sfx->registration_sequence = s_registration_sequence;
+	sfx->truename = s;
+
+	return sfx;
+}
+
+
+/*
+=====================
+S_BeginRegistration
+
+=====================
+*/
+void S_BeginRegistration (void)
+{
+	s_registration_sequence++;
+	s_registering = true;
+}
+
+/*
+==================
+S_RegisterSound
+
+==================
+*/
+sfx_t *S_RegisterSound (char *name)
+{
+	sfx_t	*sfx;
+
+	if (!sound_started)
+		return NULL;
+
+	sfx = S_FindName (name, true);
+	sfx->registration_sequence = s_registration_sequence;
+
+	if (!s_registering)
+		S_LoadSound (sfx);
+
+	return sfx;
+}
+
+
+/*
+=====================
+S_EndRegistration
+
+=====================
+*/
+void S_EndRegistration (void)
+{
+	int		i;
+	sfx_t	*sfx;
+	int		size;
+
+	// free any sounds not from this registration sequence
+	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+	{
+		if (!sfx->name[0])
+			continue;
+		if (sfx->registration_sequence != s_registration_sequence)
+		{	// don't need this sound
+			if (sfx->cache)	// it is possible to have a leftover
+				Z_Free (sfx->cache);	// from a server that didn't finish loading
+			memset (sfx, 0, sizeof(*sfx));
+		}
+		else
+		{	// make sure it is paged in
+			if (sfx->cache)
+			{
+				size = sfx->cache->length*sfx->cache->width;
+				Com_PageInMemory ((byte *)sfx->cache, size);
+			}
+		}
+
+	}
+
+	// load everything in
+	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+	{
+		if (!sfx->name[0])
+			continue;
+		S_LoadSound (sfx);
+	}
+
+	s_registering = false;
+}
+
+
+//=============================================================================
+
+/*
+=================
+S_PickChannel
+=================
+*/
+channel_t *S_PickChannel(int entnum, int entchannel)
+{
+    int			ch_idx;
+    int			first_to_die;
+    int			life_left;
+	channel_t	*ch;
+
+	if (entchannel<0)
+		Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
+
+// Check for replacement sound, or find the best one to replace
+    first_to_die = -1;
+    life_left = 0x7fffffff;
+    for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
+    {
+		if (entchannel != 0		// channel 0 never overrides
+		&& channels[ch_idx].entnum == entnum
+		&& channels[ch_idx].entchannel == entchannel)
+		{	// always 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.playernum+1 && entnum != cl.playernum+1 && 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;
+
+	ch = &channels[first_to_die];
+	memset (ch, 0, sizeof(*ch));
+
+    return ch;
+}       
+
+/*
+=================
+S_SpatializeOrigin
+
+Used for spatializing channels and autosounds
+=================
+*/
+void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
+{
+    vec_t		dot;
+    vec_t		dist;
+    vec_t		lscale, rscale, scale;
+    vec3_t		source_vec;
+
+	if (cls.state != ca_active)
+	{
+		*left_vol = *right_vol = 255;
+		return;
+	}
+
+// calculate stereo seperation and distance attenuation
+	VectorSubtract(origin, listener_origin, source_vec);
+
+	dist = VectorNormalize(source_vec);
+	dist -= SOUND_FULLVOLUME;
+	if (dist < 0)
+		dist = 0;			// close enough to be at full volume
+	dist *= dist_mult;		// different attenuation levels
+	
+	dot = DotProduct(listener_right, source_vec);
+
+	if (dma.channels == 1 || !dist_mult)
+	{ // no attenuation = no spatialization
+		rscale = 1.0;
+		lscale = 1.0;
+	}
+	else
+	{
+		rscale = 0.5 * (1.0 + dot);
+		lscale = 0.5*(1.0 - dot);
+	}
+
+	// add in distance effect
+	scale = (1.0 - dist) * rscale;
+	*right_vol = (int) (master_vol * scale);
+	if (*right_vol < 0)
+		*right_vol = 0;
+
+	scale = (1.0 - dist) * lscale;
+	*left_vol = (int) (master_vol * scale);
+	if (*left_vol < 0)
+		*left_vol = 0;
+}
+
+/*
+=================
+S_Spatialize
+=================
+*/
+void S_Spatialize(channel_t *ch)
+{
+	vec3_t		origin;
+
+	// anything coming from the view entity will always be full volume
+	if (ch->entnum == cl.playernum+1)
+	{
+		ch->leftvol = ch->master_vol;
+		ch->rightvol = ch->master_vol;
+		return;
+	}
+
+	if (ch->fixed_origin)
+	{
+		VectorCopy (ch->origin, origin);
+	}
+	else
+		CL_GetEntitySoundOrigin (ch->entnum, origin);
+
+	S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
+}           
+
+
+/*
+=================
+S_AllocPlaysound
+=================
+*/
+playsound_t *S_AllocPlaysound (void)
+{
+	playsound_t	*ps;
+
+	ps = s_freeplays.next;
+	if (ps == &s_freeplays)
+		return NULL;		// no free playsounds
+
+	// unlink from freelist
+	ps->prev->next = ps->next;
+	ps->next->prev = ps->prev;
+	
+	return ps;
+}
+
+
+/*
+=================
+S_FreePlaysound
+=================
+*/
+void S_FreePlaysound (playsound_t *ps)
+{
+	// unlink from channel
+	ps->prev->next = ps->next;
+	ps->next->prev = ps->prev;
+
+	// add to free list
+	ps->next = s_freeplays.next;
+	s_freeplays.next->prev = ps;
+	ps->prev = &s_freeplays;
+	s_freeplays.next = ps;
+}
+
+
+
+/*
+===============
+S_IssuePlaysound
+
+Take the next playsound and begin it on the channel
+This is never called directly by S_Play*, but only
+by the update loop.
+===============
+*/
+void S_IssuePlaysound (playsound_t *ps)
+{
+	channel_t	*ch;
+	sfxcache_t	*sc;
+
+	if (s_show->value)
+		Com_Printf ("Issue %i\n", ps->begin);
+	// pick a channel to play on
+	ch = S_PickChannel(ps->entnum, ps->entchannel);
+	if (!ch)
+	{
+		S_FreePlaysound (ps);
+		return;
+	}
+
+	// spatialize
+	if (ps->attenuation == ATTN_STATIC)
+		ch->dist_mult = ps->attenuation * 0.001;
+	else
+		ch->dist_mult = ps->attenuation * 0.0005;
+	ch->master_vol = ps->volume;
+	ch->entnum = ps->entnum;
+	ch->entchannel = ps->entchannel;
+	ch->sfx = ps->sfx;
+	VectorCopy (ps->origin, ch->origin);
+	ch->fixed_origin = ps->fixed_origin;
+
+	S_Spatialize(ch);
+
+	ch->pos = 0;
+	sc = S_LoadSound (ch->sfx);
+    ch->end = paintedtime + sc->length;
+
+	// free the playsound
+	S_FreePlaysound (ps);
+}
+
+struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
+{
+	int				n;
+	char			*p;
+	struct sfx_s	*sfx;
+	FILE			*f;
+	char			model[MAX_QPATH];
+	char			sexedFilename[MAX_QPATH];
+	char			maleFilename[MAX_QPATH];
+
+	// determine what model the client is using
+	model[0] = 0;
+	n = CS_PLAYERSKINS + ent->number - 1;
+	if (cl.configstrings[n][0])
+	{
+		p = strchr(cl.configstrings[n], '\\');
+		if (p)
+		{
+			p += 1;
+			strcpy(model, p);
+			p = strchr(model, '/');
+			if (p)
+				*p = 0;
+		}
+	}
+	// if we can't figure it out, they're male
+	if (!model[0])
+		strcpy(model, "male");
+
+	// see if we already know of the model specific sound
+	Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
+	sfx = S_FindName (sexedFilename, false);
+
+	if (!sfx)
+	{
+		// no, so see if it exists
+		FS_FOpenFile (&sexedFilename[1], &f);
+		if (f)
+		{
+			// yes, close the file and register it
+			FS_FCloseFile (f);
+			sfx = S_RegisterSound (sexedFilename);
+		}
+		else
+		{
+			// no, revert to the male sound in the pak0.pak
+			Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
+			sfx = S_AliasName (sexedFilename, maleFilename);
+		}
+	}
+
+	return sfx;
+}
+
+
+// =======================================================================
+// Start a sound effect
+// =======================================================================
+
+/*
+====================
+S_StartSound
+
+Validates the parms and ques the sound up
+if pos is NULL, the sound will be dynamically sourced from the entity
+Entchannel 0 will never override a playing sound
+====================
+*/
+void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
+{
+	sfxcache_t	*sc;
+	int			vol;
+	playsound_t	*ps, *sort;
+	int			start;
+
+	if (!sound_started)
+		return;
+
+	if (!sfx)
+		return;
+
+	if (sfx->name[0] == '*')
+		sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
+
+	// make sure the sound is loaded
+	sc = S_LoadSound (sfx);
+	if (!sc)
+		return;		// couldn't load the sound's data
+
+	vol = fvol*255;
+
+	// make the playsound_t
+	ps = S_AllocPlaysound ();
+	if (!ps)
+		return;
+
+	if (origin)
+	{
+		VectorCopy (origin, ps->origin);
+		ps->fixed_origin = true;
+	}
+	else
+		ps->fixed_origin = false;
+
+	ps->entnum = entnum;
+	ps->entchannel = entchannel;
+	ps->attenuation = attenuation;
+	ps->volume = vol;
+	ps->sfx = sfx;
+
+	// drift s_beginofs
+	start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
+	if (start < paintedtime)
+	{
+		start = paintedtime;
+		s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
+	}
+	else if (start > paintedtime + 0.3 * dma.speed)
+	{
+		start = paintedtime + 0.1 * dma.speed;
+		s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
+	}
+	else
+	{
+		s_beginofs-=10;
+	}
+
+	if (!timeofs)
+		ps->begin = paintedtime;
+	else
+		ps->begin = start + timeofs * dma.speed;
+
+	// sort into the pending sound list
+	for (sort = s_pendingplays.next ; 
+		sort != &s_pendingplays && sort->begin < ps->begin ;
+		sort = sort->next)
+			;
+
+	ps->next = sort;
+	ps->prev = sort->prev;
+
+	ps->next->prev = ps;
+	ps->prev->next = ps;
+}
+
+
+/*
+==================
+S_StartLocalSound
+==================
+*/
+void S_StartLocalSound (char *sound)
+{
+	sfx_t	*sfx;
+
+	if (!sound_started)
+		return;
+		
+	sfx = S_RegisterSound (sound);
+	if (!sfx)
+	{
+		Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
+		return;
+	}
+	S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
+}
+
+
+/*
+==================
+S_ClearBuffer
+==================
+*/
+void S_ClearBuffer (void)
+{
+	int		clear;
+		
+	if (!sound_started)
+		return;
+
+	s_rawend = 0;
+
+	if (dma.samplebits == 8)
+		clear = 0x80;
+	else
+		clear = 0;
+
+	SNDDMA_BeginPainting ();
+	if (dma.buffer)
+		memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
+	SNDDMA_Submit ();
+}
+
+/*
+==================
+S_StopAllSounds
+==================
+*/
+void S_StopAllSounds(void)
+{
+	int		i;
+
+	if (!sound_started)
+		return;
+
+	// clear all the playsounds
+	memset(s_playsounds, 0, sizeof(s_playsounds));
+	s_freeplays.next = s_freeplays.prev = &s_freeplays;
+	s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
+
+	for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
+	{
+		s_playsounds[i].prev = &s_freeplays;
+		s_playsounds[i].next = s_freeplays.next;
+		s_playsounds[i].prev->next = &s_playsounds[i];
+		s_playsounds[i].next->prev = &s_playsounds[i];
+	}
+
+	// clear all the channels
+	memset(channels, 0, sizeof(channels));
+
+	S_ClearBuffer ();
+}
+
+/*
+==================
+S_AddLoopSounds
+
+Entities with a ->sound field will generated looped sounds
+that are automatically started, stopped, and merged together
+as the entities are sent to the client
+==================
+*/
+void S_AddLoopSounds (void)
+{
+	int			i, j;
+	int			sounds[MAX_EDICTS];
+	int			left, right, left_total, right_total;
+	channel_t	*ch;
+	sfx_t		*sfx;
+	sfxcache_t	*sc;
+	int			num;
+	entity_state_t	*ent;
+
+	if (cl_paused->value)
+		return;
+
+	if (cls.state != ca_active)
+		return;
+
+	if (!cl.sound_prepped)
+		return;
+
+	for (i=0 ; i<cl.frame.num_entities ; i++)
+	{
+		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+		ent = &cl_parse_entities[num];
+		sounds[i] = ent->sound;
+	}
+
+	for (i=0 ; i<cl.frame.num_entities ; i++)
+	{
+		if (!sounds[i])
+			continue;
+
+		sfx = cl.sound_precache[sounds[i]];
+		if (!sfx)
+			continue;		// bad sound effect
+		sc = sfx->cache;
+		if (!sc)
+			continue;
+
+		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+		ent = &cl_parse_entities[num];
+
+		// find the total contribution of all sounds of this type
+		S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
+			&left_total, &right_total);
+		for (j=i+1 ; j<cl.frame.num_entities ; j++)
+		{
+			if (sounds[j] != sounds[i])
+				continue;
+			sounds[j] = 0;	// don't check this again later
+
+			num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
+			ent = &cl_parse_entities[num];
+
+			S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE, 
+				&left, &right);
+			left_total += left;
+			right_total += right;
+		}
+
+		if (left_total == 0 && right_total == 0)
+			continue;		// not audible
+
+		// allocate a channel
+		ch = S_PickChannel(0, 0);
+		if (!ch)
+			return;
+
+		if (left_total > 255)
+			left_total = 255;
+		if (right_total > 255)
+			right_total = 255;
+		ch->leftvol = left_total;
+		ch->rightvol = right_total;
+		ch->autosound = true;	// remove next frame
+		ch->sfx = sfx;
+		ch->pos = paintedtime % sc->length;
+		ch->end = paintedtime + sc->length - ch->pos;
+	}
+}
+
+//=============================================================================
+
+/*
+============
+S_RawSamples
+
+Cinematic streaming and voice over network
+============
+*/
+void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
+{
+	int		i;
+	int		src, dst;
+	float	scale;
+
+	if (!sound_started)
+		return;
+
+	if (s_rawend < paintedtime)
+		s_rawend = paintedtime;
+	scale = (float)rate / dma.speed;
+
+//Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
+	if (channels == 2 && width == 2)
+	{
+		if (scale == 1.0)
+		{	// optimized case
+			for (i=0 ; i<samples ; i++)
+			{
+				dst = s_rawend&(MAX_RAW_SAMPLES-1);
+				s_rawend++;
+				s_rawsamples[dst].left =
+				    LittleShort(((short *)data)[i*2]) << 8;
+				s_rawsamples[dst].right =
+				    LittleShort(((short *)data)[i*2+1]) << 8;
+			}
+		}
+		else
+		{
+			for (i=0 ; ; i++)
+			{
+				src = i*scale;
+				if (src >= samples)
+					break;
+				dst = s_rawend&(MAX_RAW_SAMPLES-1);
+				s_rawend++;
+				s_rawsamples[dst].left =
+				    LittleShort(((short *)data)[src*2]) << 8;
+				s_rawsamples[dst].right =
+				    LittleShort(((short *)data)[src*2+1]) << 8;
+			}
+		}
+	}
+	else if (channels == 1 && width == 2)
+	{
+		for (i=0 ; ; i++)
+		{
+			src = i*scale;
+			if (src >= samples)
+				break;
+			dst = s_rawend&(MAX_RAW_SAMPLES-1);
+			s_rawend++;
+			s_rawsamples[dst].left =
+			    LittleShort(((short *)data)[src]) << 8;
+			s_rawsamples[dst].right =
+			    LittleShort(((short *)data)[src]) << 8;
+		}
+	}
+	else if (channels == 2 && width == 1)
+	{
+		for (i=0 ; ; i++)
+		{
+			src = i*scale;
+			if (src >= samples)
+				break;
+			dst = s_rawend&(MAX_RAW_SAMPLES-1);
+			s_rawend++;
+			s_rawsamples[dst].left =
+			    ((char *)data)[src*2] << 16;
+			s_rawsamples[dst].right =
+			    ((char *)data)[src*2+1] << 16;
+		}
+	}
+	else if (channels == 1 && width == 1)
+	{
+		for (i=0 ; ; i++)
+		{
+			src = i*scale;
+			if (src >= samples)
+				break;
+			dst = s_rawend&(MAX_RAW_SAMPLES-1);
+			s_rawend++;
+			s_rawsamples[dst].left =
+			    (((byte *)data)[src]-128) << 16;
+			s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
+		}
+	}
+}
+
+//=============================================================================
+
+/*
+============
+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;
+	int			total;
+	channel_t	*ch;
+	channel_t	*combine;
+
+	if (!sound_started)
+		return;
+
+	// if the laoding plaque is up, clear everything
+	// out to make sure we aren't looping a dirty
+	// dma buffer while loading
+	if (cls.disable_screen)
+	{
+		S_ClearBuffer ();
+		return;
+	}
+
+	// rebuild scale tables if volume is modified
+	if (s_volume->modified)
+		S_InitScaletable ();
+
+	VectorCopy(origin, listener_origin);
+	VectorCopy(forward, listener_forward);
+	VectorCopy(right, listener_right);
+	VectorCopy(up, listener_up);
+
+	combine = NULL;
+
+	// update spatialization for dynamic sounds	
+	ch = channels;
+	for (i=0 ; i<MAX_CHANNELS; i++, ch++)
+	{
+		if (!ch->sfx)
+			continue;
+		if (ch->autosound)
+		{	// autosounds are regenerated fresh each frame
+			memset (ch, 0, sizeof(*ch));
+			continue;
+		}
+		S_Spatialize(ch);         // respatialize channel
+		if (!ch->leftvol && !ch->rightvol)
+		{
+			memset (ch, 0, sizeof(*ch));
+			continue;
+		}
+	}
+
+	// add loopsounds
+	S_AddLoopSounds ();
+
+	//
+	// debugging output
+	//
+	if (s_show->value)
+	{
+		total = 0;
+		ch = channels;
+		for (i=0 ; i<MAX_CHANNELS; i++, ch++)
+			if (ch->sfx && (ch->leftvol || ch->rightvol) )
+			{
+				Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
+				total++;
+			}
+		
+		Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
+	}
+
+// mix some sound
+	S_Update_();
+}
+
+void GetSoundtime(void)
+{
+	int		samplepos;
+	static	int		buffers;
+	static	int		oldsamplepos;
+	int		fullsamples;
+	
+	fullsamples = dma.samples / dma.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 ();
+		}
+	}
+	oldsamplepos = samplepos;
+
+	soundtime = buffers*fullsamples + samplepos/dma.channels;
+}
+
+
+void S_Update_(void)
+{
+	unsigned        endtime;
+	int				samps;
+
+	if (!sound_started)
+		return;
+
+	SNDDMA_BeginPainting ();
+
+	if (!dma.buffer)
+		return;
+
+// Updates DMA time
+	GetSoundtime();
+
+// check to make sure that we haven't overshot
+	if (paintedtime < soundtime)
+	{
+		Com_DPrintf ("S_Update_ : overflow\n");
+		paintedtime = soundtime;
+	}
+
+// mix ahead of current position
+	endtime = soundtime + s_mixahead->value * dma.speed;
+//endtime = (soundtime + 4096) & ~4095;
+
+	// mix to an even submission block size
+	endtime = (endtime + dma.submission_chunk-1)
+		& ~(dma.submission_chunk-1);
+	samps = dma.samples >> (dma.channels-1);
+	if (endtime - soundtime > samps)
+		endtime = soundtime + samps;
+
+	S_PaintChannels (endtime);
+
+	SNDDMA_Submit ();
+}
+
+/*
+===============================================================================
+
+console functions
+
+===============================================================================
+*/
+
+void S_Play(void)
+{
+	int 	i;
+	char name[256];
+	sfx_t	*sfx;
+	
+	i = 1;
+	while (i<Cmd_Argc())
+	{
+		if (!strrchr(Cmd_Argv(i), '.'))
+		{
+			strcpy(name, Cmd_Argv(i));
+			strcat(name, ".wav");
+		}
+		else
+			strcpy(name, Cmd_Argv(i));
+		sfx = S_RegisterSound(name);
+		S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
+		i++;
+	}
+}
+
+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++)
+	{
+		if (!sfx->registration_sequence)
+			continue;
+		sc = sfx->cache;
+		if (sc)
+		{
+			size = sc->length*sc->width*(sc->stereo+1);
+			total += size;
+			if (sc->loopstart >= 0)
+				Com_Printf ("L");
+			else
+				Com_Printf (" ");
+			Com_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
+		}
+		else
+		{
+			if (sfx->name[0] == '*')
+				Com_Printf("  placeholder : %s\n", sfx->name);
+			else
+				Com_Printf("  not loaded  : %s\n", sfx->name);
+		}
+	}
+	Com_Printf ("Total resident: %i\n", total);
+}
+
--- /dev/null
+++ b/client/snd_loc.h
@@ -1,0 +1,164 @@
+/*
+Copyright (C) 1997-2001 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_loc.h -- private sound functions
+
+// !!! if this is changed, the asm code must change !!!
+typedef struct
+{
+	int			left;
+	int			right;
+} portable_samplepair_t;
+
+typedef struct
+{
+	int 		length;
+	int 		loopstart;
+	int 		speed;			// not needed, because converted on load?
+	int 		width;
+	int 		stereo;
+	byte		data[1];		// variable sized
+} sfxcache_t;
+
+typedef struct sfx_s
+{
+	char 		name[MAX_QPATH];
+	int			registration_sequence;
+	sfxcache_t	*cache;
+	char 		*truename;
+} sfx_t;
+
+// a playsound_t will be generated by each call to S_StartSound,
+// when the mixer reaches playsound->begin, the playsound will
+// be assigned to a channel
+typedef struct playsound_s
+{
+	struct playsound_s	*prev, *next;
+	sfx_t		*sfx;
+	float		volume;
+	float		attenuation;
+	int			entnum;
+	int			entchannel;
+	qboolean	fixed_origin;	// use origin field instead of entnum's origin
+	vec3_t		origin;
+	unsigned	begin;			// begin on this sample
+} playsound_t;
+
+typedef struct
+{
+	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;
+	byte		*buffer;
+} dma_t;
+
+// !!! if this is changed, the asm code must change !!!
+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 OBSOLETE?
+	int			entnum;			// to allow overriding a specific sound
+	int			entchannel;		//
+	vec3_t		origin;			// only use if fixed_origin is set
+	vec_t		dist_mult;		// distance multiplier (attenuation/clipK)
+	int			master_vol;		// 0-255 master volume
+	qboolean	fixed_origin;	// use origin instead of fetching entnum's origin
+	qboolean	autosound;		// from an entity->sound, cleared each frame
+} 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;
+
+
+/*
+====================================================================
+
+  SYSTEM SPECIFIC FUNCTIONS
+
+====================================================================
+*/
+
+// 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);
+
+void	SNDDMA_BeginPainting (void);
+
+void	SNDDMA_Submit(void);
+
+//====================================================================
+
+#define	MAX_CHANNELS			32
+extern	channel_t   channels[MAX_CHANNELS];
+
+extern	int		paintedtime;
+extern	int		s_rawend;
+extern	vec3_t	listener_origin;
+extern	vec3_t	listener_forward;
+extern	vec3_t	listener_right;
+extern	vec3_t	listener_up;
+extern	dma_t	dma;
+extern	playsound_t	s_pendingplays;
+
+#define	MAX_RAW_SAMPLES	8192
+extern	portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];
+
+extern cvar_t	*s_volume;
+extern cvar_t	*s_nosound;
+extern cvar_t	*s_loadas8bit;
+extern cvar_t	*s_khz;
+extern cvar_t	*s_show;
+extern cvar_t	*s_mixahead;
+extern cvar_t	*s_testsound;
+extern cvar_t	*s_primary;
+
+wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
+
+void S_InitScaletable (void);
+
+sfxcache_t *S_LoadSound (sfx_t *s);
+
+void S_IssuePlaysound (playsound_t *ps);
+
+void S_PaintChannels(int endtime);
+
+// picks a channel based on priorities, empty slots, number of channels
+channel_t *S_PickChannel(int entnum, int entchannel);
+
+// spatializes a channel
+void S_Spatialize(channel_t *ch);
--- /dev/null
+++ b/client/snd_mem.c
@@ -1,0 +1,359 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+#include "snd_loc.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 = sfx->cache;
+	if (!sc)
+		return;
+
+	stepscale = (float)inrate / dma.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 = dma.speed;
+	if (s_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[MAX_QPATH];
+	byte	*data;
+	wavinfo_t	info;
+	int		len;
+	float	stepscale;
+	sfxcache_t	*sc;
+	int		size;
+	char	*name;
+
+	if (s->name[0] == '*')
+		return NULL;
+
+// see if still in memory
+	sc = s->cache;
+	if (sc)
+		return sc;
+
+//Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
+// load it in
+	if (s->truename)
+		name = s->truename;
+	else
+		name = s->name;
+
+	if (name[0] == '#')
+		strcpy(namebuffer, &name[1]);
+	else
+		Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
+
+//	Com_Printf ("loading %s\n",namebuffer);
+
+	size = FS_LoadFile (namebuffer, (void **)&data);
+
+	if (!data)
+	{
+		Com_DPrintf ("Couldn't load %s\n", namebuffer);
+		return NULL;
+	}
+
+	info = GetWavinfo (s->name, data, size);
+	if (info.channels != 1)
+	{
+		Com_Printf ("%s is a stereo sample\n",s->name);
+		FS_FreeFile (data);
+		return NULL;
+	}
+
+	stepscale = (float)info.rate / dma.speed;	
+	len = info.samples / stepscale;
+
+	len = len * info.width * info.channels;
+
+	sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
+	if (!sc)
+	{
+		FS_FreeFile (data);
+		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);
+
+	FS_FreeFile (data);
+
+	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 (!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();
+		Com_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 && !strncmp(data_p+8, "WAVE", 4)))
+	{
+		Com_Printf("Missing RIFF/WAVE chunks\n");
+		return info;
+	}
+
+// get "fmt " chunk
+	iff_data = data_p + 12;
+// DumpChunks ();
+
+	FindChunk("fmt ");
+	if (!data_p)
+	{
+		Com_Printf("Missing fmt chunk\n");
+		return info;
+	}
+	data_p += 8;
+	format = GetLittleShort();
+	if (format != 1)
+	{
+		Com_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();
+//		Com_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;
+//				Com_Printf("looped length: %i\n", i);
+			}
+		}
+	}
+	else
+		info.loopstart = -1;
+
+// find data chunk
+	FindChunk("data");
+	if (!data_p)
+	{
+		Com_Printf("Missing data chunk\n");
+		return info;
+	}
+
+	data_p += 4;
+	samples = GetLittleLong () / info.width;
+
+	if (info.samples)
+	{
+		if (samples < info.samples)
+			Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
+	}
+	else
+		info.samples = samples;
+
+	info.dataofs = data_p - wav;
+	
+	return info;
+}
+
--- /dev/null
+++ b/client/snd_mix.c
@@ -1,0 +1,497 @@
+/*
+Copyright (C) 1997-2001 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 "client.h"
+#include "snd_loc.h"
+
+#define	PAINTBUFFER_SIZE	2048
+portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+int		snd_scaletable[32][256];
+int 	*snd_p, snd_linear_count, snd_vol;
+short	*snd_out;
+
+void S_WriteLinearBlastStereo16 (void);
+
+#if !(defined __linux__ && defined __i386__)
+#if	!id386
+
+void S_WriteLinearBlastStereo16 (void)
+{
+	int		i;
+	int		val;
+
+	for (i=0 ; i<snd_linear_count ; i+=2)
+	{
+		val = snd_p[i]>>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]>>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;
+	}
+}
+#else
+__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
+{
+	__asm {
+
+ push edi
+ push ebx
+ mov ecx,ds:dword ptr[snd_linear_count]
+ mov ebx,ds:dword ptr[snd_p]
+ mov edi,ds:dword ptr[snd_out]
+LWLBLoopTop:
+ mov eax,ds:dword ptr[-8+ebx+ecx*4]
+ sar eax,8
+ cmp eax,07FFFh
+ jg LClampHigh
+ cmp eax,0FFFF8000h
+ jnl LClampDone
+ mov eax,0FFFF8000h
+ jmp LClampDone
+LClampHigh:
+ mov eax,07FFFh
+LClampDone:
+ mov edx,ds:dword ptr[-4+ebx+ecx*4]
+ sar edx,8
+ cmp edx,07FFFh
+ jg LClampHigh2
+ cmp edx,0FFFF8000h
+ jnl LClampDone2
+ mov edx,0FFFF8000h
+ jmp LClampDone2
+LClampHigh2:
+ mov edx,07FFFh
+LClampDone2:
+ shl edx,16
+ and eax,0FFFFh
+ or edx,eax
+ mov ds:dword ptr[-4+edi+ecx*2],edx
+ sub ecx,2
+ jnz LWLBLoopTop
+ pop ebx
+ pop edi
+ ret
+	}
+}
+
+#endif
+#endif
+
+void S_TransferStereo16 (unsigned long *pbuf, int endtime)
+{
+	int		lpos;
+	int		lpaintedtime;
+	
+	snd_p = (int *) paintbuffer;
+	lpaintedtime = paintedtime;
+
+	while (lpaintedtime < endtime)
+	{
+	// handle recirculating buffer issues
+		lpos = lpaintedtime & ((dma.samples>>1)-1);
+
+		snd_out = (short *) pbuf + (lpos<<1);
+
+		snd_linear_count = (dma.samples>>1) - lpos;
+		if (lpaintedtime + snd_linear_count > endtime)
+			snd_linear_count = endtime - lpaintedtime;
+
+		snd_linear_count <<= 1;
+
+	// write a linear blast of samples
+		S_WriteLinearBlastStereo16 ();
+
+		snd_p += snd_linear_count;
+		lpaintedtime += (snd_linear_count>>1);
+	}
+}
+
+/*
+===================
+S_TransferPaintBuffer
+
+===================
+*/
+void S_TransferPaintBuffer(int endtime)
+{
+	int 	out_idx;
+	int 	count;
+	int 	out_mask;
+	int 	*p;
+	int 	step;
+	int		val;
+	unsigned long *pbuf;
+
+	pbuf = (unsigned long *)dma.buffer;
+
+	if (s_testsound->value)
+	{
+		int		i;
+		int		count;
+
+		// write a fixed sine wave
+		count = (endtime - paintedtime);
+		for (i=0 ; i<count ; i++)
+			paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
+	}
+
+
+	if (dma.samplebits == 16 && dma.channels == 2)
+	{	// optimized case
+		S_TransferStereo16 (pbuf, endtime);
+	}
+	else
+	{	// general case
+		p = (int *) paintbuffer;
+		count = (endtime - paintedtime) * dma.channels;
+		out_mask = dma.samples - 1; 
+		out_idx = paintedtime * dma.channels & out_mask;
+		step = 3 - dma.channels;
+
+		if (dma.samplebits == 16)
+		{
+			short *out = (short *) pbuf;
+			while (count--)
+			{
+				val = *p >> 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 (dma.samplebits == 8)
+		{
+			unsigned char *out = (unsigned char *) pbuf;
+			while (count--)
+			{
+				val = *p >> 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;
+			}
+		}
+	}
+}
+
+
+/*
+===============================================================================
+
+CHANNEL MIXING
+
+===============================================================================
+*/
+
+void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
+void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
+
+void S_PaintChannels(int endtime)
+{
+	int 	i;
+	int 	end;
+	channel_t *ch;
+	sfxcache_t	*sc;
+	int		ltime, count;
+	playsound_t	*ps;
+
+	snd_vol = s_volume->value*256;
+
+//Com_Printf ("%i to %i\n", paintedtime, endtime);
+	while (paintedtime < endtime)
+	{
+	// if paintbuffer is smaller than DMA buffer
+		end = endtime;
+		if (endtime - paintedtime > PAINTBUFFER_SIZE)
+			end = paintedtime + PAINTBUFFER_SIZE;
+
+		// start any playsounds
+		while (1)
+		{
+			ps = s_pendingplays.next;
+			if (ps == &s_pendingplays)
+				break;	// no more pending sounds
+			if (ps->begin <= paintedtime)
+			{
+				S_IssuePlaysound (ps);
+				continue;
+			}
+
+			if (ps->begin < end)
+				end = ps->begin;		// stop here
+			break;
+		}
+
+	// clear the paint buffer
+		if (s_rawend < paintedtime)
+		{
+//			Com_Printf ("clear\n");
+			memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
+		}
+		else
+		{	// copy from the streaming sound source
+			int		s;
+			int		stop;
+
+			stop = (end < s_rawend) ? end : s_rawend;
+
+			for (i=paintedtime ; i<stop ; i++)
+			{
+				s = i&(MAX_RAW_SAMPLES-1);
+				paintbuffer[i-paintedtime] = s_rawsamples[s];
+			}
+//		if (i != end)
+//			Com_Printf ("partial stream\n");
+//		else
+//			Com_Printf ("full stream\n");
+			for ( ; i<end ; i++)
+			{
+				paintbuffer[i-paintedtime].left =
+				paintbuffer[i-paintedtime].right = 0;
+			}
+		}
+
+
+	// paint in the channels.
+		ch = channels;
+		for (i=0; i<MAX_CHANNELS ; i++, ch++)
+		{
+			ltime = paintedtime;
+		
+			while (ltime < end)
+			{
+				if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
+					break;
+
+				// max painting is to the end of the buffer
+				count = end - ltime;
+
+				// might be stopped by running out of data
+				if (ch->end - ltime < count)
+					count = ch->end - ltime;
+		
+				sc = S_LoadSound (ch->sfx);
+				if (!sc)
+					break;
+
+				if (count > 0 && ch->sfx)
+				{	
+					if (sc->width == 1)// FIXME; 8 bit asm is wrong now
+						S_PaintChannelFrom8(ch, sc, count,  ltime - paintedtime);
+					else
+						S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
+	
+					ltime += count;
+				}
+
+			// if at end of loop, restart
+				if (ltime >= ch->end)
+				{
+					if (ch->autosound)
+					{	// autolooping sounds always go back to start
+						ch->pos = 0;
+						ch->end = ltime + sc->length;
+					}
+					else if (sc->loopstart >= 0)
+					{
+						ch->pos = sc->loopstart;
+						ch->end = ltime + sc->length - ch->pos;
+					}
+					else				
+					{	// channel just stopped
+						ch->sfx = NULL;
+					}
+				}
+			}
+															  
+		}
+
+	// transfer out according to DMA format
+		S_TransferPaintBuffer(end);
+		paintedtime = end;
+	}
+}
+
+void S_InitScaletable (void)
+{
+	int		i, j;
+	int		scale;
+
+	s_volume->modified = false;
+	for (i=0 ; i<32 ; i++)
+	{
+		scale = i * 8 * 256 * s_volume->value;
+		for (j=0 ; j<256 ; j++)
+			snd_scaletable[i][j] = ((signed char)j) * scale;
+	}
+}
+
+
+#if !(defined __linux__ && defined __i386__)
+#if	!id386
+
+void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+{
+	int 	data;
+	int		*lscale, *rscale;
+	unsigned char *sfx;
+	int		i;
+	portable_samplepair_t	*samp;
+
+	if (ch->leftvol > 255)
+		ch->leftvol = 255;
+	if (ch->rightvol > 255)
+		ch->rightvol = 255;
+		
+	lscale = snd_scaletable[ ch->leftvol >> 11];
+	rscale = snd_scaletable[ ch->rightvol >> 11];
+	sfx = (signed char *)sc->data + ch->pos;
+
+	samp = &paintbuffer[offset];
+
+	for (i=0 ; i<count ; i++, samp++)
+	{
+		data = sfx[i];
+		samp->left += lscale[data];
+		samp->right += rscale[data];
+	}
+	
+	ch->pos += count;
+}
+
+#else
+
+__declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+{
+	__asm {
+ push esi
+ push edi
+ push ebx
+ push ebp
+ mov ebx,ds:dword ptr[4+16+esp]
+ mov esi,ds:dword ptr[8+16+esp]
+ mov eax,ds:dword ptr[4+ebx]
+ mov edx,ds:dword ptr[8+ebx]
+ cmp eax,255
+ jna LLeftSet
+ mov eax,255
+LLeftSet:
+ cmp edx,255
+ jna LRightSet
+ mov edx,255
+LRightSet:
+ and eax,0F8h
+ add esi,20
+ and edx,0F8h
+ mov edi,ds:dword ptr[16+ebx]
+ mov ecx,ds:dword ptr[12+16+esp]
+ add esi,edi
+ shl eax,7
+ add edi,ecx
+ shl edx,7
+ mov ds:dword ptr[16+ebx],edi
+ add eax,offset snd_scaletable
+ add edx,offset snd_scaletable
+ sub ebx,ebx
+ mov bl,ds:byte ptr[-1+esi+ecx*1]
+ test ecx,1
+ jz LMix8Loop
+ mov edi,ds:dword ptr[eax+ebx*4]
+ mov ebp,ds:dword ptr[edx+ebx*4]
+ add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
+ add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
+ mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
+ mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
+ mov bl,ds:byte ptr[-2+esi+ecx*1]
+ dec ecx
+ jz LDone
+LMix8Loop:
+ mov edi,ds:dword ptr[eax+ebx*4]
+ mov ebp,ds:dword ptr[edx+ebx*4]
+ add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
+ add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
+ mov bl,ds:byte ptr[-2+esi+ecx*1]
+ mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
+ mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
+ mov edi,ds:dword ptr[eax+ebx*4]
+ mov ebp,ds:dword ptr[edx+ebx*4]
+ mov bl,ds:byte ptr[-3+esi+ecx*1]
+ add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8]
+ add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8]
+ mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi
+ mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp
+ sub ecx,2
+ jnz LMix8Loop
+LDone:
+ pop ebp
+ pop ebx
+ pop edi
+ pop esi
+ ret
+	}
+}
+
+#endif
+#endif
+
+void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+{
+	int data;
+	int left, right;
+	int leftvol, rightvol;
+	signed short *sfx;
+	int	i;
+	portable_samplepair_t	*samp;
+
+	leftvol = ch->leftvol*snd_vol;
+	rightvol = ch->rightvol*snd_vol;
+	sfx = (signed short *)sc->data + ch->pos;
+
+	samp = &paintbuffer[offset];
+	for (i=0 ; i<count ; i++, samp++)
+	{
+		data = sfx[i];
+		left = (data * leftvol)>>8;
+		right = (data * rightvol)>>8;
+		samp->left += left;
+		samp->right += right;
+	}
+
+	ch->pos += count;
+}
+
--- /dev/null
+++ b/client/sound.h
@@ -1,0 +1,45 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+struct sfx_s;
+
+void S_Init (void);
+void S_Shutdown (void);
+
+// if origin is NULL, the sound will be dynamically sourced from the entity
+void S_StartSound (vec3_t origin, int entnum, int entchannel, struct sfx_s *sfx, float fvol,  float attenuation, float timeofs);
+void S_StartLocalSound (char *s);
+
+void S_RawSamples (int samples, int rate, int width, int channels, byte *data);
+
+void S_StopAllSounds(void);
+void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
+
+void S_Activate (qboolean active);
+
+void S_BeginRegistration (void);
+struct sfx_s *S_RegisterSound (char *sample);
+void S_EndRegistration (void);
+
+struct sfx_s *S_FindName (char *name, qboolean create);
+
+// the sound code makes callbacks to the client for entitiy position
+// information, so entities can be dynamically re-spatialized
+void CL_GetEntitySoundOrigin (int ent, vec3_t org);
--- /dev/null
+++ b/client/vid.h
@@ -1,0 +1,42 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// vid.h -- video driver defs
+
+typedef struct vrect_s
+{
+	int				x,y,width,height;
+} vrect_t;
+
+typedef struct
+{
+	int		width;		
+	int		height;
+} viddef_t;
+
+extern	viddef_t	viddef;				// global video state
+
+// Video module initialisation etc
+void	VID_Init (void);
+void	VID_Shutdown (void);
+void	VID_CheckChanges (void);
+
+void	VID_MenuInit( void );
+void	VID_MenuDraw( void );
+const char *VID_MenuKey( int );
--- /dev/null
+++ b/client/x86.c
@@ -1,0 +1,95 @@
+/*
+Copyright (C) 1997-2001 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 <stdlib.h>
+#include "client.h"
+
+#if id386
+
+static unsigned long bias;
+static unsigned long *histogram;
+static unsigned long start, range;
+static unsigned long bias;
+
+__declspec( naked ) void x86_TimerStart( void )
+{
+	__asm _emit 0fh
+	__asm _emit 31h
+	__asm mov  start, eax
+	__asm ret
+}
+
+__declspec( naked ) void x86_TimerStop( void )
+{
+	__asm push edi
+	__asm mov edi, histogram
+	__asm _emit 0fh
+	__asm _emit 31h
+	__asm sub eax, start
+	__asm sub eax, bias
+	__asm js discard
+	__asm cmp eax, range
+	__asm jge  discard
+	__asm lea edi, [edi + eax*4]
+	__asm inc dword ptr [edi]
+discard:
+	__asm pop edi
+	__asm ret
+}
+
+#pragma warning( disable: 4035 )
+static __declspec( naked ) unsigned long x86_TimerStopBias( void )
+{
+	__asm push edi
+	__asm mov edi, histogram
+	__asm _emit 0fh
+	__asm _emit 31h
+	__asm sub eax, start
+	__asm pop edi
+	__asm ret
+}
+#pragma warning( default:4035 )
+
+void x86_TimerInit( unsigned long smallest, unsigned length )
+{
+	int i;
+	unsigned long biastable[100];
+
+	range = length;
+	bias = 10000;
+
+	for ( i = 0; i < 100; i++ )
+	{
+		x86_TimerStart();
+		biastable[i] = x86_TimerStopBias();
+
+		if ( bias > biastable[i] )
+			bias = biastable[i];
+	}
+
+	bias += smallest;
+	histogram = Z_Malloc( range * sizeof( unsigned long ) );
+}
+
+unsigned long *x86_TimerGetHistogram( void )
+{
+	return histogram;
+}
+
+#endif
--- /dev/null
+++ b/ctf/2do.txt
@@ -1,0 +1,16 @@
+
+switching teams during setup should clear ready
+center stuff should be left aligned on admin
+match command for ingame match request
+admin kick option (menu)
+can't join team when match PREGAME (menu was still open)
+server pause in 3.15?
+
+*time changes are broken
+*ghosting in makes you invisible (svf_noclient?)
+*ghost doesn't restore frags
+*resetall needs to clear grapple (and match start)
+*reset all techs at match start
+*'and admin'
+*timelimit/fraglimit disabled in match mode
+*telefrags at start of match [needs tested]
--- /dev/null
+++ b/ctf/Makefile.Linux.i386
@@ -1,0 +1,159 @@
+#
+# Quake2 gamei386.so Makefile for Linux 2.0
+#
+# Jan '98 by Zoid <[email protected]>
+#
+# ELF only
+#
+# Probably requires GNU make
+#
+# This builds the gamei386.so for Linux based on the q2source_12_11.zip
+# release.  
+# Put his Makefile in the game subdirectory you get when you unzip
+# q2source_12_11.zip.
+#
+# There are two compiler errors you'll get, the following fixes
+# are necessary:
+#
+# In g_local.h (around line 828), you must change the 
+#    typedef struct g_client_s { ... } gclient_t;
+# to just:
+#    struct g_client_s { ... };
+# The typedef is already defined elsewhere (seems to compile fine under
+# MSCV++ for Win32 for some reason).
+#
+# m_player.h has a Ctrl-Z at the end (damn DOS editors).  Remove it or
+# gcc complains.
+#
+# Note that the source in q2source_12_11.zip is for version 3.05.  To
+# get it to run with Linux 3.10, change the following in game.h:
+#    #define	GAME_API_VERSION	1
+# change it to:
+#    #define	GAME_API_VERSION	2
+
+ARCH=i386
+CC=gcc
+BASE_CFLAGS=-Dstricmp=strcasecmp
+
+#use these cflags to optimize it
+CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \
+	-fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
+	-malign-jumps=2 -malign-functions=2
+#use these when debugging 
+#CFLAGS=$(BASE_CFLAGS) -g
+
+OBJDIR=linux
+
+LDFLAGS=-ldl -lm
+SHLIBEXT=so
+SHLIBCFLAGS=-fPIC
+SHLIBLDFLAGS=-shared
+
+DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+
+#############################################################################
+# SETUP AND BUILD
+# GAME
+#############################################################################
+
+GAME_OBJS = \
+	$(OBJDIR)/g_ai.o $(OBJDIR)/p_client.o $(OBJDIR)/g_svcmds.o $(OBJDIR)/g_cmds.o \
+	$(OBJDIR)/g_combat.o $(OBJDIR)/g_func.o $(OBJDIR)/g_items.o \
+	$(OBJDIR)/g_main.o $(OBJDIR)/g_misc.o $(OBJDIR)/g_monster.o $(OBJDIR)/g_phys.o \
+	$(OBJDIR)/g_save.o $(OBJDIR)/g_spawn.o \
+	$(OBJDIR)/g_target.o $(OBJDIR)/g_trigger.o $(OBJDIR)/g_utils.o $(OBJDIR)/g_weapon.o \
+	$(OBJDIR)/m_move.o \
+	$(OBJDIR)/p_hud.o $(OBJDIR)/p_trail.o $(OBJDIR)/p_view.o $(OBJDIR)/p_weapon.o \
+	$(OBJDIR)/q_shared.o $(OBJDIR)/g_ctf.o $(OBJDIR)/p_menu.o $(OBJDIR)/g_chase.o
+
+game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
+
+$(OBJDIR)/g_ai.o       : g_ai.c     
+	$(DO_CC)
+
+$(OBJDIR)/p_client.o   : p_client.c 
+	$(DO_CC)
+
+$(OBJDIR)/g_svcmds.o   : g_svcmds.c 
+	$(DO_CC)
+
+$(OBJDIR)/g_cmds.o     : g_cmds.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_combat.o   : g_combat.c 
+	$(DO_CC)
+
+$(OBJDIR)/g_func.o     : g_func.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_items.o    : g_items.c  
+	$(DO_CC)
+
+$(OBJDIR)/g_main.o     : g_main.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_misc.o     : g_misc.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_monster.o  : g_monster.c
+	$(DO_CC)
+
+$(OBJDIR)/g_phys.o     : g_phys.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_save.o     : g_save.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_spawn.o    : g_spawn.c  
+	$(DO_CC)
+
+$(OBJDIR)/g_target.o   : g_target.c 
+	$(DO_CC)
+
+$(OBJDIR)/g_trigger.o  : g_trigger.c
+	$(DO_CC)
+
+$(OBJDIR)/g_utils.o    : g_utils.c  
+	$(DO_CC)
+
+$(OBJDIR)/g_weapon.o   : g_weapon.c 
+	$(DO_CC)
+
+$(OBJDIR)/m_move.o     : m_move.c   
+	$(DO_CC)
+
+$(OBJDIR)/p_hud.o      : p_hud.c    
+	$(DO_CC)
+
+$(OBJDIR)/p_trail.o    : p_trail.c  
+	$(DO_CC)
+
+$(OBJDIR)/p_view.o     : p_view.c   
+	$(DO_CC)
+
+$(OBJDIR)/p_weapon.o   : p_weapon.c 
+	$(DO_CC)
+
+$(OBJDIR)/q_shared.o   : q_shared.c 
+	$(DO_CC)
+
+$(OBJDIR)/g_ctf.o      : g_ctf.c    
+	$(DO_CC)
+
+$(OBJDIR)/p_menu.o     : p_menu.c   
+	$(DO_CC)
+
+$(OBJDIR)/g_chase.o    : g_chase.c  
+	$(DO_CC)
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean:
+	-rm -f $(GAME_OBJS)
+
+depend:
+	gcc -MM $(GAME_OBJS:.o=.c)
+
--- /dev/null
+++ b/ctf/ctf.001
@@ -1,0 +1,1009 @@
+# Microsoft Developer Studio Project File - Name="ctf" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=ctf - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ctf.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ctf.mak" CFG="ctf - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ctf - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ctf - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ctf - Win32 Debug Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "ctf - Win32 Release Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+# PROP WCE_Configuration "H/PC Ver. 2.00"
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386 /out:".\release\gamex86.dll"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:".\debug\gamex86.dll" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ctf___Wi"
+# PROP BASE Intermediate_Dir "ctf___Wi"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAXP"
+# PROP Intermediate_Dir ".\DebugAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /MTd /c
+# ADD CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /MTd /c
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:ALPHA /out:".\debug\gamex86.dll" /pdbtype:sept
+# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:ALPHA /out:".\debugAXP\gameaxp.dll" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ctf___W0"
+# PROP BASE Intermediate_Dir "ctf___W0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA /out:".\release\gamex86.dll"
+# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA /out:".\ReleaseAXP\gameaxp.dll"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ctf - Win32 Release"
+# Name "ctf - Win32 Debug"
+# Name "ctf - Win32 Debug Alpha"
+# Name "ctf - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "*.c"
+# Begin Source File
+
+SOURCE=.\g_ai.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_chase.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_cmds.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_combat.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_ctf.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_CTF=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_CTF=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_func.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_items.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_main.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_misc.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_monster.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_phys.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_save.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_spawn.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_svcmds.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_target.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_trigger.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_utils.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_weapon.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_move.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_client.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_hud.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_menu.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_MEN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_MEN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_trail.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_view.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_weapon.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "*.h"
+# Begin Source File
+
+SOURCE=.\g_ctf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_player.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_menu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "*.def,*.res"
+# Begin Source File
+
+SOURCE=.\ctf.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/ctf/ctf.def
@@ -1,0 +1,2 @@
+EXPORTS
+	GetGameAPI
--- /dev/null
+++ b/ctf/ctf.dsp
@@ -1,0 +1,1007 @@
+# Microsoft Developer Studio Project File - Name="ctf" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=ctf - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ctf.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ctf.mak" CFG="ctf - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ctf - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ctf - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ctf - Win32 Debug Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "ctf - Win32 Release Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386 /out:".\release\gamex86.dll"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:".\debug\gamex86.dll" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ctf___Wi"
+# PROP BASE Intermediate_Dir "ctf___Wi"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAXP"
+# PROP Intermediate_Dir ".\DebugAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /MTd /c
+# ADD CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /MTd /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:ALPHA /out:".\debug\gamex86.dll" /pdbtype:sept
+# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:ALPHA /out:".\debugAXP\gameaxp.dll" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ctf___W0"
+# PROP BASE Intermediate_Dir "ctf___W0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA /out:".\release\gamex86.dll"
+# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA /out:".\ReleaseAXP\gameaxp.dll"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ctf - Win32 Release"
+# Name "ctf - Win32 Debug"
+# Name "ctf - Win32 Debug Alpha"
+# Name "ctf - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "*.c"
+# Begin Source File
+
+SOURCE=.\g_ai.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_chase.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_cmds.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_combat.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_ctf.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_CTF=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_CTF=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_func.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_items.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_main.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_misc.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_monster.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_phys.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_save.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_spawn.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_svcmds.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_target.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_trigger.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_utils.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_weapon.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_move.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_client.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_hud.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_menu.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_MEN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_MEN=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_trail.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_view.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_weapon.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_ctf.h"\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\p_menu.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.c
+
+!IF  "$(CFG)" == "ctf - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ctf - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "*.h"
+# Begin Source File
+
+SOURCE=.\g_ctf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_player.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_menu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "*.def,*.res"
+# Begin Source File
+
+SOURCE=.\ctf.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/ctf/ctf.plg
@@ -1,0 +1,17 @@
+--------------------Configuration: ctf - Win32 Debug Alpha--------------------
+Begining build with project "G:\quake2\code\ctf\ctf.dsp", at root.
+Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library)
+
+Project's tools are:
+			"OLE Type Library Maker" with flags "/nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 "
+			"C/C++ Compiler for Alpha" with flags "/nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR".\DebugAXP/" /Fp".\DebugAXP/ctf.pch" /YX /Fo".\DebugAXP/" /Fd".\DebugAXP/" /FD /c "
+			"Win32 Resource Compiler" with flags "/l 0x409 /d "_DEBUG" "
+			"Browser Database Maker" with flags "/nologo /o"..\DebugAXP/ctf.bsc" "
+			"COFF Linker for Alpha" with flags "winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\DebugAXP/gameaxp.pdb" /map:".\DebugAXP/gameaxp.map" /debug /machine:ALPHA /def:".\ctf.def" /out:".\debugAXP\gameaxp.dll" /implib:"..\DebugAXP/gameaxp.lib" /pdbtype:sept "
+			"Custom Build" with flags ""
+			"<Component 0xa>" with flags ""
+
+
+
+
+gameaxp.dll - 0 error(s), 0 warning(s)
binary files /dev/null b/ctf/docs/admin.gif differ
binary files /dev/null b/ctf/docs/adminset.gif differ
binary files /dev/null b/ctf/docs/automac.gif differ
binary files /dev/null b/ctf/docs/ghost.jpg differ
binary files /dev/null b/ctf/docs/grapple.jpg differ
binary files /dev/null b/ctf/docs/layout.jpg differ
binary files /dev/null b/ctf/docs/mainctf_back.jpg differ
binary files /dev/null b/ctf/docs/menu.gif differ
--- /dev/null
+++ b/ctf/docs/q2ctf.html
@@ -1,0 +1,1243 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Type"
+content="text/html; charset=iso-8859-1">
+<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
+<title>Quake II Capture The Flag User Manual</title>
+</head>
+
+<body bgcolor="#000000" text="#C0C0C0" link="#FFFFFF"
+vlink="#FFFFFF" alink="#00FF40">
+<div align="center"><center>
+
+<table border="0" cellpadding="0" cellspacing="0" width="600">
+    <tr>
+        <td bgcolor="#000040">&nbsp;</td>
+        <td>&nbsp;&nbsp;</td>
+        <td valign="top" width="100%"><div align="center"><center><table
+        border="0" cellpadding="8" cellspacing="0" width="590"
+        background="mainctf_back.jpg">
+            <tr>
+                <td align="center" valign="top"><h1
+                align="center"><font size="5" face="Arial">Quake
+                II Capture the Flag User Manual</font></h1>
+                <h2 align="center"><font size="3" face="Arial">Table
+                Of Contents</font></h2>
+                <div align="center"><center><table border="0"
+                cellpadding="0" cellspacing="0" width="500">
+                    <tr>
+                        <td width="50%"><a href="#intro"><font
+                        size="2" face="Arial">Introduction</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#rules"><font size="2"
+                        face="Arial">Rules of the game</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#join"><font size="2"
+                        face="Arial">Joining a Game</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#grapple"><font size="2"
+                        face="Arial">Using the Grapple</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#tech"><font size="2"
+                        face="Arial">Special Powerups</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#com"><font size="2"
+                        face="Arial">Communicating With Your Team</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#scoring"><font size="2"
+                        face="Arial">Scoring</font></a></td>
+                        <td width="50%"><a href="#elect"><font
+                        size="2" face="Arial">Elections</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#compmode"><font size="2"
+                        face="Arial">Competition Mode</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#ghost"><font size="2"
+                        face="Arial">Ghost Codes</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#stats"><font size="2"
+                        face="Arial">Statistics</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#console"><font size="2"
+                        face="Arial">New Console Commands</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#admin"><font size="2"
+                        face="Arial">User Admin Functions</font></a><font
+                        size="2" face="Arial"><br>
+                        </font><a href="#serverop"><font size="2"
+                        face="Arial">Server Operator Information</font></a></td>
+                    </tr>
+                </table>
+                </center></div><p align="center"><font
+                face="Arial"><br>
+                </font><font size="2" face="Arial">This document
+                Copyright �1998 by id Software.</font><font
+                size="3" face="Arial"><br>
+                <br>
+                </font></p>
+                </td>
+            </tr>
+        </table>
+        </center></div><p><a name="#intro"></a></p>
+        <h3><font face="Arial">Introduction</font></h3>
+        <p><font face="Arial">Quake II Capture The Flag (Q2CTF)
+        is a multiplayer addon for Quake2 that features a simple
+        set of rules for team based play. It features five unique
+        maps and special powerups to enhance and make the
+        gameplay more exciting.</font></p>
+        <p><font face="Arial">Q2CTF requires the full retail
+        version of Quake II installed in order to play. Once
+        installed, you simple need to connect to a Quake2 game
+        server that is running the Q2CTF addon.</font><a
+        name="#rules"></a></p>
+        <h3><font face="Arial">Rules of the Game</font></h3>
+        <p><font face="Arial">Capture the Flag is a multiplayer
+        addon for Quake2 that features a simple set of rules for
+        team based play.</font></p>
+        <p><font face="Arial">The basic rules are:</font></p>
+        <ul>
+            <li><font face="Arial">When connecting to the server,
+                you join one of two teams: the Red team and the
+                Blue team</font></li>
+            <li><font face="Arial">Each team has a base with a
+                flag positioned in it.</font></li>
+            <li><font face="Arial">The object of the game is to
+                infiltrate the enemy base, take their flag and
+                bring it back to your base.</font></li>
+            <li><font face="Arial">In order to successfully
+                complete a capture, you must be carrying the
+                enemy flag and touch your flag while carrying it
+                at your base.</font></li>
+        </ul>
+        <p><font face="Arial">When playing Q2CTF, there are
+        several different indicators on your Heads Up Display
+        (HUD) that show the status of the game. Learning to
+        interpret the information on this display is important in
+        learning how to play Q2CTF.</font></p>
+        <p align="center"><font face="Arial"><img
+        src="layout.jpg" width="573" height="402"></font><a
+        name="#join"></a></p>
+        <h3><font face="Arial">Joining a game</font></h3>
+        <p><font face="Arial">When you connect to a Q2CTF server,
+        you may be presented with the option as to which team you
+        join. You'll be present with a menu.</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="8" cellspacing="0" width="550">
+            <tr>
+                <td valign="top"><img src="menu.gif"
+                alt="Q2CTF Join Menu" width="254" height="190"></td>
+                <td><font size="2" face="Arial">This menu offers
+                you the ability to join either the Red and Blue
+                teams, select a chase camera (watch other players
+                as they play), see the credits for the Q2CTF
+                addon or Request that the server switch to Match
+                Mode.</font><p><font size="2" face="Arial">Navigating
+                the menu assumes that you haven't change the
+                default keys in Quake2. The following keys are
+                used when navigating the menu:</font></p>
+                <ul>
+                    <li><font size="2" face="Arial">&lt;]&gt; is
+                        used to move to the next menu selection</font></li>
+                    <li><font size="2" face="Arial">&lt;[&gt; is
+                        used to move to the previous menu
+                        selection</font></li>
+                    <li><font size="2" face="Arial">&lt;ENTER&gt;
+                        is used to make a menu selection</font></li>
+                    <li><font size="2" face="Arial">&lt;ESC&gt;
+                        will remove the menu (in this case,
+                        you'll be left in an &quot;observer&quot;
+                        mode and can freely move around the map,
+                        but you can not interact with the game)</font></li>
+                    <li><font size="2" face="Arial">&lt;TAB&gt;
+                        will recall the menu if you've cleared
+                        it.</font></li>
+                </ul>
+                </td>
+            </tr>
+        </table>
+        </center></div><p><font face="Arial">Note that if you
+        have change any of the key binds for those keys, the menu
+        may not work properly. The default bindings for these
+        keys are (from Quake2's default.cfg):</font></p>
+        <p><font face="Arial"><code>bind TAB inven<br>
+        bind ENTER invuse<br>
+        bind [ invprev<br>
+        bind ] invnext<br>
+        bind ESCAPE togglemenu</code></font></p>
+        <p><font face="Arial">If you have changed those keys, you
+        will have to duplicate those bindings for other keys. For
+        example, if you wanted the up and down arrows to navigate
+        the menu, you could bind it like so:</font></p>
+        <p><font face="Arial"><code>bind UPARROW invprev<br>
+        bind DOWNARROW invnext</code></font></p>
+        <dl>
+            <dt><font face="Arial">Join Red Team</font></dt>
+            <dd><font face="Arial">This joins you to the Red team
+                and places you into the game starting at the Red
+                base. You are immediately ready to go and start
+                playing.</font></dd>
+            <dt>&nbsp;</dt>
+            <dt><font face="Arial">Join Blue Team</font></dt>
+            <dd><font face="Arial">This joins you to the Blue
+                team and places you into the game starting at the
+                Blue base. You are immediately ready to go and
+                start playing.</font></dd>
+            <dt>&nbsp;</dt>
+            <dt><font face="Arial">Chase Camera</font></dt>
+            <dd><font face="Arial">This activates a chase camera
+                and lets you watch players as they play. The
+                camera will automatically be placed behind
+                someone as they are playing. If you wish to
+                change the camera to follow someone else, use the
+                &lt;[&gt; and &lt;]&gt; keys to change the player
+                you are trailing (same keys as the menu
+                selection). To get out of Chase Camera mode, hit
+                &lt;TAB&gt; to bring up the menu again and select
+                &quot;Leave Chase Camera.&quot;</font></dd>
+            <dt>&nbsp;</dt>
+            <dt><font face="Arial">Credits</font></dt>
+            <dd><font face="Arial">This shows a simple screen
+                showing the development credits for the Q2CTF
+                Addon.</font></dd>
+            <dt>&nbsp;</dt>
+            <dt><font face="Arial">Request Match</font></dt>
+            <dd><font face="Arial">If the server has match
+                capability, this will begin an election that
+                players may vote on in order to switch the server
+                to match (competition mode).</font></dd>
+            <dt>&nbsp;</dt>
+        </dl>
+        <p><a name="#grapple"></a></p>
+        <h3><font face="Arial">Using the grapple</font></h3>
+        <p><font face="Arial">One of the exciting features of the
+        Q2CTF is a new weapon/tool called the Grapple. The
+        grapple lets you get to parts of the level that were
+        previously inaccessible and can be used as a great tool
+        to increase your mobility. It can also be used as a
+        weapon, but it only does the same damage as the blaster,
+        so it's not very effective.</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="5" cellspacing="0" width="550">
+            <tr>
+                <td><img src="grapple.jpg" width="320"
+                height="240"></td>
+                <td><font size="2" face="Arial">The grapple is a
+                fun addition to Q2CTF and learning how to use is
+                required for effective CTF play.</font><p><font
+                size="2" face="Arial">To use the grapple, you
+                must bind a key or mouse action to it. For
+                example, to bind it to you right mouse button,
+                you would use:</font></p>
+                <p><font size="3" face="Arial"><code>bind MOUSE2
+                &quot;use grapple&quot;</code></font></p>
+                <p><font size="2" face="Arial">This would cause
+                the grapple to be selected whenever the right
+                mouse button was hit.</font></p>
+                </td>
+            </tr>
+        </table>
+        </center></div><p><font face="Arial">You can use the
+        grapple in a few ways:</font></p>
+        <ul>
+            <li><font face="Arial">Select the grapple, point it
+                where you want to go and press and HOLD the fire
+                button down. The grapple will launch and connect
+                to the spot you fired and once contact is made,
+                you will be pulled to the spot the grapple
+                connected. Once at your destination, let go of
+                the fire button to release the grapple.</font></li>
+            <li><font face="Arial">You can also hang from the
+                ceiling or wall with the grapple. You would go
+                there by performing a normal grapple maneuver,
+                but once you get to your destination, do not
+                release the fire button. Instead, while holding
+                down the fire button, change to a different
+                weapon in midair. Once the change is completed,
+                let go of the fire button and you'll be left
+                hanging from the ceiling. When you want to drop
+                off the ceiling, switch back to the grapple and
+                make sure your fire button is not held down.
+                You'll be released and will fall from your
+                position.</font></li>
+        </ul>
+        <p><font face="Arial"><br clear="all">
+        </font><a name="#tech"></a></p>
+        <h3><font face="Arial">Special Powerups</font></h3>
+        <p><font face="Arial">There are four special TECH
+        powerups in Q2CTF.</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="4" cellspacing="0" width="500">
+            <tr>
+                <td valign="top"><img src="tech1.gif" width="48"
+                height="48"></td>
+                <td><dl>
+                    <dt><font face="Arial"><strong><br>
+                        Disruptor Shield</strong></font></dt>
+                </dl>
+                <p align="left"><font face="Arial">This TECH
+                Powerup causes the holder to have a protective
+                shield and reduces the damage from all attackers
+                to half. Its an effective tool when attacking
+                enemy installations.</font></p>
+                </td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td><dl>
+                    <dt>&nbsp;</dt>
+                </dl>
+&nbsp;                </td>
+            </tr>
+            <tr>
+                <td valign="top"><img src="tech2.gif" width="48"
+                height="48"></td>
+                <td><dl>
+                    <dt><font face="Arial"><strong><br>
+                        Power Amplifier</strong></font></dt>
+                </dl>
+                <p><font face="Arial">This TECH Powerup causes
+                the holder to power up all his attacks to double
+                the damage normally delivered. This an excellent
+                tool for defending your base installation.</font></p>
+                </td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><img src="tech3.gif" width="48"
+                height="48"></td>
+                <td><dl>
+                    <dt><font face="Arial"><strong><br>
+                        Time Accelerator</strong></font></dt>
+                </dl>
+                <p><font face="Arial">This TECH Powerup
+                accelerates weapon time for the holder. All his
+                weapons will operate double speed in reload time,
+                switching, etc. This is also an excellent tool
+                for defense, since the holder can deliver twice
+                as much damage in the same amount of time.</font></p>
+                </td>
+            </tr>
+            <tr>
+                <td valign="top"><img src="tech4.gif" width="48"
+                height="48"></td>
+                <td><dl>
+                    <dt><font face="Arial"><strong><br>
+                        AutoDoc</strong></font></dt>
+                </dl>
+                <p><font face="Arial">This TECH Powerup
+                automatically heals and increases a players
+                health and armor (up to a maximum of 150 for
+                each). The player will slow regain health and
+                armor over time. This is an excellent tool for
+                people carrying the enemy flag since the player
+                will constantly regain health and armor, making
+                him much tougher to kill and get the flag back
+                from.<br clear="all">
+                </font></p>
+                </td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+        </table>
+        </center></div><dl>
+            <dd>&nbsp;</dd>
+            <dd>&nbsp;</dd>
+        </dl>
+        <p><a name="#com"></a></p>
+        <h3><font color="#C0C0C0" face="Arial">Communicating With
+        Your Team</font></h3>
+        <p><font face="Arial">A very important part of any
+        multiplayer team based game is communication. Letting
+        your teammates know where you are and what you are doing
+        is an essential part of teamwork.</font></p>
+        <p><font face="Arial">Q2CTF has a basic team
+        communication called &quot;say_team&quot; or
+        &quot;messagemode2&quot;. It is like the regular
+        communication of Quake2, but you need to bind a key in
+        order to use it. I use the &lt;R&gt; key myself, since
+        its right beside the normal &lt;T&gt; key used for
+        communication. To bind it, use the following:</font></p>
+        <p><font face="Arial"><code>bind r
+        &quot;messagemode2&quot;</code></font></p>
+        <p><font face="Arial">When you want to say a message to
+        your team, just hit &lt;R&gt; and type it in. This image
+        shows me telling what I'm doing to my team:</font></p>
+        <p align="center"><font face="Arial"><img
+        src="say_team.gif" alt="(Zoid): At base, defending"
+        width="462" height="32"></font></p>
+        <p><font face="Arial">Note the parenthesis around my
+        name. This indicates it is a team message and only people
+        on your team saw it.</font></p>
+        <p><font face="Arial">Now, normally I don't type a lot of
+        my team messages, I have several standard messages I use
+        to communicate with my teammates. They are bound to
+        several keys like so:</font></p>
+        <p><font face="Arial"><code>bind z &quot;say_team Base
+        secure&quot;<br>
+        bind x &quot;say_team Base overrun! Recover&quot;<br>
+        bind c &quot;say_team Incoming!&quot;<br>
+        bind v &quot;say_team I'm going offensive&quot;<br>
+        bind g &quot;say_team Going to base&quot;<br>
+        bind b &quot;say_team At base, defending&quot;</code></font></p>
+        <p><font face="Arial">So when I want to say &quot;At
+        base, defending&quot; to my teammates, I just hit my
+        &lt;B&gt; key to do so. This is much faster than typing
+        it out all the time.</font></p>
+        <p><font face="Arial">Q2CTF also features some advanced
+        options for communicating to your teammates. This feature
+        is called &quot;auto macros&quot;. It lets you configure
+        generic messages that will automatically be filled in as
+        necessary. Here's an example.</font></p>
+        <p><font face="Arial"><code>bind f &quot;say_team I'm %L,
+        %H and %A, and have %T.&quot;</code></font></p>
+        <p><font face="Arial">That looks kind of cryptic, but
+        here's what happens when I hit the F key I bound that
+        say_team to:</font></p>
+        <p align="center"><font face="Arial"><img
+        src="automac.gif" width="590" height="62"></font></p>
+        <p><font face="Arial">What this means is each of the %
+        macros in the say_team are automatically changed into
+        something specific to the situation. In this case, the %L
+        changes to a description of my current location, %H
+        changes to how much health I have, %A changes to indicate
+        how much armor I have and %T changes to indicate what
+        TECH Powerup I'm carrying.</font></p>
+        <p><font face="Arial">Here is a table of all the
+        different % automacros and what they do.</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="4" width="500">
+            <tr>
+                <td valign="top" colspan="2"><font
+                color="#00FF40" size="4" face="Arial"><strong><br>
+                </strong></font><font color="#C0C0C0" size="3"
+                face="Arial"><strong>Team Message Auto Macros</strong></font><font
+                color="#00FF40" size="4" face="Arial"><strong><br>
+                </strong></font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font color="#00FF40" size="4"
+                face="Arial">%L</font></td>
+                <td><font face="Arial">This will be substituted
+                with your current location in the map. Some
+                common examples are:<br>
+                &quot;near the Red Flag&quot;<br>
+                &quot;above the Red Armor&quot;<br>
+                &quot;near the Blue Railgun&quot;</font></td>
+            </tr>
+            <tr>
+                <td valign="top">&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font color="#00FF40" size="4"
+                face="Arial">%A</font></td>
+                <td><font face="Arial">This will be substituted
+                with what ever armor you are current carrying.
+                Some common examples are:<br>
+                &quot;Power Shield with 100 cells&quot;<br>
+                &quot;50 units of Yellow Armor&quot;<br>
+                &quot;Power Shield with 154 cells and 108 units
+                of Red Armor&quot;<br>
+                &quot;no armor&quot;</font></td>
+            </tr>
+            <tr>
+                <td valign="top">&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font color="#00FF40" size="4"
+                face="Arial">%H</font></td>
+                <td><font face="Arial">This will be substituted
+                with how much health you current have. Some
+                common examples are:<br>
+                &quot;106 health&quot;</font></td>
+            </tr>
+            <tr>
+                <td valign="top">&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font color="#00FF40" size="4"
+                face="Arial">%T</font></td>
+                <td><font face="Arial">This will be substituted
+                with the name of the TECH powerup you are
+                holding. Some common examples are:<br>
+                &quot;the Disruptor Shield&quot;<br>
+                &quot;the Power Amplifier&quot;<br>
+                &quot;no powerup&quot;</font></td>
+            </tr>
+            <tr>
+                <td valign="top">&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font color="#00FF40" size="4"
+                face="Arial">%W</font></td>
+                <td><font face="Arial">This is substituted with
+                the current weapon you are using. Some common
+                examples are:<br>
+                &quot;Railgun&quot;<br>
+                &quot;Rocket Launcher&quot;<br>
+                &quot;Grapple&quot;</font></td>
+            </tr>
+            <tr>
+                <td valign="top">&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font color="#00FF40" size="4"
+                face="Arial">%N</font></td>
+                <td><font face="Arial">This will be replaced with
+                a list of names of the people who are currently
+                in your visual range, or area. Some common
+                examples are:<br>
+                &quot;Zoid, Disruptor and Hellrot&quot;<br>
+                &quot;&gt;BC&gt;Casey and &gt;BC&gt;Mutha&quot;<br>
+                &quot;no one&quot;</font></td>
+            </tr>
+        </table>
+        </center></div><p><a name="#scoring"></a></p>
+        <h3><font face="Arial">Scoring</font></h3>
+        <p><font face="Arial">Q2CTF features many different score
+        bonus based on actions that result in a flag capture,
+        defense of the flag and your flag carrier and other
+        bonuses.</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="4" width="400">
+            <tr>
+                <td valign="top" colspan="2"><font face="Arial"><br>
+                <strong>Q2CTF Scoring</strong><br>
+                </font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Fragging
+                enemy player</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">One point</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Fragging
+                emery player within your base</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Two points.<br>
+                </font><font size="2" face="Arial">One Point for
+                the frag, one point for the base defense.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Fragging
+                enemy player within sight of your flag carrier</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Two points.<br>
+                </font><font size="2" face="Arial">One point for
+                the frag, one point for defending your flag
+                carrier.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Fragging
+                enemy player who has hurt your flag carrier</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Three points.<br>
+                </font><font size="2" face="Arial">One point for
+                the frag, two points for defending your flag
+                carrier against an aggressive enemy.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Fragging
+                enemy flag carrier</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Three points.<br>
+                </font><font size="2" face="Arial">One point for
+                the frag, two points for fragging the enemy flag
+                carrier.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Returning
+                your flag (after enemy player has lost it)</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">One point.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Getting an
+                assist for returning the flag (occurs if your
+                flag carrier captures within a few seconds of you
+                returning your flag).</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">One point.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Getting an
+                assist for fragging the enemy flag carrier
+                (occurs if you flag carrier captures within a few
+                seconds of you fragging the enemy flag carrier)</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">One point.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">Capturing the
+                enemy flag (you are the flag carrier)</font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">15 points.<br>
+                </font><font size="2" face="Arial">Everyone else
+                on your team gets 10 points.</font></td>
+            </tr>
+        </table>
+        </center></div><p><a name="#elect"></a></p>
+        <h3><font face="Arial">Elections</font></h3>
+        <p><font face="Arial">Elections are part of the new
+        competition mode for Q2CTF. They also can be used for
+        other features by users to change maps and other options.
+        Elections can occur during the following situations.</font></p>
+        <dl>
+            <dt><font face="Arial">Switching from normal to match
+                mode</font></dt>
+            <dd><font face="Arial">A user may make a selection
+                from the menu to request that the server switch
+                to match mode. If this selection is chosen, an
+                election will begin and run for twenty seconds.
+                If the election is won, the server will reset
+                into match mode; all players will be cleared and
+                placed at the join menu.</font></dd>
+            <dt><font face="Arial">Changing map (warp)</font></dt>
+            <dd><font face="Arial">If a user makes a map change
+                request (by using the &quot;warp &lt;map
+                name&gt;&quot; command) an election is started.
+                If the election is won, the game will enter the
+                intermission and then automatically change to the
+                new map.</font></dd>
+            <dt><font face="Arial">Requesting to become an admin</font></dt>
+            <dd><font face="Arial">A user can request to become
+                an administrator by typing 'admin' at the
+                console. An election will begin and if
+                successful, the user will gain access to the
+                admin menu. From here, the new admin can change
+                game settings, switch to match mode and warp to
+                different levels.</font></dd>
+        </dl>
+        <p><font face="Arial">To vote on an election, simply type
+        &quot;yes&quot; in the console. Votes are anonymous. If
+        enough people have voted (its server configurable, the
+        needed amount of votes is displayed), the election will
+        be won and the action requested will happen.</font><a
+        name="#compmode"></a></p>
+        <h3><font face="Arial">Competition mode</font></h3>
+        <p><font face="Arial">Q2CTF features a
+        tournament/competition mode that allows organized setup
+        of matches between two teams. The competition mode (once
+        it has been activated by an admin or by an election)
+        works in three stages:</font></p>
+        <ol>
+            <li><font face="Arial">When competition mode is
+                activated, the game enters the setup phase. This
+                where the players pick their teams, discuss
+                strategies and prepare for the match. Players can
+                move around the level, but can't pick up any
+                items or damage any enemy players. If the server
+                isn't dedicated to match play, there is a timer
+                in this phase that determines how long players
+                have to set up their game. If they don't set it
+                up in the needed period of time, the server will
+                reset back to normal play. When the players have
+                established their teams, each player must enter
+                'ready' to commit to the game. Once everyone has
+                committed, the game enters phase two. </font></li>
+            <li><font face="Arial">In this phase, everyone has
+                committed and the game is about to begin. There
+                is usually a twenty second countdown before the
+                match actually starts. During this time, any
+                player may enter 'notready' at the console to
+                abort the countdown. After the countdown
+                completes, phase three begins.</font></li>
+            <li><font face="Arial">At the point the match is
+                begin. Everyone is respawned (sometimes with a
+                small two or three second delay to even out the
+                spawns in the bases, if everyone respawned,
+                telefrags and overflows could occur) in their
+                base and the match begins. Players are also
+                assigned their ghost codes which can be used to
+                re-enter the game in case of a undesired
+                disconnection.</font></li>
+        </ol>
+        <p><font face="Arial">Phase three continues until the
+        match is completed (the default is a twenty minute
+        match), after which the final scores are displayed and
+        the server resets back to phase one.</font><a
+        name="#ghost"></a></p>
+        <h3><font color="#C0C0C0" face="Arial">Ghost Codes</font></h3>
+        <p><font face="Arial">Ghost codes is a special code given
+        to every player in the game when the match starts. This
+        code is used to track the players statistics and other
+        information and is also used to allow a player to enter a
+        game in case he lost connection.</font></p>
+        <p align="center"><img src="ghost.jpg" width="400"
+        height="150"></p>
+        <p><font face="Arial">As you can see in the image above,
+        just after the match started I was assigned a ghost code.
+        If I lost connection during the match, I could reconnect
+        to the server while the match was in progress and type
+        &quot;ghost 22632&quot; in the console and I would be
+        automatically put back into the game with the same team,
+        score and statistics I had just before I lost my
+        connection.</font><a name="#stats"></a></p>
+        <h3><font face="Arial">Statistics</font></h3>
+        <p><font face="Arial">The CTF match code also keeps
+        statistics of the game in progress and keeps them around
+        after the match has completed. The statistics may be
+        accessed by typing &quot;stats&quot; into the console.
+        The look like the image below:</font></p>
+        <p align="center"><img src="stats.jpg" width="600"
+        height="60"></p>
+        <p><font face="Arial">The statistics kept for each player
+        are:</font></p>
+        <ul>
+            <li><font face="Arial">Score<br>
+                How many points this player has accumulated.</font></li>
+            <li><font face="Arial">Kills<br>
+                How many frags this player has made.</font></li>
+            <li><font face="Arial">Death (Deaths)<br>
+                How many times this player has died.</font></li>
+            <li><font face="Arial">BasDf (Base Defenses)<br>
+                How many times this player got bonus points for
+                defending the base</font></li>
+            <li><font face="Arial">CarDf (Carrier Defense)<br>
+                How many times this player got bonus points for
+                defending his flag carrier</font></li>
+            <li><font face="Arial">Effcy (Efficiency)<br>
+                How efficient this player is when fighting other
+                players. It's calculated as (kills * 100) /
+                (kills + deaths)</font></li>
+        </ul>
+        <p><a name="#console"></a></p>
+        <h3><font face="Arial">New Console Commands</font></h3>
+        <p><font face="Arial">The following console commands have
+        been added for Q2CTF.</font></p>
+        <div align="center"><center><table border="0"
+        cellspacing="1" width="500">
+            <tr>
+                <td colspan="3"><font color="#C0C0C0" size="3"
+                face="Arial"><strong>Q2CTF Console Commands</strong></font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td width="30%"><font color="#00FF40"
+                face="Arial"><strong>Console Command and syntax</strong></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial"><strong>Description</strong></font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td nowrap><font color="#00FF40" face="Arial"><code><strong>team&nbsp;{
+                red |&nbsp;blue }</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Switches to the team the
+                player indicates</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>id</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Enables HUD identification
+                of the player you are looking at.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>yes</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Vote yes on an election.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>no</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Vote no on an election
+                (you must just abstain). A no vote counts against
+                the election percentage.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>ready</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Commit to the match in
+                match setup</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>notready</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Cease commitment (will
+                abort match countdown)</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>ghost
+                </strong></code><code><em><strong>ghost-code</strong></em></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Re-enter the game after
+                losing connection in a match (requires ghost code
+                that was provided)</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>admin&nbsp;[
+                </strong></code><code><em><strong>password</strong></em></code><code><strong>&nbsp;]</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Request to become an admin
+                by election, or with password become admin
+                automatically if the password matches. Once one
+                obtains admin status, the admin command by itself
+                will bring up the admin menu.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>stats</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Show the statistics of any
+                matches recently completed or in progress.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>warp
+                </strong></code><code><em><strong>level</strong></em></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Warp to a new level. It
+                must be one of the levels listed in the warp_list
+                cvar (see Server Operator section).</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>boot
+                </strong></code><code><em><strong>player-number</strong></em></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Kick a player off the
+                server. The number of the player can be
+                determined with the playerlist command.</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>playerlist</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">List out the player on a
+                server, their connect time, player number and
+                status (ready/notready, or admin).</font></td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+                <td>&nbsp;</td>
+            </tr>
+            <tr>
+                <td><font color="#00FF40" face="Arial"><code><strong>observer<br>
+                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong></code></font></td>
+                <td>&nbsp;</td>
+                <td><font face="Arial">Leave the current game and
+                become and observer (this resets your score to
+                zero).</font></td>
+            </tr>
+        </table>
+        </center></div><p><a name="#admin"></a></p>
+        <h3><font face="Arial">User admin functions</font></h3>
+        <p><font face="Arial">An admin has several function he
+        may perform. A user can become an admin by entering
+        &quot;admin&quot; at the console and starting an election
+        or by typing the admin password at the console with
+        &quot;admin &lt;password&gt;&quot; if a password is set.
+        The server operator can set an admin password using the
+        admin_password cvar.</font></p>
+        <p><font face="Arial">An admin can change settings, warp
+        to different maps and boot players from the server. Once
+        you become an admin, type &quot;admin&quot; again at the
+        console to access the admin menu.</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="8" cellspacing="0" width="550">
+            <tr>
+                <td valign="top"><img src="admin.gif" width="255"
+                height="189"></td>
+                <td><font size="2" face="Arial">The admin menu
+                (show left) has just a couple options. Settings
+                allows you to change game settings (shown below)
+                . The second option changes depending on what
+                state the server is in:<br>
+                </font><ul>
+                    <li><font size="2" face="Arial">Switch to
+                        match mode<br>
+                        This will switch the server from regular
+                        play to match/competition mode.</font></li>
+                    <li><font size="2" face="Arial">Force start
+                        match<br>
+                        If the server is in match mode and
+                        players are in the phase where they are
+                        setting up their teams, the admin can
+                        force the match to start regardless of
+                        the ready status of the players.</font></li>
+                    <li><font size="2" face="Arial">Cancel match<br>
+                        This will cancel the match that's
+                        currently in progress.</font></li>
+                </ul>
+                </td>
+            </tr>
+        </table>
+        </center></div><p><font face="Arial"><br clear="all">
+        The Settings menu has several options to allow the admin
+        to configure the server on the fly (some of these
+        settings are also applicable to normal play mode).</font></p>
+        <div align="center"><center><table border="0"
+        cellpadding="8" cellspacing="0" width="550">
+            <tr>
+                <td valign="top"><img src="adminset.gif"
+                align="left" hspace="0" width="255" height="190"></td>
+                <td valign="top"><font face="Arial">The menu
+                pictured on the left shows the different options
+                that an admin can change. They are:</font></td>
+            </tr>
+            <tr>
+                <td colspan="2"><ul>
+                    <li><font face="Arial">Match Len<br>
+                        This controls the length of the match.
+                        The default is a twenty minute match
+                        time. This <u>can</u> be changed while a
+                        match is in progress. For example, if a
+                        match started that was twenty minutes
+                        long and two minutes had already passed
+                        (so there was eighteen minutes remaining)
+                        and the admin changed the match length to
+                        ten minutes, the remaining time would
+                        automatically be changed to eight
+                        minutes. If the admin sets a match time
+                        less than the amount of time already
+                        passed, the match will immediately end.</font></li>
+                    <li><font face="Arial">Match Setup Len<br>
+                        This is the length of time that players
+                        get to setup a match before the server
+                        will reset back into normal play. This
+                        setting can be changed on the fly like
+                        Match Len (if a setup is in progress).</font></li>
+                    <li><font face="Arial">Match Start Len<br>
+                        This is the length of time before the
+                        match actually begins after everyone had
+                        committed by typing &quot;ready&quot; at
+                        the console. It should be pretty short.</font></li>
+                    <li><font face="Arial">Instant Items<br>
+                        This is the dmflag that controls whether
+                        powerups such as the Quad and
+                        Invulnerability are instantly used or may
+                        be carried and activated as desired.</font></li>
+                    <li><font face="Arial">Quad Drop<br>
+                        This is the dmflag that controls whether
+                        the quad is dropped when a player is
+                        fragged while carrying it.</font></li>
+                    <li><font face="Arial">Instant Weapons<br>
+                        This is a new option that allowed weapons
+                        to be switched without put away and
+                        activation animations. The weapons switch
+                        instantly.</font></li>
+                    <li><font face="Arial">Match Lock<br>
+                        If enabled (the default) players can not
+                        enter a match in progress (unless the
+                        have a ghost code). If disabled, anyone
+                        can enter a match while it's in progress.</font></li>
+                </ul>
+                </td>
+            </tr>
+        </table>
+        </center></div><p><font face="Arial">When you have made
+        your changes, simply select Apply to activate them.
+        Whatever you changed will be broadcast to everyone in the
+        game.<br clear="all">
+        </font><a name="#serverop"></a></p>
+        <h3><font face="Arial">Server Operator Information</font></h3>
+        <p><font face="Arial">A few notes for the server
+        operators.</font></p>
+        <ul>
+            <li><font face="Arial">You can change maps on a
+                server with two commands, &quot;map&quot; and
+                &quot;gamemap&quot;. Both take a map as a
+                parameter. They differ in CTF in that when a
+                &quot;map&quot; command is used, all player teams
+                are reset (and players must either select or be
+                assigned to new teams), where as the
+                &quot;gamemap&quot; command will retain the same
+                teams after the map change.</font></li>
+        </ul>
+        <p><font face="Arial">The following table lists the
+        various Cvars that can be configured by a server
+        operator. You can place them in a script file with
+        commands like &quot;set competition 3&quot; and then EXEC
+        that config file on server startup.</font></p>
+        <div align="center"><center><table border="0" width="500">
+            <tr>
+                <td valign="top" colspan="3"><font face="Arial"><br>
+                <strong>Q2CTF Specific CVar variables</strong><br>
+                </font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial"><strong>Variable</strong></font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>Default Value</strong></font></td>
+                <td><font face="Arial"><strong>Description</strong></font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">ctf</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>1</strong></font></td>
+                <td><font face="Arial">Enables CTF play. Normally
+                this should be enabled, but may be disabled to
+                allow deathmatch play with the Grapple and TECH
+                Powerups</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">ctf_forcejoin</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><em><strong>none</strong></em></font></td>
+                <td><font face="Arial">This may be set to
+                &quot;blue&quot; or &quot;red&quot; to force all
+                people joining a server to a specific team. This
+                may be handy when a player who has rcon access
+                wants to set up teams in a specific way.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">competition</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>0</strong></font></td>
+                <td valign="top"><font face="Arial">This variable
+                controls whether or not the server can be enabled
+                for match play. There are four legal values:<br>
+                </font><div align="center"><center><table
+                border="0">
+                    <tr>
+                        <td align="center" valign="top"
+                        width="20%"><font color="#00FF40"
+                        face="Arial">0</font></td>
+                        <td><font face="Arial">This value
+                        indicates that match play is not
+                        available on the server and can not be
+                        enabled by players (even with voting).<br>
+                        </font></td>
+                    </tr>
+                    <tr>
+                        <td align="center" valign="top"><font
+                        color="#00FF40" face="Arial">1</font></td>
+                        <td><font face="Arial">When this value is
+                        set, the server defaults to normal play
+                        (pick up CTF games) but can be changed to
+                        match play mode by an admin or by an
+                        election.<br>
+                        </font></td>
+                    </tr>
+                    <tr>
+                        <td align="center" valign="top"><font
+                        color="#00FF40" face="Arial">2</font></td>
+                        <td><font face="Arial">This value is set
+                        by the CTF game itself and should not be
+                        set directly. It indicates that a server
+                        has been voted into match play and will
+                        revert if the match setup times out.<br>
+                        </font></td>
+                    </tr>
+                    <tr>
+                        <td align="center" valign="top"><font
+                        color="#00FF40" face="Arial">3</font></td>
+                        <td><font face="Arial">This indicates
+                        that a server is in <strong>dedicated</strong>
+                        match play. The server stays in match
+                        mode at all times and does not time out
+                        and return to normal play.<br>
+                        </font></td>
+                    </tr>
+                </table>
+                </center></div></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">matchlock</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>1</strong></font></td>
+                <td><font face="Arial">This value controls
+                whether or not players can join a match in
+                progress (without a ghost code). Its default
+                value of one indicates that players can <strong>not</strong>
+                join a match in progress.<br>
+                This variable may be changed by and admin with
+                the admin settings menu.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">electpercentage</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>66</strong></font></td>
+                <td><font face="Arial">This controls how many
+                people out of the players on a server have to
+                vote in order for an election to be one. The
+                default is 66% which means that two thirds of the
+                players must vote in order for the election to
+                succeed.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">matchtime</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>20</strong></font></td>
+                <td><font face="Arial">Specifies the length of
+                time, in minutes, that the match will be played
+                for. Twenty minutes is the default standard match
+                time.<br>
+                This variable may be changed by and admin with
+                the admin settings menu.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">matchsetuptime</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>10</strong></font></td>
+                <td><font face="Arial">Specifics the length of
+                time, in minutes, that the setup phase before a
+                match must be started (by all players committing
+                by entering &quot;ready&quot; at the console). If
+                this time expires, the server will reset back
+                into normal play.<br>
+                This variable may be changed by and admin with
+                the admin settings menu.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">matchstarttime</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>20</strong></font></td>
+                <td><font face="Arial">This specifies, in
+                seconds, the amount of time after a match has
+                been committed (by all players entering
+                &quot;ready&quot; in their consoles) and the
+                actual start of the match.<br>
+                This variable may be changed by and admin with
+                the admin settings menu.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">admin_password</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><em><strong>none</strong></em></font></td>
+                <td><font face="Arial">This variable may be set
+                to a password that allows someone to grain admin
+                access without having to be elected. The admin
+                would just type &quot;admin
+                &lt;password&gt;&quot; to gain direct access to
+                the admin menu, assuming the password was
+                correct.<br>
+                For example, &quot;set admin_password bob&quot;
+                in a start up config file for the server would
+                set the password to &quot;bob&quot; and any
+                player could become an admin by typing
+                &quot;admin bob&quot; at the console.</font></td>
+            </tr>
+            <tr>
+                <td valign="top"><font face="Arial">warp_list</font></td>
+                <td valign="top"><font color="#00FF40"
+                face="Arial"><strong>&quot;q2ctf1 q2ctf2 q2ctf3
+                q2ctf4 q2ctf5&quot;</strong></font></td>
+                <td><font face="Arial">This variable is a space
+                separated list of maps that may be warped to on
+                the server using the warp command. Any base map
+                name (bsp file name) can be specified. Admins and
+                players who start elections for warp requests
+                must specific a map in this list.</font></td>
+            </tr>
+        </table>
+        </center></div></td>
+        <td>&nbsp;&nbsp;</td>
+        <td bgcolor="#400000">&nbsp;</td>
+    </tr>
+</table>
+</center></div>
+</body>
+</html>
+
\ No newline at end of file
binary files /dev/null b/ctf/docs/say_team.gif differ
binary files /dev/null b/ctf/docs/stats.jpg differ
binary files /dev/null b/ctf/docs/tech1.gif differ
binary files /dev/null b/ctf/docs/tech2.gif differ
binary files /dev/null b/ctf/docs/tech3.gif differ
binary files /dev/null b/ctf/docs/tech4.gif differ
--- /dev/null
+++ b/ctf/g_ai.c
@@ -1,0 +1,1117 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_ai.c
+
+#include "g_local.h"
+
+qboolean FindTarget (edict_t *self);
+extern cvar_t	*maxclients;
+
+qboolean ai_checkattack (edict_t *self, float dist);
+
+qboolean	enemy_vis;
+qboolean	enemy_infront;
+int			enemy_range;
+float		enemy_yaw;
+
+//============================================================================
+
+
+/*
+=================
+AI_SetSightClient
+
+Called once each frame to set level.sight_client to the
+player to be checked for in findtarget.
+
+If all clients are either dead or in notarget, sight_client
+will be null.
+
+In coop games, sight_client will cycle between the clients.
+=================
+*/
+void AI_SetSightClient (void)
+{
+	edict_t	*ent;
+	int		start, check;
+
+	if (level.sight_client == NULL)
+		start = 1;
+	else
+		start = level.sight_client - g_edicts;
+
+	check = start;
+	while (1)
+	{
+		check++;
+		if (check > game.maxclients)
+			check = 1;
+		ent = &g_edicts[check];
+		if (ent->inuse
+			&& ent->health > 0
+			&& !(ent->flags & FL_NOTARGET) )
+		{
+			level.sight_client = ent;
+			return;		// got one
+		}
+		if (check == start)
+		{
+			level.sight_client = NULL;
+			return;		// nobody to see
+		}
+	}
+}
+
+//============================================================================
+
+/*
+=============
+ai_move
+
+Move the specified distance at current facing.
+This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward
+==============
+*/
+void ai_move (edict_t *self, float dist)
+{
+	M_walkmove (self, self->s.angles[YAW], dist);
+}
+
+
+/*
+=============
+ai_stand
+
+Used for standing around and looking for players
+Distance is for slight position adjustments needed by the animations
+==============
+*/
+void ai_stand (edict_t *self, float dist)
+{
+	vec3_t	v;
+
+	if (dist)
+		M_walkmove (self, self->s.angles[YAW], dist);
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		if (self->enemy)
+		{
+			VectorSubtract (self->enemy->s.origin, self->s.origin, v);
+			self->ideal_yaw = vectoyaw(v);
+			if (self->s.angles[YAW] != self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
+			{
+				self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+				self->monsterinfo.run (self);
+			}
+			M_ChangeYaw (self);
+			ai_checkattack (self, 0);
+		}
+		else
+			FindTarget (self);
+		return;
+	}
+
+	if (FindTarget (self))
+		return;
+	
+	if (level.time > self->monsterinfo.pausetime)
+	{
+		self->monsterinfo.walk (self);
+		return;
+	}
+
+	if (!(self->spawnflags & 1) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time))
+	{
+		if (self->monsterinfo.idle_time)
+		{
+			self->monsterinfo.idle (self);
+			self->monsterinfo.idle_time = level.time + 15 + random() * 15;
+		}
+		else
+		{
+			self->monsterinfo.idle_time = level.time + random() * 15;
+		}
+	}
+}
+
+
+/*
+=============
+ai_walk
+
+The monster is walking it's beat
+=============
+*/
+void ai_walk (edict_t *self, float dist)
+{
+	M_MoveToGoal (self, dist);
+
+	// check for noticing a player
+	if (FindTarget (self))
+		return;
+
+	if ((self->monsterinfo.search) && (level.time > self->monsterinfo.idle_time))
+	{
+		if (self->monsterinfo.idle_time)
+		{
+			self->monsterinfo.search (self);
+			self->monsterinfo.idle_time = level.time + 15 + random() * 15;
+		}
+		else
+		{
+			self->monsterinfo.idle_time = level.time + random() * 15;
+		}
+	}
+}
+
+
+/*
+=============
+ai_charge
+
+Turns towards target and advances
+Use this call with a distnace of 0 to replace ai_face
+==============
+*/
+void ai_charge (edict_t *self, float dist)
+{
+	vec3_t	v;
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, v);
+	self->ideal_yaw = vectoyaw(v);
+	M_ChangeYaw (self);
+
+	if (dist)
+		M_walkmove (self, self->s.angles[YAW], dist);
+}
+
+
+/*
+=============
+ai_turn
+
+don't move, but turn towards ideal_yaw
+Distance is for slight position adjustments needed by the animations
+=============
+*/
+void ai_turn (edict_t *self, float dist)
+{
+	if (dist)
+		M_walkmove (self, self->s.angles[YAW], dist);
+
+	if (FindTarget (self))
+		return;
+	
+	M_ChangeYaw (self);
+}
+
+
+/*
+
+.enemy
+Will be world if not currently angry at anyone.
+
+.movetarget
+The next path spot to walk toward.  If .enemy, ignore .movetarget.
+When an enemy is killed, the monster will try to return to it's path.
+
+.hunt_time
+Set to time + something when the player is in sight, but movement straight for
+him is blocked.  This causes the monster to use wall following code for
+movement direction instead of sighting on the player.
+
+.ideal_yaw
+A yaw angle of the intended direction, which will be turned towards at up
+to 45 deg / state.  If the enemy is in view and hunt_time is not active,
+this will be the exact line towards the enemy.
+
+.pausetime
+A monster will leave it's stand state and head towards it's .movetarget when
+time > .pausetime.
+
+walkmove(angle, speed) primitive is all or nothing
+*/
+
+/*
+=============
+range
+
+returns the range catagorization of an entity reletive to self
+0	melee range, will become hostile even if back is turned
+1	visibility and infront, or visibility and show hostile
+2	infront and show hostile
+3	only triggered by damage
+=============
+*/
+int range (edict_t *self, edict_t *other)
+{
+	vec3_t	v;
+	float	len;
+
+	VectorSubtract (self->s.origin, other->s.origin, v);
+	len = VectorLength (v);
+	if (len < MELEE_DISTANCE)
+		return RANGE_MELEE;
+	if (len < 500)
+		return RANGE_NEAR;
+	if (len < 1000)
+		return RANGE_MID;
+	return RANGE_FAR;
+}
+
+/*
+=============
+visible
+
+returns 1 if the entity is visible to self, even if not infront ()
+=============
+*/
+qboolean visible (edict_t *self, edict_t *other)
+{
+	vec3_t	spot1;
+	vec3_t	spot2;
+	trace_t	trace;
+
+	VectorCopy (self->s.origin, spot1);
+	spot1[2] += self->viewheight;
+	VectorCopy (other->s.origin, spot2);
+	spot2[2] += other->viewheight;
+	trace = gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
+	
+	if (trace.fraction == 1.0)
+		return true;
+	return false;
+}
+
+
+/*
+=============
+infront
+
+returns 1 if the entity is in front (in sight) of self
+=============
+*/
+qboolean infront (edict_t *self, edict_t *other)
+{
+	vec3_t	vec;
+	float	dot;
+	vec3_t	forward;
+	
+	AngleVectors (self->s.angles, forward, NULL, NULL);
+	VectorSubtract (other->s.origin, self->s.origin, vec);
+	VectorNormalize (vec);
+	dot = DotProduct (vec, forward);
+	
+	if (dot > 0.3)
+		return true;
+	return false;
+}
+
+
+//============================================================================
+
+void HuntTarget (edict_t *self)
+{
+	vec3_t	vec;
+
+	self->goalentity = self->enemy;
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.stand (self);
+	else
+		self->monsterinfo.run (self);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	self->ideal_yaw = vectoyaw(vec);
+	// wait a while before first attack
+	if (!(self->monsterinfo.aiflags & AI_STAND_GROUND))
+		AttackFinished (self, 1);
+}
+
+void FoundTarget (edict_t *self)
+{
+	// let other monsters see this monster for a while
+	if (self->enemy->client)
+	{
+		level.sight_entity = self;
+		level.sight_entity_framenum = level.framenum;
+		level.sight_entity->light_level = 128;
+	}
+
+	self->show_hostile = level.time + 1;		// wake up other monsters
+
+	VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
+	self->monsterinfo.trail_time = level.time;
+
+	if (!self->combattarget)
+	{
+		HuntTarget (self);
+		return;
+	}
+
+	self->goalentity = self->movetarget = G_PickTarget(self->combattarget);
+	if (!self->movetarget)
+	{
+		self->goalentity = self->movetarget = self->enemy;
+		HuntTarget (self);
+		gi.dprintf("%s at %s, combattarget %s not found\n", self->classname, vtos(self->s.origin), self->combattarget);
+		return;
+	}
+
+	// clear out our combattarget, these are a one shot deal
+	self->combattarget = NULL;
+	self->monsterinfo.aiflags |= AI_COMBAT_POINT;
+
+	// clear the targetname, that point is ours!
+	self->movetarget->targetname = NULL;
+	self->monsterinfo.pausetime = 0;
+
+	// run for it
+	self->monsterinfo.run (self);
+}
+
+
+/*
+===========
+FindTarget
+
+Self is currently not attacking anything, so try to find a target
+
+Returns TRUE if an enemy was sighted
+
+When a player fires a missile, the point of impact becomes a fakeplayer so
+that monsters that see the impact will respond as if they had seen the
+player.
+
+To avoid spending too much time, only a single client (or fakeclient) is
+checked each frame.  This means multi player games will have slightly
+slower noticing monsters.
+============
+*/
+qboolean FindTarget (edict_t *self)
+{
+	edict_t		*client;
+	qboolean	heardit;
+	int			r;
+
+	if (self->monsterinfo.aiflags & AI_GOOD_GUY)
+	{
+		if (self->goalentity && self->goalentity->inuse && self->goalentity->classname)
+		{
+			if (strcmp(self->goalentity->classname, "target_actor") == 0)
+				return false;
+		}
+
+		//FIXME look for monsters?
+		return false;
+	}
+
+	// if we're going to a combat point, just proceed
+	if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
+		return false;
+
+// if the first spawnflag bit is set, the monster will only wake up on
+// really seeing the player, not another monster getting angry or hearing
+// something
+
+// revised behavior so they will wake up if they "see" a player make a noise
+// but not weapon impact/explosion noises
+
+	heardit = false;
+	if ((level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
+	{
+		client = level.sight_entity;
+		if (client->enemy == self->enemy)
+		{
+			return false;
+		}
+	}
+	else if (level.sound_entity_framenum >= (level.framenum - 1))
+	{
+		client = level.sound_entity;
+		heardit = true;
+	}
+	else if (!(self->enemy) && (level.sound2_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
+	{
+		client = level.sound2_entity;
+		heardit = true;
+	}
+	else
+	{
+		client = level.sight_client;
+		if (!client)
+			return false;	// no clients to get mad at
+	}
+
+	// if the entity went away, forget it
+	if (!client->inuse)
+		return false;
+
+	if (client == self->enemy)
+		return true;	// JDC false;
+
+	if (client->client)
+	{
+		if (client->flags & FL_NOTARGET)
+			return false;
+	}
+	else if (client->svflags & SVF_MONSTER)
+	{
+		if (!client->enemy)
+			return false;
+		if (client->enemy->flags & FL_NOTARGET)
+			return false;
+	}
+	else if (heardit)
+	{
+		if (client->owner->flags & FL_NOTARGET)
+			return false;
+	}
+	else
+		return false;
+
+	if (!heardit)
+	{
+		r = range (self, client);
+
+		if (r == RANGE_FAR)
+			return false;
+
+// this is where we would check invisibility
+
+		// is client in an spot too dark to be seen?
+		if (client->light_level <= 5)
+			return false;
+
+		if (!visible (self, client))
+		{
+			return false;
+		}
+
+		if (r == RANGE_NEAR)
+		{
+			if (client->show_hostile < level.time && !infront (self, client))
+			{
+				return false;
+			}
+		}
+		else if (r == RANGE_MID)
+		{
+			if (!infront (self, client))
+			{
+				return false;
+			}
+		}
+
+		self->enemy = client;
+
+		if (strcmp(self->enemy->classname, "player_noise") != 0)
+		{
+			self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+
+			if (!self->enemy->client)
+			{
+				self->enemy = self->enemy->enemy;
+				if (!self->enemy->client)
+				{
+					self->enemy = NULL;
+					return false;
+				}
+			}
+		}
+	}
+	else	// heardit
+	{
+		vec3_t	temp;
+
+		if (self->spawnflags & 1)
+		{
+			if (!visible (self, client))
+				return false;
+		}
+		else
+		{
+			if (!gi.inPHS(self->s.origin, client->s.origin))
+				return false;
+		}
+
+		VectorSubtract (client->s.origin, self->s.origin, temp);
+
+		if (VectorLength(temp) > 1000)	// too far to hear
+		{
+			return false;
+		}
+
+		// check area portals - if they are different and not connected then we can't hear it
+		if (client->areanum != self->areanum)
+			if (!gi.AreasConnected(self->areanum, client->areanum))
+				return false;
+
+		self->ideal_yaw = vectoyaw(temp);
+		M_ChangeYaw (self);
+
+		// hunt the sound for a bit; hopefully find the real player
+		self->monsterinfo.aiflags |= AI_SOUND_TARGET;
+		self->enemy = client;
+	}
+
+//
+// got one
+//
+	FoundTarget (self);
+
+	if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) && (self->monsterinfo.sight))
+		self->monsterinfo.sight (self, self->enemy);
+
+	return true;
+}
+
+
+//=============================================================================
+
+/*
+============
+FacingIdeal
+
+============
+*/
+qboolean FacingIdeal(edict_t *self)
+{
+	float	delta;
+
+	delta = anglemod(self->s.angles[YAW] - self->ideal_yaw);
+	if (delta > 45 && delta < 315)
+		return false;
+	return true;
+}
+
+
+//=============================================================================
+
+qboolean M_CheckAttack (edict_t *self)
+{
+	vec3_t	spot1, spot2;
+	float	chance;
+	trace_t	tr;
+
+	if (self->enemy->health > 0)
+	{
+	// see if any entities are in the way of the shot
+		VectorCopy (self->s.origin, spot1);
+		spot1[2] += self->viewheight;
+		VectorCopy (self->enemy->s.origin, spot2);
+		spot2[2] += self->enemy->viewheight;
+
+		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WINDOW);
+
+		// do we have a clear shot?
+		if (tr.ent != self->enemy)
+			return false;
+	}
+	
+	// melee attack
+	if (enemy_range == RANGE_MELEE)
+	{
+		// don't always melee in easy mode
+		if (skill->value == 0 && (rand()&3) )
+			return false;
+		if (self->monsterinfo.melee)
+			self->monsterinfo.attack_state = AS_MELEE;
+		else
+			self->monsterinfo.attack_state = AS_MISSILE;
+		return true;
+	}
+	
+// missile attack
+	if (!self->monsterinfo.attack)
+		return false;
+		
+	if (level.time < self->monsterinfo.attack_finished)
+		return false;
+		
+	if (enemy_range == RANGE_FAR)
+		return false;
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MELEE)
+	{
+		chance = 0.2;
+	}
+	else if (enemy_range == RANGE_NEAR)
+	{
+		chance = 0.1;
+	}
+	else if (enemy_range == RANGE_MID)
+	{
+		chance = 0.02;
+	}
+	else
+	{
+		return false;
+	}
+
+	if (skill->value == 0)
+		chance *= 0.5;
+	else if (skill->value >= 2)
+		chance *= 2;
+
+	if (random () < chance)
+	{
+		self->monsterinfo.attack_state = AS_MISSILE;
+		self->monsterinfo.attack_finished = level.time + 2*random();
+		return true;
+	}
+
+	if (self->flags & FL_FLY)
+	{
+		if (random() < 0.3)
+			self->monsterinfo.attack_state = AS_SLIDING;
+		else
+			self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+
+	return false;
+}
+
+
+/*
+=============
+ai_run_melee
+
+Turn and close until within an angle to launch a melee attack
+=============
+*/
+void ai_run_melee(edict_t *self)
+{
+	self->ideal_yaw = enemy_yaw;
+	M_ChangeYaw (self);
+
+	if (FacingIdeal(self))
+	{
+		self->monsterinfo.melee (self);
+		self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+}
+
+
+/*
+=============
+ai_run_missile
+
+Turn in place until within an angle to launch a missile attack
+=============
+*/
+void ai_run_missile(edict_t *self)
+{
+	self->ideal_yaw = enemy_yaw;
+	M_ChangeYaw (self);
+
+	if (FacingIdeal(self))
+	{
+		self->monsterinfo.attack (self);
+		self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+};
+
+
+/*
+=============
+ai_run_slide
+
+Strafe sideways, but stay at aproximately the same range
+=============
+*/
+void ai_run_slide(edict_t *self, float distance)
+{
+	float	ofs;
+	
+	self->ideal_yaw = enemy_yaw;
+	M_ChangeYaw (self);
+
+	if (self->monsterinfo.lefty)
+		ofs = 90;
+	else
+		ofs = -90;
+	
+	if (M_walkmove (self, self->ideal_yaw + ofs, distance))
+		return;
+		
+	self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
+	M_walkmove (self, self->ideal_yaw - ofs, distance);
+}
+
+
+/*
+=============
+ai_checkattack
+
+Decides if we're going to attack or do something else
+used by ai_run and ai_stand
+=============
+*/
+qboolean ai_checkattack (edict_t *self, float dist)
+{
+	vec3_t		temp;
+	qboolean	hesDeadJim;
+
+// this causes monsters to run blindly to the combat point w/o firing
+	if (self->goalentity)
+	{
+		if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
+			return false;
+
+		if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
+		{
+			if ((level.time - self->enemy->teleport_time) > 5.0)
+			{
+				if (self->goalentity == self->enemy)
+					if (self->movetarget)
+						self->goalentity = self->movetarget;
+					else
+						self->goalentity = NULL;
+				self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+				if (self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
+					self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+			}
+			else
+			{
+				self->show_hostile = level.time + 1;
+				return false;
+			}
+		}
+	}
+
+	enemy_vis = false;
+
+// see if the enemy is dead
+	hesDeadJim = false;
+	if ((!self->enemy) || (!self->enemy->inuse))
+	{
+		hesDeadJim = true;
+	}
+	else if (self->monsterinfo.aiflags & AI_MEDIC)
+	{
+		if (self->enemy->health > 0)
+		{
+			hesDeadJim = true;
+			self->monsterinfo.aiflags &= ~AI_MEDIC;
+		}
+	}
+	else
+	{
+		if (self->monsterinfo.aiflags & AI_BRUTAL)
+		{
+			if (self->enemy->health <= -80)
+				hesDeadJim = true;
+		}
+		else
+		{
+			if (self->enemy->health <= 0)
+				hesDeadJim = true;
+		}
+	}
+
+	if (hesDeadJim)
+	{
+		self->enemy = NULL;
+	// FIXME: look all around for other targets
+		if (self->oldenemy && self->oldenemy->health > 0)
+		{
+			self->enemy = self->oldenemy;
+			self->oldenemy = NULL;
+			HuntTarget (self);
+		}
+		else
+		{
+			if (self->movetarget)
+			{
+				self->goalentity = self->movetarget;
+				self->monsterinfo.walk (self);
+			}
+			else
+			{
+				// we need the pausetime otherwise the stand code
+				// will just revert to walking with no target and
+				// the monsters will wonder around aimlessly trying
+				// to hunt the world entity
+				self->monsterinfo.pausetime = level.time + 100000000;
+				self->monsterinfo.stand (self);
+			}
+			return true;
+		}
+	}
+
+	self->show_hostile = level.time + 1;		// wake up other monsters
+
+// check knowledge of enemy
+	enemy_vis = visible(self, self->enemy);
+	if (enemy_vis)
+	{
+		self->monsterinfo.search_time = level.time + 5;
+		VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
+	}
+
+// look for other coop players here
+//	if (coop && self->monsterinfo.search_time < level.time)
+//	{
+//		if (FindTarget (self))
+//			return true;
+//	}
+
+	enemy_infront = infront(self, self->enemy);
+	enemy_range = range(self, self->enemy);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
+	enemy_yaw = vectoyaw(temp);
+
+
+	// JDC self->ideal_yaw = enemy_yaw;
+
+	if (self->monsterinfo.attack_state == AS_MISSILE)
+	{
+		ai_run_missile (self);
+		return true;
+	}
+	if (self->monsterinfo.attack_state == AS_MELEE)
+	{
+		ai_run_melee (self);
+		return true;
+	}
+
+	// if enemy is not currently visible, we will never attack
+	if (!enemy_vis)
+		return false;
+
+	return self->monsterinfo.checkattack (self);
+}
+
+
+/*
+=============
+ai_run
+
+The monster has an enemy it is trying to kill
+=============
+*/
+void ai_run (edict_t *self, float dist)
+{
+	vec3_t		v;
+	edict_t		*tempgoal;
+	edict_t		*save;
+	qboolean	new;
+	edict_t		*marker;
+	float		d1, d2;
+	trace_t		tr;
+	vec3_t		v_forward, v_right;
+	float		left, center, right;
+	vec3_t		left_target, right_target;
+
+	// if we're going to a combat point, just proceed
+	if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
+	{
+		M_MoveToGoal (self, dist);
+		return;
+	}
+
+	if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
+	{
+		VectorSubtract (self->s.origin, self->enemy->s.origin, v);
+		if (VectorLength(v) < 64)
+		{
+			self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+			self->monsterinfo.stand (self);
+			return;
+		}
+
+		M_MoveToGoal (self, dist);
+
+		if (!FindTarget (self))
+			return;
+	}
+
+	if (ai_checkattack (self, dist))
+		return;
+
+	if (self->monsterinfo.attack_state == AS_SLIDING)
+	{
+		ai_run_slide (self, dist);
+		return;
+	}
+
+	if (enemy_vis)
+	{
+//		if (self.aiflags & AI_LOST_SIGHT)
+//			dprint("regained sight\n");
+		M_MoveToGoal (self, dist);
+		self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+		VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
+		self->monsterinfo.trail_time = level.time;
+		return;
+	}
+
+	// coop will change to another enemy if visible
+	if (coop->value)
+	{	// FIXME: insane guys get mad with this, which causes crashes!
+		if (FindTarget (self))
+			return;
+	}
+
+	if ((self->monsterinfo.search_time) && (level.time > (self->monsterinfo.search_time + 20)))
+	{
+		M_MoveToGoal (self, dist);
+		self->monsterinfo.search_time = 0;
+//		dprint("search timeout\n");
+		return;
+	}
+
+	save = self->goalentity;
+	tempgoal = G_Spawn();
+	self->goalentity = tempgoal;
+
+	new = false;
+
+	if (!(self->monsterinfo.aiflags & AI_LOST_SIGHT))
+	{
+		// just lost sight of the player, decide where to go first
+//		dprint("lost sight of player, last seen at "); dprint(vtos(self.last_sighting)); dprint("\n");
+		self->monsterinfo.aiflags |= (AI_LOST_SIGHT | AI_PURSUIT_LAST_SEEN);
+		self->monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP);
+		new = true;
+	}
+
+	if (self->monsterinfo.aiflags & AI_PURSUE_NEXT)
+	{
+		self->monsterinfo.aiflags &= ~AI_PURSUE_NEXT;
+//		dprint("reached current goal: "); dprint(vtos(self.origin)); dprint(" "); dprint(vtos(self.last_sighting)); dprint(" "); dprint(ftos(vlen(self.origin - self.last_sighting))); dprint("\n");
+
+		// give ourself more time since we got this far
+		self->monsterinfo.search_time = level.time + 5;
+
+		if (self->monsterinfo.aiflags & AI_PURSUE_TEMP)
+		{
+//			dprint("was temp goal; retrying original\n");
+			self->monsterinfo.aiflags &= ~AI_PURSUE_TEMP;
+			marker = NULL;
+			VectorCopy (self->monsterinfo.saved_goal, self->monsterinfo.last_sighting);
+			new = true;
+		}
+		else if (self->monsterinfo.aiflags & AI_PURSUIT_LAST_SEEN)
+		{
+			self->monsterinfo.aiflags &= ~AI_PURSUIT_LAST_SEEN;
+			marker = PlayerTrail_PickFirst (self);
+		}
+		else
+		{
+			marker = PlayerTrail_PickNext (self);
+		}
+
+		if (marker)
+		{
+			VectorCopy (marker->s.origin, self->monsterinfo.last_sighting);
+			self->monsterinfo.trail_time = marker->timestamp;
+			self->s.angles[YAW] = self->ideal_yaw = marker->s.angles[YAW];
+//			dprint("heading is "); dprint(ftos(self.ideal_yaw)); dprint("\n");
+
+//			debug_drawline(self.origin, self.last_sighting, 52);
+			new = true;
+		}
+	}
+
+	VectorSubtract (self->s.origin, self->monsterinfo.last_sighting, v);
+	d1 = VectorLength(v);
+	if (d1 <= dist)
+	{
+		self->monsterinfo.aiflags |= AI_PURSUE_NEXT;
+		dist = d1;
+	}
+
+	VectorCopy (self->monsterinfo.last_sighting, self->goalentity->s.origin);
+
+	if (new)
+	{
+//		gi.dprintf("checking for course correction\n");
+
+		tr = gi.trace(self->s.origin, self->mins, self->maxs, self->monsterinfo.last_sighting, self, MASK_PLAYERSOLID);
+		if (tr.fraction < 1)
+		{
+			VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+			d1 = VectorLength(v);
+			center = tr.fraction;
+			d2 = d1 * ((center+1)/2);
+			self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
+			AngleVectors(self->s.angles, v_forward, v_right, NULL);
+
+			VectorSet(v, d2, -16, 0);
+			G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
+			tr = gi.trace(self->s.origin, self->mins, self->maxs, left_target, self, MASK_PLAYERSOLID);
+			left = tr.fraction;
+
+			VectorSet(v, d2, 16, 0);
+			G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
+			tr = gi.trace(self->s.origin, self->mins, self->maxs, right_target, self, MASK_PLAYERSOLID);
+			right = tr.fraction;
+
+			center = (d1*center)/d2;
+			if (left >= center && left > right)
+			{
+				if (left < 1)
+				{
+					VectorSet(v, d2 * left * 0.5, -16, 0);
+					G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
+//					gi.dprintf("incomplete path, go part way and adjust again\n");
+				}
+				VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal);
+				self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
+				VectorCopy (left_target, self->goalentity->s.origin);
+				VectorCopy (left_target, self->monsterinfo.last_sighting);
+				VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+				self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
+//				gi.dprintf("adjusted left\n");
+//				debug_drawline(self.origin, self.last_sighting, 152);
+			}
+			else if (right >= center && right > left)
+			{
+				if (right < 1)
+				{
+					VectorSet(v, d2 * right * 0.5, 16, 0);
+					G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
+//					gi.dprintf("incomplete path, go part way and adjust again\n");
+				}
+				VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal);
+				self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
+				VectorCopy (right_target, self->goalentity->s.origin);
+				VectorCopy (right_target, self->monsterinfo.last_sighting);
+				VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+				self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
+//				gi.dprintf("adjusted right\n");
+//				debug_drawline(self.origin, self.last_sighting, 152);
+			}
+		}
+//		else gi.dprintf("course was fine\n");
+	}
+
+	M_MoveToGoal (self, dist);
+
+	G_FreeEdict(tempgoal);
+
+	if (self)
+		self->goalentity = save;
+}
--- /dev/null
+++ b/ctf/g_chase.c
@@ -1,0 +1,157 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+void UpdateChaseCam(edict_t *ent)
+{
+	vec3_t o, ownerv, goal;
+	edict_t *targ;
+	vec3_t forward, right;
+	trace_t trace;
+	int i;
+	vec3_t oldgoal;
+	vec3_t angles;
+
+	// is our chase target gone?
+	if (!ent->client->chase_target->inuse) {
+		ent->client->chase_target = NULL;
+		return;
+	}
+
+	targ = ent->client->chase_target;
+
+	VectorCopy(targ->s.origin, ownerv);
+	VectorCopy(ent->s.origin, oldgoal);
+
+	ownerv[2] += targ->viewheight;
+
+	VectorCopy(targ->client->v_angle, angles);
+	if (angles[PITCH] > 56)
+		angles[PITCH] = 56;
+	AngleVectors (angles, forward, right, NULL);
+	VectorNormalize(forward);
+	VectorMA(ownerv, -30, forward, o);
+
+	if (o[2] < targ->s.origin[2] + 20)
+		o[2] = targ->s.origin[2] + 20;
+
+	// jump animation lifts
+	if (!targ->groundentity)
+		o[2] += 16;
+
+	trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+
+	VectorCopy(trace.endpos, goal);
+
+	VectorMA(goal, 2, forward, goal);
+
+	// pad for floors and ceilings
+	VectorCopy(goal, o);
+	o[2] += 6;
+	trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+	if (trace.fraction < 1) {
+		VectorCopy(trace.endpos, goal);
+		goal[2] -= 6;
+	}
+
+	VectorCopy(goal, o);
+	o[2] -= 6;
+	trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+	if (trace.fraction < 1) {
+		VectorCopy(trace.endpos, goal);
+		goal[2] += 6;
+	}
+
+	ent->client->ps.pmove.pm_type = PM_FREEZE;
+
+	VectorCopy(goal, ent->s.origin);
+	for (i=0 ; i<3 ; i++)
+		ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
+
+	VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
+	VectorCopy(targ->client->v_angle, ent->client->v_angle);
+
+	ent->viewheight = 0;
+	ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
+	gi.linkentity(ent);
+
+	if ((!ent->client->showscores && !ent->client->menu &&
+		!ent->client->showinventory && !ent->client->showhelp &&
+		!(level.framenum & 31)) || ent->client->update_chase) {
+		char s[1024];
+
+		ent->client->update_chase = false;
+		sprintf(s, "xv 0 yb -68 string2 \"Chasing %s\"",
+			targ->client->pers.netname);
+		gi.WriteByte (svc_layout);
+		gi.WriteString (s);
+		gi.unicast(ent, false);
+	}
+
+}
+
+void ChaseNext(edict_t *ent)
+{
+	int i;
+	edict_t *e;
+
+	if (!ent->client->chase_target)
+		return;
+
+	i = ent->client->chase_target - g_edicts;
+	do {
+		i++;
+		if (i > maxclients->value)
+			i = 1;
+		e = g_edicts + i;
+		if (!e->inuse)
+			continue;
+		if (e->solid != SOLID_NOT)
+			break;
+	} while (e != ent->client->chase_target);
+
+	ent->client->chase_target = e;
+	ent->client->update_chase = true;
+}
+
+void ChasePrev(edict_t *ent)
+{
+	int i;
+	edict_t *e;
+
+	if (!ent->client->chase_target)
+		return;
+
+	i = ent->client->chase_target - g_edicts;
+	do {
+		i--;
+		if (i < 1)
+			i = maxclients->value;
+		e = g_edicts + i;
+		if (!e->inuse)
+			continue;
+		if (e->solid != SOLID_NOT)
+			break;
+	} while (e != ent->client->chase_target);
+
+	ent->client->chase_target = e;
+	ent->client->update_chase = true;
+}
--- /dev/null
+++ b/ctf/g_cmds.c
@@ -1,0 +1,1066 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+
+char *ClientTeam (edict_t *ent)
+{
+	char		*p;
+	static char	value[512];
+
+	value[0] = 0;
+
+	if (!ent->client)
+		return value;
+
+	strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
+	p = strchr(value, '/');
+	if (!p)
+		return value;
+
+	if ((int)(dmflags->value) & DF_MODELTEAMS)
+	{
+		*p = 0;
+		return value;
+	}
+
+	// if ((int)(dmflags->value) & DF_SKINTEAMS)
+	return ++p;
+}
+
+qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
+{
+	char	ent1Team [512];
+	char	ent2Team [512];
+
+	if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
+		return false;
+
+	strcpy (ent1Team, ClientTeam (ent1));
+	strcpy (ent2Team, ClientTeam (ent2));
+
+	if (strcmp(ent1Team, ent2Team) == 0)
+		return true;
+	return false;
+}
+
+
+void SelectNextItem (edict_t *ent, int itflags)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+
+	cl = ent->client;
+
+//ZOID
+	if (cl->menu) {
+		PMenu_Next(ent);
+		return;
+	} else if (cl->chase_target) {
+		ChaseNext(ent);
+		return;
+	}
+//ZOID
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (cl->pers.selected_item + i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (!(it->flags & itflags))
+			continue;
+
+		cl->pers.selected_item = index;
+		return;
+	}
+
+	cl->pers.selected_item = -1;
+}
+
+void SelectPrevItem (edict_t *ent, int itflags)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+
+	cl = ent->client;
+
+//ZOID
+	if (cl->menu) {
+		PMenu_Prev(ent);
+		return;
+	} else if (cl->chase_target) {
+		ChasePrev(ent);
+		return;
+	}
+//ZOID
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (cl->pers.selected_item + MAX_ITEMS - i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (!(it->flags & itflags))
+			continue;
+
+		cl->pers.selected_item = index;
+		return;
+	}
+
+	cl->pers.selected_item = -1;
+}
+
+void ValidateSelectedItem (edict_t *ent)
+{
+	gclient_t	*cl;
+
+	cl = ent->client;
+
+	if (cl->pers.inventory[cl->pers.selected_item])
+		return;		// valid
+
+	SelectNextItem (ent, -1);
+}
+
+
+//=================================================================================
+
+/*
+==================
+Cmd_Give_f
+
+Give items to a client
+==================
+*/
+void Cmd_Give_f (edict_t *ent)
+{
+	char		*name;
+	gitem_t		*it;
+	int			index;
+	int			i;
+	qboolean	give_all;
+	edict_t		*it_ent;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	name = gi.args();
+
+	if (Q_stricmp(name, "all") == 0)
+		give_all = true;
+	else
+		give_all = false;
+
+	if (give_all || Q_stricmp(gi.argv(1), "health") == 0)
+	{
+		if (gi.argc() == 3)
+			ent->health = atoi(gi.argv(2));
+		else
+			ent->health = ent->max_health;
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "weapons") == 0)
+	{
+		for (i=0 ; i<game.num_items ; i++)
+		{
+			it = itemlist + i;
+			if (!it->pickup)
+				continue;
+			if (!(it->flags & IT_WEAPON))
+				continue;
+			ent->client->pers.inventory[i] += 1;
+		}
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "ammo") == 0)
+	{
+		for (i=0 ; i<game.num_items ; i++)
+		{
+			it = itemlist + i;
+			if (!it->pickup)
+				continue;
+			if (!(it->flags & IT_AMMO))
+				continue;
+			Add_Ammo (ent, it, 1000);
+		}
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "armor") == 0)
+	{
+		gitem_armor_t	*info;
+
+		it = FindItem("Jacket Armor");
+		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
+
+		it = FindItem("Combat Armor");
+		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
+
+		it = FindItem("Body Armor");
+		info = (gitem_armor_t *)it->info;
+		ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;
+
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "Power Shield") == 0)
+	{
+		it = FindItem("Power Shield");
+		it_ent = G_Spawn();
+		it_ent->classname = it->classname;
+		SpawnItem (it_ent, it);
+		Touch_Item (it_ent, ent, NULL, NULL);
+		if (it_ent->inuse)
+			G_FreeEdict(it_ent);
+
+		if (!give_all)
+			return;
+	}
+
+	if (give_all)
+	{
+		for (i=0 ; i<game.num_items ; i++)
+		{
+			it = itemlist + i;
+			if (!it->pickup)
+				continue;
+			if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO))
+				continue;
+			ent->client->pers.inventory[i] = 1;
+		}
+		return;
+	}
+
+	it = FindItem (name);
+	if (!it)
+	{
+		name = gi.argv(1);
+		it = FindItem (name);
+		if (!it)
+		{
+			gi.cprintf (ent, PRINT_HIGH, "unknown item\n");
+			return;
+		}
+	}
+
+	if (!it->pickup)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "non-pickup item\n");
+		return;
+	}
+
+	index = ITEM_INDEX(it);
+
+	if (it->flags & IT_AMMO)
+	{
+		if (gi.argc() == 3)
+			ent->client->pers.inventory[index] = atoi(gi.argv(2));
+		else
+			ent->client->pers.inventory[index] += it->quantity;
+	}
+	else
+	{
+		it_ent = G_Spawn();
+		it_ent->classname = it->classname;
+		SpawnItem (it_ent, it);
+		Touch_Item (it_ent, ent, NULL, NULL);
+		if (it_ent->inuse)
+			G_FreeEdict(it_ent);
+	}
+}
+
+
+/*
+==================
+Cmd_God_f
+
+Sets client to godmode
+
+argv(0) god
+==================
+*/
+void Cmd_God_f (edict_t *ent)
+{
+	char	*msg;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	ent->flags ^= FL_GODMODE;
+	if (!(ent->flags & FL_GODMODE) )
+		msg = "godmode OFF\n";
+	else
+		msg = "godmode ON\n";
+
+	gi.cprintf (ent, PRINT_HIGH, msg);
+}
+
+
+/*
+==================
+Cmd_Notarget_f
+
+Sets client to notarget
+
+argv(0) notarget
+==================
+*/
+void Cmd_Notarget_f (edict_t *ent)
+{
+	char	*msg;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	ent->flags ^= FL_NOTARGET;
+	if (!(ent->flags & FL_NOTARGET) )
+		msg = "notarget OFF\n";
+	else
+		msg = "notarget ON\n";
+
+	gi.cprintf (ent, PRINT_HIGH, msg);
+}
+
+
+/*
+==================
+Cmd_Noclip_f
+
+argv(0) noclip
+==================
+*/
+void Cmd_Noclip_f (edict_t *ent)
+{
+	char	*msg;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	if (ent->movetype == MOVETYPE_NOCLIP)
+	{
+		ent->movetype = MOVETYPE_WALK;
+		msg = "noclip OFF\n";
+	}
+	else
+	{
+		ent->movetype = MOVETYPE_NOCLIP;
+		msg = "noclip ON\n";
+	}
+
+	gi.cprintf (ent, PRINT_HIGH, msg);
+}
+
+
+/*
+==================
+Cmd_Use_f
+
+Use an inventory item
+==================
+*/
+void Cmd_Use_f (edict_t *ent)
+{
+	int			index;
+	gitem_t		*it;
+	char		*s;
+
+	s = gi.args();
+	it = FindItem (s);
+	if (!it)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
+		return;
+	}
+	if (!it->use)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
+		return;
+	}
+	index = ITEM_INDEX(it);
+	if (!ent->client->pers.inventory[index])
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
+		return;
+	}
+
+	it->use (ent, it);
+}
+
+
+/*
+==================
+Cmd_Drop_f
+
+Drop an inventory item
+==================
+*/
+void Cmd_Drop_f (edict_t *ent)
+{
+	int			index;
+	gitem_t		*it;
+	char		*s;
+
+//ZOID--special case for tech powerups
+	if (Q_stricmp(gi.args(), "tech") == 0 && (it = CTFWhat_Tech(ent)) != NULL) {
+		it->drop (ent, it);
+		return;
+	}
+//ZOID
+
+	s = gi.args();
+	it = FindItem (s);
+	if (!it)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
+		return;
+	}
+	if (!it->drop)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
+		return;
+	}
+	index = ITEM_INDEX(it);
+	if (!ent->client->pers.inventory[index])
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
+		return;
+	}
+
+	it->drop (ent, it);
+}
+
+
+/*
+=================
+Cmd_Inven_f
+=================
+*/
+void Cmd_Inven_f (edict_t *ent)
+{
+	int			i;
+	gclient_t	*cl;
+
+	cl = ent->client;
+
+	cl->showscores = false;
+	cl->showhelp = false;
+
+//ZOID
+	if (ent->client->menu) {
+		PMenu_Close(ent);
+		ent->client->update_chase = true;
+		return;
+	}
+//ZOID
+
+	if (cl->showinventory)
+	{
+		cl->showinventory = false;
+		return;
+	}
+
+//ZOID
+	if (ctf->value && cl->resp.ctf_team == CTF_NOTEAM) {
+		CTFOpenJoinMenu(ent);
+		return;
+	}
+//ZOID
+
+	cl->showinventory = true;
+
+	gi.WriteByte (svc_inventory);
+	for (i=0 ; i<MAX_ITEMS ; i++)
+	{
+		gi.WriteShort (cl->pers.inventory[i]);
+	}
+	gi.unicast (ent, true);
+}
+
+/*
+=================
+Cmd_InvUse_f
+=================
+*/
+void Cmd_InvUse_f (edict_t *ent)
+{
+	gitem_t		*it;
+
+//ZOID
+	if (ent->client->menu) {
+		PMenu_Select(ent);
+		return;
+	}
+//ZOID
+
+	ValidateSelectedItem (ent);
+
+	if (ent->client->pers.selected_item == -1)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "No item to use.\n");
+		return;
+	}
+
+	it = &itemlist[ent->client->pers.selected_item];
+	if (!it->use)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
+		return;
+	}
+	it->use (ent, it);
+}
+
+//ZOID
+/*
+=================
+Cmd_LastWeap_f
+=================
+*/
+void Cmd_LastWeap_f (edict_t *ent)
+{
+	gclient_t	*cl;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon || !cl->pers.lastweapon)
+		return;
+
+	cl->pers.lastweapon->use (ent, cl->pers.lastweapon);
+}
+//ZOID
+
+/*
+=================
+Cmd_WeapPrev_f
+=================
+*/
+void Cmd_WeapPrev_f (edict_t *ent)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+	int			selected_weapon;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon)
+		return;
+
+	selected_weapon = ITEM_INDEX(cl->pers.weapon);
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (selected_weapon + i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (! (it->flags & IT_WEAPON) )
+			continue;
+		it->use (ent, it);
+		if (cl->pers.weapon == it)
+			return;	// successful
+	}
+}
+
+/*
+=================
+Cmd_WeapNext_f
+=================
+*/
+void Cmd_WeapNext_f (edict_t *ent)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+	int			selected_weapon;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon)
+		return;
+
+	selected_weapon = ITEM_INDEX(cl->pers.weapon);
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (selected_weapon + MAX_ITEMS - i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (! (it->flags & IT_WEAPON) )
+			continue;
+		it->use (ent, it);
+		if (cl->pers.weapon == it)
+			return;	// successful
+	}
+}
+
+/*
+=================
+Cmd_WeapLast_f
+=================
+*/
+void Cmd_WeapLast_f (edict_t *ent)
+{
+	gclient_t	*cl;
+	int			index;
+	gitem_t		*it;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon || !cl->pers.lastweapon)
+		return;
+
+	index = ITEM_INDEX(cl->pers.lastweapon);
+	if (!cl->pers.inventory[index])
+		return;
+	it = &itemlist[index];
+	if (!it->use)
+		return;
+	if (! (it->flags & IT_WEAPON) )
+		return;
+	it->use (ent, it);
+}
+
+/*
+=================
+Cmd_InvDrop_f
+=================
+*/
+void Cmd_InvDrop_f (edict_t *ent)
+{
+	gitem_t		*it;
+
+	ValidateSelectedItem (ent);
+
+	if (ent->client->pers.selected_item == -1)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "No item to drop.\n");
+		return;
+	}
+
+	it = &itemlist[ent->client->pers.selected_item];
+	if (!it->drop)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
+		return;
+	}
+	it->drop (ent, it);
+}
+
+/*
+=================
+Cmd_Kill_f
+=================
+*/
+void Cmd_Kill_f (edict_t *ent)
+{
+//ZOID
+	if (ent->solid == SOLID_NOT)
+		return;
+//ZOID
+
+	if((level.time - ent->client->respawn_time) < 5)
+		return;
+	ent->flags &= ~FL_GODMODE;
+	ent->health = 0;
+	meansOfDeath = MOD_SUICIDE;
+	player_die (ent, ent, ent, 100000, vec3_origin);
+}
+
+/*
+=================
+Cmd_PutAway_f
+=================
+*/
+void Cmd_PutAway_f (edict_t *ent)
+{
+	ent->client->showscores = false;
+	ent->client->showhelp = false;
+	ent->client->showinventory = false;
+//ZOID
+	if (ent->client->menu)
+		PMenu_Close(ent);
+	ent->client->update_chase = true;
+//ZOID
+}
+
+
+int PlayerSort (void const *a, void const *b)
+{
+	int		anum, bnum;
+
+	anum = *(int *)a;
+	bnum = *(int *)b;
+
+	anum = game.clients[anum].ps.stats[STAT_FRAGS];
+	bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
+
+	if (anum < bnum)
+		return -1;
+	if (anum > bnum)
+		return 1;
+	return 0;
+}
+
+/*
+=================
+Cmd_Players_f
+=================
+*/
+void Cmd_Players_f (edict_t *ent)
+{
+	int		i;
+	int		count;
+	char	small[64];
+	char	large[1280];
+	int		index[256];
+
+	count = 0;
+	for (i = 0 ; i < maxclients->value ; i++)
+		if (game.clients[i].pers.connected)
+		{
+			index[count] = i;
+			count++;
+		}
+
+	// sort by frags
+	qsort (index, count, sizeof(index[0]), PlayerSort);
+
+	// print information
+	large[0] = 0;
+
+	for (i = 0 ; i < count ; i++)
+	{
+		Com_sprintf (small, sizeof(small), "%3i %s\n",
+			game.clients[index[i]].ps.stats[STAT_FRAGS],
+			game.clients[index[i]].pers.netname);
+		if (strlen (small) + strlen(large) > sizeof(large) - 100 )
+		{	// can't print all of them in one packet
+			strcat (large, "...\n");
+			break;
+		}
+		strcat (large, small);
+	}
+
+	gi.cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count);
+}
+
+/*
+=================
+Cmd_Wave_f
+=================
+*/
+void Cmd_Wave_f (edict_t *ent)
+{
+	int		i;
+
+	i = atoi (gi.argv(1));
+
+	// can't wave when ducked
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+		return;
+
+	if (ent->client->anim_priority > ANIM_WAVE)
+		return;
+
+	ent->client->anim_priority = ANIM_WAVE;
+
+	switch (i)
+	{
+	case 0:
+		gi.cprintf (ent, PRINT_HIGH, "flipoff\n");
+		ent->s.frame = FRAME_flip01-1;
+		ent->client->anim_end = FRAME_flip12;
+		break;
+	case 1:
+		gi.cprintf (ent, PRINT_HIGH, "salute\n");
+		ent->s.frame = FRAME_salute01-1;
+		ent->client->anim_end = FRAME_salute11;
+		break;
+	case 2:
+		gi.cprintf (ent, PRINT_HIGH, "taunt\n");
+		ent->s.frame = FRAME_taunt01-1;
+		ent->client->anim_end = FRAME_taunt17;
+		break;
+	case 3:
+		gi.cprintf (ent, PRINT_HIGH, "wave\n");
+		ent->s.frame = FRAME_wave01-1;
+		ent->client->anim_end = FRAME_wave11;
+		break;
+	case 4:
+	default:
+		gi.cprintf (ent, PRINT_HIGH, "point\n");
+		ent->s.frame = FRAME_point01-1;
+		ent->client->anim_end = FRAME_point12;
+		break;
+	}
+}
+
+qboolean CheckFlood(edict_t *ent)
+{
+	int		i;
+	gclient_t *cl;
+
+	if (flood_msgs->value) {
+		cl = ent->client;
+
+        if (level.time < cl->flood_locktill) {
+			gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
+				(int)(cl->flood_locktill - level.time));
+            return true;
+        }
+        i = cl->flood_whenhead - flood_msgs->value + 1;
+        if (i < 0)
+            i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i;
+		if (cl->flood_when[i] && 
+			level.time - cl->flood_when[i] < flood_persecond->value) {
+			cl->flood_locktill = level.time + flood_waitdelay->value;
+			gi.cprintf(ent, PRINT_CHAT, "Flood protection:  You can't talk for %d seconds.\n",
+				(int)flood_waitdelay->value);
+            return true;
+        }
+		cl->flood_whenhead = (cl->flood_whenhead + 1) %
+			(sizeof(cl->flood_when)/sizeof(cl->flood_when[0]));
+		cl->flood_when[cl->flood_whenhead] = level.time;
+	}
+	return false;
+}
+
+/*
+==================
+Cmd_Say_f
+==================
+*/
+void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0)
+{
+	int		j;
+	edict_t	*other;
+	char	*p;
+	char	text[2048];
+
+	if (gi.argc () < 2 && !arg0)
+		return;
+
+	if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
+		team = false;
+
+	if (team)
+		Com_sprintf (text, sizeof(text), "(%s): ", ent->client->pers.netname);
+	else
+		Com_sprintf (text, sizeof(text), "%s: ", ent->client->pers.netname);
+
+	if (arg0)
+	{
+		strcat (text, gi.argv(0));
+		strcat (text, " ");
+		strcat (text, gi.args());
+	}
+	else
+	{
+		p = gi.args();
+
+		if (*p == '"')
+		{
+			p++;
+			p[strlen(p)-1] = 0;
+		}
+		strcat(text, p);
+	}
+
+	// don't let text be too long for malicious reasons
+	if (strlen(text) > 150)
+		text[150] = 0;
+
+	strcat(text, "\n");
+
+	if (CheckFlood(ent))
+		return;
+
+	if (dedicated->value)
+		gi.cprintf(NULL, PRINT_CHAT, "%s", text);
+
+	for (j = 1; j <= game.maxclients; j++)
+	{
+		other = &g_edicts[j];
+		if (!other->inuse)
+			continue;
+		if (!other->client)
+			continue;
+		if (team)
+		{
+			if (!OnSameTeam(ent, other))
+				continue;
+		}
+		gi.cprintf(other, PRINT_CHAT, "%s", text);
+	}
+}
+
+/*
+=================
+ClientCommand
+=================
+*/
+void ClientCommand (edict_t *ent)
+{
+	char	*cmd;
+
+	if (!ent->client)
+		return;		// not fully in game yet
+
+	cmd = gi.argv(0);
+
+	if (Q_stricmp (cmd, "players") == 0)
+	{
+		Cmd_Players_f (ent);
+		return;
+	}
+	if (Q_stricmp (cmd, "say") == 0)
+	{
+		Cmd_Say_f (ent, false, false);
+		return;
+	}
+	if (Q_stricmp (cmd, "say_team") == 0 || Q_stricmp (cmd, "steam") == 0)
+	{
+		CTFSay_Team(ent, gi.args());
+		return;
+	}
+	if (Q_stricmp (cmd, "score") == 0)
+	{
+		Cmd_Score_f (ent);
+		return;
+	}
+	if (Q_stricmp (cmd, "help") == 0)
+	{
+		Cmd_Help_f (ent);
+		return;
+	}
+
+	if (level.intermissiontime)
+		return;
+
+	if (Q_stricmp (cmd, "use") == 0)
+		Cmd_Use_f (ent);
+	else if (Q_stricmp (cmd, "drop") == 0)
+		Cmd_Drop_f (ent);
+	else if (Q_stricmp (cmd, "give") == 0)
+		Cmd_Give_f (ent);
+	else if (Q_stricmp (cmd, "god") == 0)
+		Cmd_God_f (ent);
+	else if (Q_stricmp (cmd, "notarget") == 0)
+		Cmd_Notarget_f (ent);
+	else if (Q_stricmp (cmd, "noclip") == 0)
+		Cmd_Noclip_f (ent);
+	else if (Q_stricmp (cmd, "inven") == 0)
+		Cmd_Inven_f (ent);
+	else if (Q_stricmp (cmd, "invnext") == 0)
+		SelectNextItem (ent, -1);
+	else if (Q_stricmp (cmd, "invprev") == 0)
+		SelectPrevItem (ent, -1);
+	else if (Q_stricmp (cmd, "invnextw") == 0)
+		SelectNextItem (ent, IT_WEAPON);
+	else if (Q_stricmp (cmd, "invprevw") == 0)
+		SelectPrevItem (ent, IT_WEAPON);
+	else if (Q_stricmp (cmd, "invnextp") == 0)
+		SelectNextItem (ent, IT_POWERUP);
+	else if (Q_stricmp (cmd, "invprevp") == 0)
+		SelectPrevItem (ent, IT_POWERUP);
+	else if (Q_stricmp (cmd, "invuse") == 0)
+		Cmd_InvUse_f (ent);
+	else if (Q_stricmp (cmd, "invdrop") == 0)
+		Cmd_InvDrop_f (ent);
+	else if (Q_stricmp (cmd, "weapprev") == 0)
+		Cmd_WeapPrev_f (ent);
+	else if (Q_stricmp (cmd, "weapnext") == 0)
+		Cmd_WeapNext_f (ent);
+	else if (Q_stricmp (cmd, "weaplast") == 0)
+		Cmd_WeapLast_f (ent);
+	else if (Q_stricmp (cmd, "kill") == 0)
+		Cmd_Kill_f (ent);
+	else if (Q_stricmp (cmd, "putaway") == 0)
+		Cmd_PutAway_f (ent);
+	else if (Q_stricmp (cmd, "wave") == 0)
+		Cmd_Wave_f (ent);
+//ZOID
+	else if (Q_stricmp (cmd, "team") == 0)
+	{
+		CTFTeam_f (ent);
+	} else if (Q_stricmp(cmd, "id") == 0) {
+		CTFID_f (ent);
+	} else if (Q_stricmp(cmd, "yes") == 0) {
+		CTFVoteYes(ent);
+	} else if (Q_stricmp(cmd, "no") == 0) {
+		CTFVoteNo(ent);
+	} else if (Q_stricmp(cmd, "ready") == 0) {
+		CTFReady(ent);
+	} else if (Q_stricmp(cmd, "notready") == 0) {
+		CTFNotReady(ent);
+	} else if (Q_stricmp(cmd, "ghost") == 0) {
+		CTFGhost(ent);
+	} else if (Q_stricmp(cmd, "admin") == 0) {
+		CTFAdmin(ent);
+	} else if (Q_stricmp(cmd, "stats") == 0) {
+		CTFStats(ent);
+	} else if (Q_stricmp(cmd, "warp") == 0) {
+		CTFWarp(ent);
+	} else if (Q_stricmp(cmd, "boot") == 0) {
+		CTFBoot(ent);
+	} else if (Q_stricmp(cmd, "playerlist") == 0) {
+		CTFPlayerList(ent);
+	} else if (Q_stricmp(cmd, "observer") == 0) {
+		CTFObserver(ent);
+	}
+//ZOID
+	else	// anything that doesn't match a command will be a chat
+		Cmd_Say_f (ent, false, true);
+}
--- /dev/null
+++ b/ctf/g_combat.c
@@ -1,0 +1,596 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_combat.c
+
+#include "g_local.h"
+
+/*
+============
+CanDamage
+
+Returns true if the inflictor can directly damage the target.  Used for
+explosions and melee attacks.
+============
+*/
+qboolean CanDamage (edict_t *targ, edict_t *inflictor)
+{
+	vec3_t	dest;
+	trace_t	trace;
+
+// bmodels need special checking because their origin is 0,0,0
+	if (targ->movetype == MOVETYPE_PUSH)
+	{
+		VectorAdd (targ->absmin, targ->absmax, dest);
+		VectorScale (dest, 0.5, dest);
+		trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+		if (trace.fraction == 1.0)
+			return true;
+		if (trace.ent == targ)
+			return true;
+		return false;
+	}
+	
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] += 15.0;
+	dest[1] += 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] += 15.0;
+	dest[1] -= 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] -= 15.0;
+	dest[1] += 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] -= 15.0;
+	dest[1] -= 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+
+	return false;
+}
+
+
+/*
+============
+Killed
+============
+*/
+void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	if (targ->health < -999)
+		targ->health = -999;
+
+	targ->enemy = attacker;
+
+	if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
+	{
+//		targ->svflags |= SVF_DEADMONSTER;	// now treat as a different content type
+		if (!(targ->monsterinfo.aiflags & AI_GOOD_GUY))
+		{
+			level.killed_monsters++;
+			if (coop->value && attacker->client)
+				attacker->client->resp.score++;
+			// medics won't heal monsters that they kill themselves
+			if (strcmp(attacker->classname, "monster_medic") == 0)
+				targ->owner = attacker;
+		}
+	}
+
+	if (targ->movetype == MOVETYPE_PUSH || targ->movetype == MOVETYPE_STOP || targ->movetype == MOVETYPE_NONE)
+	{	// doors, triggers, etc
+		targ->die (targ, inflictor, attacker, damage, point);
+		return;
+	}
+
+	if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
+	{
+		targ->touch = NULL;
+		monster_death_use (targ);
+	}
+
+	targ->die (targ, inflictor, attacker, damage, point);
+}
+
+
+/*
+================
+SpawnDamage
+================
+*/
+void SpawnDamage (int type, vec3_t origin, vec3_t normal, int damage)
+{
+	if (damage > 255)
+		damage = 255;
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (type);
+//	gi.WriteByte (damage);
+	gi.WritePosition (origin);
+	gi.WriteDir (normal);
+	gi.multicast (origin, MULTICAST_PVS);
+}
+
+
+/*
+============
+T_Damage
+
+targ		entity that is being damaged
+inflictor	entity that is causing the damage
+attacker	entity that caused the inflictor to damage targ
+	example: targ=monster, inflictor=rocket, attacker=player
+
+dir			direction of the attack
+point		point at which the damage is being inflicted
+normal		normal vector from that point
+damage		amount of damage being inflicted
+knockback	force to be applied against targ as a result of the damage
+
+dflags		these flags are used to control how T_Damage works
+	DAMAGE_RADIUS			damage was indirect (from a nearby explosion)
+	DAMAGE_NO_ARMOR			armor does not protect from this damage
+	DAMAGE_ENERGY			damage is from an energy based weapon
+	DAMAGE_NO_KNOCKBACK		do not affect velocity, just view angles
+	DAMAGE_BULLET			damage is from a bullet (used for ricochets)
+	DAMAGE_NO_PROTECTION	kills godmode, armor, everything
+============
+*/
+static int CheckPowerArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags)
+{
+	gclient_t	*client;
+	int			save;
+	int			power_armor_type;
+	int			index;
+	int			damagePerCell;
+	int			pa_te_type;
+	int			power;
+	int			power_used;
+
+	if (!damage)
+		return 0;
+
+	client = ent->client;
+
+	if (dflags & DAMAGE_NO_ARMOR)
+		return 0;
+
+	if (client)
+	{
+		power_armor_type = PowerArmorType (ent);
+		if (power_armor_type != POWER_ARMOR_NONE)
+		{
+			index = ITEM_INDEX(FindItem("Cells"));
+			power = client->pers.inventory[index];
+		}
+	}
+	else if (ent->svflags & SVF_MONSTER)
+	{
+		power_armor_type = ent->monsterinfo.power_armor_type;
+		power = ent->monsterinfo.power_armor_power;
+	}
+	else
+		return 0;
+
+	if (power_armor_type == POWER_ARMOR_NONE)
+		return 0;
+	if (!power)
+		return 0;
+
+	if (power_armor_type == POWER_ARMOR_SCREEN)
+	{
+		vec3_t		vec;
+		float		dot;
+		vec3_t		forward;
+
+		// only works if damage point is in front
+		AngleVectors (ent->s.angles, forward, NULL, NULL);
+		VectorSubtract (point, ent->s.origin, vec);
+		VectorNormalize (vec);
+		dot = DotProduct (vec, forward);
+		if (dot <= 0.3)
+			return 0;
+
+		damagePerCell = 1;
+		pa_te_type = TE_SCREEN_SPARKS;
+		damage = damage / 3;
+	}
+	else
+	{
+		damagePerCell = 1; // power armor is weaker in CTF
+		pa_te_type = TE_SHIELD_SPARKS;
+		damage = (2 * damage) / 3;
+	}
+
+	save = power * damagePerCell;
+	if (!save)
+		return 0;
+	if (save > damage)
+		save = damage;
+
+	SpawnDamage (pa_te_type, point, normal, save);
+	ent->powerarmor_time = level.time + 0.2;
+
+	power_used = save / damagePerCell;
+
+	if (client)
+		client->pers.inventory[index] -= power_used;
+	else
+		ent->monsterinfo.power_armor_power -= power_used;
+	return save;
+}
+
+static int CheckArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags)
+{
+	gclient_t	*client;
+	int			save;
+	int			index;
+	gitem_t		*armor;
+
+	if (!damage)
+		return 0;
+
+	client = ent->client;
+
+	if (!client)
+		return 0;
+
+	if (dflags & DAMAGE_NO_ARMOR)
+		return 0;
+
+	index = ArmorIndex (ent);
+	if (!index)
+		return 0;
+
+	armor = GetItemByIndex (index);
+
+	if (dflags & DAMAGE_ENERGY)
+		save = ceil(((gitem_armor_t *)armor->info)->energy_protection*damage);
+	else
+		save = ceil(((gitem_armor_t *)armor->info)->normal_protection*damage);
+	if (save >= client->pers.inventory[index])
+		save = client->pers.inventory[index];
+
+	if (!save)
+		return 0;
+
+	client->pers.inventory[index] -= save;
+	SpawnDamage (te_sparks, point, normal, save);
+
+	return save;
+}
+
+void M_ReactToDamage (edict_t *targ, edict_t *attacker)
+{
+	if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
+		return;
+
+	if (attacker == targ || attacker == targ->enemy)
+		return;
+
+	// if we are a good guy monster and our attacker is a player
+	// or another good guy, do not get mad at them
+	if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
+	{
+		if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
+			return;
+	}
+
+	// we now know that we are not both good guys
+
+	// if attacker is a client, get mad at them because he's good and we're not
+	if (attacker->client)
+	{
+		// this can only happen in coop (both new and old enemies are clients)
+		// only switch if can't see the current enemy
+		if (targ->enemy && targ->enemy->client)
+		{
+			if (visible(targ, targ->enemy))
+			{
+				targ->oldenemy = attacker;
+				return;
+			}
+			targ->oldenemy = targ->enemy;
+		}
+		targ->enemy = attacker;
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
+			FoundTarget (targ);
+		return;
+	}
+
+	// it's the same base (walk/swim/fly) type and a different classname and it's not a tank
+	// (they spray too much), get mad at them
+	if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
+		 (strcmp (targ->classname, attacker->classname) != 0) &&
+		 (strcmp(attacker->classname, "monster_tank") != 0) &&
+		 (strcmp(attacker->classname, "monster_supertank") != 0) &&
+		 (strcmp(attacker->classname, "monster_makron") != 0) &&
+		 (strcmp(attacker->classname, "monster_jorg") != 0) )
+	{
+		if (targ->enemy)
+			if (targ->enemy->client)
+				targ->oldenemy = targ->enemy;
+		targ->enemy = attacker;
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
+			FoundTarget (targ);
+	}
+	else
+	// otherwise get mad at whoever they are mad at (help our buddy)
+	{
+		if (targ->enemy)
+			if (targ->enemy->client)
+				targ->oldenemy = targ->enemy;
+		targ->enemy = attacker->enemy;
+		FoundTarget (targ);
+	}
+}
+
+qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker)
+{
+//ZOID
+	if (ctf->value && targ->client && attacker->client)
+		if (targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
+			targ != attacker)
+			return true;
+//ZOID
+
+		//FIXME make the next line real and uncomment this block
+		// if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
+	return false;
+}
+
+void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
+{
+	gclient_t	*client;
+	int			take;
+	int			save;
+	int			asave;
+	int			psave;
+	int			te_sparks;
+
+	if (!targ->takedamage)
+		return;
+
+	// friendly fire avoidance
+	// if enabled you can't hurt teammates (but you can hurt yourself)
+	// knockback still occurs
+	if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
+	{
+		if (OnSameTeam (targ, attacker))
+		{
+			if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
+				damage = 0;
+			else
+				mod |= MOD_FRIENDLY_FIRE;
+		}
+	}
+	meansOfDeath = mod;
+
+	// easy mode takes half damage
+	if (skill->value == 0 && deathmatch->value == 0 && targ->client)
+	{
+		damage *= 0.5;
+		if (!damage)
+			damage = 1;
+	}
+
+	client = targ->client;
+
+	if (dflags & DAMAGE_BULLET)
+		te_sparks = TE_BULLET_SPARKS;
+	else
+		te_sparks = TE_SPARKS;
+
+	VectorNormalize(dir);
+
+// bonus damage for suprising a monster
+	if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
+		damage *= 2;
+
+//ZOID
+//strength tech
+	damage = CTFApplyStrength(attacker, damage);
+//ZOID
+
+	if (targ->flags & FL_NO_KNOCKBACK)
+		knockback = 0;
+
+// figure momentum add
+	if (!(dflags & DAMAGE_NO_KNOCKBACK))
+	{
+		if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
+		{
+			vec3_t	kvel;
+			float	mass;
+
+			if (targ->mass < 50)
+				mass = 50;
+			else
+				mass = targ->mass;
+
+			if (targ->client  && attacker == targ)
+				VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
+			else
+				VectorScale (dir, 500.0 * (float)knockback / mass, kvel);
+
+			VectorAdd (targ->velocity, kvel, targ->velocity);
+		}
+	}
+
+	take = damage;
+	save = 0;
+
+	// check for godmode
+	if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
+	{
+		take = 0;
+		save = damage;
+		SpawnDamage (te_sparks, point, normal, save);
+	}
+
+	// check for invincibility
+	if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
+	{
+		if (targ->pain_debounce_time < level.time)
+		{
+			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
+			targ->pain_debounce_time = level.time + 2;
+		}
+		take = 0;
+		save = damage;
+	}
+
+//ZOID
+//team armor protect
+	if (ctf->value && targ->client && attacker->client &&
+		targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
+		targ != attacker && ((int)dmflags->value & DF_ARMOR_PROTECT)) {
+		psave = asave = 0;
+	} else {
+//ZOID
+		psave = CheckPowerArmor (targ, point, normal, take, dflags);
+		take -= psave;
+	
+		asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
+		take -= asave;
+	}
+
+	//treat cheat/powerup savings the same as armor
+	asave += save;
+
+//ZOID
+//resistance tech
+	take = CTFApplyResistance(targ, take);
+//ZOID
+
+	// team damage avoidance
+	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
+		return;
+
+//ZOID
+	CTFCheckHurtCarrier(targ, attacker);
+//ZOID
+
+// do the damage
+	if (take)
+	{
+		if ((targ->svflags & SVF_MONSTER) || (client))
+			SpawnDamage (TE_BLOOD, point, normal, take);
+		else
+			SpawnDamage (te_sparks, point, normal, take);
+
+		if (!CTFMatchSetup())
+			targ->health = targ->health - take;
+			
+		if (targ->health <= 0)
+		{
+			if ((targ->svflags & SVF_MONSTER) || (client))
+				targ->flags |= FL_NO_KNOCKBACK;
+			Killed (targ, inflictor, attacker, take, point);
+			return;
+		}
+	}
+
+	if (targ->svflags & SVF_MONSTER)
+	{
+		M_ReactToDamage (targ, attacker);
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
+		{
+			targ->pain (targ, attacker, knockback, take);
+			// nightmare mode monsters don't go into pain frames often
+			if (skill->value == 3)
+				targ->pain_debounce_time = level.time + 5;
+		}
+	}
+	else if (client)
+	{
+		if (!(targ->flags & FL_GODMODE) && (take) && !CTFMatchSetup())
+			targ->pain (targ, attacker, knockback, take);
+	}
+	else if (take)
+	{
+		if (targ->pain)
+			targ->pain (targ, attacker, knockback, take);
+	}
+
+	// add to the damage inflicted on a player this frame
+	// the total will be turned into screen blends and view angle kicks
+	// at the end of the frame
+	if (client)
+	{
+		client->damage_parmor += psave;
+		client->damage_armor += asave;
+		client->damage_blood += take;
+		client->damage_knockback += knockback;
+		VectorCopy (point, client->damage_from);
+	}
+}
+
+
+/*
+============
+T_RadiusDamage
+============
+*/
+void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
+{
+	float	points;
+	edict_t	*ent = NULL;
+	vec3_t	v;
+	vec3_t	dir;
+
+	while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL)
+	{
+		if (ent == ignore)
+			continue;
+		if (!ent->takedamage)
+			continue;
+
+		VectorAdd (ent->mins, ent->maxs, v);
+		VectorMA (ent->s.origin, 0.5, v, v);
+		VectorSubtract (inflictor->s.origin, v, v);
+		points = damage - 0.5 * VectorLength (v);
+		if (ent == attacker)
+			points = points * 0.5;
+		if (points > 0)
+		{
+			if (CanDamage (ent, inflictor))
+			{
+				VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
+				T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
+			}
+		}
+	}
+}
--- /dev/null
+++ b/ctf/g_ctf.c
@@ -1,0 +1,4016 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+typedef enum match_s {
+	MATCH_NONE,
+	MATCH_SETUP,
+	MATCH_PREGAME,
+	MATCH_GAME,
+	MATCH_POST
+} match_t;
+
+typedef enum {
+	ELECT_NONE,
+	ELECT_MATCH,
+	ELECT_ADMIN,
+	ELECT_MAP
+} elect_t;
+
+typedef struct ctfgame_s
+{
+	int team1, team2;
+	int total1, total2; // these are only set when going into intermission!
+	float last_flag_capture;
+	int last_capture_team;
+
+	match_t match;		// match state
+	float matchtime;	// time for match start/end (depends on state)
+	int lasttime;		// last time update
+
+	elect_t election;	// election type
+	edict_t *etarget;	// for admin election, who's being elected
+	char elevel[32];	// for map election, target level
+	int evotes;			// votes so far
+	int needvotes;		// votes needed
+	float electtime;	// remaining time until election times out
+	char emsg[256];		// election name
+
+
+	ghost_t ghosts[MAX_CLIENTS]; // ghost codes
+} ctfgame_t;
+
+ctfgame_t ctfgame;
+
+cvar_t *ctf;
+cvar_t *ctf_forcejoin;
+
+cvar_t *competition;
+cvar_t *matchlock;
+cvar_t *electpercentage;
+cvar_t *matchtime;
+cvar_t *matchsetuptime;
+cvar_t *matchstarttime;
+cvar_t *admin_password;
+cvar_t *warp_list;
+
+char *ctf_statusbar =
+"yb	-24 "
+
+// health
+"xv	0 "
+"hnum "
+"xv	50 "
+"pic 0 "
+
+// ammo
+"if 2 "
+"	xv	100 "
+"	anum "
+"	xv	150 "
+"	pic 2 "
+"endif "
+
+// armor
+"if 4 "
+"	xv	200 "
+"	rnum "
+"	xv	250 "
+"	pic 4 "
+"endif "
+
+// selected item
+"if 6 "
+"	xv	296 "
+"	pic 6 "
+"endif "
+
+"yb	-50 "
+
+// picked up item
+"if 7 "
+"	xv	0 "
+"	pic 7 "
+"	xv	26 "
+"	yb	-42 "
+"	stat_string 8 "
+"	yb	-50 "
+"endif "
+
+// timer
+"if 9 "
+  "xv 246 "
+  "num 2 10 "
+  "xv 296 "
+  "pic 9 "
+"endif "
+
+//  help / weapon icon 
+"if 11 "
+  "xv 148 "
+  "pic 11 "
+"endif "
+
+//  frags
+"xr	-50 "
+"yt 2 "
+"num 3 14 "
+
+//tech
+"yb -129 "
+"if 26 "
+  "xr -26 "
+  "pic 26 "
+"endif "
+
+// red team
+"yb -102 "
+"if 17 "
+  "xr -26 "
+  "pic 17 "
+"endif "
+"xr -62 "
+"num 2 18 "
+//joined overlay
+"if 22 "
+  "yb -104 "
+  "xr -28 "
+  "pic 22 "
+"endif "
+
+// blue team
+"yb -75 "
+"if 19 "
+  "xr -26 "
+  "pic 19 "
+"endif "
+"xr -62 "
+"num 2 20 "
+"if 23 "
+  "yb -77 "
+  "xr -28 "
+  "pic 23 "
+"endif "
+
+// have flag graph
+"if 21 "
+  "yt 26 "
+  "xr -24 "
+  "pic 21 "
+"endif "
+
+// id view state
+"if 27 "
+  "xv 0 "
+  "yb -58 "
+  "string \"Viewing\" "
+  "xv 64 "
+  "stat_string 27 "
+"endif "
+
+"if 28 "
+  "xl 0 "
+  "yb -78 "
+  "stat_string 28 "
+"endif "
+;
+
+static char *tnames[] = {
+	"item_tech1", "item_tech2", "item_tech3", "item_tech4",
+	NULL
+};
+
+void stuffcmd(edict_t *ent, char *s) 	
+{
+   	gi.WriteByte (11);	        
+	gi.WriteString (s);
+    gi.unicast (ent, true);	
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+=================
+findradius
+
+Returns entities that have origins within a spherical area
+
+findradius (origin, radius)
+=================
+*/
+static edict_t *loc_findradius (edict_t *from, vec3_t org, float rad)
+{
+	vec3_t	eorg;
+	int		j;
+
+	if (!from)
+		from = g_edicts;
+	else
+		from++;
+	for ( ; from < &g_edicts[globals.num_edicts]; from++)
+	{
+		if (!from->inuse)
+			continue;
+#if 0
+		if (from->solid == SOLID_NOT)
+			continue;
+#endif
+		for (j=0 ; j<3 ; j++)
+			eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
+		if (VectorLength(eorg) > rad)
+			continue;
+		return from;
+	}
+
+	return NULL;
+}
+
+static void loc_buildboxpoints(vec3_t p[8], vec3_t org, vec3_t mins, vec3_t maxs)
+{
+	VectorAdd(org, mins, p[0]);
+	VectorCopy(p[0], p[1]);
+	p[1][0] -= mins[0];
+	VectorCopy(p[0], p[2]);
+	p[2][1] -= mins[1];
+	VectorCopy(p[0], p[3]);
+	p[3][0] -= mins[0];
+	p[3][1] -= mins[1];
+	VectorAdd(org, maxs, p[4]);
+	VectorCopy(p[4], p[5]);
+	p[5][0] -= maxs[0];
+	VectorCopy(p[0], p[6]);
+	p[6][1] -= maxs[1];
+	VectorCopy(p[0], p[7]);
+	p[7][0] -= maxs[0];
+	p[7][1] -= maxs[1];
+}
+
+static qboolean loc_CanSee (edict_t *targ, edict_t *inflictor)
+{
+	trace_t	trace;
+	vec3_t	targpoints[8];
+	int i;
+	vec3_t viewpoint;
+
+// bmodels need special checking because their origin is 0,0,0
+	if (targ->movetype == MOVETYPE_PUSH)
+		return false; // bmodels not supported
+
+	loc_buildboxpoints(targpoints, targ->s.origin, targ->mins, targ->maxs);
+	
+	VectorCopy(inflictor->s.origin, viewpoint);
+	viewpoint[2] += inflictor->viewheight;
+
+	for (i = 0; i < 8; i++) {
+		trace = gi.trace (viewpoint, vec3_origin, vec3_origin, targpoints[i], inflictor, MASK_SOLID);
+		if (trace.fraction == 1.0)
+			return true;
+	}
+
+	return false;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static gitem_t *flag1_item;
+static gitem_t *flag2_item;
+
+void CTFSpawn(void)
+{
+	if (!flag1_item)
+		flag1_item = FindItemByClassname("item_flag_team1");
+	if (!flag2_item)
+		flag2_item = FindItemByClassname("item_flag_team2");
+	memset(&ctfgame, 0, sizeof(ctfgame));
+	CTFSetupTechSpawn();
+
+	if (competition->value > 1) {
+		ctfgame.match = MATCH_SETUP;
+		ctfgame.matchtime = level.time + matchsetuptime->value * 60;
+	}
+}
+
+void CTFInit(void)
+{
+	ctf = gi.cvar("ctf", "1", CVAR_SERVERINFO);
+	ctf_forcejoin = gi.cvar("ctf_forcejoin", "", 0);
+	competition = gi.cvar("competition", "0", CVAR_SERVERINFO);
+	matchlock = gi.cvar("matchlock", "1", CVAR_SERVERINFO);
+	electpercentage = gi.cvar("electpercentage", "66", 0);
+	matchtime = gi.cvar("matchtime", "20", CVAR_SERVERINFO);
+	matchsetuptime = gi.cvar("matchsetuptime", "10", 0);
+	matchstarttime = gi.cvar("matchstarttime", "20", 0);
+	admin_password = gi.cvar("admin_password", "", 0);
+	warp_list = gi.cvar("warp_list", "q2ctf1 q2ctf2 q2ctf3 q2ctf4 q2ctf5", 0);
+}
+
+/*--------------------------------------------------------------------------*/
+
+char *CTFTeamName(int team)
+{
+	switch (team) {
+	case CTF_TEAM1:
+		return "RED";
+	case CTF_TEAM2:
+		return "BLUE";
+	}
+	return "UKNOWN";
+}
+
+char *CTFOtherTeamName(int team)
+{
+	switch (team) {
+	case CTF_TEAM1:
+		return "BLUE";
+	case CTF_TEAM2:
+		return "RED";
+	}
+	return "UKNOWN";
+}
+
+int CTFOtherTeam(int team)
+{
+	switch (team) {
+	case CTF_TEAM1:
+		return CTF_TEAM2;
+	case CTF_TEAM2:
+		return CTF_TEAM1;
+	}
+	return -1; // invalid value
+}
+
+/*--------------------------------------------------------------------------*/
+
+edict_t *SelectRandomDeathmatchSpawnPoint (void);
+edict_t *SelectFarthestDeathmatchSpawnPoint (void);
+float	PlayersRangeFromSpot (edict_t *spot);
+
+void CTFAssignSkin(edict_t *ent, char *s)
+{
+	int playernum = ent-g_edicts-1;
+	char *p;
+	char t[64];
+
+	Com_sprintf(t, sizeof(t), "%s", s);
+
+	if ((p = strrchr(t, '/')) != NULL)
+		p[1] = 0;
+	else
+		strcpy(t, "male/");
+
+	switch (ent->client->resp.ctf_team) {
+	case CTF_TEAM1:
+		gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s%s", 
+			ent->client->pers.netname, t, CTF_TEAM1_SKIN) );
+		break;
+	case CTF_TEAM2:
+		gi.configstring (CS_PLAYERSKINS+playernum,
+			va("%s\\%s%s", ent->client->pers.netname, t, CTF_TEAM2_SKIN) );
+		break;
+	default:
+		gi.configstring (CS_PLAYERSKINS+playernum, 
+			va("%s\\%s", ent->client->pers.netname, s) );
+		break;
+	}
+//	gi.cprintf(ent, PRINT_HIGH, "You have been assigned to %s team.\n", ent->client->pers.netname);
+}
+
+void CTFAssignTeam(gclient_t *who)
+{
+	edict_t		*player;
+	int i;
+	int team1count = 0, team2count = 0;
+
+	who->resp.ctf_state = 0;
+
+	if (!((int)dmflags->value & DF_CTF_FORCEJOIN)) {
+		who->resp.ctf_team = CTF_NOTEAM;
+		return;
+	}
+
+	for (i = 1; i <= maxclients->value; i++) {
+		player = &g_edicts[i];
+
+		if (!player->inuse || player->client == who)
+			continue;
+
+		switch (player->client->resp.ctf_team) {
+		case CTF_TEAM1:
+			team1count++;
+			break;
+		case CTF_TEAM2:
+			team2count++;
+		}
+	}
+	if (team1count < team2count)
+		who->resp.ctf_team = CTF_TEAM1;
+	else if (team2count < team1count)
+		who->resp.ctf_team = CTF_TEAM2;
+	else if (rand() & 1)
+		who->resp.ctf_team = CTF_TEAM1;
+	else
+		who->resp.ctf_team = CTF_TEAM2;
+}
+
+/*
+================
+SelectCTFSpawnPoint
+
+go to a ctf point, but NOT the two points closest
+to other players
+================
+*/
+edict_t *SelectCTFSpawnPoint (edict_t *ent)
+{
+	edict_t	*spot, *spot1, *spot2;
+	int		count = 0;
+	int		selection;
+	float	range, range1, range2;
+	char	*cname;
+
+	if (ent->client->resp.ctf_state)
+		if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
+			return SelectFarthestDeathmatchSpawnPoint ();
+		else
+			return SelectRandomDeathmatchSpawnPoint ();
+
+	ent->client->resp.ctf_state++;
+
+	switch (ent->client->resp.ctf_team) {
+	case CTF_TEAM1:
+		cname = "info_player_team1";
+		break;
+	case CTF_TEAM2:
+		cname = "info_player_team2";
+		break;
+	default:
+		return SelectRandomDeathmatchSpawnPoint();
+	}
+
+	spot = NULL;
+	range1 = range2 = 99999;
+	spot1 = spot2 = NULL;
+
+	while ((spot = G_Find (spot, FOFS(classname), cname)) != NULL)
+	{
+		count++;
+		range = PlayersRangeFromSpot(spot);
+		if (range < range1)
+		{
+			range1 = range;
+			spot1 = spot;
+		}
+		else if (range < range2)
+		{
+			range2 = range;
+			spot2 = spot;
+		}
+	}
+
+	if (!count)
+		return SelectRandomDeathmatchSpawnPoint();
+
+	if (count <= 2)
+	{
+		spot1 = spot2 = NULL;
+	}
+	else
+		count -= 2;
+
+	selection = rand() % count;
+
+	spot = NULL;
+	do
+	{
+		spot = G_Find (spot, FOFS(classname), cname);
+		if (spot == spot1 || spot == spot2)
+			selection++;
+	} while(selection--);
+
+	return spot;
+}
+
+/*------------------------------------------------------------------------*/
+/*
+CTFFragBonuses
+
+Calculate the bonuses for flag defense, flag carrier defense, etc.
+Note that bonuses are not cumaltive.  You get one, they are in importance
+order.
+*/
+void CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
+{
+	int i;
+	edict_t *ent;
+	gitem_t *flag_item, *enemy_flag_item;
+	int otherteam;
+	edict_t *flag, *carrier;
+	char *c;
+	vec3_t v1, v2;
+
+	if (targ->client && attacker->client) {
+		if (attacker->client->resp.ghost)
+			if (attacker != targ)
+				attacker->client->resp.ghost->kills++;
+		if (targ->client->resp.ghost)
+			targ->client->resp.ghost->deaths++;
+	}
+
+	// no bonus for fragging yourself
+	if (!targ->client || !attacker->client || targ == attacker)
+		return;
+
+	otherteam = CTFOtherTeam(targ->client->resp.ctf_team);
+	if (otherteam < 0)
+		return; // whoever died isn't on a team
+
+	// same team, if the flag at base, check to he has the enemy flag
+	if (targ->client->resp.ctf_team == CTF_TEAM1) {
+		flag_item = flag1_item;
+		enemy_flag_item = flag2_item;
+	} else {
+		flag_item = flag2_item;
+		enemy_flag_item = flag1_item;
+	}
+
+	// did the attacker frag the flag carrier?
+	if (targ->client->pers.inventory[ITEM_INDEX(enemy_flag_item)]) {
+		attacker->client->resp.ctf_lastfraggedcarrier = level.time;
+		attacker->client->resp.score += CTF_FRAG_CARRIER_BONUS;
+		gi.cprintf(attacker, PRINT_MEDIUM, "BONUS: %d points for fragging enemy flag carrier.\n",
+			CTF_FRAG_CARRIER_BONUS);
+
+		// the target had the flag, clear the hurt carrier
+		// field on the other team
+		for (i = 1; i <= maxclients->value; i++) {
+			ent = g_edicts + i;
+			if (ent->inuse && ent->client->resp.ctf_team == otherteam)
+				ent->client->resp.ctf_lasthurtcarrier = 0;
+		}
+		return;
+	}
+
+	if (targ->client->resp.ctf_lasthurtcarrier &&
+		level.time - targ->client->resp.ctf_lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
+		!attacker->client->pers.inventory[ITEM_INDEX(flag_item)]) {
+		// attacker is on the same team as the flag carrier and
+		// fragged a guy who hurt our flag carrier
+		attacker->client->resp.score += CTF_CARRIER_DANGER_PROTECT_BONUS;
+		gi.bprintf(PRINT_MEDIUM, "%s defends %s's flag carrier against an agressive enemy\n",
+			attacker->client->pers.netname, 
+			CTFTeamName(attacker->client->resp.ctf_team));
+		if (attacker->client->resp.ghost)
+			attacker->client->resp.ghost->carrierdef++;
+		return;
+	}
+
+	// flag and flag carrier area defense bonuses
+
+	// we have to find the flag and carrier entities
+
+	// find the flag
+	switch (attacker->client->resp.ctf_team) {
+	case CTF_TEAM1:
+		c = "item_flag_team1";
+		break;
+	case CTF_TEAM2:
+		c = "item_flag_team2";
+		break;
+	default:
+		return;
+	}
+
+	flag = NULL;
+	while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
+		if (!(flag->spawnflags & DROPPED_ITEM))
+			break;
+	}
+
+	if (!flag)
+		return; // can't find attacker's flag
+
+	// find attacker's team's flag carrier
+	for (i = 1; i <= maxclients->value; i++) {
+		carrier = g_edicts + i;
+		if (carrier->inuse && 
+			carrier->client->pers.inventory[ITEM_INDEX(flag_item)])
+			break;
+		carrier = NULL;
+	}
+
+	// ok we have the attackers flag and a pointer to the carrier
+
+	// check to see if we are defending the base's flag
+	VectorSubtract(targ->s.origin, flag->s.origin, v1);
+	VectorSubtract(attacker->s.origin, flag->s.origin, v2);
+
+	if ((VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS ||
+		VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS ||
+		loc_CanSee(flag, targ) || loc_CanSee(flag, attacker)) &&
+		attacker->client->resp.ctf_team != targ->client->resp.ctf_team) {
+		// we defended the base flag
+		attacker->client->resp.score += CTF_FLAG_DEFENSE_BONUS;
+		if (flag->solid == SOLID_NOT)
+			gi.bprintf(PRINT_MEDIUM, "%s defends the %s base.\n",
+				attacker->client->pers.netname, 
+				CTFTeamName(attacker->client->resp.ctf_team));
+		else
+			gi.bprintf(PRINT_MEDIUM, "%s defends the %s flag.\n",
+				attacker->client->pers.netname, 
+				CTFTeamName(attacker->client->resp.ctf_team));
+		if (attacker->client->resp.ghost)
+			attacker->client->resp.ghost->basedef++;
+		return;
+	}
+
+	if (carrier && carrier != attacker) {
+		VectorSubtract(targ->s.origin, carrier->s.origin, v1);
+		VectorSubtract(attacker->s.origin, carrier->s.origin, v1);
+
+		if (VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS ||
+			VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS ||
+			loc_CanSee(carrier, targ) || loc_CanSee(carrier, attacker)) {
+			attacker->client->resp.score += CTF_CARRIER_PROTECT_BONUS;
+			gi.bprintf(PRINT_MEDIUM, "%s defends the %s's flag carrier.\n",
+				attacker->client->pers.netname, 
+				CTFTeamName(attacker->client->resp.ctf_team));
+			if (attacker->client->resp.ghost)
+				attacker->client->resp.ghost->carrierdef++;
+			return;
+		}
+	}
+}
+
+void CTFCheckHurtCarrier(edict_t *targ, edict_t *attacker)
+{
+	gitem_t *flag_item;
+
+	if (!targ->client || !attacker->client)
+		return;
+
+	if (targ->client->resp.ctf_team == CTF_TEAM1)
+		flag_item = flag2_item;
+	else
+		flag_item = flag1_item;
+
+	if (targ->client->pers.inventory[ITEM_INDEX(flag_item)] &&
+		targ->client->resp.ctf_team != attacker->client->resp.ctf_team)
+		attacker->client->resp.ctf_lasthurtcarrier = level.time;
+}
+
+
+/*------------------------------------------------------------------------*/
+
+void CTFResetFlag(int ctf_team)
+{
+	char *c;
+	edict_t *ent;
+
+	switch (ctf_team) {
+	case CTF_TEAM1:
+		c = "item_flag_team1";
+		break;
+	case CTF_TEAM2:
+		c = "item_flag_team2";
+		break;
+	default:
+		return;
+	}
+
+	ent = NULL;
+	while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
+		if (ent->spawnflags & DROPPED_ITEM)
+			G_FreeEdict(ent);
+		else {
+			ent->svflags &= ~SVF_NOCLIENT;
+			ent->solid = SOLID_TRIGGER;
+			gi.linkentity(ent);
+			ent->s.event = EV_ITEM_RESPAWN;
+		}
+	}
+}
+
+void CTFResetFlags(void)
+{
+	CTFResetFlag(CTF_TEAM1);
+	CTFResetFlag(CTF_TEAM2);
+}
+
+qboolean CTFPickup_Flag(edict_t *ent, edict_t *other)
+{
+	int ctf_team;
+	int i;
+	edict_t *player;
+	gitem_t *flag_item, *enemy_flag_item;
+
+	// figure out what team this flag is
+	if (strcmp(ent->classname, "item_flag_team1") == 0)
+		ctf_team = CTF_TEAM1;
+	else if (strcmp(ent->classname, "item_flag_team2") == 0)
+		ctf_team = CTF_TEAM2;
+	else {
+		gi.cprintf(ent, PRINT_HIGH, "Don't know what team the flag is on.\n");
+		return false;
+	}
+
+	// same team, if the flag at base, check to he has the enemy flag
+	if (ctf_team == CTF_TEAM1) {
+		flag_item = flag1_item;
+		enemy_flag_item = flag2_item;
+	} else {
+		flag_item = flag2_item;
+		enemy_flag_item = flag1_item;
+	}
+
+	if (ctf_team == other->client->resp.ctf_team) {
+
+		if (!(ent->spawnflags & DROPPED_ITEM)) {
+			// the flag is at home base.  if the player has the enemy
+			// flag, he's just won!
+		
+			if (other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)]) {
+				gi.bprintf(PRINT_HIGH, "%s captured the %s flag!\n",
+						other->client->pers.netname, CTFOtherTeamName(ctf_team));
+				other->client->pers.inventory[ITEM_INDEX(enemy_flag_item)] = 0;
+
+				ctfgame.last_flag_capture = level.time;
+				ctfgame.last_capture_team = ctf_team;
+				if (ctf_team == CTF_TEAM1)
+					ctfgame.team1++;
+				else
+					ctfgame.team2++;
+
+				gi.sound (ent, CHAN_RELIABLE+CHAN_NO_PHS_ADD+CHAN_VOICE, gi.soundindex("ctf/flagcap.wav"), 1, ATTN_NONE, 0);
+
+				// other gets another 10 frag bonus
+				other->client->resp.score += CTF_CAPTURE_BONUS;
+				if (other->client->resp.ghost)
+					other->client->resp.ghost->caps++;
+
+				// Ok, let's do the player loop, hand out the bonuses
+				for (i = 1; i <= maxclients->value; i++) {
+					player = &g_edicts[i];
+					if (!player->inuse)
+						continue;
+
+					if (player->client->resp.ctf_team != other->client->resp.ctf_team)
+						player->client->resp.ctf_lasthurtcarrier = -5;
+					else if (player->client->resp.ctf_team == other->client->resp.ctf_team) {
+						if (player != other)
+							player->client->resp.score += CTF_TEAM_BONUS;
+						// award extra points for capture assists
+						if (player->client->resp.ctf_lastreturnedflag + CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
+							gi.bprintf(PRINT_HIGH, "%s gets an assist for returning the flag!\n", player->client->pers.netname);
+							player->client->resp.score += CTF_RETURN_FLAG_ASSIST_BONUS;
+						}
+						if (player->client->resp.ctf_lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
+							gi.bprintf(PRINT_HIGH, "%s gets an assist for fragging the flag carrier!\n", player->client->pers.netname);
+							player->client->resp.score += CTF_FRAG_CARRIER_ASSIST_BONUS;
+						}
+					}
+				}
+
+				CTFResetFlags();
+				return false;
+			}
+			return false; // its at home base already
+		}	
+		// hey, its not home.  return it by teleporting it back
+		gi.bprintf(PRINT_HIGH, "%s returned the %s flag!\n", 
+			other->client->pers.netname, CTFTeamName(ctf_team));
+		other->client->resp.score += CTF_RECOVERY_BONUS;
+		other->client->resp.ctf_lastreturnedflag = level.time;
+		gi.sound (ent, CHAN_RELIABLE+CHAN_NO_PHS_ADD+CHAN_VOICE, gi.soundindex("ctf/flagret.wav"), 1, ATTN_NONE, 0);
+		//CTFResetFlag will remove this entity!  We must return false
+		CTFResetFlag(ctf_team);
+		return false;
+	}
+
+	// hey, its not our flag, pick it up
+	gi.bprintf(PRINT_HIGH, "%s got the %s flag!\n",
+		other->client->pers.netname, CTFTeamName(ctf_team));
+	other->client->resp.score += CTF_FLAG_BONUS;
+
+	other->client->pers.inventory[ITEM_INDEX(flag_item)] = 1;
+	other->client->resp.ctf_flagsince = level.time;
+
+	// pick up the flag
+	// if it's not a dropped flag, we just make is disappear
+	// if it's dropped, it will be removed by the pickup caller
+	if (!(ent->spawnflags & DROPPED_ITEM)) {
+		ent->flags |= FL_RESPAWN;
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+	}
+	return true;
+}
+
+static void CTFDropFlagTouch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	//owner (who dropped us) can't touch for two secs
+	if (other == ent->owner && 
+		ent->nextthink - level.time > CTF_AUTO_FLAG_RETURN_TIMEOUT-2)
+		return;
+
+	Touch_Item (ent, other, plane, surf);
+}
+
+static void CTFDropFlagThink(edict_t *ent)
+{
+	// auto return the flag
+	// reset flag will remove ourselves
+	if (strcmp(ent->classname, "item_flag_team1") == 0) {
+		CTFResetFlag(CTF_TEAM1);
+		gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
+			CTFTeamName(CTF_TEAM1));
+	} else if (strcmp(ent->classname, "item_flag_team2") == 0) {
+		CTFResetFlag(CTF_TEAM2);
+		gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
+			CTFTeamName(CTF_TEAM2));
+	}
+}
+
+// Called from PlayerDie, to drop the flag from a dying player
+void CTFDeadDropFlag(edict_t *self)
+{
+	edict_t *dropped = NULL;
+
+	if (self->client->pers.inventory[ITEM_INDEX(flag1_item)]) {
+		dropped = Drop_Item(self, flag1_item);
+		self->client->pers.inventory[ITEM_INDEX(flag1_item)] = 0;
+		gi.bprintf(PRINT_HIGH, "%s lost the %s flag!\n",
+			self->client->pers.netname, CTFTeamName(CTF_TEAM1));
+	} else if (self->client->pers.inventory[ITEM_INDEX(flag2_item)]) {
+		dropped = Drop_Item(self, flag2_item);
+		self->client->pers.inventory[ITEM_INDEX(flag2_item)] = 0;
+		gi.bprintf(PRINT_HIGH, "%s lost the %s flag!\n",
+			self->client->pers.netname, CTFTeamName(CTF_TEAM2));
+	}
+
+	if (dropped) {
+		dropped->think = CTFDropFlagThink;
+		dropped->nextthink = level.time + CTF_AUTO_FLAG_RETURN_TIMEOUT;
+		dropped->touch = CTFDropFlagTouch;
+	}
+}
+
+qboolean CTFDrop_Flag(edict_t *ent, gitem_t *item)
+{
+	if (rand() & 1) 
+		gi.cprintf(ent, PRINT_HIGH, "Only lusers drop flags.\n");
+	else
+		gi.cprintf(ent, PRINT_HIGH, "Winners don't drop flags.\n");
+	return false;
+}
+
+static void CTFFlagThink(edict_t *ent)
+{
+	if (ent->solid != SOLID_NOT)
+		ent->s.frame = 173 + (((ent->s.frame - 173) + 1) % 16);
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+
+void CTFFlagSetup (edict_t *ent)
+{
+	trace_t		tr;
+	vec3_t		dest;
+	float		*v;
+
+	v = tv(-15,-15,-15);
+	VectorCopy (v, ent->mins);
+	v = tv(15,15,15);
+	VectorCopy (v, ent->maxs);
+
+	if (ent->model)
+		gi.setmodel (ent, ent->model);
+	else
+		gi.setmodel (ent, ent->item->world_model);
+	ent->solid = SOLID_TRIGGER;
+	ent->movetype = MOVETYPE_TOSS;  
+	ent->touch = Touch_Item;
+
+	v = tv(0,0,-128);
+	VectorAdd (ent->s.origin, v, dest);
+
+	tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
+	if (tr.startsolid)
+	{
+		gi.dprintf ("CTFFlagSetup: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	VectorCopy (tr.endpos, ent->s.origin);
+
+	gi.linkentity (ent);
+
+	ent->nextthink = level.time + FRAMETIME;
+	ent->think = CTFFlagThink;
+}
+
+void CTFEffects(edict_t *player)
+{
+	player->s.effects &= ~(EF_FLAG1 | EF_FLAG2);
+	if (player->health > 0) {
+		if (player->client->pers.inventory[ITEM_INDEX(flag1_item)]) {
+			player->s.effects |= EF_FLAG1;
+		}
+		if (player->client->pers.inventory[ITEM_INDEX(flag2_item)]) {
+			player->s.effects |= EF_FLAG2;
+		}
+	}
+
+	if (player->client->pers.inventory[ITEM_INDEX(flag1_item)])
+		player->s.modelindex3 = gi.modelindex("players/male/flag1.md2");
+	else if (player->client->pers.inventory[ITEM_INDEX(flag2_item)])
+		player->s.modelindex3 = gi.modelindex("players/male/flag2.md2");
+	else
+		player->s.modelindex3 = 0;
+}
+
+// called when we enter the intermission
+void CTFCalcScores(void)
+{
+	int i;
+
+	ctfgame.total1 = ctfgame.total2 = 0;
+	for (i = 0; i < maxclients->value; i++) {
+		if (!g_edicts[i+1].inuse)
+			continue;
+		if (game.clients[i].resp.ctf_team == CTF_TEAM1)
+			ctfgame.total1 += game.clients[i].resp.score;
+		else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
+			ctfgame.total2 += game.clients[i].resp.score;
+	}
+}
+
+void CTFID_f (edict_t *ent)
+{
+	if (ent->client->resp.id_state) {
+		gi.cprintf(ent, PRINT_HIGH, "Disabling player identication display.\n");
+		ent->client->resp.id_state = false;
+	} else {
+		gi.cprintf(ent, PRINT_HIGH, "Activating player identication display.\n");
+		ent->client->resp.id_state = true;
+	}
+}
+
+static void CTFSetIDView(edict_t *ent)
+{
+	vec3_t	forward, dir;
+	trace_t	tr;
+	edict_t	*who, *best;
+	float	bd = 0, d;
+	int i;
+
+	ent->client->ps.stats[STAT_CTF_ID_VIEW] = 0;
+
+	AngleVectors(ent->client->v_angle, forward, NULL, NULL);
+	VectorScale(forward, 1024, forward);
+	VectorAdd(ent->s.origin, forward, forward);
+	tr = gi.trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
+	if (tr.fraction < 1 && tr.ent && tr.ent->client) {
+		ent->client->ps.stats[STAT_CTF_ID_VIEW] = 
+			CS_PLAYERSKINS + (ent - g_edicts - 1);
+		return;
+	}
+
+	AngleVectors(ent->client->v_angle, forward, NULL, NULL);
+	best = NULL;
+	for (i = 1; i <= maxclients->value; i++) {
+		who = g_edicts + i;
+		if (!who->inuse || who->solid == SOLID_NOT)
+			continue;
+		VectorSubtract(who->s.origin, ent->s.origin, dir);
+		VectorNormalize(dir);
+		d = DotProduct(forward, dir);
+		if (d > bd && loc_CanSee(ent, who)) {
+			bd = d;
+			best = who;
+		}
+	}
+	if (bd > 0.90)
+		ent->client->ps.stats[STAT_CTF_ID_VIEW] = 
+			CS_PLAYERSKINS + (best - g_edicts - 1);
+}
+
+void SetCTFStats(edict_t *ent)
+{
+	gitem_t *tech;
+	int i;
+	int p1, p2;
+	edict_t *e;
+
+	if (ctfgame.match > MATCH_NONE)
+		ent->client->ps.stats[STAT_CTF_MATCH] = CONFIG_CTF_MATCH;
+	else
+		ent->client->ps.stats[STAT_CTF_MATCH] = 0;
+
+	//ghosting
+	if (ent->client->resp.ghost) {
+		ent->client->resp.ghost->score = ent->client->resp.score;
+		strcpy(ent->client->resp.ghost->netname, ent->client->pers.netname);
+		ent->client->resp.ghost->number = ent->s.number;
+	}
+
+	// logo headers for the frag display
+	ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = gi.imageindex ("ctfsb1");
+	ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = gi.imageindex ("ctfsb2");
+
+	// if during intermission, we must blink the team header of the winning team
+	if (level.intermissiontime && (level.framenum & 8)) { // blink 1/8th second
+		// note that ctfgame.total[12] is set when we go to intermission
+		if (ctfgame.team1 > ctfgame.team2)
+			ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
+		else if (ctfgame.team2 > ctfgame.team1)
+			ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
+		else if (ctfgame.total1 > ctfgame.total2) // frag tie breaker
+			ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
+		else if (ctfgame.total2 > ctfgame.total1) 
+			ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
+		else { // tie game!
+			ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
+			ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
+		}
+	}
+
+	// tech icon
+	i = 0;
+	ent->client->ps.stats[STAT_CTF_TECH] = 0;
+	while (tnames[i]) {
+		if ((tech = FindItemByClassname(tnames[i])) != NULL &&
+			ent->client->pers.inventory[ITEM_INDEX(tech)]) {
+			ent->client->ps.stats[STAT_CTF_TECH] = gi.imageindex(tech->icon);
+			break;
+		}
+		i++;
+	}
+
+	// figure out what icon to display for team logos
+	// three states:
+	//   flag at base
+	//   flag taken
+	//   flag dropped
+	p1 = gi.imageindex ("i_ctf1");
+	e = G_Find(NULL, FOFS(classname), "item_flag_team1");
+	if (e != NULL) {
+		if (e->solid == SOLID_NOT) {
+			int i;
+
+			// not at base
+			// check if on player
+			p1 = gi.imageindex ("i_ctf1d"); // default to dropped
+			for (i = 1; i <= maxclients->value; i++)
+				if (g_edicts[i].inuse &&
+					g_edicts[i].client->pers.inventory[ITEM_INDEX(flag1_item)]) {
+					// enemy has it
+					p1 = gi.imageindex ("i_ctf1t");
+					break;
+				}
+		} else if (e->spawnflags & DROPPED_ITEM)
+			p1 = gi.imageindex ("i_ctf1d"); // must be dropped
+	}
+	p2 = gi.imageindex ("i_ctf2");
+	e = G_Find(NULL, FOFS(classname), "item_flag_team2");
+	if (e != NULL) {
+		if (e->solid == SOLID_NOT) {
+			int i;
+
+			// not at base
+			// check if on player
+			p2 = gi.imageindex ("i_ctf2d"); // default to dropped
+			for (i = 1; i <= maxclients->value; i++)
+				if (g_edicts[i].inuse &&
+					g_edicts[i].client->pers.inventory[ITEM_INDEX(flag2_item)]) {
+					// enemy has it
+					p2 = gi.imageindex ("i_ctf2t");
+					break;
+				}
+		} else if (e->spawnflags & DROPPED_ITEM)
+			p2 = gi.imageindex ("i_ctf2d"); // must be dropped
+	}
+
+
+	ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
+	ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
+
+	if (ctfgame.last_flag_capture && level.time - ctfgame.last_flag_capture < 5) {
+		if (ctfgame.last_capture_team == CTF_TEAM1)
+			if (level.framenum & 8)
+				ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
+			else
+				ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = 0;
+		else
+			if (level.framenum & 8)
+				ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
+			else
+				ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = 0;
+	}
+
+	ent->client->ps.stats[STAT_CTF_TEAM1_CAPS] = ctfgame.team1;
+	ent->client->ps.stats[STAT_CTF_TEAM2_CAPS] = ctfgame.team2;
+
+	ent->client->ps.stats[STAT_CTF_FLAG_PIC] = 0;
+	if (ent->client->resp.ctf_team == CTF_TEAM1 &&
+		ent->client->pers.inventory[ITEM_INDEX(flag2_item)] &&
+		(level.framenum & 8))
+		ent->client->ps.stats[STAT_CTF_FLAG_PIC] = gi.imageindex ("i_ctf2");
+
+	else if (ent->client->resp.ctf_team == CTF_TEAM2 &&
+		ent->client->pers.inventory[ITEM_INDEX(flag1_item)] &&
+		(level.framenum & 8))
+		ent->client->ps.stats[STAT_CTF_FLAG_PIC] = gi.imageindex ("i_ctf1");
+
+	ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = 0;
+	ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = 0;
+	if (ent->client->resp.ctf_team == CTF_TEAM1)
+		ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = gi.imageindex ("i_ctfj");
+	else if (ent->client->resp.ctf_team == CTF_TEAM2)
+		ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = gi.imageindex ("i_ctfj");
+
+	ent->client->ps.stats[STAT_CTF_ID_VIEW] = 0;
+	if (ent->client->resp.id_state)
+		CTFSetIDView(ent);
+}
+
+/*------------------------------------------------------------------------*/
+
+/*QUAKED info_player_team1 (1 0 0) (-16 -16 -24) (16 16 32)
+potential team1 spawning position for ctf games
+*/
+void SP_info_player_team1(edict_t *self)
+{
+}
+
+/*QUAKED info_player_team2 (0 0 1) (-16 -16 -24) (16 16 32)
+potential team2 spawning position for ctf games
+*/
+void SP_info_player_team2(edict_t *self)
+{
+}
+
+
+/*------------------------------------------------------------------------*/
+/* GRAPPLE																  */
+/*------------------------------------------------------------------------*/
+
+// ent is player
+void CTFPlayerResetGrapple(edict_t *ent)
+{
+	if (ent->client && ent->client->ctf_grapple)
+		CTFResetGrapple(ent->client->ctf_grapple);
+}
+
+// self is grapple, not player
+void CTFResetGrapple(edict_t *self)
+{
+	if (self->owner->client->ctf_grapple) {
+		float volume = 1.0;
+		gclient_t *cl;
+
+		if (self->owner->client->silencer_shots)
+			volume = 0.2;
+
+		gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grreset.wav"), volume, ATTN_NORM, 0);
+		cl = self->owner->client;
+		cl->ctf_grapple = NULL;
+		cl->ctf_grapplereleasetime = level.time;
+		cl->ctf_grapplestate = CTF_GRAPPLE_STATE_FLY; // we're firing, not on hook
+		cl->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
+		G_FreeEdict(self);
+	}
+}
+
+void CTFGrappleTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	float volume = 1.0;
+
+	if (other == self->owner)
+		return;
+
+	if (self->owner->client->ctf_grapplestate != CTF_GRAPPLE_STATE_FLY)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		CTFResetGrapple(self);
+		return;
+	}
+
+	VectorCopy(vec3_origin, self->velocity);
+
+	PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
+
+	if (other->takedamage) {
+		T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, 0, MOD_GRAPPLE);
+		CTFResetGrapple(self);
+		return;
+	}
+
+	self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_PULL; // we're on hook
+	self->enemy = other;
+
+	self->solid = SOLID_NOT;
+
+	if (self->owner->client->silencer_shots)
+		volume = 0.2;
+
+	gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grpull.wav"), volume, ATTN_NORM, 0);
+	gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhit.wav"), volume, ATTN_NORM, 0);
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_SPARKS);
+	gi.WritePosition (self->s.origin);
+	if (!plane)
+		gi.WriteDir (vec3_origin);
+	else
+		gi.WriteDir (plane->normal);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+}
+
+// draw beam between grapple and self
+void CTFGrappleDrawCable(edict_t *self)
+{
+	vec3_t	offset, start, end, f, r;
+	vec3_t	dir;
+	float	distance;
+
+	AngleVectors (self->owner->client->v_angle, f, r, NULL);
+	VectorSet(offset, 16, 16, self->owner->viewheight-8);
+	P_ProjectSource (self->owner->client, self->owner->s.origin, offset, f, r, start);
+
+	VectorSubtract(start, self->owner->s.origin, offset);
+
+	VectorSubtract (start, self->s.origin, dir);
+	distance = VectorLength(dir);
+	// don't draw cable if close
+	if (distance < 64)
+		return;
+
+#if 0
+	if (distance > 256)
+		return;
+
+	// check for min/max pitch
+	vectoangles (dir, angles);
+	if (angles[0] < -180)
+		angles[0] += 360;
+	if (fabs(angles[0]) > 45)
+		return;
+
+	trace_t	tr; //!!
+
+	tr = gi.trace (start, NULL, NULL, self->s.origin, self, MASK_SHOT);
+	if (tr.ent != self) {
+		CTFResetGrapple(self);
+		return;
+	}
+#endif
+
+	// adjust start for beam origin being in middle of a segment
+//	VectorMA (start, 8, f, start);
+
+	VectorCopy (self->s.origin, end);
+	// adjust end z for end spot since the monster is currently dead
+//	end[2] = self->absmin[2] + self->size[2] / 2;
+
+	gi.WriteByte (svc_temp_entity);
+#if 1 //def USE_GRAPPLE_CABLE
+	gi.WriteByte (TE_GRAPPLE_CABLE);
+	gi.WriteShort (self->owner - g_edicts);
+	gi.WritePosition (self->owner->s.origin);
+	gi.WritePosition (end);
+	gi.WritePosition (offset);
+#else
+	gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
+	gi.WriteShort (self - g_edicts);
+	gi.WritePosition (end);
+	gi.WritePosition (start);
+#endif
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+}
+
+void SV_AddGravity (edict_t *ent);
+
+// pull the player toward the grapple
+void CTFGrapplePull(edict_t *self)
+{
+	vec3_t hookdir, v;
+	float vlen;
+
+	if (strcmp(self->owner->client->pers.weapon->classname, "weapon_grapple") == 0 &&
+		!self->owner->client->newweapon &&
+		self->owner->client->weaponstate != WEAPON_FIRING &&
+		self->owner->client->weaponstate != WEAPON_ACTIVATING) {
+		CTFResetGrapple(self);
+		return;
+	}
+
+	if (self->enemy) {
+		if (self->enemy->solid == SOLID_NOT) {
+			CTFResetGrapple(self);
+			return;
+		}
+		if (self->enemy->solid == SOLID_BBOX) {
+			VectorScale(self->enemy->size, 0.5, v);
+			VectorAdd(v, self->enemy->s.origin, v);
+			VectorAdd(v, self->enemy->mins, self->s.origin);
+			gi.linkentity (self);
+		} else
+			VectorCopy(self->enemy->velocity, self->velocity);
+		if (self->enemy->takedamage &&
+			!CheckTeamDamage (self->enemy, self->owner)) {
+			float volume = 1.0;
+
+			if (self->owner->client->silencer_shots)
+				volume = 0.2;
+
+			T_Damage (self->enemy, self, self->owner, self->velocity, self->s.origin, vec3_origin, 1, 1, 0, MOD_GRAPPLE);
+			gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhurt.wav"), volume, ATTN_NORM, 0);
+		}
+		if (self->enemy->deadflag) { // he died
+			CTFResetGrapple(self);
+			return;
+		}
+	}
+
+	CTFGrappleDrawCable(self);
+
+	if (self->owner->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) {
+		// pull player toward grapple
+		// this causes icky stuff with prediction, we need to extend
+		// the prediction layer to include two new fields in the player
+		// move stuff: a point and a velocity.  The client should add
+		// that velociy in the direction of the point
+		vec3_t forward, up;
+
+		AngleVectors (self->owner->client->v_angle, forward, NULL, up);
+		VectorCopy(self->owner->s.origin, v);
+		v[2] += self->owner->viewheight;
+		VectorSubtract (self->s.origin, v, hookdir);
+
+		vlen = VectorLength(hookdir);
+
+		if (self->owner->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL &&
+			vlen < 64) {
+			float volume = 1.0;
+
+			if (self->owner->client->silencer_shots)
+				volume = 0.2;
+
+			self->owner->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
+			gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grhang.wav"), volume, ATTN_NORM, 0);
+			self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_HANG;
+		}
+
+		VectorNormalize (hookdir);
+		VectorScale(hookdir, CTF_GRAPPLE_PULL_SPEED, hookdir);
+		VectorCopy(hookdir, self->owner->velocity);
+		SV_AddGravity(self->owner);
+	}
+}
+
+void CTFFireGrapple (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect)
+{
+	edict_t	*grapple;
+	trace_t	tr;
+
+	VectorNormalize (dir);
+
+	grapple = G_Spawn();
+	VectorCopy (start, grapple->s.origin);
+	VectorCopy (start, grapple->s.old_origin);
+	vectoangles (dir, grapple->s.angles);
+	VectorScale (dir, speed, grapple->velocity);
+	grapple->movetype = MOVETYPE_FLYMISSILE;
+	grapple->clipmask = MASK_SHOT;
+	grapple->solid = SOLID_BBOX;
+	grapple->s.effects |= effect;
+	VectorClear (grapple->mins);
+	VectorClear (grapple->maxs);
+	grapple->s.modelindex = gi.modelindex ("models/weapons/grapple/hook/tris.md2");
+//	grapple->s.sound = gi.soundindex ("misc/lasfly.wav");
+	grapple->owner = self;
+	grapple->touch = CTFGrappleTouch;
+//	grapple->nextthink = level.time + FRAMETIME;
+//	grapple->think = CTFGrappleThink;
+	grapple->dmg = damage;
+	self->client->ctf_grapple = grapple;
+	self->client->ctf_grapplestate = CTF_GRAPPLE_STATE_FLY; // we're firing, not on hook
+	gi.linkentity (grapple);
+
+	tr = gi.trace (self->s.origin, NULL, NULL, grapple->s.origin, grapple, MASK_SHOT);
+	if (tr.fraction < 1.0)
+	{
+		VectorMA (grapple->s.origin, -10, dir, grapple->s.origin);
+		grapple->touch (grapple, tr.ent, NULL, NULL);
+	}
+}	
+
+void CTFGrappleFire (edict_t *ent, vec3_t g_offset, int damage, int effect)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	offset;
+	float volume = 1.0;
+
+	if (ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY)
+		return; // it's already out
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+//	VectorSet(offset, 24, 16, ent->viewheight-8+2);
+	VectorSet(offset, 24, 8, ent->viewheight-8+2);
+	VectorAdd (offset, g_offset, offset);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	if (ent->client->silencer_shots)
+		volume = 0.2;
+
+	gi.sound (ent, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grfire.wav"), volume, ATTN_NORM, 0);
+	CTFFireGrapple (ent, start, forward, damage, CTF_GRAPPLE_SPEED, effect);
+
+#if 0
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_BLASTER);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+#endif
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+}
+
+
+void CTFWeapon_Grapple_Fire (edict_t *ent)
+{
+	int		damage;
+
+	damage = 10;
+	CTFGrappleFire (ent, vec3_origin, damage, 0);
+	ent->client->ps.gunframe++;
+}
+
+void CTFWeapon_Grapple (edict_t *ent)
+{
+	static int	pause_frames[]	= {10, 18, 27, 0};
+	static int	fire_frames[]	= {6, 0};
+	int prevstate;
+
+	// if the the attack button is still down, stay in the firing frame
+	if ((ent->client->buttons & BUTTON_ATTACK) && 
+		ent->client->weaponstate == WEAPON_FIRING &&
+		ent->client->ctf_grapple)
+		ent->client->ps.gunframe = 9;
+
+	if (!(ent->client->buttons & BUTTON_ATTACK) && 
+		ent->client->ctf_grapple) {
+		CTFResetGrapple(ent->client->ctf_grapple);
+		if (ent->client->weaponstate == WEAPON_FIRING)
+			ent->client->weaponstate = WEAPON_READY;
+	}
+
+
+	if (ent->client->newweapon && 
+		ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY &&
+		ent->client->weaponstate == WEAPON_FIRING) {
+		// he wants to change weapons while grappled
+		ent->client->weaponstate = WEAPON_DROPPING;
+		ent->client->ps.gunframe = 32;
+	}
+
+	prevstate = ent->client->weaponstate;
+	Weapon_Generic (ent, 5, 9, 31, 36, pause_frames, fire_frames, 
+		CTFWeapon_Grapple_Fire);
+
+	// if we just switched back to grapple, immediately go to fire frame
+	if (prevstate == WEAPON_ACTIVATING &&
+		ent->client->weaponstate == WEAPON_READY &&
+		ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) {
+		if (!(ent->client->buttons & BUTTON_ATTACK))
+			ent->client->ps.gunframe = 9;
+		else
+			ent->client->ps.gunframe = 5;
+		ent->client->weaponstate = WEAPON_FIRING;
+	}
+}
+
+void CTFTeam_f (edict_t *ent)
+{
+	char *t, *s;
+	int desired_team;
+
+	t = gi.args();
+	if (!*t) {
+		gi.cprintf(ent, PRINT_HIGH, "You are on the %s team.\n",
+			CTFTeamName(ent->client->resp.ctf_team));
+		return;
+	}
+
+	if (ctfgame.match > MATCH_SETUP) {
+		gi.cprintf(ent, PRINT_HIGH, "Can't change teams in a match.\n");
+		return;
+	}
+
+	if (Q_stricmp(t, "red") == 0)
+		desired_team = CTF_TEAM1;
+	else if (Q_stricmp(t, "blue") == 0)
+		desired_team = CTF_TEAM2;
+	else {
+		gi.cprintf(ent, PRINT_HIGH, "Unknown team %s.\n", t);
+		return;
+	}
+
+	if (ent->client->resp.ctf_team == desired_team) {
+		gi.cprintf(ent, PRINT_HIGH, "You are already on the %s team.\n",
+			CTFTeamName(ent->client->resp.ctf_team));
+		return;
+	}
+
+////
+	ent->svflags = 0;
+	ent->flags &= ~FL_GODMODE;
+	ent->client->resp.ctf_team = desired_team;
+	ent->client->resp.ctf_state = 0;
+	s = Info_ValueForKey (ent->client->pers.userinfo, "skin");
+	CTFAssignSkin(ent, s);
+
+	if (ent->solid == SOLID_NOT) { // spectator
+		PutClientInServer (ent);
+		// add a teleportation effect
+		ent->s.event = EV_PLAYER_TELEPORT;
+		// hold in place briefly
+		ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+		ent->client->ps.pmove.pm_time = 14;
+		gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
+			ent->client->pers.netname, CTFTeamName(desired_team));
+		return;
+	}
+
+	ent->health = 0;
+	player_die (ent, ent, ent, 100000, vec3_origin);
+	// don't even bother waiting for death frames
+	ent->deadflag = DEAD_DEAD;
+	respawn (ent);
+
+	ent->client->resp.score = 0;
+
+	gi.bprintf(PRINT_HIGH, "%s changed to the %s team.\n",
+		ent->client->pers.netname, CTFTeamName(desired_team));
+}
+
+/*
+==================
+CTFScoreboardMessage
+==================
+*/
+void CTFScoreboardMessage (edict_t *ent, edict_t *killer)
+{
+	char	entry[1024];
+	char	string[1400];
+	int		len;
+	int		i, j, k, n;
+	int		sorted[2][MAX_CLIENTS];
+	int		sortedscores[2][MAX_CLIENTS];
+	int		score, total[2], totalscore[2];
+	int		last[2];
+	gclient_t	*cl;
+	edict_t		*cl_ent;
+	int team;
+	int maxsize = 1000;
+
+	// sort the clients by team and score
+	total[0] = total[1] = 0;
+	last[0] = last[1] = 0;
+	totalscore[0] = totalscore[1] = 0;
+	for (i=0 ; i<game.maxclients ; i++)
+	{
+		cl_ent = g_edicts + 1 + i;
+		if (!cl_ent->inuse)
+			continue;
+		if (game.clients[i].resp.ctf_team == CTF_TEAM1)
+			team = 0;
+		else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
+			team = 1;
+		else
+			continue; // unknown team?
+
+		score = game.clients[i].resp.score;
+		for (j=0 ; j<total[team] ; j++)
+		{
+			if (score > sortedscores[team][j])
+				break;
+		}
+		for (k=total[team] ; k>j ; k--)
+		{
+			sorted[team][k] = sorted[team][k-1];
+			sortedscores[team][k] = sortedscores[team][k-1];
+		}
+		sorted[team][j] = i;
+		sortedscores[team][j] = score;
+		totalscore[team] += score;
+		total[team]++;
+	}
+
+	// print level name and exit rules
+	// add the clients in sorted order
+	*string = 0;
+	len = 0;
+
+	// team one
+	sprintf(string, "if 24 xv 8 yv 8 pic 24 endif "
+		"xv 40 yv 28 string \"%4d/%-3d\" "
+		"xv 98 yv 12 num 2 18 "
+		"if 25 xv 168 yv 8 pic 25 endif "
+		"xv 200 yv 28 string \"%4d/%-3d\" "
+		"xv 256 yv 12 num 2 20 ",
+		totalscore[0], total[0],
+		totalscore[1], total[1]);
+	len = strlen(string);
+
+	for (i=0 ; i<16 ; i++)
+	{
+		if (i >= total[0] && i >= total[1])
+			break; // we're done
+
+#if 0 //ndef NEW_SCORE
+		// set up y
+		sprintf(entry, "yv %d ", 42 + i * 8);
+		if (maxsize - len > strlen(entry)) {
+			strcat(string, entry);
+			len = strlen(string);
+		}
+#else
+		*entry = 0;
+#endif
+
+		// left side
+		if (i < total[0]) {
+			cl = &game.clients[sorted[0][i]];
+			cl_ent = g_edicts + 1 + sorted[0][i];
+
+#if 0 //ndef NEW_SCORE
+			sprintf(entry+strlen(entry),
+			"xv 0 %s \"%3d %3d %-12.12s\" ",
+			(cl_ent == ent) ? "string2" : "string",
+			cl->resp.score, 
+			(cl->ping > 999) ? 999 : cl->ping, 
+			cl->pers.netname);
+
+			if (cl_ent->client->pers.inventory[ITEM_INDEX(flag2_item)])
+				strcat(entry, "xv 56 picn sbfctf2 ");
+#else
+			sprintf(entry+strlen(entry),
+				"ctf 0 %d %d %d %d ",
+				42 + i * 8,
+				sorted[0][i],
+				cl->resp.score,
+				cl->ping > 999 ? 999 : cl->ping);
+
+			if (cl_ent->client->pers.inventory[ITEM_INDEX(flag2_item)])
+				sprintf(entry + strlen(entry), "xv 56 yv %d picn sbfctf2 ",
+					42 + i * 8);
+#endif
+
+			if (maxsize - len > strlen(entry)) {
+				strcat(string, entry);
+				len = strlen(string);
+				last[0] = i;
+			}
+		}
+
+		// right side
+		if (i < total[1]) {
+			cl = &game.clients[sorted[1][i]];
+			cl_ent = g_edicts + 1 + sorted[1][i];
+
+#if 0 //ndef NEW_SCORE
+			sprintf(entry+strlen(entry),
+			"xv 160 %s \"%3d %3d %-12.12s\" ",
+			(cl_ent == ent) ? "string2" : "string",
+			cl->resp.score, 
+			(cl->ping > 999) ? 999 : cl->ping, 
+			cl->pers.netname);
+
+			if (cl_ent->client->pers.inventory[ITEM_INDEX(flag1_item)])
+				strcat(entry, "xv 216 picn sbfctf1 ");
+
+#else
+
+			sprintf(entry+strlen(entry),
+				"ctf 160 %d %d %d %d ",
+				42 + i * 8,
+				sorted[1][i],
+				cl->resp.score,
+				cl->ping > 999 ? 999 : cl->ping);
+
+			if (cl_ent->client->pers.inventory[ITEM_INDEX(flag1_item)])
+				sprintf(entry + strlen(entry), "xv 216 yv %d picn sbfctf1 ",
+					42 + i * 8);
+#endif
+			if (maxsize - len > strlen(entry)) {
+				strcat(string, entry);
+				len = strlen(string);
+				last[1] = i;
+			}
+		}
+	}
+
+	// put in spectators if we have enough room
+	if (last[0] > last[1])
+		j = last[0];
+	else
+		j = last[1];
+	j = (j + 2) * 8 + 42;
+
+	k = n = 0;
+	if (maxsize - len > 50) {
+		for (i = 0; i < maxclients->value; i++) {
+			cl_ent = g_edicts + 1 + i;
+			cl = &game.clients[i];
+			if (!cl_ent->inuse ||
+				cl_ent->solid != SOLID_NOT ||
+				cl_ent->client->resp.ctf_team != CTF_NOTEAM)
+				continue;
+
+			if (!k) {
+				k = 1;
+				sprintf(entry, "xv 0 yv %d string2 \"Spectators\" ", j);
+				strcat(string, entry);
+				len = strlen(string);
+				j += 8;
+			}
+
+			sprintf(entry+strlen(entry),
+				"ctf %d %d %d %d %d ",
+				(n & 1) ? 160 : 0, // x
+				j, // y
+				i, // playernum
+				cl->resp.score,
+				cl->ping > 999 ? 999 : cl->ping);
+			if (maxsize - len > strlen(entry)) {
+				strcat(string, entry);
+				len = strlen(string);
+			}
+			
+			if (n & 1)
+				j += 8;
+			n++;
+		}
+	}
+
+	if (total[0] - last[0] > 1) // couldn't fit everyone
+		sprintf(string + strlen(string), "xv 8 yv %d string \"..and %d more\" ",
+			42 + (last[0]+1)*8, total[0] - last[0] - 1);
+	if (total[1] - last[1] > 1) // couldn't fit everyone
+		sprintf(string + strlen(string), "xv 168 yv %d string \"..and %d more\" ",
+			42 + (last[1]+1)*8, total[1] - last[1] - 1);
+
+	gi.WriteByte (svc_layout);
+	gi.WriteString (string);
+}
+
+/*------------------------------------------------------------------------*/
+/* TECH																	  */
+/*------------------------------------------------------------------------*/
+
+void CTFHasTech(edict_t *who)
+{
+	if (level.time - who->client->ctf_lasttechmsg > 2) {
+		gi.centerprintf(who, "You already have a TECH powerup.");
+		who->client->ctf_lasttechmsg = level.time;
+	}
+}
+
+gitem_t *CTFWhat_Tech(edict_t *ent)
+{
+	gitem_t *tech;
+	int i;
+
+	i = 0;
+	while (tnames[i]) {
+		if ((tech = FindItemByClassname(tnames[i])) != NULL &&
+			ent->client->pers.inventory[ITEM_INDEX(tech)]) {
+			return tech;
+		}
+		i++;
+	}
+	return NULL;
+}
+
+qboolean CTFPickup_Tech (edict_t *ent, edict_t *other)
+{
+	gitem_t *tech;
+	int i;
+
+	i = 0;
+	while (tnames[i]) {
+		if ((tech = FindItemByClassname(tnames[i])) != NULL &&
+			other->client->pers.inventory[ITEM_INDEX(tech)]) {
+			CTFHasTech(other);
+			return false; // has this one
+		}
+		i++;
+	}
+	
+	// client only gets one tech
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+	other->client->ctf_regentime = level.time;
+	return true;
+}
+
+static void SpawnTech(gitem_t *item, edict_t *spot);
+
+static edict_t *FindTechSpawn(void)
+{
+	edict_t *spot = NULL;
+	int i = rand() % 16;
+
+	while (i--)
+		spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
+	if (!spot)
+		spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
+	return spot;
+}
+
+static void TechThink(edict_t *tech)
+{
+	edict_t *spot;
+
+	if ((spot = FindTechSpawn()) != NULL) {
+		SpawnTech(tech->item, spot);
+		G_FreeEdict(tech);
+	} else {
+		tech->nextthink = level.time + CTF_TECH_TIMEOUT;
+		tech->think = TechThink;
+	}
+}
+
+void CTFDrop_Tech(edict_t *ent, gitem_t *item)
+{
+	edict_t *tech;
+
+	tech = Drop_Item(ent, item);
+	tech->nextthink = level.time + CTF_TECH_TIMEOUT;
+	tech->think = TechThink;
+	ent->client->pers.inventory[ITEM_INDEX(item)] = 0;
+}
+
+void CTFDeadDropTech(edict_t *ent)
+{
+	gitem_t *tech;
+	edict_t *dropped;
+	int i;
+
+	i = 0;
+	while (tnames[i]) {
+		if ((tech = FindItemByClassname(tnames[i])) != NULL &&
+			ent->client->pers.inventory[ITEM_INDEX(tech)]) {
+			dropped = Drop_Item(ent, tech);
+			// hack the velocity to make it bounce random
+			dropped->velocity[0] = (rand() % 600) - 300;
+			dropped->velocity[1] = (rand() % 600) - 300;
+			dropped->nextthink = level.time + CTF_TECH_TIMEOUT;
+			dropped->think = TechThink;
+			dropped->owner = NULL;
+			ent->client->pers.inventory[ITEM_INDEX(tech)] = 0;
+		}
+		i++;
+	}
+}
+
+static void SpawnTech(gitem_t *item, edict_t *spot)
+{
+	edict_t	*ent;
+	vec3_t	forward, right;
+	vec3_t  angles;
+
+	ent = G_Spawn();
+
+	ent->classname = item->classname;
+	ent->item = item;
+	ent->spawnflags = DROPPED_ITEM;
+	ent->s.effects = item->world_model_flags;
+	ent->s.renderfx = RF_GLOW;
+	VectorSet (ent->mins, -15, -15, -15);
+	VectorSet (ent->maxs, 15, 15, 15);
+	gi.setmodel (ent, ent->item->world_model);
+	ent->solid = SOLID_TRIGGER;
+	ent->movetype = MOVETYPE_TOSS;  
+	ent->touch = Touch_Item;
+	ent->owner = ent;
+
+	angles[0] = 0;
+	angles[1] = rand() % 360;
+	angles[2] = 0;
+
+	AngleVectors (angles, forward, right, NULL);
+	VectorCopy (spot->s.origin, ent->s.origin);
+	ent->s.origin[2] += 16;
+	VectorScale (forward, 100, ent->velocity);
+	ent->velocity[2] = 300;
+
+	ent->nextthink = level.time + CTF_TECH_TIMEOUT;
+	ent->think = TechThink;
+
+	gi.linkentity (ent);
+}
+
+static void SpawnTechs(edict_t *ent)
+{
+	gitem_t *tech;
+	edict_t *spot;
+	int i;
+
+	i = 0;
+	while (tnames[i]) {
+		if ((tech = FindItemByClassname(tnames[i])) != NULL &&
+			(spot = FindTechSpawn()) != NULL)
+			SpawnTech(tech, spot);
+		i++;
+	}
+	if (ent)
+		G_FreeEdict(ent);
+}
+
+// frees the passed edict!
+void CTFRespawnTech(edict_t *ent)
+{
+	edict_t *spot;
+
+	if ((spot = FindTechSpawn()) != NULL)
+		SpawnTech(ent->item, spot);
+	G_FreeEdict(ent);
+}
+
+void CTFSetupTechSpawn(void)
+{
+	edict_t *ent;
+
+	if (((int)dmflags->value & DF_CTF_NO_TECH))
+		return;
+
+	ent = G_Spawn();
+	ent->nextthink = level.time + 2;
+	ent->think = SpawnTechs;
+}
+
+void CTFResetTech(void)
+{
+	edict_t *ent;
+	int i;
+
+	for (ent = g_edicts + 1, i = 1; i < globals.num_edicts; i++, ent++) {
+		if (ent->inuse)
+			if (ent->item && (ent->item->flags & IT_TECH))
+				G_FreeEdict(ent);
+	}
+	SpawnTechs(NULL);
+}
+
+int CTFApplyResistance(edict_t *ent, int dmg)
+{
+	static gitem_t *tech = NULL;
+	float volume = 1.0;
+
+	if (ent->client && ent->client->silencer_shots)
+		volume = 0.2;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech1");
+	if (dmg && tech && ent->client && ent->client->pers.inventory[ITEM_INDEX(tech)]) {
+		// make noise
+	   	gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech1.wav"), volume, ATTN_NORM, 0);
+		return dmg / 2;
+	}
+	return dmg;
+}
+
+int CTFApplyStrength(edict_t *ent, int dmg)
+{
+	static gitem_t *tech = NULL;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech2");
+	if (dmg && tech && ent->client && ent->client->pers.inventory[ITEM_INDEX(tech)]) {
+		return dmg * 2;
+	}
+	return dmg;
+}
+
+qboolean CTFApplyStrengthSound(edict_t *ent)
+{
+	static gitem_t *tech = NULL;
+	float volume = 1.0;
+
+	if (ent->client && ent->client->silencer_shots)
+		volume = 0.2;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech2");
+	if (tech && ent->client &&
+		ent->client->pers.inventory[ITEM_INDEX(tech)]) {
+		if (ent->client->ctf_techsndtime < level.time) {
+			ent->client->ctf_techsndtime = level.time + 1;
+			if (ent->client->quad_framenum > level.framenum)
+				gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech2x.wav"), volume, ATTN_NORM, 0);
+			else
+				gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech2.wav"), volume, ATTN_NORM, 0);
+		}
+		return true;
+	}
+	return false;
+}
+
+
+qboolean CTFApplyHaste(edict_t *ent)
+{
+	static gitem_t *tech = NULL;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech3");
+	if (tech && ent->client &&
+		ent->client->pers.inventory[ITEM_INDEX(tech)])
+		return true;
+	return false;
+}
+
+void CTFApplyHasteSound(edict_t *ent)
+{
+	static gitem_t *tech = NULL;
+	float volume = 1.0;
+
+	if (ent->client && ent->client->silencer_shots)
+		volume = 0.2;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech3");
+	if (tech && ent->client &&
+		ent->client->pers.inventory[ITEM_INDEX(tech)] &&
+		ent->client->ctf_techsndtime < level.time) {
+		ent->client->ctf_techsndtime = level.time + 1;
+		gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech3.wav"), volume, ATTN_NORM, 0);
+	}
+}
+
+void CTFApplyRegeneration(edict_t *ent)
+{
+	static gitem_t *tech = NULL;
+	qboolean noise = false;
+	gclient_t *client;
+	int index;
+	float volume = 1.0;
+
+	client = ent->client;
+	if (!client)
+		return;
+
+	if (ent->client->silencer_shots)
+		volume = 0.2;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech4");
+	if (tech && client->pers.inventory[ITEM_INDEX(tech)]) {
+		if (client->ctf_regentime < level.time) {
+			client->ctf_regentime = level.time;
+			if (ent->health < 150) {
+				ent->health += 5;
+				if (ent->health > 150)
+					ent->health = 150;
+				client->ctf_regentime += 0.5;
+				noise = true;
+			}
+			index = ArmorIndex (ent);
+			if (index && client->pers.inventory[index] < 150) {
+				client->pers.inventory[index] += 5;
+				if (client->pers.inventory[index] > 150)
+					client->pers.inventory[index] = 150;
+				client->ctf_regentime += 0.5;
+				noise = true;
+			}
+		}
+		if (noise && ent->client->ctf_techsndtime < level.time) {
+			ent->client->ctf_techsndtime = level.time + 1;
+			gi.sound(ent, CHAN_VOICE, gi.soundindex("ctf/tech4.wav"), volume, ATTN_NORM, 0);
+		}
+	}
+}
+
+qboolean CTFHasRegeneration(edict_t *ent)
+{
+	static gitem_t *tech = NULL;
+
+	if (!tech)
+		tech = FindItemByClassname("item_tech4");
+	if (tech && ent->client &&
+		ent->client->pers.inventory[ITEM_INDEX(tech)])
+		return true;
+	return false;
+}
+
+/*
+======================================================================
+
+SAY_TEAM
+
+======================================================================
+*/
+
+// This array is in 'importance order', it indicates what items are
+// more important when reporting their names.
+struct {
+	char *classname;
+	int priority;
+} loc_names[] = 
+{
+	{	"item_flag_team1",			1 },
+	{	"item_flag_team2",			1 },
+	{	"item_quad",				2 }, 
+	{	"item_invulnerability",		2 },
+	{	"weapon_bfg",				3 },
+	{	"weapon_railgun",			4 },
+	{	"weapon_rocketlauncher",	4 },
+	{	"weapon_hyperblaster",		4 },
+	{	"weapon_chaingun",			4 },
+	{	"weapon_grenadelauncher",	4 },
+	{	"weapon_machinegun",		4 },
+	{	"weapon_supershotgun",		4 },
+	{	"weapon_shotgun",			4 },
+	{	"item_power_screen",		5 },
+	{	"item_power_shield",		5 },
+	{	"item_armor_body",			6 },
+	{	"item_armor_combat",		6 },
+	{	"item_armor_jacket",		6 },
+	{	"item_silencer",			7 },
+	{	"item_breather",			7 },
+	{	"item_enviro",				7 },
+	{	"item_adrenaline",			7 },
+	{	"item_bandolier",			8 },
+	{	"item_pack",				8 },
+	{ NULL, 0 }
+};
+
+
+static void CTFSay_Team_Location(edict_t *who, char *buf)
+{
+	edict_t *what = NULL;
+	edict_t *hot = NULL;
+	float hotdist = 999999, newdist;
+	vec3_t v;
+	int hotindex = 999;
+	int i;
+	gitem_t *item;
+	int nearteam = -1;
+	edict_t *flag1, *flag2;
+	qboolean hotsee = false;
+	qboolean cansee;
+
+	while ((what = loc_findradius(what, who->s.origin, 1024)) != NULL) {
+		// find what in loc_classnames
+		for (i = 0; loc_names[i].classname; i++)
+			if (strcmp(what->classname, loc_names[i].classname) == 0)
+				break;
+		if (!loc_names[i].classname)
+			continue;
+		// something we can see get priority over something we can't
+		cansee = loc_CanSee(what, who);
+		if (cansee && !hotsee) {
+			hotsee = true;
+			hotindex = loc_names[i].priority;
+			hot = what;
+			VectorSubtract(what->s.origin, who->s.origin, v);
+			hotdist = VectorLength(v);
+			continue;
+		}
+		// if we can't see this, but we have something we can see, skip it
+		if (hotsee && !cansee)
+			continue;
+		if (hotsee && hotindex < loc_names[i].priority)
+			continue;
+		VectorSubtract(what->s.origin, who->s.origin, v);
+		newdist = VectorLength(v);
+		if (newdist < hotdist || 
+			(cansee && loc_names[i].priority < hotindex)) {
+			hot = what;
+			hotdist = newdist;
+			hotindex = i;
+			hotsee = loc_CanSee(hot, who);
+		}
+	}
+
+	if (!hot) {
+		strcpy(buf, "nowhere");
+		return;
+	}
+
+	// we now have the closest item
+	// see if there's more than one in the map, if so
+	// we need to determine what team is closest
+	what = NULL;
+	while ((what = G_Find(what, FOFS(classname), hot->classname)) != NULL) {
+		if (what == hot)
+			continue;
+		// if we are here, there is more than one, find out if hot
+		// is closer to red flag or blue flag
+		if ((flag1 = G_Find(NULL, FOFS(classname), "item_flag_team1")) != NULL &&
+			(flag2 = G_Find(NULL, FOFS(classname), "item_flag_team2")) != NULL) {
+			VectorSubtract(hot->s.origin, flag1->s.origin, v);
+			hotdist = VectorLength(v);
+			VectorSubtract(hot->s.origin, flag2->s.origin, v);
+			newdist = VectorLength(v);
+			if (hotdist < newdist)
+				nearteam = CTF_TEAM1;
+			else if (hotdist > newdist)
+				nearteam = CTF_TEAM2;
+		}
+		break;
+	}
+
+	if ((item = FindItemByClassname(hot->classname)) == NULL) {
+		strcpy(buf, "nowhere");
+		return;
+	}
+
+	// in water?
+	if (who->waterlevel)
+		strcpy(buf, "in the water ");
+	else
+		*buf = 0;
+
+	// near or above
+	VectorSubtract(who->s.origin, hot->s.origin, v);
+	if (fabs(v[2]) > fabs(v[0]) && fabs(v[2]) > fabs(v[1]))
+		if (v[2] > 0)
+			strcat(buf, "above ");
+		else
+			strcat(buf, "below ");
+	else
+		strcat(buf, "near ");
+
+	if (nearteam == CTF_TEAM1)
+		strcat(buf, "the red ");
+	else if (nearteam == CTF_TEAM2)
+		strcat(buf, "the blue ");
+	else
+		strcat(buf, "the ");
+
+	strcat(buf, item->pickup_name);
+}
+
+static void CTFSay_Team_Armor(edict_t *who, char *buf)
+{
+	gitem_t		*item;
+	int			index, cells;
+	int			power_armor_type;
+
+	*buf = 0;
+
+	power_armor_type = PowerArmorType (who);
+	if (power_armor_type)
+	{
+		cells = who->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
+		if (cells)
+			sprintf(buf+strlen(buf), "%s with %i cells ",
+				(power_armor_type == POWER_ARMOR_SCREEN) ?
+				"Power Screen" : "Power Shield", cells);
+	}
+
+	index = ArmorIndex (who);
+	if (index)
+	{
+		item = GetItemByIndex (index);
+		if (item) {
+			if (*buf)
+				strcat(buf, "and ");
+			sprintf(buf+strlen(buf), "%i units of %s",
+				who->client->pers.inventory[index], item->pickup_name);
+		}
+	}
+
+	if (!*buf)
+		strcpy(buf, "no armor");
+}
+
+static void CTFSay_Team_Health(edict_t *who, char *buf)
+{
+	if (who->health <= 0)
+		strcpy(buf, "dead");
+	else
+		sprintf(buf, "%i health", who->health);
+}
+
+static void CTFSay_Team_Tech(edict_t *who, char *buf)
+{
+	gitem_t *tech;
+	int i;
+
+	// see if the player has a tech powerup
+	i = 0;
+	while (tnames[i]) {
+		if ((tech = FindItemByClassname(tnames[i])) != NULL &&
+			who->client->pers.inventory[ITEM_INDEX(tech)]) {
+			sprintf(buf, "the %s", tech->pickup_name);
+			return;
+		}
+		i++;
+	}
+	strcpy(buf, "no powerup");
+}
+
+static void CTFSay_Team_Weapon(edict_t *who, char *buf)
+{
+	if (who->client->pers.weapon)
+		strcpy(buf, who->client->pers.weapon->pickup_name);
+	else
+		strcpy(buf, "none");
+}
+
+static void CTFSay_Team_Sight(edict_t *who, char *buf)
+{
+	int i;
+	edict_t *targ;
+	int n = 0;
+	char s[1024];
+	char s2[1024];
+
+	*s = *s2 = 0;
+	for (i = 1; i <= maxclients->value; i++) {
+		targ = g_edicts + i;
+		if (!targ->inuse || 
+			targ == who ||
+			!loc_CanSee(targ, who))
+			continue;
+		if (*s2) {
+			if (strlen(s) + strlen(s2) + 3 < sizeof(s)) {
+				if (n)
+					strcat(s, ", ");
+				strcat(s, s2);
+				*s2 = 0;
+			}
+			n++;
+		}
+		strcpy(s2, targ->client->pers.netname);
+	}
+	if (*s2) {
+		if (strlen(s) + strlen(s2) + 6 < sizeof(s)) {
+			if (n)
+				strcat(s, " and ");
+			strcat(s, s2);
+		}
+		strcpy(buf, s);
+	} else
+		strcpy(buf, "no one");
+}
+
+void CTFSay_Team(edict_t *who, char *msg)
+{
+	char outmsg[1024];
+	char buf[1024];
+	int i;
+	char *p;
+	edict_t *cl_ent;
+
+	if (CheckFlood(who))
+		return;
+
+	outmsg[0] = 0;
+
+	if (*msg == '\"') {
+		msg[strlen(msg) - 1] = 0;
+		msg++;
+	}
+
+	for (p = outmsg; *msg && (p - outmsg) < sizeof(outmsg) - 1; msg++) {
+		if (*msg == '%') {
+			switch (*++msg) {
+				case 'l' :
+				case 'L' :
+					CTFSay_Team_Location(who, buf);
+					strcpy(p, buf);
+					p += strlen(buf);
+					break;
+				case 'a' :
+				case 'A' :
+					CTFSay_Team_Armor(who, buf);
+					strcpy(p, buf);
+					p += strlen(buf);
+					break;
+				case 'h' :
+				case 'H' :
+					CTFSay_Team_Health(who, buf);
+					strcpy(p, buf);
+					p += strlen(buf);
+					break;
+				case 't' :
+				case 'T' :
+					CTFSay_Team_Tech(who, buf);
+					strcpy(p, buf);
+					p += strlen(buf);
+					break;
+				case 'w' :
+				case 'W' :
+					CTFSay_Team_Weapon(who, buf);
+					strcpy(p, buf);
+					p += strlen(buf);
+					break;
+
+				case 'n' :
+				case 'N' :
+					CTFSay_Team_Sight(who, buf);
+					strcpy(p, buf);
+					p += strlen(buf);
+					break;
+
+				default :
+					*p++ = *msg;
+			}
+		} else
+			*p++ = *msg;
+	}
+	*p = 0;
+
+	for (i = 0; i < maxclients->value; i++) {
+		cl_ent = g_edicts + 1 + i;
+		if (!cl_ent->inuse)
+			continue;
+		if (cl_ent->client->resp.ctf_team == who->client->resp.ctf_team)
+			gi.cprintf(cl_ent, PRINT_CHAT, "(%s): %s\n", 
+				who->client->pers.netname, outmsg);
+	}
+}
+
+/*-----------------------------------------------------------------------*/
+/*QUAKED misc_ctf_banner (1 .5 0) (-4 -64 0) (4 64 248) TEAM2
+The origin is the bottom of the banner.
+The banner is 248 tall.
+*/
+static void misc_ctf_banner_think (edict_t *ent)
+{
+	ent->s.frame = (ent->s.frame + 1) % 16;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void SP_misc_ctf_banner (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/ctf/banner/tris.md2");
+	if (ent->spawnflags & 1) // team2
+		ent->s.skinnum = 1;
+
+	ent->s.frame = rand() % 16;
+	gi.linkentity (ent);
+
+	ent->think = misc_ctf_banner_think;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+/*QUAKED misc_ctf_small_banner (1 .5 0) (-4 -32 0) (4 32 124) TEAM2
+The origin is the bottom of the banner.
+The banner is 124 tall.
+*/
+void SP_misc_ctf_small_banner (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/ctf/banner/small.md2");
+	if (ent->spawnflags & 1) // team2
+		ent->s.skinnum = 1;
+
+	ent->s.frame = rand() % 16;
+	gi.linkentity (ent);
+
+	ent->think = misc_ctf_banner_think;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+/*-----------------------------------------------------------------------*/
+
+static void SetLevelName(pmenu_t *p)
+{
+	static char levelname[33];
+
+	levelname[0] = '*';
+	if (g_edicts[0].message)
+		strncpy(levelname+1, g_edicts[0].message, sizeof(levelname) - 2);
+	else
+		strncpy(levelname+1, level.mapname, sizeof(levelname) - 2);
+	levelname[sizeof(levelname) - 1] = 0;
+	p->text = levelname;
+}
+
+
+/*-----------------------------------------------------------------------*/
+
+
+/* ELECTIONS */
+
+qboolean CTFBeginElection(edict_t *ent, elect_t type, char *msg)
+{
+	int i;
+	int count;
+	edict_t *e;
+
+	if (electpercentage->value == 0) {
+		gi.cprintf(ent, PRINT_HIGH, "Elections are disabled, only an admin can process this action.\n");
+		return false;
+	}
+
+
+	if (ctfgame.election != ELECT_NONE) {
+		gi.cprintf(ent, PRINT_HIGH, "Election already in progress.\n");
+		return false;
+	}
+
+	// clear votes
+	count = 0;
+	for (i = 1; i <= maxclients->value; i++) {
+		e = g_edicts + i;
+		e->client->resp.voted = false;
+		if (e->inuse)
+			count++;
+	}
+
+	if (count < 2) {
+		gi.cprintf(ent, PRINT_HIGH, "Not enough players for election.\n");
+		return false;
+	}
+
+	ctfgame.etarget = ent;
+	ctfgame.election = type;
+	ctfgame.evotes = 0;
+	ctfgame.needvotes = (count * electpercentage->value) / 100;
+	ctfgame.electtime = level.time + 20; // twenty seconds for election
+	strncpy(ctfgame.emsg, msg, sizeof(ctfgame.emsg) - 1);
+
+	// tell everyone
+	gi.bprintf(PRINT_CHAT, "%s\n", ctfgame.emsg);
+	gi.bprintf(PRINT_HIGH, "Type YES or NO to vote on this request.\n");
+	gi.bprintf(PRINT_HIGH, "Votes: %d  Needed: %d  Time left: %ds\n", ctfgame.evotes, ctfgame.needvotes,
+		(int)(ctfgame.electtime - level.time));
+
+	return true;
+}
+
+void DoRespawn (edict_t *ent);
+
+void CTFResetAllPlayers(void)
+{
+	int i;
+	edict_t *ent;
+
+	for (i = 1; i <= maxclients->value; i++) {
+		ent = g_edicts + i;
+		if (!ent->inuse)
+			continue;
+
+		if (ent->client->menu)
+			PMenu_Close(ent);
+
+		CTFPlayerResetGrapple(ent);
+		CTFDeadDropFlag(ent);
+		CTFDeadDropTech(ent);
+
+		ent->client->resp.ctf_team = CTF_NOTEAM;
+		ent->client->resp.ready = false;
+
+		ent->svflags = 0;
+		ent->flags &= ~FL_GODMODE;
+		PutClientInServer(ent);
+	}
+
+	// reset the level
+	CTFResetTech();
+	CTFResetFlags();
+
+	for (ent = g_edicts + 1, i = 1; i < globals.num_edicts; i++, ent++) {
+		if (ent->inuse && !ent->client) {
+			if (ent->solid == SOLID_NOT && ent->think == DoRespawn &&
+				ent->nextthink >= level.time) {
+				ent->nextthink = 0;
+				DoRespawn(ent);
+			}
+		}
+	}
+	if (ctfgame.match == MATCH_SETUP)
+		ctfgame.matchtime = level.time + matchsetuptime->value * 60;
+}
+
+void CTFAssignGhost(edict_t *ent)
+{
+	int ghost, i;
+
+	for (ghost = 0; ghost < MAX_CLIENTS; ghost++)
+		if (!ctfgame.ghosts[ghost].code)
+			break;
+	if (ghost == MAX_CLIENTS)
+		return;
+	ctfgame.ghosts[ghost].team = ent->client->resp.ctf_team;
+	ctfgame.ghosts[ghost].score = 0;
+	for (;;) {
+		ctfgame.ghosts[ghost].code = 10000 + (rand() % 90000);
+		for (i = 0; i < MAX_CLIENTS; i++)
+			if (i != ghost && ctfgame.ghosts[i].code == ctfgame.ghosts[ghost].code)
+				break;
+		if (i == MAX_CLIENTS)
+			break;
+	}
+	ctfgame.ghosts[ghost].ent = ent;
+	strcpy(ctfgame.ghosts[ghost].netname, ent->client->pers.netname);
+	ent->client->resp.ghost = ctfgame.ghosts + ghost;
+	gi.cprintf(ent, PRINT_CHAT, "Your ghost code is **** %d ****\n", ctfgame.ghosts[ghost].code);
+	gi.cprintf(ent, PRINT_HIGH, "If you lose connection, you can rejoin with your score "
+		"intact by typing \"ghost %d\".\n", ctfgame.ghosts[ghost].code);
+}
+
+// start a match
+void CTFStartMatch(void)
+{
+	int i;
+	edict_t *ent;
+	int ghost = 0;
+
+	ctfgame.match = MATCH_GAME;
+	ctfgame.matchtime = level.time + matchtime->value * 60;
+
+	ctfgame.team1 = ctfgame.team2 = 0;
+
+	memset(ctfgame.ghosts, 0, sizeof(ctfgame.ghosts));
+
+	for (i = 1; i <= maxclients->value; i++) {
+		ent = g_edicts + i;
+		if (!ent->inuse)
+			continue;
+
+		ent->client->resp.score = 0;
+		ent->client->resp.ctf_state = 0;
+		ent->client->resp.ghost = NULL;
+
+		gi.centerprintf(ent, "******************\n\nMATCH HAS STARTED!\n\n******************");
+
+		if (ent->client->resp.ctf_team != CTF_NOTEAM) {
+			// make up a ghost code
+			CTFAssignGhost(ent);
+			CTFPlayerResetGrapple(ent);
+			ent->svflags = SVF_NOCLIENT;
+			ent->flags &= ~FL_GODMODE;
+
+			ent->client->respawn_time = level.time + 1.0 + ((rand()%30)/10.0);
+			ent->client->ps.pmove.pm_type = PM_DEAD;
+			ent->client->anim_priority = ANIM_DEATH;
+			ent->s.frame = FRAME_death308-1;
+			ent->client->anim_end = FRAME_death308;
+			ent->deadflag = DEAD_DEAD;
+			ent->movetype = MOVETYPE_NOCLIP;
+			ent->client->ps.gunindex = 0;
+			gi.linkentity (ent);
+		}
+	}
+}
+
+void CTFEndMatch(void)
+{
+	ctfgame.match = MATCH_POST;
+	gi.bprintf(PRINT_CHAT, "MATCH COMPLETED!\n");
+
+	CTFCalcScores();
+
+	gi.bprintf(PRINT_HIGH, "RED TEAM:  %d captures, %d points\n",
+		ctfgame.team1, ctfgame.total1);
+	gi.bprintf(PRINT_HIGH, "BLUE TEAM:  %d captures, %d points\n",
+		ctfgame.team2, ctfgame.total2);
+
+	if (ctfgame.team1 > ctfgame.team2)
+		gi.bprintf(PRINT_CHAT, "RED team won over the BLUE team by %d CAPTURES!\n",
+			ctfgame.team1 - ctfgame.team2);
+	else if (ctfgame.team2 > ctfgame.team1)
+		gi.bprintf(PRINT_CHAT, "BLUE team won over the RED team by %d CAPTURES!\n",
+			ctfgame.team2 - ctfgame.team1);
+	else if (ctfgame.total1 > ctfgame.total2) // frag tie breaker
+		gi.bprintf(PRINT_CHAT, "RED team won over the BLUE team by %d POINTS!\n",
+			ctfgame.total1 - ctfgame.total2);
+	else if (ctfgame.total2 > ctfgame.total1) 
+		gi.bprintf(PRINT_CHAT, "BLUE team won over the RED team by %d POINTS!\n",
+			ctfgame.total2 - ctfgame.total1);
+	else
+		gi.bprintf(PRINT_CHAT, "TIE GAME!\n");
+
+	EndDMLevel();
+}
+
+qboolean CTFNextMap(void)
+{
+	if (ctfgame.match == MATCH_POST) {
+		ctfgame.match = MATCH_SETUP;
+		CTFResetAllPlayers();
+		return true;
+	}
+	return false;
+}
+
+void CTFWinElection(void)
+{
+	switch (ctfgame.election) {
+	case ELECT_MATCH :
+		// reset into match mode
+		if (competition->value < 3)
+			gi.cvar_set("competition", "2");
+		ctfgame.match = MATCH_SETUP;
+		CTFResetAllPlayers();
+		break;
+
+	case ELECT_ADMIN :
+		ctfgame.etarget->client->resp.admin = true;
+		gi.bprintf(PRINT_HIGH, "%s has become an admin.\n", ctfgame.etarget->client->pers.netname);
+		gi.cprintf(ctfgame.etarget, PRINT_HIGH, "Type 'admin' to access the adminstration menu.\n");
+		break;
+
+	case ELECT_MAP :
+		gi.bprintf(PRINT_HIGH, "%s is warping to level %s.\n", 
+			ctfgame.etarget->client->pers.netname, ctfgame.elevel);
+		strncpy(level.forcemap, ctfgame.elevel, sizeof(level.forcemap) - 1);
+		EndDMLevel();
+		break;
+	}
+	ctfgame.election = ELECT_NONE;
+}
+
+void CTFVoteYes(edict_t *ent)
+{
+	if (ctfgame.election == ELECT_NONE) {
+		gi.cprintf(ent, PRINT_HIGH, "No election is in progress.\n");
+		return;
+	}
+	if (ent->client->resp.voted) {
+		gi.cprintf(ent, PRINT_HIGH, "You already voted.\n");
+		return;
+	}
+	if (ctfgame.etarget == ent) {
+		gi.cprintf(ent, PRINT_HIGH, "You can't vote for yourself.\n");
+		return;
+	}
+
+	ent->client->resp.voted = true;
+
+	ctfgame.evotes++;
+	if (ctfgame.evotes == ctfgame.needvotes) {
+		// the election has been won
+		CTFWinElection();
+		return;
+	}
+	gi.bprintf(PRINT_HIGH, "%s\n", ctfgame.emsg);
+	gi.bprintf(PRINT_CHAT, "Votes: %d  Needed: %d  Time left: %ds\n", ctfgame.evotes, ctfgame.needvotes,
+		(int)(ctfgame.electtime - level.time));
+}
+
+void CTFVoteNo(edict_t *ent)
+{
+	if (ctfgame.election == ELECT_NONE) {
+		gi.cprintf(ent, PRINT_HIGH, "No election is in progress.\n");
+		return;
+	}
+	if (ent->client->resp.voted) {
+		gi.cprintf(ent, PRINT_HIGH, "You already voted.\n");
+		return;
+	}
+	if (ctfgame.etarget == ent) {
+		gi.cprintf(ent, PRINT_HIGH, "You can't vote for yourself.\n");
+		return;
+	}
+
+	ent->client->resp.voted = true;
+
+	gi.bprintf(PRINT_HIGH, "%s\n", ctfgame.emsg);
+	gi.bprintf(PRINT_CHAT, "Votes: %d  Needed: %d  Time left: %ds\n", ctfgame.evotes, ctfgame.needvotes,
+		(int)(ctfgame.electtime - level.time));
+}
+
+void CTFReady(edict_t *ent)
+{
+	int i, j;
+	edict_t *e;
+	int t1, t2;
+
+	if (ent->client->resp.ctf_team == CTF_NOTEAM) {
+		gi.cprintf(ent, PRINT_HIGH, "Pick a team first (hit <TAB> for menu)\n");
+		return;
+	}
+
+	if (ctfgame.match != MATCH_SETUP) {
+		gi.cprintf(ent, PRINT_HIGH, "A match is not being setup.\n");
+		return;
+	}
+
+	if (ent->client->resp.ready) {
+		gi.cprintf(ent, PRINT_HIGH, "You have already commited.\n");
+		return;
+	}
+
+	ent->client->resp.ready = true;
+	gi.bprintf(PRINT_HIGH, "%s is ready.\n", ent->client->pers.netname);
+
+	t1 = t2 = 0;
+	for (j = 0, i = 1; i <= maxclients->value; i++) {
+		e = g_edicts + i;
+		if (!e->inuse)
+			continue;
+		if (e->client->resp.ctf_team != CTF_NOTEAM && !e->client->resp.ready)
+			j++;
+		if (e->client->resp.ctf_team == CTF_TEAM1)
+			t1++;
+		else if (e->client->resp.ctf_team == CTF_TEAM2)
+			t2++;
+	}
+	if (!j && t1 && t2) {
+		// everyone has commited
+		gi.bprintf(PRINT_CHAT, "All players have commited.  Match starting\n");
+		ctfgame.match = MATCH_PREGAME;
+		ctfgame.matchtime = level.time + matchstarttime->value;
+	}
+}
+
+void CTFNotReady(edict_t *ent)
+{
+	if (ent->client->resp.ctf_team == CTF_NOTEAM) {
+		gi.cprintf(ent, PRINT_HIGH, "Pick a team first (hit <TAB> for menu)\n");
+		return;
+	}
+
+	if (ctfgame.match != MATCH_SETUP && ctfgame.match != MATCH_PREGAME) {
+		gi.cprintf(ent, PRINT_HIGH, "A match is not being setup.\n");
+		return;
+	}
+
+	if (!ent->client->resp.ready) {
+		gi.cprintf(ent, PRINT_HIGH, "You haven't commited.\n");
+		return;
+	}
+
+	ent->client->resp.ready = false;
+	gi.bprintf(PRINT_HIGH, "%s is no longer ready.\n", ent->client->pers.netname);
+
+	if (ctfgame.match == MATCH_PREGAME) {
+		gi.bprintf(PRINT_CHAT, "Match halted.\n");
+		ctfgame.match = MATCH_SETUP;
+		ctfgame.matchtime = level.time + matchsetuptime->value * 60;
+	}
+}
+
+void CTFGhost(edict_t *ent)
+{
+	int i;
+	int n;
+
+	if (gi.argc() < 2) {
+		gi.cprintf(ent, PRINT_HIGH, "Usage:  ghost <code>\n");
+		return;
+	}
+
+	if (ent->client->resp.ctf_team != CTF_NOTEAM) {
+		gi.cprintf(ent, PRINT_HIGH, "You are already in the game.\n");
+		return;
+	}
+	if (ctfgame.match != MATCH_GAME) {
+		gi.cprintf(ent, PRINT_HIGH, "No match is in progress.\n");
+		return;
+	}
+
+	n = atoi(gi.argv(1));
+
+	for (i = 0; i < MAX_CLIENTS; i++) {
+		if (ctfgame.ghosts[i].code && ctfgame.ghosts[i].code == n) {
+			gi.cprintf(ent, PRINT_HIGH, "Ghost code accepted, your position has been reinstated.\n");
+			ctfgame.ghosts[i].ent->client->resp.ghost = NULL;
+			ent->client->resp.ctf_team = ctfgame.ghosts[i].team;
+			ent->client->resp.ghost = ctfgame.ghosts + i;
+			ent->client->resp.score = ctfgame.ghosts[i].score;
+			ent->client->resp.ctf_state = 0;
+			ctfgame.ghosts[i].ent = ent;
+			ent->svflags = 0;
+			ent->flags &= ~FL_GODMODE;
+			PutClientInServer(ent);
+			gi.bprintf(PRINT_HIGH, "%s has been reinstated to %s team.\n",
+				ent->client->pers.netname, CTFTeamName(ent->client->resp.ctf_team));
+			return;
+		}
+	}
+	gi.cprintf(ent, PRINT_HIGH, "Invalid ghost code.\n");
+}
+
+qboolean CTFMatchSetup(void)
+{
+	if (ctfgame.match == MATCH_SETUP || ctfgame.match == MATCH_PREGAME)
+		return true;
+	return false;
+}
+
+qboolean CTFMatchOn(void)
+{
+	if (ctfgame.match == MATCH_GAME)
+		return true;
+	return false;
+}
+
+
+/*-----------------------------------------------------------------------*/
+
+void CTFJoinTeam1(edict_t *ent, pmenuhnd_t *p);
+void CTFJoinTeam2(edict_t *ent, pmenuhnd_t *p);
+void CTFCredits(edict_t *ent, pmenuhnd_t *p);
+void CTFReturnToMain(edict_t *ent, pmenuhnd_t *p);
+void CTFChaseCam(edict_t *ent, pmenuhnd_t *p);
+
+pmenu_t creditsmenu[] = {
+	{ "*Quake II",						PMENU_ALIGN_CENTER, NULL },
+	{ "*ThreeWave Capture the Flag",	PMENU_ALIGN_CENTER, NULL },
+	{ NULL,								PMENU_ALIGN_CENTER, NULL },
+	{ "*Programming",					PMENU_ALIGN_CENTER, NULL }, 
+	{ "Dave 'Zoid' Kirsch",				PMENU_ALIGN_CENTER, NULL },
+	{ "*Level Design", 					PMENU_ALIGN_CENTER, NULL },
+	{ "Christian Antkow",				PMENU_ALIGN_CENTER, NULL },
+	{ "Tim Willits",					PMENU_ALIGN_CENTER, NULL },
+	{ "Dave 'Zoid' Kirsch",				PMENU_ALIGN_CENTER, NULL },
+	{ "*Art",							PMENU_ALIGN_CENTER, NULL },
+	{ "Adrian Carmack Paul Steed",		PMENU_ALIGN_CENTER, NULL },
+	{ "Kevin Cloud",					PMENU_ALIGN_CENTER, NULL },
+	{ "*Sound",							PMENU_ALIGN_CENTER, NULL },
+	{ "Tom 'Bjorn' Klok",				PMENU_ALIGN_CENTER, NULL },
+	{ "*Original CTF Art Design",		PMENU_ALIGN_CENTER, NULL },
+	{ "Brian 'Whaleboy' Cozzens",		PMENU_ALIGN_CENTER, NULL },
+	{ NULL,								PMENU_ALIGN_CENTER, NULL },
+	{ "Return to Main Menu",			PMENU_ALIGN_LEFT, CTFReturnToMain }
+};
+
+static const int jmenu_level = 2;
+static const int jmenu_match = 3;
+static const int jmenu_red = 5;
+static const int jmenu_blue = 7;
+static const int jmenu_chase = 9;
+static const int jmenu_reqmatch = 11;
+
+pmenu_t joinmenu[] = {
+	{ "*Quake II",			PMENU_ALIGN_CENTER, NULL },
+	{ "*ThreeWave Capture the Flag",	PMENU_ALIGN_CENTER, NULL },
+	{ NULL,					PMENU_ALIGN_CENTER, NULL },
+	{ NULL,					PMENU_ALIGN_CENTER, NULL },
+	{ NULL,					PMENU_ALIGN_CENTER, NULL },
+	{ "Join Red Team",		PMENU_ALIGN_LEFT, CTFJoinTeam1 },
+	{ NULL,					PMENU_ALIGN_LEFT, NULL },
+	{ "Join Blue Team",		PMENU_ALIGN_LEFT, CTFJoinTeam2 },
+	{ NULL,					PMENU_ALIGN_LEFT, NULL },
+	{ "Chase Camera",		PMENU_ALIGN_LEFT, CTFChaseCam },
+	{ "Credits",			PMENU_ALIGN_LEFT, CTFCredits },
+	{ NULL,					PMENU_ALIGN_LEFT, NULL },
+	{ NULL,					PMENU_ALIGN_LEFT, NULL },
+	{ "Use [ and ] to move cursor",	PMENU_ALIGN_LEFT, NULL },
+	{ "ENTER to select",	PMENU_ALIGN_LEFT, NULL },
+	{ "ESC to Exit Menu",	PMENU_ALIGN_LEFT, NULL },
+	{ "(TAB to Return)",	PMENU_ALIGN_LEFT, NULL },
+	{ "v" CTF_STRING_VERSION,	PMENU_ALIGN_RIGHT, NULL },
+};
+
+pmenu_t nochasemenu[] = {
+	{ "*Quake II",			PMENU_ALIGN_CENTER, NULL },
+	{ "*ThreeWave Capture the Flag",	PMENU_ALIGN_CENTER, NULL },
+	{ NULL,					PMENU_ALIGN_CENTER, NULL },
+	{ NULL,					PMENU_ALIGN_CENTER, NULL },
+	{ "No one to chase",	PMENU_ALIGN_LEFT, NULL },
+	{ NULL,					PMENU_ALIGN_CENTER, NULL },
+	{ "Return to Main Menu", PMENU_ALIGN_LEFT, CTFReturnToMain }
+};
+
+void CTFJoinTeam(edict_t *ent, int desired_team)
+{
+	char *s;
+
+	PMenu_Close(ent);
+
+	ent->svflags &= ~SVF_NOCLIENT;
+	ent->client->resp.ctf_team = desired_team;
+	ent->client->resp.ctf_state = 0;
+	s = Info_ValueForKey (ent->client->pers.userinfo, "skin");
+	CTFAssignSkin(ent, s);
+
+	// assign a ghost if we are in match mode
+	if (ctfgame.match == MATCH_GAME) {
+		if (ent->client->resp.ghost)
+			ent->client->resp.ghost->code = 0;
+		ent->client->resp.ghost = NULL;
+		CTFAssignGhost(ent);
+	}
+
+	PutClientInServer (ent);
+	// add a teleportation effect
+	ent->s.event = EV_PLAYER_TELEPORT;
+	// hold in place briefly
+	ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+	ent->client->ps.pmove.pm_time = 14;
+	gi.bprintf(PRINT_HIGH, "%s joined the %s team.\n",
+		ent->client->pers.netname, CTFTeamName(desired_team));
+
+	if (ctfgame.match == MATCH_SETUP) {
+		gi.centerprintf(ent,	"***********************\n"
+								"Type \"ready\" in console\n"
+								"to ready up.\n"
+								"***********************");
+	}
+}
+
+void CTFJoinTeam1(edict_t *ent, pmenuhnd_t *p)
+{
+	CTFJoinTeam(ent, CTF_TEAM1);
+}
+
+void CTFJoinTeam2(edict_t *ent, pmenuhnd_t *p)
+{
+	CTFJoinTeam(ent, CTF_TEAM2);
+}
+
+void CTFChaseCam(edict_t *ent, pmenuhnd_t *p)
+{
+	int i;
+	edict_t *e;
+
+	if (ent->client->chase_target) {
+		ent->client->chase_target = NULL;
+		PMenu_Close(ent);
+		return;
+	}
+
+	for (i = 1; i <= maxclients->value; i++) {
+		e = g_edicts + i;
+		if (e->inuse && e->solid != SOLID_NOT) {
+			ent->client->chase_target = e;
+			PMenu_Close(ent);
+			ent->client->update_chase = true;
+			return;
+		}
+	}
+
+	SetLevelName(nochasemenu + jmenu_level);
+
+	PMenu_Close(ent);
+	PMenu_Open(ent, nochasemenu, -1, sizeof(nochasemenu) / sizeof(pmenu_t), NULL);
+}
+
+void CTFReturnToMain(edict_t *ent, pmenuhnd_t *p)
+{
+	PMenu_Close(ent);
+	CTFOpenJoinMenu(ent);
+}
+
+void CTFRequestMatch(edict_t *ent, pmenuhnd_t *p)
+{
+	char text[1024];
+
+	PMenu_Close(ent);
+
+	sprintf(text, "%s has requested to switch to competition mode.",
+		ent->client->pers.netname);
+	CTFBeginElection(ent, ELECT_MATCH, text);
+}
+
+void DeathmatchScoreboard (edict_t *ent);
+
+void CTFShowScores(edict_t *ent, pmenu_t *p)
+{
+	PMenu_Close(ent);
+
+	ent->client->showscores = true;
+	ent->client->showinventory = false;
+	DeathmatchScoreboard (ent);
+}
+
+int CTFUpdateJoinMenu(edict_t *ent)
+{
+	static char team1players[32];
+	static char team2players[32];
+	int num1, num2, i;
+
+	if (ctfgame.match >= MATCH_PREGAME && matchlock->value) {
+		joinmenu[jmenu_red].text = "MATCH IS LOCKED";
+		joinmenu[jmenu_red].SelectFunc = NULL;
+		joinmenu[jmenu_blue].text = "  (entry is not permitted)";
+		joinmenu[jmenu_blue].SelectFunc = NULL;
+	} else {
+		if (ctfgame.match >= MATCH_PREGAME) {
+			joinmenu[jmenu_red].text = "Join Red MATCH Team";
+			joinmenu[jmenu_blue].text = "Join Blue MATCH Team";
+		} else {
+			joinmenu[jmenu_red].text = "Join Red Team";
+			joinmenu[jmenu_blue].text = "Join Blue Team";
+		}
+		joinmenu[jmenu_red].SelectFunc = CTFJoinTeam1;
+		joinmenu[jmenu_blue].SelectFunc = CTFJoinTeam2;
+	}
+
+	if (ctf_forcejoin->string && *ctf_forcejoin->string) {
+		if (stricmp(ctf_forcejoin->string, "red") == 0) {
+			joinmenu[jmenu_blue].text = NULL;
+			joinmenu[jmenu_blue].SelectFunc = NULL;
+		} else if (stricmp(ctf_forcejoin->string, "blue") == 0) {
+			joinmenu[jmenu_red].text = NULL;
+			joinmenu[jmenu_red].SelectFunc = NULL;
+		}
+	}
+
+	if (ent->client->chase_target)
+		joinmenu[jmenu_chase].text = "Leave Chase Camera";
+	else
+		joinmenu[jmenu_chase].text = "Chase Camera";
+
+	SetLevelName(joinmenu + jmenu_level);
+
+	num1 = num2 = 0;
+	for (i = 0; i < maxclients->value; i++) {
+		if (!g_edicts[i+1].inuse)
+			continue;
+		if (game.clients[i].resp.ctf_team == CTF_TEAM1)
+			num1++;
+		else if (game.clients[i].resp.ctf_team == CTF_TEAM2)
+			num2++;
+	}
+
+	sprintf(team1players, "  (%d players)", num1);
+	sprintf(team2players, "  (%d players)", num2);
+
+	switch (ctfgame.match) {
+	case MATCH_NONE :
+		joinmenu[jmenu_match].text = NULL;
+		break;
+
+	case MATCH_SETUP :
+		joinmenu[jmenu_match].text = "*MATCH SETUP IN PROGRESS";
+		break;
+
+	case MATCH_PREGAME :
+		joinmenu[jmenu_match].text = "*MATCH STARTING";
+		break;
+
+	case MATCH_GAME :
+		joinmenu[jmenu_match].text = "*MATCH IN PROGRESS";
+		break;
+	}
+
+	if (joinmenu[jmenu_red].text)
+		joinmenu[jmenu_red+1].text = team1players;
+	else
+		joinmenu[jmenu_red+1].text = NULL;
+	if (joinmenu[jmenu_blue].text)
+		joinmenu[jmenu_blue+1].text = team2players;
+	else
+		joinmenu[jmenu_blue+1].text = NULL;
+
+	joinmenu[jmenu_reqmatch].text = NULL;
+	joinmenu[jmenu_reqmatch].SelectFunc = NULL;
+	if (competition->value && ctfgame.match < MATCH_SETUP) {
+		joinmenu[jmenu_reqmatch].text = "Request Match";
+		joinmenu[jmenu_reqmatch].SelectFunc = CTFRequestMatch;
+	}
+	
+	if (num1 > num2)
+		return CTF_TEAM1;
+	else if (num2 > num1)
+		return CTF_TEAM2;
+	return (rand() & 1) ? CTF_TEAM1 : CTF_TEAM2;
+}
+
+void CTFOpenJoinMenu(edict_t *ent)
+{
+	int team;
+
+	team = CTFUpdateJoinMenu(ent);
+	if (ent->client->chase_target)
+		team = 8;
+	else if (team == CTF_TEAM1)
+		team = 4;
+	else
+		team = 6;
+	PMenu_Open(ent, joinmenu, team, sizeof(joinmenu) / sizeof(pmenu_t), NULL);
+}
+
+void CTFCredits(edict_t *ent, pmenuhnd_t *p)
+{
+	PMenu_Close(ent);
+	PMenu_Open(ent, creditsmenu, -1, sizeof(creditsmenu) / sizeof(pmenu_t), NULL);
+}
+
+qboolean CTFStartClient(edict_t *ent)
+{
+	if (ent->client->resp.ctf_team != CTF_NOTEAM)
+		return false;
+
+	if (!((int)dmflags->value & DF_CTF_FORCEJOIN) || ctfgame.match >= MATCH_SETUP) {
+		// start as 'observer'
+		ent->movetype = MOVETYPE_NOCLIP;
+		ent->solid = SOLID_NOT;
+		ent->svflags |= SVF_NOCLIENT;
+		ent->client->resp.ctf_team = CTF_NOTEAM;
+		ent->client->ps.gunindex = 0;
+		gi.linkentity (ent);
+
+		CTFOpenJoinMenu(ent);
+		return true;
+	}
+	return false;
+}
+
+void CTFObserver(edict_t *ent)
+{
+	// start as 'observer'
+	if (ent->movetype == MOVETYPE_NOCLIP) {
+		gi.cprintf(ent, PRINT_HIGH, "You are already an observer.\n");
+		return;
+	}
+
+	CTFPlayerResetGrapple(ent);
+	CTFDeadDropFlag(ent);
+	CTFDeadDropTech(ent);
+
+	ent->movetype = MOVETYPE_NOCLIP;
+	ent->solid = SOLID_NOT;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->client->resp.ctf_team = CTF_NOTEAM;
+	ent->client->ps.gunindex = 0;
+	ent->client->resp.score = 0;
+	gi.linkentity (ent);
+	CTFOpenJoinMenu(ent);
+}
+
+qboolean CTFInMatch(void)
+{
+	if (ctfgame.match > MATCH_NONE)
+		return true;
+	return false;
+}
+
+qboolean CTFCheckRules(void)
+{
+	int t;
+	int i, j;
+	char text[64];
+	edict_t *ent;
+
+	if (ctfgame.election != ELECT_NONE && ctfgame.electtime <= level.time) {
+		gi.bprintf(PRINT_CHAT, "Election timed out and has been cancelled.\n");
+		ctfgame.election = ELECT_NONE;
+	}
+
+	if (ctfgame.match != MATCH_NONE) {
+		t = ctfgame.matchtime - level.time;
+
+		if (t <= 0) { // time ended on something
+			switch (ctfgame.match) {
+			case MATCH_SETUP :
+				// go back to normal mode
+				if (competition->value < 3) {
+					ctfgame.match = MATCH_NONE;
+					gi.cvar_set("competition", "1");
+					CTFResetAllPlayers();
+				} else {
+					// reset the time
+					ctfgame.matchtime = level.time + matchsetuptime->value * 60;
+				}
+				return false;
+
+			case MATCH_PREGAME :
+				// match started!
+				CTFStartMatch();
+				return false;
+
+			case MATCH_GAME :
+				// match ended!
+				CTFEndMatch();
+				return false;
+			}
+		}
+
+		if (t == ctfgame.lasttime)
+			return false;
+
+		ctfgame.lasttime = t;
+
+		switch (ctfgame.match) {
+		case MATCH_SETUP :
+			for (j = 0, i = 1; i <= maxclients->value; i++) {
+				ent = g_edicts + i;
+				if (!ent->inuse)
+					continue;
+				if (ent->client->resp.ctf_team != CTF_NOTEAM &&
+					!ent->client->resp.ready)
+					j++;
+			}
+
+			if (competition->value < 3)
+				sprintf(text, "%02d:%02d SETUP: %d not ready",
+					t / 60, t % 60, j);
+			else
+				sprintf(text, "SETUP: %d not ready", j);
+
+			gi.configstring (CONFIG_CTF_MATCH, text);
+			break;
+
+
+		case MATCH_PREGAME :
+			sprintf(text, "%02d:%02d UNTIL START",
+				t / 60, t % 60);
+			gi.configstring (CONFIG_CTF_MATCH, text);
+			break;
+
+		case MATCH_GAME:
+			sprintf(text, "%02d:%02d MATCH",
+				t / 60, t % 60);
+			gi.configstring (CONFIG_CTF_MATCH, text);
+			break;
+		}
+		return false;
+	}
+
+	if (capturelimit->value && 
+		(ctfgame.team1 >= capturelimit->value ||
+		ctfgame.team2 >= capturelimit->value)) {
+		gi.bprintf (PRINT_HIGH, "Capturelimit hit.\n");
+		return true;
+	}
+	return false;
+}
+
+/*--------------------------------------------------------------------------
+ * just here to help old map conversions
+ *--------------------------------------------------------------------------*/
+
+static void old_teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	edict_t		*dest;
+	int			i;
+	vec3_t		forward;
+
+	if (!other->client)
+		return;
+	dest = G_Find (NULL, FOFS(targetname), self->target);
+	if (!dest)
+	{
+		gi.dprintf ("Couldn't find destination\n");
+		return;
+	}
+
+//ZOID
+	CTFPlayerResetGrapple(other);
+//ZOID
+
+	// unlink to make sure it can't possibly interfere with KillBox
+	gi.unlinkentity (other);
+
+	VectorCopy (dest->s.origin, other->s.origin);
+	VectorCopy (dest->s.origin, other->s.old_origin);
+//	other->s.origin[2] += 10;
+
+	// clear the velocity and hold them in place briefly
+	VectorClear (other->velocity);
+	other->client->ps.pmove.pm_time = 160>>3;		// hold time
+	other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
+
+	// draw the teleport splash at source and on the player
+	self->enemy->s.event = EV_PLAYER_TELEPORT;
+	other->s.event = EV_PLAYER_TELEPORT;
+
+	// set angles
+	for (i=0 ; i<3 ; i++)
+		other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
+
+	other->s.angles[PITCH] = 0;
+	other->s.angles[YAW] = dest->s.angles[YAW];
+	other->s.angles[ROLL] = 0;
+	VectorCopy (dest->s.angles, other->client->ps.viewangles);
+	VectorCopy (dest->s.angles, other->client->v_angle);
+
+	// give a little forward velocity
+	AngleVectors (other->client->v_angle, forward, NULL, NULL);
+	VectorScale(forward, 200, other->velocity);
+
+	// kill anything at the destination
+	if (!KillBox (other))
+	{
+	}
+
+	gi.linkentity (other);
+}
+
+/*QUAKED trigger_teleport (0.5 0.5 0.5) ?
+Players touching this will be teleported
+*/
+void SP_trigger_teleport (edict_t *ent)
+{
+	edict_t *s;
+	int i;
+
+	if (!ent->target)
+	{
+		gi.dprintf ("teleporter without a target.\n");
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->svflags |= SVF_NOCLIENT;
+	ent->solid = SOLID_TRIGGER;
+	ent->touch = old_teleporter_touch;
+	gi.setmodel (ent, ent->model);
+	gi.linkentity (ent);
+
+	// noise maker and splash effect dude
+	s = G_Spawn();
+	ent->enemy = s;
+	for (i = 0; i < 3; i++)
+		s->s.origin[i] = ent->mins[i] + (ent->maxs[i] - ent->mins[i])/2;
+	s->s.sound = gi.soundindex ("world/hum1.wav");
+	gi.linkentity(s);
+	
+}
+
+/*QUAKED info_teleport_destination (0.5 0.5 0.5) (-16 -16 -24) (16 16 32)
+Point trigger_teleports at these.
+*/
+void SP_info_teleport_destination (edict_t *ent)
+{
+	ent->s.origin[2] += 16;
+}
+
+/*----------------------------------------------------------------------------------*/
+/* ADMIN */
+
+typedef struct admin_settings_s {
+	int matchlen;
+	int matchsetuplen;
+	int matchstartlen;
+	qboolean weaponsstay;
+	qboolean instantitems;
+	qboolean quaddrop;
+	qboolean instantweap;
+	qboolean matchlock;
+} admin_settings_t;
+
+#define SETMENU_SIZE (7 + 5)
+
+void CTFAdmin_UpdateSettings(edict_t *ent, pmenuhnd_t *setmenu);
+void CTFOpenAdminMenu(edict_t *ent);
+
+void CTFAdmin_SettingsApply(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+	char st[80];
+	int i;
+
+	if (settings->matchlen != matchtime->value) {
+		gi.bprintf(PRINT_HIGH, "%s changed the match length to %d minutes.\n",
+			ent->client->pers.netname, settings->matchlen);
+		if (ctfgame.match == MATCH_GAME) {
+			// in the middle of a match, change it on the fly
+			ctfgame.matchtime = (ctfgame.matchtime - matchtime->value*60) + settings->matchlen*60;
+		} 
+		sprintf(st, "%d", settings->matchlen);
+		gi.cvar_set("matchtime", st);
+	}
+
+	if (settings->matchsetuplen != matchsetuptime->value) {
+		gi.bprintf(PRINT_HIGH, "%s changed the match setup time to %d minutes.\n",
+			ent->client->pers.netname, settings->matchsetuplen);
+		if (ctfgame.match == MATCH_SETUP) {
+			// in the middle of a match, change it on the fly
+			ctfgame.matchtime = (ctfgame.matchtime - matchsetuptime->value*60) + settings->matchsetuplen*60;
+		} 
+		sprintf(st, "%d", settings->matchsetuplen);
+		gi.cvar_set("matchsetuptime", st);
+	}
+
+	if (settings->matchstartlen != matchstarttime->value) {
+		gi.bprintf(PRINT_HIGH, "%s changed the match start time to %d seconds.\n",
+			ent->client->pers.netname, settings->matchstartlen);
+		if (ctfgame.match == MATCH_PREGAME) {
+			// in the middle of a match, change it on the fly
+			ctfgame.matchtime = (ctfgame.matchtime - matchstarttime->value) + settings->matchstartlen;
+		} 
+		sprintf(st, "%d", settings->matchstartlen);
+		gi.cvar_set("matchstarttime", st);
+	}
+
+	if (settings->weaponsstay != !!((int)dmflags->value & DF_WEAPONS_STAY)) {
+		gi.bprintf(PRINT_HIGH, "%s turned %s weapons stay.\n",
+			ent->client->pers.netname, settings->weaponsstay ? "on" : "off");
+		i = (int)dmflags->value;
+		if (settings->weaponsstay)
+			i |= DF_WEAPONS_STAY;
+		else
+			i &= ~DF_WEAPONS_STAY;
+		sprintf(st, "%d", i);
+		gi.cvar_set("dmflags", st);
+	}
+
+	if (settings->instantitems != !!((int)dmflags->value & DF_INSTANT_ITEMS)) {
+		gi.bprintf(PRINT_HIGH, "%s turned %s instant items.\n",
+			ent->client->pers.netname, settings->instantitems ? "on" : "off");
+		i = (int)dmflags->value;
+		if (settings->instantitems)
+			i |= DF_INSTANT_ITEMS;
+		else
+			i &= ~DF_INSTANT_ITEMS;
+		sprintf(st, "%d", i);
+		gi.cvar_set("dmflags", st);
+	}
+
+	if (settings->quaddrop != !!((int)dmflags->value & DF_QUAD_DROP)) {
+		gi.bprintf(PRINT_HIGH, "%s turned %s quad drop.\n",
+			ent->client->pers.netname, settings->quaddrop ? "on" : "off");
+		i = (int)dmflags->value;
+		if (settings->quaddrop)
+			i |= DF_QUAD_DROP;
+		else
+			i &= ~DF_QUAD_DROP;
+		sprintf(st, "%d", i);
+		gi.cvar_set("dmflags", st);
+	}
+
+	if (settings->instantweap != !!((int)instantweap->value)) {
+		gi.bprintf(PRINT_HIGH, "%s turned %s instant weapons.\n",
+			ent->client->pers.netname, settings->instantweap ? "on" : "off");
+		sprintf(st, "%d", (int)settings->instantweap);
+		gi.cvar_set("instantweap", st);
+	}
+
+	if (settings->matchlock != !!((int)matchlock->value)) {
+		gi.bprintf(PRINT_HIGH, "%s turned %s match lock.\n",
+			ent->client->pers.netname, settings->matchlock ? "on" : "off");
+		sprintf(st, "%d", (int)settings->matchlock);
+		gi.cvar_set("matchlock", st);
+	}
+
+	PMenu_Close(ent);
+	CTFOpenAdminMenu(ent);
+}
+
+void CTFAdmin_SettingsCancel(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	PMenu_Close(ent);
+	CTFOpenAdminMenu(ent);
+}
+
+void CTFAdmin_ChangeMatchLen(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->matchlen = (settings->matchlen % 60) + 5;
+	if (settings->matchlen < 5)
+		settings->matchlen = 5;
+
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeMatchSetupLen(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->matchsetuplen = (settings->matchsetuplen % 60) + 5;
+	if (settings->matchsetuplen < 5)
+		settings->matchsetuplen = 5;
+
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeMatchStartLen(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->matchstartlen = (settings->matchstartlen % 600) + 10;
+	if (settings->matchstartlen < 20)
+		settings->matchstartlen = 20;
+
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeWeapStay(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->weaponsstay = !settings->weaponsstay;
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeInstantItems(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->instantitems = !settings->instantitems;
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeQuadDrop(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->quaddrop = !settings->quaddrop;
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeInstantWeap(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->instantweap = !settings->instantweap;
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_ChangeMatchLock(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings = p->arg;
+
+	settings->matchlock = !settings->matchlock;
+	CTFAdmin_UpdateSettings(ent, p);
+}
+
+void CTFAdmin_UpdateSettings(edict_t *ent, pmenuhnd_t *setmenu)
+{
+	int i = 2;
+	char text[64];
+	admin_settings_t *settings = setmenu->arg;
+
+	sprintf(text, "Match Len:       %2d mins", settings->matchlen);
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchLen);
+	i++;
+
+	sprintf(text, "Match Setup Len: %2d mins", settings->matchsetuplen);
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchSetupLen);
+	i++;
+
+	sprintf(text, "Match Start Len: %2d secs", settings->matchstartlen);
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchStartLen);
+	i++;
+
+	sprintf(text, "Weapons Stay:    %s", settings->weaponsstay ? "Yes" : "No");
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeWeapStay);
+	i++;
+
+	sprintf(text, "Instant Items:   %s", settings->instantitems ? "Yes" : "No");
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeInstantItems);
+	i++;
+
+	sprintf(text, "Quad Drop:       %s", settings->quaddrop ? "Yes" : "No");
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeQuadDrop);
+	i++;
+
+	sprintf(text, "Instant Weapons: %s", settings->instantweap ? "Yes" : "No");
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeInstantWeap);
+	i++;
+
+	sprintf(text, "Match Lock:      %s", settings->matchlock ? "Yes" : "No");
+	PMenu_UpdateEntry(setmenu->entries + i, text, PMENU_ALIGN_LEFT, CTFAdmin_ChangeMatchLock);
+	i++;
+
+	PMenu_Update(ent);
+}
+
+pmenu_t def_setmenu[] = {
+	{ "*Settings Menu", PMENU_ALIGN_CENTER, NULL },
+	{ NULL,				PMENU_ALIGN_CENTER, NULL },
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//int matchlen;         
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//int matchsetuplen;    
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//int matchstartlen;    
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//qboolean weaponsstay; 
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//qboolean instantitems;
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//qboolean quaddrop;    
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//qboolean instantweap; 
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },	//qboolean matchlock; 
+	{ NULL,				PMENU_ALIGN_LEFT, NULL },
+	{ "Apply",			PMENU_ALIGN_LEFT, CTFAdmin_SettingsApply },
+	{ "Cancel",			PMENU_ALIGN_LEFT, CTFAdmin_SettingsCancel }
+};
+
+void CTFAdmin_Settings(edict_t *ent, pmenuhnd_t *p)
+{
+	admin_settings_t *settings;
+	pmenuhnd_t *menu;
+
+	PMenu_Close(ent);
+
+	settings = malloc(sizeof(*settings));
+
+	settings->matchlen = matchtime->value;
+	settings->matchsetuplen = matchsetuptime->value;
+	settings->matchstartlen = matchstarttime->value;
+	settings->weaponsstay = !!((int)dmflags->value & DF_WEAPONS_STAY);
+	settings->instantitems = !!((int)dmflags->value & DF_INSTANT_ITEMS);
+	settings->quaddrop = !!((int)dmflags->value & DF_QUAD_DROP);
+	settings->instantweap = instantweap->value != 0;
+	settings->matchlock = matchlock->value != 0;
+
+	menu = PMenu_Open(ent, def_setmenu, -1, sizeof(def_setmenu) / sizeof(pmenu_t), settings);
+	CTFAdmin_UpdateSettings(ent, menu);
+}
+
+void CTFAdmin_MatchSet(edict_t *ent, pmenuhnd_t *p)
+{
+	PMenu_Close(ent);
+
+	if (ctfgame.match == MATCH_SETUP) {
+		gi.bprintf(PRINT_CHAT, "Match has been forced to start.\n");
+		ctfgame.match = MATCH_PREGAME;
+		ctfgame.matchtime = level.time + matchstarttime->value;
+	} else if (ctfgame.match == MATCH_GAME) {
+		gi.bprintf(PRINT_CHAT, "Match has been forced to terminate.\n");
+		ctfgame.match = MATCH_SETUP;
+		ctfgame.matchtime = level.time + matchsetuptime->value * 60;
+		CTFResetAllPlayers();
+	}
+}
+
+void CTFAdmin_MatchMode(edict_t *ent, pmenuhnd_t *p)
+{
+	PMenu_Close(ent);
+
+	if (ctfgame.match != MATCH_SETUP) {
+		if (competition->value < 3)
+			gi.cvar_set("competition", "2");
+		ctfgame.match = MATCH_SETUP;
+		CTFResetAllPlayers();
+	}
+}
+
+void CTFAdmin_Cancel(edict_t *ent, pmenuhnd_t *p)
+{
+	PMenu_Close(ent);
+}
+
+
+pmenu_t adminmenu[] = {
+	{ "*Administration Menu",	PMENU_ALIGN_CENTER, NULL },
+	{ NULL,						PMENU_ALIGN_CENTER, NULL }, // blank
+	{ "Settings",				PMENU_ALIGN_LEFT, CTFAdmin_Settings },
+	{ NULL,						PMENU_ALIGN_LEFT, NULL },
+	{ NULL,						PMENU_ALIGN_LEFT, NULL },
+	{ "Cancel",					PMENU_ALIGN_LEFT, CTFAdmin_Cancel },
+	{ NULL,						PMENU_ALIGN_CENTER, NULL },
+};
+
+void CTFOpenAdminMenu(edict_t *ent)
+{
+	adminmenu[3].text = NULL;
+	adminmenu[3].SelectFunc = NULL;
+	if (ctfgame.match == MATCH_SETUP) {
+		adminmenu[3].text = "Force start match";
+		adminmenu[3].SelectFunc = CTFAdmin_MatchSet;
+	} else if (ctfgame.match == MATCH_GAME) {
+		adminmenu[3].text = "Cancel match";
+		adminmenu[3].SelectFunc = CTFAdmin_MatchSet;
+	} else if (ctfgame.match == MATCH_NONE && competition->value) {
+		adminmenu[3].text = "Switch to match mode";
+		adminmenu[3].SelectFunc = CTFAdmin_MatchMode;
+	}
+
+//	if (ent->client->menu)
+//		PMenu_Close(ent->client->menu);
+
+	PMenu_Open(ent, adminmenu, -1, sizeof(adminmenu) / sizeof(pmenu_t), NULL);
+}
+
+void CTFAdmin(edict_t *ent)
+{
+	char text[1024];
+
+	if (gi.argc() > 1 && admin_password->string && *admin_password->string &&
+		!ent->client->resp.admin && strcmp(admin_password->string, gi.argv(1)) == 0) {
+		ent->client->resp.admin = true;
+		gi.bprintf(PRINT_HIGH, "%s has become an admin.\n", ent->client->pers.netname);
+		gi.cprintf(ent, PRINT_HIGH, "Type 'admin' to access the adminstration menu.\n");
+	}
+
+	if (!ent->client->resp.admin) {
+		sprintf(text, "%s has requested admin rights.",
+			ent->client->pers.netname);
+		CTFBeginElection(ent, ELECT_ADMIN, text);
+		return;
+	}
+
+	if (ent->client->menu)
+		PMenu_Close(ent);
+
+	CTFOpenAdminMenu(ent);
+}
+
+/*----------------------------------------------------------------*/
+
+void CTFStats(edict_t *ent)
+{
+	int i, e;
+	ghost_t *g;
+	char st[80];
+	char text[1400];
+	edict_t *e2;
+
+	*text = 0;
+	if (ctfgame.match == MATCH_SETUP) {
+		for (i = 1; i <= maxclients->value; i++) {
+			e2 = g_edicts + i;
+			if (!e2->inuse)
+				continue;
+			if (!e2->client->resp.ready && e2->client->resp.ctf_team != CTF_NOTEAM) {
+				sprintf(st, "%s is not ready.\n", e2->client->pers.netname);
+				if (strlen(text) + strlen(st) < sizeof(text) - 50)
+					strcat(text, st);
+			}
+		}
+	}
+
+	for (i = 0, g = ctfgame.ghosts; i < MAX_CLIENTS; i++, g++)
+		if (g->ent)
+			break;
+
+	if (i == MAX_CLIENTS) {
+		if (*text)
+			gi.cprintf(ent, PRINT_HIGH, "%s", text);
+		gi.cprintf(ent, PRINT_HIGH, "No statistics available.\n");
+		return;
+	}
+
+	strcat(text, "  #|Name            |Score|Kills|Death|BasDf|CarDf|Effcy|\n");
+
+	for (i = 0, g = ctfgame.ghosts; i < MAX_CLIENTS; i++, g++) {
+		if (!*g->netname)
+			continue;
+
+		if (g->deaths + g->kills == 0)
+			e = 50;
+		else
+			e = g->kills * 100 / (g->kills + g->deaths);
+		sprintf(st, "%3d|%-16.16s|%5d|%5d|%5d|%5d|%5d|%4d%%|\n",
+			g->number, 
+			g->netname, 
+			g->score, 
+			g->kills, 
+			g->deaths, 
+			g->basedef,
+			g->carrierdef, 
+			e);
+		if (strlen(text) + strlen(st) > sizeof(text) - 50) {
+			sprintf(text+strlen(text), "And more...\n");
+			gi.cprintf(ent, PRINT_HIGH, "%s", text);
+			return;
+		}
+		strcat(text, st);
+	}
+	gi.cprintf(ent, PRINT_HIGH, "%s", text);
+}
+
+void CTFPlayerList(edict_t *ent)
+{
+	int i;
+	char st[80];
+	char text[1400];
+	edict_t *e2;
+
+	*text = 0;
+	if (ctfgame.match == MATCH_SETUP) {
+		for (i = 1; i <= maxclients->value; i++) {
+			e2 = g_edicts + i;
+			if (!e2->inuse)
+				continue;
+			if (!e2->client->resp.ready && e2->client->resp.ctf_team != CTF_NOTEAM) {
+				sprintf(st, "%s is not ready.\n", e2->client->pers.netname);
+				if (strlen(text) + strlen(st) < sizeof(text) - 50)
+					strcat(text, st);
+			}
+		}
+	}
+
+	// number, name, connect time, ping, score, admin
+
+	*text = 0;
+	for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++) {
+		if (!e2->inuse)
+			continue;
+
+		sprintf(st, "%3d %-16.16s %02d:%02d %4d %3d%s%s\n",
+			i + 1,
+			e2->client->pers.netname,
+			(level.framenum - e2->client->resp.enterframe) / 600,
+			((level.framenum - e2->client->resp.enterframe) % 600)/10,
+			e2->client->ping,
+			e2->client->resp.score,
+			(ctfgame.match == MATCH_SETUP || ctfgame.match == MATCH_PREGAME) ?
+			(e2->client->resp.ready ? " (ready)" : " (notready)") : "",
+			e2->client->resp.admin ? " (admin)" : "");
+		if (strlen(text) + strlen(st) > sizeof(text) - 50) {
+			sprintf(text+strlen(text), "And more...\n");
+			gi.cprintf(ent, PRINT_HIGH, "%s", text);
+			return;
+		}
+		strcat(text, st);
+	}
+	gi.cprintf(ent, PRINT_HIGH, "%s", text);
+}
+
+
+void CTFWarp(edict_t *ent)
+{
+	char text[1024];
+	char *mlist, *token;
+	static const char *seps = " \t\n\r";
+
+	if (gi.argc() < 2) {
+		gi.cprintf(ent, PRINT_HIGH, "Where do you want to warp to?\n");
+		gi.cprintf(ent, PRINT_HIGH, "Available levels are: %s\n", warp_list->string);
+		return;
+	}
+
+	mlist = strdup(warp_list->string);
+
+	token = strtok(mlist, seps);
+	while (token != NULL) {
+		if (Q_stricmp(token, gi.argv(1)) == 0)
+			break;
+		token = strtok(NULL, seps);
+	}
+
+	if (token == NULL) {
+		gi.cprintf(ent, PRINT_HIGH, "Unknown CTF level.\n");
+		gi.cprintf(ent, PRINT_HIGH, "Available levels are: %s\n", warp_list->string);
+		free(mlist);
+		return;
+	}
+
+	free(mlist);
+
+
+	if (ent->client->resp.admin) {
+		gi.bprintf(PRINT_HIGH, "%s is warping to level %s.\n", 
+			ent->client->pers.netname, gi.argv(1));
+		strncpy(level.forcemap, gi.argv(1), sizeof(level.forcemap) - 1);
+		EndDMLevel();
+		return;
+	}
+
+	sprintf(text, "%s has requested warping to level %s.", 
+			ent->client->pers.netname, gi.argv(1));
+	if (CTFBeginElection(ent, ELECT_MAP, text))
+		strncpy(ctfgame.elevel, gi.argv(1), sizeof(ctfgame.elevel) - 1);
+}
+
+void CTFBoot(edict_t *ent)
+{
+	int i;
+	edict_t *targ;
+	char text[80];
+
+	if (!ent->client->resp.admin) {
+		gi.cprintf(ent, PRINT_HIGH, "You are not an admin.\n");
+		return;
+	}
+
+	if (gi.argc() < 2) {
+		gi.cprintf(ent, PRINT_HIGH, "Who do you want to kick?\n");
+		return;
+	}
+
+	if (*gi.argv(1) < '0' && *gi.argv(1) > '9') {
+		gi.cprintf(ent, PRINT_HIGH, "Specify the player number to kick.\n");
+		return;
+	}
+
+	i = atoi(gi.argv(1));
+	if (i < 1 || i > maxclients->value) {
+		gi.cprintf(ent, PRINT_HIGH, "Invalid player number.\n");
+		return;
+	}
+
+	targ = g_edicts + i;
+	if (!targ->inuse) {
+		gi.cprintf(ent, PRINT_HIGH, "That player number is not connected.\n");
+		return;
+	}
+
+	sprintf(text, "kick %d\n", i - 1);
+	gi.AddCommandString(text);
+}
+
+
+		
--- /dev/null
+++ b/ctf/g_ctf.h
@@ -1,0 +1,185 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+#define CTF_VERSION			1.09b
+#define CTF_VSTRING2(x) #x
+#define CTF_VSTRING(x) CTF_VSTRING2(x)
+#define CTF_STRING_VERSION  CTF_VSTRING(CTF_VERSION)
+
+#define STAT_CTF_TEAM1_PIC			17
+#define STAT_CTF_TEAM1_CAPS			18
+#define STAT_CTF_TEAM2_PIC			19
+#define STAT_CTF_TEAM2_CAPS			20
+#define STAT_CTF_FLAG_PIC			21
+#define STAT_CTF_JOINED_TEAM1_PIC	22
+#define STAT_CTF_JOINED_TEAM2_PIC	23
+#define STAT_CTF_TEAM1_HEADER		24
+#define STAT_CTF_TEAM2_HEADER		25
+#define STAT_CTF_TECH				26
+#define STAT_CTF_ID_VIEW			27
+#define STAT_CTF_MATCH				28
+
+#define CONFIG_CTF_MATCH (CS_MAXCLIENTS-1)
+
+typedef enum {
+	CTF_NOTEAM,
+	CTF_TEAM1,
+	CTF_TEAM2
+} ctfteam_t;
+
+typedef enum {
+	CTF_GRAPPLE_STATE_FLY,
+	CTF_GRAPPLE_STATE_PULL,
+	CTF_GRAPPLE_STATE_HANG
+} ctfgrapplestate_t;
+
+typedef struct ghost_s {
+	char netname[16];
+	int number;
+
+	// stats
+	int deaths;
+	int kills;
+	int caps;
+	int basedef;
+	int carrierdef;
+
+	int code; // ghost code
+	int team; // team
+	int score; // frags at time of disconnect
+	edict_t *ent;
+} ghost_t;
+
+extern cvar_t *ctf;
+
+#define CTF_TEAM1_SKIN "ctf_r"
+#define CTF_TEAM2_SKIN "ctf_b"
+
+#define DF_CTF_FORCEJOIN	131072	
+#define DF_ARMOR_PROTECT	262144
+#define DF_CTF_NO_TECH      524288
+
+#define CTF_CAPTURE_BONUS		15	// what you get for capture
+#define CTF_TEAM_BONUS			10	// what your team gets for capture
+#define CTF_RECOVERY_BONUS		1	// what you get for recovery
+#define CTF_FLAG_BONUS			0	// what you get for picking up enemy flag
+#define CTF_FRAG_CARRIER_BONUS	2	// what you get for fragging enemy flag carrier
+#define CTF_FLAG_RETURN_TIME	40	// seconds until auto return
+
+#define CTF_CARRIER_DANGER_PROTECT_BONUS	2	// bonus for fraggin someone who has recently hurt your flag carrier
+#define CTF_CARRIER_PROTECT_BONUS			1	// bonus for fraggin someone while either you or your target are near your flag carrier
+#define CTF_FLAG_DEFENSE_BONUS				1	// bonus for fraggin someone while either you or your target are near your flag
+#define CTF_RETURN_FLAG_ASSIST_BONUS		1	// awarded for returning a flag that causes a capture to happen almost immediately
+#define CTF_FRAG_CARRIER_ASSIST_BONUS		2	// award for fragging a flag carrier if a capture happens almost immediately
+
+#define CTF_TARGET_PROTECT_RADIUS			400	// the radius around an object being defended where a target will be worth extra frags
+#define CTF_ATTACKER_PROTECT_RADIUS			400	// the radius around an object being defended where an attacker will get extra frags when making kills
+
+#define CTF_CARRIER_DANGER_PROTECT_TIMEOUT	8
+#define CTF_FRAG_CARRIER_ASSIST_TIMEOUT		10
+#define CTF_RETURN_FLAG_ASSIST_TIMEOUT		10
+
+#define CTF_AUTO_FLAG_RETURN_TIMEOUT		30	// number of seconds before dropped flag auto-returns
+
+#define CTF_TECH_TIMEOUT					60  // seconds before techs spawn again
+
+#define CTF_GRAPPLE_SPEED					650 // speed of grapple in flight
+#define CTF_GRAPPLE_PULL_SPEED				650	// speed player is pulled at
+
+void CTFInit(void);
+void CTFSpawn(void);
+
+void SP_info_player_team1(edict_t *self);
+void SP_info_player_team2(edict_t *self);
+
+char *CTFTeamName(int team);
+char *CTFOtherTeamName(int team);
+void CTFAssignSkin(edict_t *ent, char *s);
+void CTFAssignTeam(gclient_t *who);
+edict_t *SelectCTFSpawnPoint (edict_t *ent);
+qboolean CTFPickup_Flag(edict_t *ent, edict_t *other);
+qboolean CTFDrop_Flag(edict_t *ent, gitem_t *item);
+void CTFEffects(edict_t *player);
+void CTFCalcScores(void);
+void SetCTFStats(edict_t *ent);
+void CTFDeadDropFlag(edict_t *self);
+void CTFScoreboardMessage (edict_t *ent, edict_t *killer);
+void CTFTeam_f (edict_t *ent);
+void CTFID_f (edict_t *ent);
+void CTFSay_Team(edict_t *who, char *msg);
+void CTFFlagSetup (edict_t *ent);
+void CTFResetFlag(int ctf_team);
+void CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker);
+void CTFCheckHurtCarrier(edict_t *targ, edict_t *attacker);
+
+// GRAPPLE
+void CTFWeapon_Grapple (edict_t *ent);
+void CTFPlayerResetGrapple(edict_t *ent);
+void CTFGrapplePull(edict_t *self);
+void CTFResetGrapple(edict_t *self);
+
+//TECH
+gitem_t *CTFWhat_Tech(edict_t *ent);
+qboolean CTFPickup_Tech (edict_t *ent, edict_t *other);
+void CTFDrop_Tech(edict_t *ent, gitem_t *item);
+void CTFDeadDropTech(edict_t *ent);
+void CTFSetupTechSpawn(void);
+int CTFApplyResistance(edict_t *ent, int dmg);
+int CTFApplyStrength(edict_t *ent, int dmg);
+qboolean CTFApplyStrengthSound(edict_t *ent);
+qboolean CTFApplyHaste(edict_t *ent);
+void CTFApplyHasteSound(edict_t *ent);
+void CTFApplyRegeneration(edict_t *ent);
+qboolean CTFHasRegeneration(edict_t *ent);
+void CTFRespawnTech(edict_t *ent);
+void CTFResetTech(void);
+
+void CTFOpenJoinMenu(edict_t *ent);
+qboolean CTFStartClient(edict_t *ent);
+void CTFVoteYes(edict_t *ent);
+void CTFVoteNo(edict_t *ent);
+void CTFReady(edict_t *ent);
+void CTFNotReady(edict_t *ent);
+qboolean CTFNextMap(void);
+qboolean CTFMatchSetup(void);
+qboolean CTFMatchOn(void);
+void CTFGhost(edict_t *ent);
+void CTFAdmin(edict_t *ent);
+qboolean CTFInMatch(void);
+void CTFStats(edict_t *ent);
+void CTFWarp(edict_t *ent);
+void CTFBoot(edict_t *ent);
+void CTFPlayerList(edict_t *ent);
+
+qboolean CTFCheckRules(void);
+
+void SP_misc_ctf_banner (edict_t *ent);
+void SP_misc_ctf_small_banner (edict_t *ent);
+
+extern char *ctf_statusbar;
+
+void UpdateChaseCam(edict_t *ent);
+void ChaseNext(edict_t *ent);
+void ChasePrev(edict_t *ent);
+
+void CTFObserver(edict_t *ent);
+
+void SP_trigger_teleport (edict_t *ent);
+void SP_info_teleport_destination (edict_t *ent);
--- /dev/null
+++ b/ctf/g_func.c
@@ -1,0 +1,2047 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+/*
+=========================================================
+
+  PLATS
+
+  movement options:
+
+  linear
+  smooth start, hard stop
+  smooth start, smooth stop
+
+  start
+  end
+  acceleration
+  speed
+  deceleration
+  begin sound
+  end sound
+  target fired when reaching end
+  wait at end
+
+  object characteristics that use move segments
+  ---------------------------------------------
+  movetype_push, or movetype_stop
+  action when touched
+  action when blocked
+  action when used
+	disabled?
+  auto trigger spawning
+
+
+=========================================================
+*/
+
+#define PLAT_LOW_TRIGGER	1
+
+#define	STATE_TOP			0
+#define	STATE_BOTTOM		1
+#define STATE_UP			2
+#define STATE_DOWN			3
+
+#define DOOR_START_OPEN		1
+#define DOOR_REVERSE		2
+#define DOOR_CRUSHER		4
+#define DOOR_NOMONSTER		8
+#define DOOR_TOGGLE			32
+#define DOOR_X_AXIS			64
+#define DOOR_Y_AXIS			128
+
+
+//
+// Support routines for movement (changes in origin using velocity)
+//
+
+void Move_Done (edict_t *ent)
+{
+	VectorClear (ent->velocity);
+	ent->moveinfo.endfunc (ent);
+}
+
+void Move_Final (edict_t *ent)
+{
+	if (ent->moveinfo.remaining_distance == 0)
+	{
+		Move_Done (ent);
+		return;
+	}
+
+	VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance / FRAMETIME, ent->velocity);
+
+	ent->think = Move_Done;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void Move_Begin (edict_t *ent)
+{
+	float	frames;
+
+	if ((ent->moveinfo.speed * FRAMETIME) >= ent->moveinfo.remaining_distance)
+	{
+		Move_Final (ent);
+		return;
+	}
+	VectorScale (ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity);
+	frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME);
+	ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME;
+	ent->nextthink = level.time + (frames * FRAMETIME);
+	ent->think = Move_Final;
+}
+
+void Think_AccelMove (edict_t *ent);
+
+void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*))
+{
+	VectorClear (ent->velocity);
+	VectorSubtract (dest, ent->s.origin, ent->moveinfo.dir);
+	ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir);
+	ent->moveinfo.endfunc = func;
+
+	if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel)
+	{
+		if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
+		{
+			Move_Begin (ent);
+		}
+		else
+		{
+			ent->nextthink = level.time + FRAMETIME;
+			ent->think = Move_Begin;
+		}
+	}
+	else
+	{
+		// accelerative
+		ent->moveinfo.current_speed = 0;
+		ent->think = Think_AccelMove;
+		ent->nextthink = level.time + FRAMETIME;
+	}
+}
+
+
+//
+// Support routines for angular movement (changes in angle using avelocity)
+//
+
+void AngleMove_Done (edict_t *ent)
+{
+	VectorClear (ent->avelocity);
+	ent->moveinfo.endfunc (ent);
+}
+
+void AngleMove_Final (edict_t *ent)
+{
+	vec3_t	move;
+
+	if (ent->moveinfo.state == STATE_UP)
+		VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, move);
+	else
+		VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, move);
+
+	if (VectorCompare (move, vec3_origin))
+	{
+		AngleMove_Done (ent);
+		return;
+	}
+
+	VectorScale (move, 1.0/FRAMETIME, ent->avelocity);
+
+	ent->think = AngleMove_Done;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void AngleMove_Begin (edict_t *ent)
+{
+	vec3_t	destdelta;
+	float	len;
+	float	traveltime;
+	float	frames;
+
+	// set destdelta to the vector needed to move
+	if (ent->moveinfo.state == STATE_UP)
+		VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, destdelta);
+	else
+		VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta);
+	
+	// calculate length of vector
+	len = VectorLength (destdelta);
+	
+	// divide by speed to get time to reach dest
+	traveltime = len / ent->moveinfo.speed;
+
+	if (traveltime < FRAMETIME)
+	{
+		AngleMove_Final (ent);
+		return;
+	}
+
+	frames = floor(traveltime / FRAMETIME);
+
+	// scale the destdelta vector by the time spent traveling to get velocity
+	VectorScale (destdelta, 1.0 / traveltime, ent->avelocity);
+
+	// set nextthink to trigger a think when dest is reached
+	ent->nextthink = level.time + frames * FRAMETIME;
+	ent->think = AngleMove_Final;
+}
+
+void AngleMove_Calc (edict_t *ent, void(*func)(edict_t*))
+{
+	VectorClear (ent->avelocity);
+	ent->moveinfo.endfunc = func;
+	if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
+	{
+		AngleMove_Begin (ent);
+	}
+	else
+	{
+		ent->nextthink = level.time + FRAMETIME;
+		ent->think = AngleMove_Begin;
+	}
+}
+
+
+/*
+==============
+Think_AccelMove
+
+The team has completed a frame of movement, so
+change the speed for the next frame
+==============
+*/
+#define AccelerationDistance(target, rate)	(target * ((target / rate) + 1) / 2)
+
+void plat_CalcAcceleratedMove(moveinfo_t *moveinfo)
+{
+	float	accel_dist;
+	float	decel_dist;
+
+	moveinfo->move_speed = moveinfo->speed;
+
+	if (moveinfo->remaining_distance < moveinfo->accel)
+	{
+		moveinfo->current_speed = moveinfo->remaining_distance;
+		return;
+	}
+
+	accel_dist = AccelerationDistance (moveinfo->speed, moveinfo->accel);
+	decel_dist = AccelerationDistance (moveinfo->speed, moveinfo->decel);
+
+	if ((moveinfo->remaining_distance - accel_dist - decel_dist) < 0)
+	{
+		float	f;
+
+		f = (moveinfo->accel + moveinfo->decel) / (moveinfo->accel * moveinfo->decel);
+		moveinfo->move_speed = (-2 + sqrt(4 - 4 * f * (-2 * moveinfo->remaining_distance))) / (2 * f);
+		decel_dist = AccelerationDistance (moveinfo->move_speed, moveinfo->decel);
+	}
+
+	moveinfo->decel_distance = decel_dist;
+};
+
+void plat_Accelerate (moveinfo_t *moveinfo)
+{
+	// are we decelerating?
+	if (moveinfo->remaining_distance <= moveinfo->decel_distance)
+	{
+		if (moveinfo->remaining_distance < moveinfo->decel_distance)
+		{
+			if (moveinfo->next_speed)
+			{
+				moveinfo->current_speed = moveinfo->next_speed;
+				moveinfo->next_speed = 0;
+				return;
+			}
+			if (moveinfo->current_speed > moveinfo->decel)
+				moveinfo->current_speed -= moveinfo->decel;
+		}
+		return;
+	}
+
+	// are we at full speed and need to start decelerating during this move?
+	if (moveinfo->current_speed == moveinfo->move_speed)
+		if ((moveinfo->remaining_distance - moveinfo->current_speed) < moveinfo->decel_distance)
+		{
+			float	p1_distance;
+			float	p2_distance;
+			float	distance;
+
+			p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance;
+			p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / moveinfo->move_speed));
+			distance = p1_distance + p2_distance;
+			moveinfo->current_speed = moveinfo->move_speed;
+			moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance);
+			return;
+		}
+
+	// are we accelerating?
+	if (moveinfo->current_speed < moveinfo->speed)
+	{
+		float	old_speed;
+		float	p1_distance;
+		float	p1_speed;
+		float	p2_distance;
+		float	distance;
+
+		old_speed = moveinfo->current_speed;
+
+		// figure simple acceleration up to move_speed
+		moveinfo->current_speed += moveinfo->accel;
+		if (moveinfo->current_speed > moveinfo->speed)
+			moveinfo->current_speed = moveinfo->speed;
+
+		// are we accelerating throughout this entire move?
+		if ((moveinfo->remaining_distance - moveinfo->current_speed) >= moveinfo->decel_distance)
+			return;
+
+		// during this move we will accelrate from current_speed to move_speed
+		// and cross over the decel_distance; figure the average speed for the
+		// entire move
+		p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance;
+		p1_speed = (old_speed + moveinfo->move_speed) / 2.0;
+		p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / p1_speed));
+		distance = p1_distance + p2_distance;
+		moveinfo->current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo->move_speed * (p2_distance / distance));
+		moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance);
+		return;
+	}
+
+	// we are at constant velocity (move_speed)
+	return;
+};
+
+void Think_AccelMove (edict_t *ent)
+{
+	ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed;
+
+	if (ent->moveinfo.current_speed == 0)		// starting or blocked
+		plat_CalcAcceleratedMove(&ent->moveinfo);
+
+	plat_Accelerate (&ent->moveinfo);
+
+	// will the entire move complete on next frame?
+	if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed)
+	{
+		Move_Final (ent);
+		return;
+	}
+
+	VectorScale (ent->moveinfo.dir, ent->moveinfo.current_speed*10, ent->velocity);
+	ent->nextthink = level.time + FRAMETIME;
+	ent->think = Think_AccelMove;
+}
+
+
+void plat_go_down (edict_t *ent);
+
+void plat_hit_top (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_end)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		ent->s.sound = 0;
+	}
+	ent->moveinfo.state = STATE_TOP;
+
+	ent->think = plat_go_down;
+	ent->nextthink = level.time + 3;
+}
+
+void plat_hit_bottom (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_end)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		ent->s.sound = 0;
+	}
+	ent->moveinfo.state = STATE_BOTTOM;
+}
+
+void plat_go_down (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_start)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		ent->s.sound = ent->moveinfo.sound_middle;
+	}
+	ent->moveinfo.state = STATE_DOWN;
+	Move_Calc (ent, ent->moveinfo.end_origin, plat_hit_bottom);
+}
+
+void plat_go_up (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_start)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		ent->s.sound = ent->moveinfo.sound_middle;
+	}
+	ent->moveinfo.state = STATE_UP;
+	Move_Calc (ent, ent->moveinfo.start_origin, plat_hit_top);
+}
+
+void plat_blocked (edict_t *self, edict_t *other)
+{
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+
+	if (self->moveinfo.state == STATE_UP)
+		plat_go_down (self);
+	else if (self->moveinfo.state == STATE_DOWN)
+		plat_go_up (self);
+}
+
+
+void Use_Plat (edict_t *ent, edict_t *other, edict_t *activator)
+{ 
+	if (ent->think)
+		return;		// already down
+	plat_go_down (ent);
+}
+
+
+void Touch_Plat_Center (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (!other->client)
+		return;
+		
+	if (other->health <= 0)
+		return;
+
+	ent = ent->enemy;	// now point at the plat, not the trigger
+	if (ent->moveinfo.state == STATE_BOTTOM)
+		plat_go_up (ent);
+	else if (ent->moveinfo.state == STATE_TOP)
+		ent->nextthink = level.time + 1;	// the player is still on the plat, so delay going down
+}
+
+void plat_spawn_inside_trigger (edict_t *ent)
+{
+	edict_t	*trigger;
+	vec3_t	tmin, tmax;
+
+//
+// middle trigger
+//	
+	trigger = G_Spawn();
+	trigger->touch = Touch_Plat_Center;
+	trigger->movetype = MOVETYPE_NONE;
+	trigger->solid = SOLID_TRIGGER;
+	trigger->enemy = ent;
+	
+	tmin[0] = ent->mins[0] + 25;
+	tmin[1] = ent->mins[1] + 25;
+	tmin[2] = ent->mins[2];
+
+	tmax[0] = ent->maxs[0] - 25;
+	tmax[1] = ent->maxs[1] - 25;
+	tmax[2] = ent->maxs[2] + 8;
+
+	tmin[2] = tmax[2] - (ent->pos1[2] - ent->pos2[2] + st.lip);
+
+	if (ent->spawnflags & PLAT_LOW_TRIGGER)
+		tmax[2] = tmin[2] + 8;
+	
+	if (tmax[0] - tmin[0] <= 0)
+	{
+		tmin[0] = (ent->mins[0] + ent->maxs[0]) *0.5;
+		tmax[0] = tmin[0] + 1;
+	}
+	if (tmax[1] - tmin[1] <= 0)
+	{
+		tmin[1] = (ent->mins[1] + ent->maxs[1]) *0.5;
+		tmax[1] = tmin[1] + 1;
+	}
+	
+	VectorCopy (tmin, trigger->mins);
+	VectorCopy (tmax, trigger->maxs);
+
+	gi.linkentity (trigger);
+}
+
+
+/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
+speed	default 150
+
+Plats are always drawn in the extended position, so they will light correctly.
+
+If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
+
+"speed"	overrides default 200.
+"accel" overrides default 500
+"lip"	overrides default 8 pixel lip
+
+If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height.
+
+Set "sounds" to one of the following:
+1) base fast
+2) chain slow
+*/
+void SP_func_plat (edict_t *ent)
+{
+	VectorClear (ent->s.angles);
+	ent->solid = SOLID_BSP;
+	ent->movetype = MOVETYPE_PUSH;
+
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = plat_blocked;
+
+	if (!ent->speed)
+		ent->speed = 20;
+	else
+		ent->speed *= 0.1;
+
+	if (!ent->accel)
+		ent->accel = 5;
+	else
+		ent->accel *= 0.1;
+
+	if (!ent->decel)
+		ent->decel = 5;
+	else
+		ent->decel *= 0.1;
+
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	if (!st.lip)
+		st.lip = 8;
+
+	// pos1 is the top position, pos2 is the bottom
+	VectorCopy (ent->s.origin, ent->pos1);
+	VectorCopy (ent->s.origin, ent->pos2);
+	if (st.height)
+		ent->pos2[2] -= st.height;
+	else
+		ent->pos2[2] -= (ent->maxs[2] - ent->mins[2]) - st.lip;
+
+	ent->use = Use_Plat;
+
+	plat_spawn_inside_trigger (ent);	// the "start moving" trigger	
+
+	if (ent->targetname)
+	{
+		ent->moveinfo.state = STATE_UP;
+	}
+	else
+	{
+		VectorCopy (ent->pos2, ent->s.origin);
+		gi.linkentity (ent);
+		ent->moveinfo.state = STATE_BOTTOM;
+	}
+
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->pos1, ent->moveinfo.start_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
+	VectorCopy (ent->pos2, ent->moveinfo.end_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
+
+	ent->moveinfo.sound_start = gi.soundindex ("plats/pt1_strt.wav");
+	ent->moveinfo.sound_middle = gi.soundindex ("plats/pt1_mid.wav");
+	ent->moveinfo.sound_end = gi.soundindex ("plats/pt1_end.wav");
+}
+
+//====================================================================
+
+/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS TOUCH_PAIN STOP ANIMATED ANIMATED_FAST
+You need to have an origin brush as part of this entity.  The center of that brush will be
+the point around which it is rotated. It will rotate around the Z axis by default.  You can
+check either the X_AXIS or Y_AXIS box to change that.
+
+"speed" determines how fast it moves; default value is 100.
+"dmg"	damage to inflict when blocked (2 default)
+
+REVERSE will cause the it to rotate in the opposite direction.
+STOP mean it will stop moving instead of pushing entities
+*/
+
+void rotating_blocked (edict_t *self, edict_t *other)
+{
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void rotating_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (self->avelocity[0] || self->avelocity[1] || self->avelocity[2])
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void rotating_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (!VectorCompare (self->avelocity, vec3_origin))
+	{
+		self->s.sound = 0;
+		VectorClear (self->avelocity);
+		self->touch = NULL;
+	}
+	else
+	{
+		self->s.sound = self->moveinfo.sound_middle;
+		VectorScale (self->movedir, self->speed, self->avelocity);
+		if (self->spawnflags & 16)
+			self->touch = rotating_touch;
+	}
+}
+
+void SP_func_rotating (edict_t *ent)
+{
+	ent->solid = SOLID_BSP;
+	if (ent->spawnflags & 32)
+		ent->movetype = MOVETYPE_STOP;
+	else
+		ent->movetype = MOVETYPE_PUSH;
+
+	// set the axis of rotation
+	VectorClear(ent->movedir);
+	if (ent->spawnflags & 4)
+		ent->movedir[2] = 1.0;
+	else if (ent->spawnflags & 8)
+		ent->movedir[0] = 1.0;
+	else // Z_AXIS
+		ent->movedir[1] = 1.0;
+
+	// check for reverse rotation
+	if (ent->spawnflags & 2)
+		VectorNegate (ent->movedir, ent->movedir);
+
+	if (!ent->speed)
+		ent->speed = 100;
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+//	ent->moveinfo.sound_middle = "doors/hydro1.wav";
+
+	ent->use = rotating_use;
+	if (ent->dmg)
+		ent->blocked = rotating_blocked;
+
+	if (ent->spawnflags & 1)
+		ent->use (ent, NULL, NULL);
+
+	if (ent->spawnflags & 64)
+		ent->s.effects |= EF_ANIM_ALL;
+	if (ent->spawnflags & 128)
+		ent->s.effects |= EF_ANIM_ALLFAST;
+
+	gi.setmodel (ent, ent->model);
+	gi.linkentity (ent);
+}
+
+/*
+======================================================================
+
+BUTTONS
+
+======================================================================
+*/
+
+/*QUAKED func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle"		determines the opening direction
+"target"	all entities with a matching targetname will be used
+"speed"		override the default 40 speed
+"wait"		override the default 1 second wait (-1 = never return)
+"lip"		override the default 4 pixel lip remaining at end of move
+"health"	if set, the button must be killed instead of touched
+"sounds"
+1) silent
+2) steam metal
+3) wooden clunk
+4) metallic click
+5) in-out
+*/
+
+void button_done (edict_t *self)
+{
+	self->moveinfo.state = STATE_BOTTOM;
+	self->s.effects &= ~EF_ANIM23;
+	self->s.effects |= EF_ANIM01;
+}
+
+void button_return (edict_t *self)
+{
+	self->moveinfo.state = STATE_DOWN;
+
+	Move_Calc (self, self->moveinfo.start_origin, button_done);
+
+	self->s.frame = 0;
+
+	if (self->health)
+		self->takedamage = DAMAGE_YES;
+}
+
+void button_wait (edict_t *self)
+{
+	self->moveinfo.state = STATE_TOP;
+	self->s.effects &= ~EF_ANIM01;
+	self->s.effects |= EF_ANIM23;
+
+	G_UseTargets (self, self->activator);
+	self->s.frame = 1;
+	if (self->moveinfo.wait >= 0)
+	{
+		self->nextthink = level.time + self->moveinfo.wait;
+		self->think = button_return;
+	}
+}
+
+void button_fire (edict_t *self)
+{
+	if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP)
+		return;
+
+	self->moveinfo.state = STATE_UP;
+	if (self->moveinfo.sound_start && !(self->flags & FL_TEAMSLAVE))
+		gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+	Move_Calc (self, self->moveinfo.end_origin, button_wait);
+}
+
+void button_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+	button_fire (self);
+}
+
+void button_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (!other->client)
+		return;
+
+	if (other->health <= 0)
+		return;
+
+	self->activator = other;
+	button_fire (self);
+}
+
+void button_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	self->activator = attacker;
+	self->health = self->max_health;
+	self->takedamage = DAMAGE_NO;
+	button_fire (self);
+}
+
+void SP_func_button (edict_t *ent)
+{
+	vec3_t	abs_movedir;
+	float	dist;
+
+	G_SetMovedir (ent->s.angles, ent->movedir);
+	ent->movetype = MOVETYPE_STOP;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	if (ent->sounds != 1)
+		ent->moveinfo.sound_start = gi.soundindex ("switches/butn2.wav");
+	
+	if (!ent->speed)
+		ent->speed = 40;
+	if (!ent->accel)
+		ent->accel = ent->speed;
+	if (!ent->decel)
+		ent->decel = ent->speed;
+
+	if (!ent->wait)
+		ent->wait = 3;
+	if (!st.lip)
+		st.lip = 4;
+
+	VectorCopy (ent->s.origin, ent->pos1);
+	abs_movedir[0] = fabs(ent->movedir[0]);
+	abs_movedir[1] = fabs(ent->movedir[1]);
+	abs_movedir[2] = fabs(ent->movedir[2]);
+	dist = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip;
+	VectorMA (ent->pos1, dist, ent->movedir, ent->pos2);
+
+	ent->use = button_use;
+	ent->s.effects |= EF_ANIM01;
+
+	if (ent->health)
+	{
+		ent->max_health = ent->health;
+		ent->die = button_killed;
+		ent->takedamage = DAMAGE_YES;
+	}
+	else if (! ent->targetname)
+		ent->touch = button_touch;
+
+	ent->moveinfo.state = STATE_BOTTOM;
+
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->pos1, ent->moveinfo.start_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
+	VectorCopy (ent->pos2, ent->moveinfo.end_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
+
+	gi.linkentity (ent);
+}
+
+/*
+======================================================================
+
+DOORS
+
+  spawn a trigger surrounding the entire team unless it is
+  allready targeted by another
+
+======================================================================
+*/
+
+/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER NOMONSTER ANIMATED TOGGLE ANIMATED_FAST
+TOGGLE		wait in both the start and end states for a trigger event.
+START_OPEN	the door to moves to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+NOMONSTER	monsters will not trigger this door
+
+"message"	is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"		determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"	if set, door must be shot open
+"speed"		movement speed (100 default)
+"wait"		wait before returning (3 default, -1 = never return)
+"lip"		lip remaining at end of move (8 default)
+"dmg"		damage to inflict when blocked (2 default)
+"sounds"
+1)	silent
+2)	light
+3)	medium
+4)	heavy
+*/
+
+void door_use_areaportals (edict_t *self, qboolean open)
+{
+	edict_t	*t = NULL;
+
+	if (!self->target)
+		return;
+
+	while ((t = G_Find (t, FOFS(targetname), self->target)))
+	{
+		if (Q_stricmp(t->classname, "func_areaportal") == 0)
+		{
+			gi.SetAreaPortalState (t->style, open);
+		}
+	}
+}
+
+void door_go_down (edict_t *self);
+
+void door_hit_top (edict_t *self)
+{
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_end)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		self->s.sound = 0;
+	}
+	self->moveinfo.state = STATE_TOP;
+	if (self->spawnflags & DOOR_TOGGLE)
+		return;
+	if (self->moveinfo.wait >= 0)
+	{
+		self->think = door_go_down;
+		self->nextthink = level.time + self->moveinfo.wait;
+	}
+}
+
+void door_hit_bottom (edict_t *self)
+{
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_end)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		self->s.sound = 0;
+	}
+	self->moveinfo.state = STATE_BOTTOM;
+	door_use_areaportals (self, false);
+}
+
+void door_go_down (edict_t *self)
+{
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_start)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		self->s.sound = self->moveinfo.sound_middle;
+	}
+	if (self->max_health)
+	{
+		self->takedamage = DAMAGE_YES;
+		self->health = self->max_health;
+	}
+	
+	self->moveinfo.state = STATE_DOWN;
+	if (strcmp(self->classname, "func_door") == 0)
+		Move_Calc (self, self->moveinfo.start_origin, door_hit_bottom);
+	else if (strcmp(self->classname, "func_door_rotating") == 0)
+		AngleMove_Calc (self, door_hit_bottom);
+}
+
+void door_go_up (edict_t *self, edict_t *activator)
+{
+	if (self->moveinfo.state == STATE_UP)
+		return;		// already going up
+
+	if (self->moveinfo.state == STATE_TOP)
+	{	// reset top wait time
+		if (self->moveinfo.wait >= 0)
+			self->nextthink = level.time + self->moveinfo.wait;
+		return;
+	}
+	
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_start)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		self->s.sound = self->moveinfo.sound_middle;
+	}
+	self->moveinfo.state = STATE_UP;
+	if (strcmp(self->classname, "func_door") == 0)
+		Move_Calc (self, self->moveinfo.end_origin, door_hit_top);
+	else if (strcmp(self->classname, "func_door_rotating") == 0)
+		AngleMove_Calc (self, door_hit_top);
+
+	G_UseTargets (self, activator);
+	door_use_areaportals (self, true);
+}
+
+void door_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t	*ent;
+
+	if (self->flags & FL_TEAMSLAVE)
+		return;
+
+	if (self->spawnflags & DOOR_TOGGLE)
+	{
+		if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP)
+		{
+			// trigger all paired doors
+			for (ent = self ; ent ; ent = ent->teamchain)
+			{
+				ent->message = NULL;
+				ent->touch = NULL;
+				door_go_down (ent);
+			}
+			return;
+		}
+	}
+	
+	// trigger all paired doors
+	for (ent = self ; ent ; ent = ent->teamchain)
+	{
+		ent->message = NULL;
+		ent->touch = NULL;
+		door_go_up (ent, activator);
+	}
+};
+
+void Touch_DoorTrigger (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other->health <= 0)
+		return;
+
+	if (!(other->svflags & SVF_MONSTER) && (!other->client))
+		return;
+
+	if ((self->owner->spawnflags & DOOR_NOMONSTER) && (other->svflags & SVF_MONSTER))
+		return;
+
+	if (level.time < self->touch_debounce_time)
+		return;
+	self->touch_debounce_time = level.time + 1.0;
+
+	door_use (self->owner, other, other);
+}
+
+void Think_CalcMoveSpeed (edict_t *self)
+{
+	edict_t	*ent;
+	float	min;
+	float	time;
+	float	newspeed;
+	float	ratio;
+	float	dist;
+
+	if (self->flags & FL_TEAMSLAVE)
+		return;		// only the team master does this
+
+	// find the smallest distance any member of the team will be moving
+	min = fabs(self->moveinfo.distance);
+	for (ent = self->teamchain; ent; ent = ent->teamchain)
+	{
+		dist = fabs(ent->moveinfo.distance);
+		if (dist < min)
+			min = dist;
+	}
+
+	time = min / self->moveinfo.speed;
+
+	// adjust speeds so they will all complete at the same time
+	for (ent = self; ent; ent = ent->teamchain)
+	{
+		newspeed = fabs(ent->moveinfo.distance) / time;
+		ratio = newspeed / ent->moveinfo.speed;
+		if (ent->moveinfo.accel == ent->moveinfo.speed)
+			ent->moveinfo.accel = newspeed;
+		else
+			ent->moveinfo.accel *= ratio;
+		if (ent->moveinfo.decel == ent->moveinfo.speed)
+			ent->moveinfo.decel = newspeed;
+		else
+			ent->moveinfo.decel *= ratio;
+		ent->moveinfo.speed = newspeed;
+	}
+}
+
+void Think_SpawnDoorTrigger (edict_t *ent)
+{
+	edict_t		*other;
+	vec3_t		mins, maxs;
+
+	if (ent->flags & FL_TEAMSLAVE)
+		return;		// only the team leader spawns a trigger
+
+	VectorCopy (ent->absmin, mins);
+	VectorCopy (ent->absmax, maxs);
+
+	for (other = ent->teamchain ; other ; other=other->teamchain)
+	{
+		AddPointToBounds (other->absmin, mins, maxs);
+		AddPointToBounds (other->absmax, mins, maxs);
+	}
+
+	// expand 
+	mins[0] -= 60;
+	mins[1] -= 60;
+	maxs[0] += 60;
+	maxs[1] += 60;
+
+	other = G_Spawn ();
+	VectorCopy (mins, other->mins);
+	VectorCopy (maxs, other->maxs);
+	other->owner = ent;
+	other->solid = SOLID_TRIGGER;
+	other->movetype = MOVETYPE_NONE;
+	other->touch = Touch_DoorTrigger;
+	gi.linkentity (other);
+
+	if (ent->spawnflags & DOOR_START_OPEN)
+		door_use_areaportals (ent, true);
+
+	Think_CalcMoveSpeed (ent);
+}
+
+void door_blocked  (edict_t *self, edict_t *other)
+{
+	edict_t	*ent;
+
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+
+	if (self->spawnflags & DOOR_CRUSHER)
+		return;
+
+
+// if a door has a negative wait, it would never come back if blocked,
+// so let it just squash the object to death real fast
+	if (self->moveinfo.wait >= 0)
+	{
+		if (self->moveinfo.state == STATE_DOWN)
+		{
+			for (ent = self->teammaster ; ent ; ent = ent->teamchain)
+				door_go_up (ent, ent->activator);
+		}
+		else
+		{
+			for (ent = self->teammaster ; ent ; ent = ent->teamchain)
+				door_go_down (ent);
+		}
+	}
+}
+
+void door_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	edict_t	*ent;
+
+	for (ent = self->teammaster ; ent ; ent = ent->teamchain)
+	{
+		ent->health = ent->max_health;
+		ent->takedamage = DAMAGE_NO;
+	}
+	door_use (self->teammaster, attacker, attacker);
+}
+
+void door_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (!other->client)
+		return;
+
+	if (level.time < self->touch_debounce_time)
+		return;
+	self->touch_debounce_time = level.time + 5.0;
+
+	gi.centerprintf (other, "%s", self->message);
+	gi.sound (other, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+}
+
+void SP_func_door (edict_t *ent)
+{
+	vec3_t	abs_movedir;
+
+	if (ent->sounds != 1)
+	{
+		ent->moveinfo.sound_start = gi.soundindex  ("doors/dr1_strt.wav");
+		ent->moveinfo.sound_middle = gi.soundindex  ("doors/dr1_mid.wav");
+		ent->moveinfo.sound_end = gi.soundindex  ("doors/dr1_end.wav");
+	}
+
+	G_SetMovedir (ent->s.angles, ent->movedir);
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = door_blocked;
+	ent->use = door_use;
+	
+	if (!ent->speed)
+		ent->speed = 100;
+	if (deathmatch->value)
+		ent->speed *= 2;
+
+	if (!ent->accel)
+		ent->accel = ent->speed;
+	if (!ent->decel)
+		ent->decel = ent->speed;
+
+	if (!ent->wait)
+		ent->wait = 3;
+	if (!st.lip)
+		st.lip = 8;
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	// calculate second position
+	VectorCopy (ent->s.origin, ent->pos1);
+	abs_movedir[0] = fabs(ent->movedir[0]);
+	abs_movedir[1] = fabs(ent->movedir[1]);
+	abs_movedir[2] = fabs(ent->movedir[2]);
+	ent->moveinfo.distance = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip;
+	VectorMA (ent->pos1, ent->moveinfo.distance, ent->movedir, ent->pos2);
+
+	// if it starts open, switch the positions
+	if (ent->spawnflags & DOOR_START_OPEN)
+	{
+		VectorCopy (ent->pos2, ent->s.origin);
+		VectorCopy (ent->pos1, ent->pos2);
+		VectorCopy (ent->s.origin, ent->pos1);
+	}
+
+	ent->moveinfo.state = STATE_BOTTOM;
+
+	if (ent->health)
+	{
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_killed;
+		ent->max_health = ent->health;
+	}
+	else if (ent->targetname && ent->message)
+	{
+		gi.soundindex ("misc/talk.wav");
+		ent->touch = door_touch;
+	}
+	
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->pos1, ent->moveinfo.start_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
+	VectorCopy (ent->pos2, ent->moveinfo.end_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
+
+	if (ent->spawnflags & 16)
+		ent->s.effects |= EF_ANIM_ALL;
+	if (ent->spawnflags & 64)
+		ent->s.effects |= EF_ANIM_ALLFAST;
+
+	// to simplify logic elsewhere, make non-teamed doors into a team of one
+	if (!ent->team)
+		ent->teammaster = ent;
+
+	gi.linkentity (ent);
+
+	ent->nextthink = level.time + FRAMETIME;
+	if (ent->health || ent->targetname)
+		ent->think = Think_CalcMoveSpeed;
+	else
+		ent->think = Think_SpawnDoorTrigger;
+}
+
+
+/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE CRUSHER NOMONSTER ANIMATED TOGGLE X_AXIS Y_AXIS
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+START_OPEN	the door to moves to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+NOMONSTER	monsters will not trigger this door
+
+You need to have an origin brush as part of this entity.  The center of that brush will be
+the point around which it is rotated. It will rotate around the Z axis by default.  You can
+check either the X_AXIS or Y_AXIS box to change that.
+
+"distance" is how many degrees the door will be rotated.
+"speed" determines how fast the door moves; default value is 100.
+
+REVERSE will cause the door to rotate in the opposite direction.
+
+"message"	is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"		determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"	if set, door must be shot open
+"speed"		movement speed (100 default)
+"wait"		wait before returning (3 default, -1 = never return)
+"dmg"		damage to inflict when blocked (2 default)
+"sounds"
+1)	silent
+2)	light
+3)	medium
+4)	heavy
+*/
+
+void SP_func_door_rotating (edict_t *ent)
+{
+	VectorClear (ent->s.angles);
+
+	// set the axis of rotation
+	VectorClear(ent->movedir);
+	if (ent->spawnflags & DOOR_X_AXIS)
+		ent->movedir[2] = 1.0;
+	else if (ent->spawnflags & DOOR_Y_AXIS)
+		ent->movedir[0] = 1.0;
+	else // Z_AXIS
+		ent->movedir[1] = 1.0;
+
+	// check for reverse rotation
+	if (ent->spawnflags & DOOR_REVERSE)
+		VectorNegate (ent->movedir, ent->movedir);
+
+	if (!st.distance)
+	{
+		gi.dprintf("%s at %s with no distance set\n", ent->classname, vtos(ent->s.origin));
+		st.distance = 90;
+	}
+
+	VectorCopy (ent->s.angles, ent->pos1);
+	VectorMA (ent->s.angles, st.distance, ent->movedir, ent->pos2);
+	ent->moveinfo.distance = st.distance;
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = door_blocked;
+	ent->use = door_use;
+
+	if (!ent->speed)
+		ent->speed = 100;
+	if (!ent->accel)
+		ent->accel = ent->speed;
+	if (!ent->decel)
+		ent->decel = ent->speed;
+
+	if (!ent->wait)
+		ent->wait = 3;
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	if (ent->sounds != 1)
+	{
+		ent->moveinfo.sound_start = gi.soundindex  ("doors/dr1_strt.wav");
+		ent->moveinfo.sound_middle = gi.soundindex  ("doors/dr1_mid.wav");
+		ent->moveinfo.sound_end = gi.soundindex  ("doors/dr1_end.wav");
+	}
+
+	// if it starts open, switch the positions
+	if (ent->spawnflags & DOOR_START_OPEN)
+	{
+		VectorCopy (ent->pos2, ent->s.angles);
+		VectorCopy (ent->pos1, ent->pos2);
+		VectorCopy (ent->s.angles, ent->pos1);
+		VectorNegate (ent->movedir, ent->movedir);
+	}
+
+	if (ent->health)
+	{
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_killed;
+		ent->max_health = ent->health;
+	}
+	
+	if (ent->targetname && ent->message)
+	{
+		gi.soundindex ("misc/talk.wav");
+		ent->touch = door_touch;
+	}
+
+	ent->moveinfo.state = STATE_BOTTOM;
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->s.origin, ent->moveinfo.start_origin);
+	VectorCopy (ent->pos1, ent->moveinfo.start_angles);
+	VectorCopy (ent->s.origin, ent->moveinfo.end_origin);
+	VectorCopy (ent->pos2, ent->moveinfo.end_angles);
+
+	if (ent->spawnflags & 16)
+		ent->s.effects |= EF_ANIM_ALL;
+
+	// to simplify logic elsewhere, make non-teamed doors into a team of one
+	if (!ent->team)
+		ent->teammaster = ent;
+
+	gi.linkentity (ent);
+
+	ent->nextthink = level.time + FRAMETIME;
+	if (ent->health || ent->targetname)
+		ent->think = Think_CalcMoveSpeed;
+	else
+		ent->think = Think_SpawnDoorTrigger;
+}
+
+
+/*QUAKED func_water (0 .5 .8) ? START_OPEN
+func_water is a moveable water brush.  It must be targeted to operate.  Use a non-water texture at your own risk.
+
+START_OPEN causes the water to move to its destination when spawned and operate in reverse.
+
+"angle"		determines the opening direction (up or down only)
+"speed"		movement speed (25 default)
+"wait"		wait before returning (-1 default, -1 = TOGGLE)
+"lip"		lip remaining at end of move (0 default)
+"sounds"	(yes, these need to be changed)
+0)	no sound
+1)	water
+2)	lava
+*/
+
+void SP_func_water (edict_t *self)
+{
+	vec3_t	abs_movedir;
+
+	G_SetMovedir (self->s.angles, self->movedir);
+	self->movetype = MOVETYPE_PUSH;
+	self->solid = SOLID_BSP;
+	gi.setmodel (self, self->model);
+
+	switch (self->sounds)
+	{
+		default:
+			break;
+
+		case 1: // water
+			self->moveinfo.sound_start = gi.soundindex  ("world/mov_watr.wav");
+			self->moveinfo.sound_end = gi.soundindex  ("world/stp_watr.wav");
+			break;
+
+		case 2: // lava
+			self->moveinfo.sound_start = gi.soundindex  ("world/mov_watr.wav");
+			self->moveinfo.sound_end = gi.soundindex  ("world/stp_watr.wav");
+			break;
+	}
+
+	// calculate second position
+	VectorCopy (self->s.origin, self->pos1);
+	abs_movedir[0] = fabs(self->movedir[0]);
+	abs_movedir[1] = fabs(self->movedir[1]);
+	abs_movedir[2] = fabs(self->movedir[2]);
+	self->moveinfo.distance = abs_movedir[0] * self->size[0] + abs_movedir[1] * self->size[1] + abs_movedir[2] * self->size[2] - st.lip;
+	VectorMA (self->pos1, self->moveinfo.distance, self->movedir, self->pos2);
+
+	// if it starts open, switch the positions
+	if (self->spawnflags & DOOR_START_OPEN)
+	{
+		VectorCopy (self->pos2, self->s.origin);
+		VectorCopy (self->pos1, self->pos2);
+		VectorCopy (self->s.origin, self->pos1);
+	}
+
+	VectorCopy (self->pos1, self->moveinfo.start_origin);
+	VectorCopy (self->s.angles, self->moveinfo.start_angles);
+	VectorCopy (self->pos2, self->moveinfo.end_origin);
+	VectorCopy (self->s.angles, self->moveinfo.end_angles);
+
+	self->moveinfo.state = STATE_BOTTOM;
+
+	if (!self->speed)
+		self->speed = 25;
+	self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed = self->speed;
+
+	if (!self->wait)
+		self->wait = -1;
+	self->moveinfo.wait = self->wait;
+
+	self->use = door_use;
+
+	if (self->wait == -1)
+		self->spawnflags |= DOOR_TOGGLE;
+
+	self->classname = "func_door";
+
+	gi.linkentity (self);
+}
+
+
+#define TRAIN_START_ON		1
+#define TRAIN_TOGGLE		2
+#define TRAIN_BLOCK_STOPS	4
+
+/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
+Trains are moving platforms that players can ride.
+The targets origin specifies the min point of the train at each corner.
+The train spawns at the first target it is pointing at.
+If the train is the target of a button or trigger, it will not begin moving until activated.
+speed	default 100
+dmg		default	2
+noise	looping sound to play when the train is in motion
+
+*/
+void train_next (edict_t *self);
+
+void train_blocked (edict_t *self, edict_t *other)
+{
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	if (level.time < self->touch_debounce_time)
+		return;
+
+	if (!self->dmg)
+		return;
+	self->touch_debounce_time = level.time + 0.5;
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void train_wait (edict_t *self)
+{
+	if (self->target_ent->pathtarget)
+	{
+		char	*savetarget;
+		edict_t	*ent;
+
+		ent = self->target_ent;
+		savetarget = ent->target;
+		ent->target = ent->pathtarget;
+		G_UseTargets (ent, self->activator);
+		ent->target = savetarget;
+
+		// make sure we didn't get killed by a killtarget
+		if (!self->inuse)
+			return;
+	}
+
+	if (self->moveinfo.wait)
+	{
+		if (self->moveinfo.wait > 0)
+		{
+			self->nextthink = level.time + self->moveinfo.wait;
+			self->think = train_next;
+		}
+		else if (self->spawnflags & TRAIN_TOGGLE)  // && wait < 0
+		{
+			train_next (self);
+			self->spawnflags &= ~TRAIN_START_ON;
+			VectorClear (self->velocity);
+			self->nextthink = 0;
+		}
+
+		if (!(self->flags & FL_TEAMSLAVE))
+		{
+			if (self->moveinfo.sound_end)
+				gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+			self->s.sound = 0;
+		}
+	}
+	else
+	{
+		train_next (self);
+	}
+	
+}
+
+void train_next (edict_t *self)
+{
+	edict_t		*ent;
+	vec3_t		dest;
+	qboolean	first;
+
+	first = true;
+again:
+	if (!self->target)
+	{
+//		gi.dprintf ("train_next: no next target\n");
+		return;
+	}
+
+	ent = G_PickTarget (self->target);
+	if (!ent)
+	{
+		gi.dprintf ("train_next: bad target %s\n", self->target);
+		return;
+	}
+
+	self->target = ent->target;
+
+	// check for a teleport path_corner
+	if (ent->spawnflags & 1)
+	{
+		if (!first)
+		{
+			gi.dprintf ("connected teleport path_corners, see %s at %s\n", ent->classname, vtos(ent->s.origin));
+			return;
+		}
+		first = false;
+		VectorSubtract (ent->s.origin, self->mins, self->s.origin);
+		VectorCopy (self->s.origin, self->s.old_origin);
+		gi.linkentity (self);
+		goto again;
+	}
+
+	self->moveinfo.wait = ent->wait;
+	self->target_ent = ent;
+
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_start)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		self->s.sound = self->moveinfo.sound_middle;
+	}
+
+	VectorSubtract (ent->s.origin, self->mins, dest);
+	self->moveinfo.state = STATE_TOP;
+	VectorCopy (self->s.origin, self->moveinfo.start_origin);
+	VectorCopy (dest, self->moveinfo.end_origin);
+	Move_Calc (self, dest, train_wait);
+	self->spawnflags |= TRAIN_START_ON;
+}
+
+void train_resume (edict_t *self)
+{
+	edict_t	*ent;
+	vec3_t	dest;
+
+	ent = self->target_ent;
+
+	VectorSubtract (ent->s.origin, self->mins, dest);
+	self->moveinfo.state = STATE_TOP;
+	VectorCopy (self->s.origin, self->moveinfo.start_origin);
+	VectorCopy (dest, self->moveinfo.end_origin);
+	Move_Calc (self, dest, train_wait);
+	self->spawnflags |= TRAIN_START_ON;
+}
+
+void func_train_find (edict_t *self)
+{
+	edict_t *ent;
+
+	if (!self->target)
+	{
+		gi.dprintf ("train_find: no target\n");
+		return;
+	}
+	ent = G_PickTarget (self->target);
+	if (!ent)
+	{
+		gi.dprintf ("train_find: target %s not found\n", self->target);
+		return;
+	}
+	self->target = ent->target;
+
+	VectorSubtract (ent->s.origin, self->mins, self->s.origin);
+	gi.linkentity (self);
+
+	// if not triggered, start immediately
+	if (!self->targetname)
+		self->spawnflags |= TRAIN_START_ON;
+
+	if (self->spawnflags & TRAIN_START_ON)
+	{
+		self->nextthink = level.time + FRAMETIME;
+		self->think = train_next;
+		self->activator = self;
+	}
+}
+
+void train_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+
+	if (self->spawnflags & TRAIN_START_ON)
+	{
+		if (!(self->spawnflags & TRAIN_TOGGLE))
+			return;
+		self->spawnflags &= ~TRAIN_START_ON;
+		VectorClear (self->velocity);
+		self->nextthink = 0;
+	}
+	else
+	{
+		if (self->target_ent)
+			train_resume(self);
+		else
+			train_next(self);
+	}
+}
+
+void SP_func_train (edict_t *self)
+{
+	self->movetype = MOVETYPE_PUSH;
+
+	VectorClear (self->s.angles);
+	self->blocked = train_blocked;
+	if (self->spawnflags & TRAIN_BLOCK_STOPS)
+		self->dmg = 0;
+	else
+	{
+		if (!self->dmg)
+			self->dmg = 100;
+	}
+	self->solid = SOLID_BSP;
+	gi.setmodel (self, self->model);
+
+	if (st.noise)
+		self->moveinfo.sound_middle = gi.soundindex  (st.noise);
+
+	if (!self->speed)
+		self->speed = 100;
+
+	self->moveinfo.speed = self->speed;
+	self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed;
+
+	self->use = train_use;
+
+	gi.linkentity (self);
+
+	if (self->target)
+	{
+		// start trains on the second frame, to make sure their targets have had
+		// a chance to spawn
+		self->nextthink = level.time + FRAMETIME;
+		self->think = func_train_find;
+	}
+	else
+	{
+		gi.dprintf ("func_train without a target at %s\n", vtos(self->absmin));
+	}
+}
+
+
+/*QUAKED trigger_elevator (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
+*/
+void trigger_elevator_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t *target;
+
+	if (self->movetarget->nextthink)
+	{
+//		gi.dprintf("elevator busy\n");
+		return;
+	}
+
+	if (!other->pathtarget)
+	{
+		gi.dprintf("elevator used with no pathtarget\n");
+		return;
+	}
+
+	target = G_PickTarget (other->pathtarget);
+	if (!target)
+	{
+		gi.dprintf("elevator used with bad pathtarget: %s\n", other->pathtarget);
+		return;
+	}
+
+	self->movetarget->target_ent = target;
+	train_resume (self->movetarget);
+}
+
+void trigger_elevator_init (edict_t *self)
+{
+	if (!self->target)
+	{
+		gi.dprintf("trigger_elevator has no target\n");
+		return;
+	}
+	self->movetarget = G_PickTarget (self->target);
+	if (!self->movetarget)
+	{
+		gi.dprintf("trigger_elevator unable to find target %s\n", self->target);
+		return;
+	}
+	if (strcmp(self->movetarget->classname, "func_train") != 0)
+	{
+		gi.dprintf("trigger_elevator target %s is not a train\n", self->target);
+		return;
+	}
+
+	self->use = trigger_elevator_use;
+	self->svflags = SVF_NOCLIENT;
+
+}
+
+void SP_trigger_elevator (edict_t *self)
+{
+	self->think = trigger_elevator_init;
+	self->nextthink = level.time + FRAMETIME;
+}
+
+
+/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
+"wait"			base time between triggering all targets, default is 1
+"random"		wait variance, default is 0
+
+so, the basic time between firing is a random time between
+(wait - random) and (wait + random)
+
+"delay"			delay before first firing when turned on, default is 0
+
+"pausetime"		additional delay used only the very first time
+				and only if spawned with START_ON
+
+These can used but not touched.
+*/
+void func_timer_think (edict_t *self)
+{
+	G_UseTargets (self, self->activator);
+	self->nextthink = level.time + self->wait + crandom() * self->random;
+}
+
+void func_timer_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+
+	// if on, turn it off
+	if (self->nextthink)
+	{
+		self->nextthink = 0;
+		return;
+	}
+
+	// turn it on
+	if (self->delay)
+		self->nextthink = level.time + self->delay;
+	else
+		func_timer_think (self);
+}
+
+void SP_func_timer (edict_t *self)
+{
+	if (!self->wait)
+		self->wait = 1.0;
+
+	self->use = func_timer_use;
+	self->think = func_timer_think;
+
+	if (self->random >= self->wait)
+	{
+		self->random = self->wait - FRAMETIME;
+		gi.dprintf("func_timer at %s has random >= wait\n", vtos(self->s.origin));
+	}
+
+	if (self->spawnflags & 1)
+	{
+		self->nextthink = level.time + 1.0 + st.pausetime + self->delay + self->wait + crandom() * self->random;
+		self->activator = self;
+	}
+
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+/*QUAKED func_conveyor (0 .5 .8) ? START_ON TOGGLE
+Conveyors are stationary brushes that move what's on them.
+The brush should be have a surface with at least one current content enabled.
+speed	default 100
+*/
+
+void func_conveyor_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->spawnflags & 1)
+	{
+		self->speed = 0;
+		self->spawnflags &= ~1;
+	}
+	else
+	{
+		self->speed = self->count;
+		self->spawnflags |= 1;
+	}
+
+	if (!(self->spawnflags & 2))
+		self->count = 0;
+}
+
+void SP_func_conveyor (edict_t *self)
+{
+	if (!self->speed)
+		self->speed = 100;
+
+	if (!(self->spawnflags & 1))
+	{
+		self->count = self->speed;
+		self->speed = 0;
+	}
+
+	self->use = func_conveyor_use;
+
+	gi.setmodel (self, self->model);
+	self->solid = SOLID_BSP;
+	gi.linkentity (self);
+}
+
+
+/*QUAKED func_door_secret (0 .5 .8) ? always_shoot 1st_left 1st_down
+A secret door.  Slide back and then to the side.
+
+open_once		doors never closes
+1st_left		1st move is left of arrow
+1st_down		1st move is down from arrow
+always_shoot	door is shootebale even if targeted
+
+"angle"		determines the direction
+"dmg"		damage to inflic when blocked (default 2)
+"wait"		how long to hold in the open position (default 5, -1 means hold)
+*/
+
+#define SECRET_ALWAYS_SHOOT	1
+#define SECRET_1ST_LEFT		2
+#define SECRET_1ST_DOWN		4
+
+void door_secret_move1 (edict_t *self);
+void door_secret_move2 (edict_t *self);
+void door_secret_move3 (edict_t *self);
+void door_secret_move4 (edict_t *self);
+void door_secret_move5 (edict_t *self);
+void door_secret_move6 (edict_t *self);
+void door_secret_done (edict_t *self);
+
+void door_secret_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	// make sure we're not already moving
+	if (!VectorCompare(self->s.origin, vec3_origin))
+		return;
+
+	Move_Calc (self, self->pos1, door_secret_move1);
+	door_use_areaportals (self, true);
+}
+
+void door_secret_move1 (edict_t *self)
+{
+	self->nextthink = level.time + 1.0;
+	self->think = door_secret_move2;
+}
+
+void door_secret_move2 (edict_t *self)
+{
+	Move_Calc (self, self->pos2, door_secret_move3);
+}
+
+void door_secret_move3 (edict_t *self)
+{
+	if (self->wait == -1)
+		return;
+	self->nextthink = level.time + self->wait;
+	self->think = door_secret_move4;
+}
+
+void door_secret_move4 (edict_t *self)
+{
+	Move_Calc (self, self->pos1, door_secret_move5);
+}
+
+void door_secret_move5 (edict_t *self)
+{
+	self->nextthink = level.time + 1.0;
+	self->think = door_secret_move6;
+}
+
+void door_secret_move6 (edict_t *self)
+{
+	Move_Calc (self, vec3_origin, door_secret_done);
+}
+
+void door_secret_done (edict_t *self)
+{
+	if (!(self->targetname) || (self->spawnflags & SECRET_ALWAYS_SHOOT))
+	{
+		self->health = 0;
+		self->takedamage = DAMAGE_YES;
+	}
+	door_use_areaportals (self, false);
+}
+
+void door_secret_blocked  (edict_t *self, edict_t *other)
+{
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	if (level.time < self->touch_debounce_time)
+		return;
+	self->touch_debounce_time = level.time + 0.5;
+
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void door_secret_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	self->takedamage = DAMAGE_NO;
+	door_secret_use (self, attacker, attacker);
+}
+
+void SP_func_door_secret (edict_t *ent)
+{
+	vec3_t	forward, right, up;
+	float	side;
+	float	width;
+	float	length;
+
+	ent->moveinfo.sound_start = gi.soundindex  ("doors/dr1_strt.wav");
+	ent->moveinfo.sound_middle = gi.soundindex  ("doors/dr1_mid.wav");
+	ent->moveinfo.sound_end = gi.soundindex  ("doors/dr1_end.wav");
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = door_secret_blocked;
+	ent->use = door_secret_use;
+
+	if (!(ent->targetname) || (ent->spawnflags & SECRET_ALWAYS_SHOOT))
+	{
+		ent->health = 0;
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_secret_die;
+	}
+
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	if (!ent->wait)
+		ent->wait = 5;
+
+	ent->moveinfo.accel =
+	ent->moveinfo.decel =
+	ent->moveinfo.speed = 50;
+
+	// calculate positions
+	AngleVectors (ent->s.angles, forward, right, up);
+	VectorClear (ent->s.angles);
+	side = 1.0 - (ent->spawnflags & SECRET_1ST_LEFT);
+	if (ent->spawnflags & SECRET_1ST_DOWN)
+		width = fabs(DotProduct(up, ent->size));
+	else
+		width = fabs(DotProduct(right, ent->size));
+	length = fabs(DotProduct(forward, ent->size));
+	if (ent->spawnflags & SECRET_1ST_DOWN)
+		VectorMA (ent->s.origin, -1 * width, up, ent->pos1);
+	else
+		VectorMA (ent->s.origin, side * width, right, ent->pos1);
+	VectorMA (ent->pos1, length, forward, ent->pos2);
+
+	if (ent->health)
+	{
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_killed;
+		ent->max_health = ent->health;
+	}
+	else if (ent->targetname && ent->message)
+	{
+		gi.soundindex ("misc/talk.wav");
+		ent->touch = door_touch;
+	}
+	
+	ent->classname = "func_door";
+
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED func_killbox (1 0 0) ?
+Kills everything inside when fired, irrespective of protection.
+*/
+void use_killbox (edict_t *self, edict_t *other, edict_t *activator)
+{
+	KillBox (self);
+}
+
+void SP_func_killbox (edict_t *ent)
+{
+	gi.setmodel (ent, ent->model);
+	ent->use = use_killbox;
+	ent->svflags = SVF_NOCLIENT;
+}
+
--- /dev/null
+++ b/ctf/g_items.c
@@ -1,0 +1,2446 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+qboolean	Pickup_Weapon (edict_t *ent, edict_t *other);
+void		Use_Weapon (edict_t *ent, gitem_t *inv);
+void		Drop_Weapon (edict_t *ent, gitem_t *inv);
+
+void Weapon_Blaster (edict_t *ent);
+void Weapon_Shotgun (edict_t *ent);
+void Weapon_SuperShotgun (edict_t *ent);
+void Weapon_Machinegun (edict_t *ent);
+void Weapon_Chaingun (edict_t *ent);
+void Weapon_HyperBlaster (edict_t *ent);
+void Weapon_RocketLauncher (edict_t *ent);
+void Weapon_Grenade (edict_t *ent);
+void Weapon_GrenadeLauncher (edict_t *ent);
+void Weapon_Railgun (edict_t *ent);
+void Weapon_BFG (edict_t *ent);
+
+gitem_armor_t jacketarmor_info	= { 25,  50, .30, .00, ARMOR_JACKET};
+gitem_armor_t combatarmor_info	= { 50, 100, .60, .30, ARMOR_COMBAT};
+gitem_armor_t bodyarmor_info	= {100, 200, .80, .60, ARMOR_BODY};
+
+static int	jacket_armor_index;
+static int	combat_armor_index;
+static int	body_armor_index;
+static int	power_screen_index;
+static int	power_shield_index;
+
+#define HEALTH_IGNORE_MAX	1
+#define HEALTH_TIMED		2
+
+void Use_Quad (edict_t *ent, gitem_t *item);
+static int	quad_drop_timeout_hack;
+
+//======================================================================
+
+/*
+===============
+GetItemByIndex
+===============
+*/
+gitem_t	*GetItemByIndex (int index)
+{
+	if (index == 0 || index >= game.num_items)
+		return NULL;
+
+	return &itemlist[index];
+}
+
+
+/*
+===============
+FindItemByClassname
+
+===============
+*/
+gitem_t	*FindItemByClassname (char *classname)
+{
+	int		i;
+	gitem_t	*it;
+
+	it = itemlist;
+	for (i=0 ; i<game.num_items ; i++, it++)
+	{
+		if (!it->classname)
+			continue;
+		if (!Q_stricmp(it->classname, classname))
+			return it;
+	}
+
+	return NULL;
+}
+
+/*
+===============
+FindItem
+
+===============
+*/
+gitem_t	*FindItem (char *pickup_name)
+{
+	int		i;
+	gitem_t	*it;
+
+	it = itemlist;
+	for (i=0 ; i<game.num_items ; i++, it++)
+	{
+		if (!it->pickup_name)
+			continue;
+		if (!Q_stricmp(it->pickup_name, pickup_name))
+			return it;
+	}
+
+	return NULL;
+}
+
+//======================================================================
+
+void DoRespawn (edict_t *ent)
+{
+	if (ent->team)
+	{
+		edict_t	*master;
+		int	count;
+		int choice;
+
+		master = ent->teammaster;
+
+//ZOID
+//in ctf, when we are weapons stay, only the master of a team of weapons
+//is spawned
+		if (ctf->value &&
+			((int)dmflags->value & DF_WEAPONS_STAY) &&
+			master->item && (master->item->flags & IT_WEAPON))
+			ent = master;
+		else {
+//ZOID
+
+			for (count = 0, ent = master; ent; ent = ent->chain, count++)
+				;
+
+			choice = rand() % count;
+
+			for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
+				;
+		}
+	}
+
+	ent->svflags &= ~SVF_NOCLIENT;
+	ent->solid = SOLID_TRIGGER;
+	gi.linkentity (ent);
+
+	// send an effect
+	ent->s.event = EV_ITEM_RESPAWN;
+}
+
+void SetRespawn (edict_t *ent, float delay)
+{
+	ent->flags |= FL_RESPAWN;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->solid = SOLID_NOT;
+	ent->nextthink = level.time + delay;
+	ent->think = DoRespawn;
+	gi.linkentity (ent);
+}
+
+
+//======================================================================
+
+qboolean Pickup_Powerup (edict_t *ent, edict_t *other)
+{
+	int		quantity;
+
+	quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)];
+	if ((skill->value == 1 && quantity >= 2) || (skill->value >= 2 && quantity >= 1))
+		return false;
+
+	if ((coop->value) && (ent->item->flags & IT_STAY_COOP) && (quantity > 0))
+		return false;
+
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+
+	if (deathmatch->value)
+	{
+		if (!(ent->spawnflags & DROPPED_ITEM) )
+			SetRespawn (ent, ent->item->quantity);
+		if (((int)dmflags->value & DF_INSTANT_ITEMS) || ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM)))
+		{
+			if ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM))
+				quad_drop_timeout_hack = (ent->nextthink - level.time) / FRAMETIME;
+			ent->item->use (other, ent->item);
+		}
+	}
+
+	return true;
+}
+
+void Drop_General (edict_t *ent, gitem_t *item)
+{
+	Drop_Item (ent, item);
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+}
+
+
+//======================================================================
+
+qboolean Pickup_Adrenaline (edict_t *ent, edict_t *other)
+{
+	if (!deathmatch->value)
+		other->max_health += 1;
+
+	if (other->health < other->max_health)
+		other->health = other->max_health;
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+qboolean Pickup_AncientHead (edict_t *ent, edict_t *other)
+{
+	other->max_health += 2;
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+qboolean Pickup_Bandolier (edict_t *ent, edict_t *other)
+{
+	gitem_t	*item;
+	int		index;
+
+	if (other->client->pers.max_bullets < 250)
+		other->client->pers.max_bullets = 250;
+	if (other->client->pers.max_shells < 150)
+		other->client->pers.max_shells = 150;
+	if (other->client->pers.max_cells < 250)
+		other->client->pers.max_cells = 250;
+	if (other->client->pers.max_slugs < 75)
+		other->client->pers.max_slugs = 75;
+
+	item = FindItem("Bullets");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_bullets)
+			other->client->pers.inventory[index] = other->client->pers.max_bullets;
+	}
+
+	item = FindItem("Shells");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_shells)
+			other->client->pers.inventory[index] = other->client->pers.max_shells;
+	}
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+qboolean Pickup_Pack (edict_t *ent, edict_t *other)
+{
+	gitem_t	*item;
+	int		index;
+
+	if (other->client->pers.max_bullets < 300)
+		other->client->pers.max_bullets = 300;
+	if (other->client->pers.max_shells < 200)
+		other->client->pers.max_shells = 200;
+	if (other->client->pers.max_rockets < 100)
+		other->client->pers.max_rockets = 100;
+	if (other->client->pers.max_grenades < 100)
+		other->client->pers.max_grenades = 100;
+	if (other->client->pers.max_cells < 300)
+		other->client->pers.max_cells = 300;
+	if (other->client->pers.max_slugs < 100)
+		other->client->pers.max_slugs = 100;
+
+	item = FindItem("Bullets");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_bullets)
+			other->client->pers.inventory[index] = other->client->pers.max_bullets;
+	}
+
+	item = FindItem("Shells");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_shells)
+			other->client->pers.inventory[index] = other->client->pers.max_shells;
+	}
+
+	item = FindItem("Cells");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_cells)
+			other->client->pers.inventory[index] = other->client->pers.max_cells;
+	}
+
+	item = FindItem("Grenades");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_grenades)
+			other->client->pers.inventory[index] = other->client->pers.max_grenades;
+	}
+
+	item = FindItem("Rockets");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_rockets)
+			other->client->pers.inventory[index] = other->client->pers.max_rockets;
+	}
+
+	item = FindItem("Slugs");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_slugs)
+			other->client->pers.inventory[index] = other->client->pers.max_slugs;
+	}
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+//======================================================================
+
+void Use_Quad (edict_t *ent, gitem_t *item)
+{
+	int		timeout;
+
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (quad_drop_timeout_hack)
+	{
+		timeout = quad_drop_timeout_hack;
+		quad_drop_timeout_hack = 0;
+	}
+	else
+	{
+		timeout = 300;
+	}
+
+	if (ent->client->quad_framenum > level.framenum)
+		ent->client->quad_framenum += timeout;
+	else
+		ent->client->quad_framenum = level.framenum + timeout;
+
+	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void Use_Breather (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (ent->client->breather_framenum > level.framenum)
+		ent->client->breather_framenum += 300;
+	else
+		ent->client->breather_framenum = level.framenum + 300;
+
+//	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void Use_Envirosuit (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (ent->client->enviro_framenum > level.framenum)
+		ent->client->enviro_framenum += 300;
+	else
+		ent->client->enviro_framenum = level.framenum + 300;
+
+//	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void	Use_Invulnerability (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (ent->client->invincible_framenum > level.framenum)
+		ent->client->invincible_framenum += 300;
+	else
+		ent->client->invincible_framenum = level.framenum + 300;
+
+	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void	Use_Silencer (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+	ent->client->silencer_shots += 30;
+
+//	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+qboolean Pickup_Key (edict_t *ent, edict_t *other)
+{
+	if (coop->value)
+	{
+		if (strcmp(ent->classname, "key_power_cube") == 0)
+		{
+			if (other->client->pers.power_cubes & ((ent->spawnflags & 0x0000ff00)>> 8))
+				return false;
+			other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+			other->client->pers.power_cubes |= ((ent->spawnflags & 0x0000ff00) >> 8);
+		}
+		else
+		{
+			if (other->client->pers.inventory[ITEM_INDEX(ent->item)])
+				return false;
+			other->client->pers.inventory[ITEM_INDEX(ent->item)] = 1;
+		}
+		return true;
+	}
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+	return true;
+}
+
+//======================================================================
+
+qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count)
+{
+	int			index;
+	int			max;
+
+	if (!ent->client)
+		return false;
+
+	if (item->tag == AMMO_BULLETS)
+		max = ent->client->pers.max_bullets;
+	else if (item->tag == AMMO_SHELLS)
+		max = ent->client->pers.max_shells;
+	else if (item->tag == AMMO_ROCKETS)
+		max = ent->client->pers.max_rockets;
+	else if (item->tag == AMMO_GRENADES)
+		max = ent->client->pers.max_grenades;
+	else if (item->tag == AMMO_CELLS)
+		max = ent->client->pers.max_cells;
+	else if (item->tag == AMMO_SLUGS)
+		max = ent->client->pers.max_slugs;
+	else
+		return false;
+
+	index = ITEM_INDEX(item);
+
+	if (ent->client->pers.inventory[index] == max)
+		return false;
+
+	ent->client->pers.inventory[index] += count;
+
+	if (ent->client->pers.inventory[index] > max)
+		ent->client->pers.inventory[index] = max;
+
+	return true;
+}
+
+qboolean Pickup_Ammo (edict_t *ent, edict_t *other)
+{
+	int			oldcount;
+	int			count;
+	qboolean	weapon;
+
+	weapon = (ent->item->flags & IT_WEAPON);
+	if ( (weapon) && ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		count = 1000;
+	else if (ent->count)
+		count = ent->count;
+	else
+		count = ent->item->quantity;
+
+	oldcount = other->client->pers.inventory[ITEM_INDEX(ent->item)];
+
+	if (!Add_Ammo (other, ent->item, count))
+		return false;
+
+	if (weapon && !oldcount)
+	{
+		if (other->client->pers.weapon != ent->item && ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
+			other->client->newweapon = ent->item;
+	}
+
+	if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) && (deathmatch->value))
+		SetRespawn (ent, 30);
+	return true;
+}
+
+void Drop_Ammo (edict_t *ent, gitem_t *item)
+{
+	edict_t	*dropped;
+	int		index;
+
+	index = ITEM_INDEX(item);
+	dropped = Drop_Item (ent, item);
+	if (ent->client->pers.inventory[index] >= item->quantity)
+		dropped->count = item->quantity;
+	else
+		dropped->count = ent->client->pers.inventory[index];
+	ent->client->pers.inventory[index] -= dropped->count;
+	ValidateSelectedItem (ent);
+}
+
+
+//======================================================================
+
+void MegaHealth_think (edict_t *self)
+{
+	if (self->owner->health > self->owner->max_health
+//ZOID
+		&& !CTFHasRegeneration(self->owner)
+//ZOID
+		)
+	{
+		self->nextthink = level.time + 1;
+		self->owner->health -= 1;
+		return;
+	}
+
+	if (!(self->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (self, 20);
+	else
+		G_FreeEdict (self);
+}
+
+qboolean Pickup_Health (edict_t *ent, edict_t *other)
+{
+	if (!(ent->style & HEALTH_IGNORE_MAX))
+		if (other->health >= other->max_health)
+			return false;
+
+//ZOID
+	if (other->health >= 250 && ent->count > 25)
+		return false;
+//ZOID
+
+	other->health += ent->count;
+
+//ZOID
+	if (other->health > 250 && ent->count > 25)
+		other->health = 250;
+//ZOID
+
+	if (!(ent->style & HEALTH_IGNORE_MAX))
+	{
+		if (other->health > other->max_health)
+			other->health = other->max_health;
+	}
+
+//ZOID
+	if ((ent->style & HEALTH_TIMED)
+		&& !CTFHasRegeneration(other)
+//ZOID
+	)
+	{
+		ent->think = MegaHealth_think;
+		ent->nextthink = level.time + 5;
+		ent->owner = other;
+		ent->flags |= FL_RESPAWN;
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+	}
+	else
+	{
+		if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+			SetRespawn (ent, 30);
+	}
+
+	return true;
+}
+
+//======================================================================
+
+int ArmorIndex (edict_t *ent)
+{
+	if (!ent->client)
+		return 0;
+
+	if (ent->client->pers.inventory[jacket_armor_index] > 0)
+		return jacket_armor_index;
+
+	if (ent->client->pers.inventory[combat_armor_index] > 0)
+		return combat_armor_index;
+
+	if (ent->client->pers.inventory[body_armor_index] > 0)
+		return body_armor_index;
+
+	return 0;
+}
+
+qboolean Pickup_Armor (edict_t *ent, edict_t *other)
+{
+	int				old_armor_index;
+	gitem_armor_t	*oldinfo;
+	gitem_armor_t	*newinfo;
+	int				newcount;
+	float			salvage;
+	int				salvagecount;
+
+	// get info on new armor
+	newinfo = (gitem_armor_t *)ent->item->info;
+
+	old_armor_index = ArmorIndex (other);
+
+	// handle armor shards specially
+	if (ent->item->tag == ARMOR_SHARD)
+	{
+		if (!old_armor_index)
+			other->client->pers.inventory[jacket_armor_index] = 2;
+		else
+			other->client->pers.inventory[old_armor_index] += 2;
+	}
+
+	// if player has no armor, just use it
+	else if (!old_armor_index)
+	{
+		other->client->pers.inventory[ITEM_INDEX(ent->item)] = newinfo->base_count;
+	}
+
+	// use the better armor
+	else
+	{
+		// get info on old armor
+		if (old_armor_index == jacket_armor_index)
+			oldinfo = &jacketarmor_info;
+		else if (old_armor_index == combat_armor_index)
+			oldinfo = &combatarmor_info;
+		else // (old_armor_index == body_armor_index)
+			oldinfo = &bodyarmor_info;
+
+		if (newinfo->normal_protection > oldinfo->normal_protection)
+		{
+			// calc new armor values
+			salvage = oldinfo->normal_protection / newinfo->normal_protection;
+			salvagecount = salvage * other->client->pers.inventory[old_armor_index];
+			newcount = newinfo->base_count + salvagecount;
+			if (newcount > newinfo->max_count)
+				newcount = newinfo->max_count;
+
+			// zero count of old armor so it goes away
+			other->client->pers.inventory[old_armor_index] = 0;
+
+			// change armor to new item with computed value
+			other->client->pers.inventory[ITEM_INDEX(ent->item)] = newcount;
+		}
+		else
+		{
+			// calc new armor values
+			salvage = newinfo->normal_protection / oldinfo->normal_protection;
+			salvagecount = salvage * newinfo->base_count;
+			newcount = other->client->pers.inventory[old_armor_index] + salvagecount;
+			if (newcount > oldinfo->max_count)
+				newcount = oldinfo->max_count;
+
+			// if we're already maxed out then we don't need the new armor
+			if (other->client->pers.inventory[old_armor_index] >= newcount)
+				return false;
+
+			// update current armor value
+			other->client->pers.inventory[old_armor_index] = newcount;
+		}
+	}
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, 20);
+
+	return true;
+}
+
+//======================================================================
+
+int PowerArmorType (edict_t *ent)
+{
+	if (!ent->client)
+		return POWER_ARMOR_NONE;
+
+	if (!(ent->flags & FL_POWER_ARMOR))
+		return POWER_ARMOR_NONE;
+
+	if (ent->client->pers.inventory[power_shield_index] > 0)
+		return POWER_ARMOR_SHIELD;
+
+	if (ent->client->pers.inventory[power_screen_index] > 0)
+		return POWER_ARMOR_SCREEN;
+
+	return POWER_ARMOR_NONE;
+}
+
+void Use_PowerArmor (edict_t *ent, gitem_t *item)
+{
+	int		index;
+
+	if (ent->flags & FL_POWER_ARMOR)
+	{
+		ent->flags &= ~FL_POWER_ARMOR;
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		index = ITEM_INDEX(FindItem("cells"));
+		if (!ent->client->pers.inventory[index])
+		{
+			gi.cprintf (ent, PRINT_HIGH, "No cells for power armor.\n");
+			return;
+		}
+		ent->flags |= FL_POWER_ARMOR;
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_NORM, 0);
+	}
+}
+
+qboolean Pickup_PowerArmor (edict_t *ent, edict_t *other)
+{
+	int		quantity;
+
+	quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)];
+
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+
+	if (deathmatch->value)
+	{
+		if (!(ent->spawnflags & DROPPED_ITEM) )
+			SetRespawn (ent, ent->item->quantity);
+		// auto-use for DM only if we didn't already have one
+		if (!quantity)
+			ent->item->use (other, ent->item);
+	}
+
+	return true;
+}
+
+void Drop_PowerArmor (edict_t *ent, gitem_t *item)
+{
+	if ((ent->flags & FL_POWER_ARMOR) && (ent->client->pers.inventory[ITEM_INDEX(item)] == 1))
+		Use_PowerArmor (ent, item);
+	Drop_General (ent, item);
+}
+
+//======================================================================
+
+/*
+===============
+Touch_Item
+===============
+*/
+void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	qboolean	taken;
+
+	if (!other->client)
+		return;
+	if (other->health < 1)
+		return;		// dead people can't pickup
+	if (!ent->item->pickup)
+		return;		// not a grabbable item?
+
+	if (CTFMatchSetup())
+		return; // can't pick stuff up right now
+
+	taken = ent->item->pickup(ent, other);
+
+	if (taken)
+	{
+		// flash the screen
+		other->client->bonus_alpha = 0.25;	
+
+		// show icon and name on status bar
+		other->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(ent->item->icon);
+		other->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(ent->item);
+		other->client->pickup_msg_time = level.time + 3.0;
+
+		// change selected item
+		if (ent->item->use)
+			other->client->pers.selected_item = other->client->ps.stats[STAT_SELECTED_ITEM] = ITEM_INDEX(ent->item);
+
+		if (ent->item->pickup == Pickup_Health)
+		{
+			if (ent->count == 2)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/s_health.wav"), 1, ATTN_NORM, 0);
+			else if (ent->count == 10)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/n_health.wav"), 1, ATTN_NORM, 0);
+			else if (ent->count == 25)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/l_health.wav"), 1, ATTN_NORM, 0);
+			else // (ent->count == 100)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/m_health.wav"), 1, ATTN_NORM, 0);
+		}
+		else if (ent->item->pickup_sound)
+		{
+			gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0);
+		}
+	}
+
+	if (!(ent->spawnflags & ITEM_TARGETS_USED))
+	{
+		G_UseTargets (ent, other);
+		ent->spawnflags |= ITEM_TARGETS_USED;
+	}
+
+	if (!taken)
+		return;
+
+	if (!((coop->value) &&  (ent->item->flags & IT_STAY_COOP)) || (ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)))
+	{
+		if (ent->flags & FL_RESPAWN)
+			ent->flags &= ~FL_RESPAWN;
+		else
+			G_FreeEdict (ent);
+	}
+}
+
+//======================================================================
+
+static void drop_temp_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other == ent->owner)
+		return;
+
+	Touch_Item (ent, other, plane, surf);
+}
+
+static void drop_make_touchable (edict_t *ent)
+{
+	ent->touch = Touch_Item;
+	if (deathmatch->value)
+	{
+		ent->nextthink = level.time + 29;
+		ent->think = G_FreeEdict;
+	}
+}
+
+edict_t *Drop_Item (edict_t *ent, gitem_t *item)
+{
+	edict_t	*dropped;
+	vec3_t	forward, right;
+	vec3_t	offset;
+
+	dropped = G_Spawn();
+
+	dropped->classname = item->classname;
+	dropped->item = item;
+	dropped->spawnflags = DROPPED_ITEM;
+	dropped->s.effects = item->world_model_flags;
+	dropped->s.renderfx = RF_GLOW;
+	VectorSet (dropped->mins, -15, -15, -15);
+	VectorSet (dropped->maxs, 15, 15, 15);
+	gi.setmodel (dropped, dropped->item->world_model);
+	dropped->solid = SOLID_TRIGGER;
+	dropped->movetype = MOVETYPE_TOSS;  
+	dropped->touch = drop_temp_touch;
+	dropped->owner = ent;
+
+	if (ent->client)
+	{
+		trace_t	trace;
+
+		AngleVectors (ent->client->v_angle, forward, right, NULL);
+		VectorSet(offset, 24, 0, -16);
+		G_ProjectSource (ent->s.origin, offset, forward, right, dropped->s.origin);
+		trace = gi.trace (ent->s.origin, dropped->mins, dropped->maxs,
+			dropped->s.origin, ent, CONTENTS_SOLID);
+		VectorCopy (trace.endpos, dropped->s.origin);
+	}
+	else
+	{
+		AngleVectors (ent->s.angles, forward, right, NULL);
+		VectorCopy (ent->s.origin, dropped->s.origin);
+	}
+
+	VectorScale (forward, 100, dropped->velocity);
+	dropped->velocity[2] = 300;
+
+	dropped->think = drop_make_touchable;
+	dropped->nextthink = level.time + 1;
+
+	gi.linkentity (dropped);
+
+	return dropped;
+}
+
+void Use_Item (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	ent->svflags &= ~SVF_NOCLIENT;
+	ent->use = NULL;
+
+	if (ent->spawnflags & ITEM_NO_TOUCH)
+	{
+		ent->solid = SOLID_BBOX;
+		ent->touch = NULL;
+	}
+	else
+	{
+		ent->solid = SOLID_TRIGGER;
+		ent->touch = Touch_Item;
+	}
+
+	gi.linkentity (ent);
+}
+
+//======================================================================
+
+/*
+================
+droptofloor
+================
+*/
+void droptofloor (edict_t *ent)
+{
+	trace_t		tr;
+	vec3_t		dest;
+	float		*v;
+
+	v = tv(-15,-15,-15);
+	VectorCopy (v, ent->mins);
+	v = tv(15,15,15);
+	VectorCopy (v, ent->maxs);
+
+	if (ent->model)
+		gi.setmodel (ent, ent->model);
+	else
+		gi.setmodel (ent, ent->item->world_model);
+	ent->solid = SOLID_TRIGGER;
+	ent->movetype = MOVETYPE_TOSS;  
+	ent->touch = Touch_Item;
+
+	v = tv(0,0,-128);
+	VectorAdd (ent->s.origin, v, dest);
+
+	tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
+	if (tr.startsolid)
+	{
+		gi.dprintf ("droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	VectorCopy (tr.endpos, ent->s.origin);
+
+	if (ent->team)
+	{
+		ent->flags &= ~FL_TEAMSLAVE;
+		ent->chain = ent->teamchain;
+		ent->teamchain = NULL;
+
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+		if (ent == ent->teammaster)
+		{
+			ent->nextthink = level.time + FRAMETIME;
+			ent->think = DoRespawn;
+		}
+	}
+
+	if (ent->spawnflags & ITEM_NO_TOUCH)
+	{
+		ent->solid = SOLID_BBOX;
+		ent->touch = NULL;
+		ent->s.effects &= ~EF_ROTATE;
+		ent->s.renderfx &= ~RF_GLOW;
+	}
+
+	if (ent->spawnflags & ITEM_TRIGGER_SPAWN)
+	{
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+		ent->use = Use_Item;
+	}
+
+	gi.linkentity (ent);
+}
+
+
+/*
+===============
+PrecacheItem
+
+Precaches all data needed for a given item.
+This will be called for each item spawned in a level,
+and for each item in each client's inventory.
+===============
+*/
+void PrecacheItem (gitem_t *it)
+{
+	char	*s, *start;
+	char	data[MAX_QPATH];
+	int		len;
+	gitem_t	*ammo;
+
+	if (!it)
+		return;
+
+	if (it->pickup_sound)
+		gi.soundindex (it->pickup_sound);
+	if (it->world_model)
+		gi.modelindex (it->world_model);
+	if (it->view_model)
+		gi.modelindex (it->view_model);
+	if (it->icon)
+		gi.imageindex (it->icon);
+
+	// parse everything for its ammo
+	if (it->ammo && it->ammo[0])
+	{
+		ammo = FindItem (it->ammo);
+		if (ammo != it)
+			PrecacheItem (ammo);
+	}
+
+	// parse the space seperated precache string for other items
+	s = it->precaches;
+	if (!s || !s[0])
+		return;
+
+	while (*s)
+	{
+		start = s;
+		while (*s && *s != ' ')
+			s++;
+
+		len = s-start;
+		if (len >= MAX_QPATH || len < 5)
+			gi.error ("PrecacheItem: %s has bad precache string", it->classname);
+		memcpy (data, start, len);
+		data[len] = 0;
+		if (*s)
+			s++;
+
+		// determine type based on extension
+		if (!strcmp(data+len-3, "md2"))
+			gi.modelindex (data);
+		else if (!strcmp(data+len-3, "sp2"))
+			gi.modelindex (data);
+		else if (!strcmp(data+len-3, "wav"))
+			gi.soundindex (data);
+		if (!strcmp(data+len-3, "pcx"))
+			gi.imageindex (data);
+	}
+}
+
+/*
+============
+SpawnItem
+
+Sets the clipping size and plants the object on the floor.
+
+Items can't be immediately dropped to floor, because they might
+be on an entity that hasn't spawned yet.
+============
+*/
+void SpawnItem (edict_t *ent, gitem_t *item)
+{
+	PrecacheItem (item);
+
+	if (ent->spawnflags)
+	{
+		if (strcmp(ent->classname, "key_power_cube") != 0)
+		{
+			ent->spawnflags = 0;
+			gi.dprintf("%s at %s has invalid spawnflags set\n", ent->classname, vtos(ent->s.origin));
+		}
+	}
+
+	// some items will be prevented in deathmatch
+	if (deathmatch->value)
+	{
+		if ( (int)dmflags->value & DF_NO_ARMOR )
+		{
+			if (item->pickup == Pickup_Armor || item->pickup == Pickup_PowerArmor)
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+		if ( (int)dmflags->value & DF_NO_ITEMS )
+		{
+			if (item->pickup == Pickup_Powerup)
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+		if ( (int)dmflags->value & DF_NO_HEALTH )
+		{
+			if (item->pickup == Pickup_Health || item->pickup == Pickup_Adrenaline || item->pickup == Pickup_AncientHead)
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+		if ( (int)dmflags->value & DF_INFINITE_AMMO )
+		{
+			if ( (item->flags == IT_AMMO) || (strcmp(ent->classname, "weapon_bfg") == 0) )
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+	}
+
+	if (coop->value && (strcmp(ent->classname, "key_power_cube") == 0))
+	{
+		ent->spawnflags |= (1 << (8 + level.power_cubes));
+		level.power_cubes++;
+	}
+
+	// don't let them drop items that stay in a coop game
+	if ((coop->value) && (item->flags & IT_STAY_COOP))
+	{
+		item->drop = NULL;
+	}
+
+//ZOID
+//Don't spawn the flags unless enabled
+	if (!ctf->value &&
+		(strcmp(ent->classname, "item_flag_team1") == 0 ||
+		strcmp(ent->classname, "item_flag_team2") == 0)) {
+		G_FreeEdict(ent);
+		return;
+	}
+//ZOID
+
+	ent->item = item;
+	ent->nextthink = level.time + 2 * FRAMETIME;    // items start after other solids
+	ent->think = droptofloor;
+	ent->s.effects = item->world_model_flags;
+	ent->s.renderfx = RF_GLOW;
+	if (ent->model)
+		gi.modelindex (ent->model);
+
+//ZOID
+//flags are server animated and have special handling
+	if (strcmp(ent->classname, "item_flag_team1") == 0 ||
+		strcmp(ent->classname, "item_flag_team2") == 0) {
+		ent->think = CTFFlagSetup;
+	}
+//ZOID
+
+}
+
+//======================================================================
+
+gitem_t	itemlist[] = 
+{
+	{
+		NULL
+	},	// leave index 0 alone
+
+	//
+	// ARMOR
+	//
+
+/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_body", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar1_pkup.wav",
+		"models/items/armor/body/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_bodyarmor",
+/* pickup */	"Body Armor",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		&bodyarmor_info,
+		ARMOR_BODY,
+/* precache */ ""
+	},
+
+/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_combat", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar1_pkup.wav",
+		"models/items/armor/combat/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_combatarmor",
+/* pickup */	"Combat Armor",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		&combatarmor_info,
+		ARMOR_COMBAT,
+/* precache */ ""
+	},
+
+/*QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_jacket", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar1_pkup.wav",
+		"models/items/armor/jacket/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_jacketarmor",
+/* pickup */	"Jacket Armor",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		&jacketarmor_info,
+		ARMOR_JACKET,
+/* precache */ ""
+	},
+
+/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_shard", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar2_pkup.wav",
+		"models/items/armor/shard/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_jacketarmor",
+/* pickup */	"Armor Shard",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		NULL,
+		ARMOR_SHARD,
+/* precache */ ""
+	},
+
+
+/*QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_power_screen", 
+		Pickup_PowerArmor,
+		Use_PowerArmor,
+		Drop_PowerArmor,
+		NULL,
+		"misc/ar3_pkup.wav",
+		"models/items/armor/screen/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_powerscreen",
+/* pickup */	"Power Screen",
+/* width */		0,
+		60,
+		NULL,
+		IT_ARMOR,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_power_shield",
+		Pickup_PowerArmor,
+		Use_PowerArmor,
+		Drop_PowerArmor,
+		NULL,
+		"misc/ar3_pkup.wav",
+		"models/items/armor/shield/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_powershield",
+/* pickup */	"Power Shield",
+/* width */		0,
+		60,
+		NULL,
+		IT_ARMOR,
+		0,
+		NULL,
+		0,
+/* precache */ "misc/power2.wav misc/power1.wav"
+	},
+
+
+	//
+	// WEAPONS 
+	//
+
+/* weapon_grapple (.3 .3 1) (-16 -16 -16) (16 16 16)
+always owned, never in the world
+*/
+	{
+		"weapon_grapple", 
+		NULL,
+		Use_Weapon,
+		NULL,
+		CTFWeapon_Grapple,
+		"misc/w_pkup.wav",
+		NULL, 0,
+		"models/weapons/grapple/tris.md2",
+/* icon */		"w_grapple",
+/* pickup */	"Grapple",
+		0,
+		0,
+		NULL,
+		IT_WEAPON,
+		WEAP_GRAPPLE,
+		NULL,
+		0,
+/* precache */ "weapons/grapple/grfire.wav weapons/grapple/grpull.wav weapons/grapple/grhang.wav weapons/grapple/grreset.wav weapons/grapple/grhit.wav"
+	},
+
+/* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
+always owned, never in the world
+*/
+	{
+		"weapon_blaster", 
+		NULL,
+		Use_Weapon,
+		NULL,
+		Weapon_Blaster,
+		"misc/w_pkup.wav",
+		NULL, 0,
+		"models/weapons/v_blast/tris.md2",
+/* icon */		"w_blaster",
+/* pickup */	"Blaster",
+		0,
+		0,
+		NULL,
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_BLASTER,
+		NULL,
+		0,
+/* precache */ "weapons/blastf1a.wav misc/lasfly.wav"
+	},
+
+	
+/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_shotgun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Shotgun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_shotg/tris.md2", EF_ROTATE,
+		"models/weapons/v_shotg/tris.md2",
+/* icon */		"w_shotgun",
+/* pickup */	"Shotgun",
+		0,
+		1,
+		"Shells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_SHOTGUN,
+		NULL,
+		0,
+/* precache */ "weapons/shotgf1b.wav weapons/shotgr1b.wav"
+	},
+
+/*QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_supershotgun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_SuperShotgun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_shotg2/tris.md2", EF_ROTATE,
+		"models/weapons/v_shotg2/tris.md2",
+/* icon */		"w_sshotgun",
+/* pickup */	"Super Shotgun",
+		0,
+		2,
+		"Shells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_SUPERSHOTGUN,
+		NULL,
+		0,
+/* precache */ "weapons/sshotf1b.wav"
+	},
+
+/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_machinegun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Machinegun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_machn/tris.md2", EF_ROTATE,
+		"models/weapons/v_machn/tris.md2",
+/* icon */		"w_machinegun",
+/* pickup */	"Machinegun",
+		0,
+		1,
+		"Bullets",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_MACHINEGUN,
+		NULL,
+		0,
+/* precache */ "weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav"
+	},
+
+/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_chaingun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Chaingun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_chain/tris.md2", EF_ROTATE,
+		"models/weapons/v_chain/tris.md2",
+/* icon */		"w_chaingun",
+/* pickup */	"Chaingun",
+		0,
+		1,
+		"Bullets",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_CHAINGUN,
+		NULL,
+		0,
+/* precache */ "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav"
+	},
+
+/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_grenades",
+		Pickup_Ammo,
+		Use_Weapon,
+		Drop_Ammo,
+		Weapon_Grenade,
+		"misc/am_pkup.wav",
+		"models/items/ammo/grenades/medium/tris.md2", 0,
+		"models/weapons/v_handgr/tris.md2",
+/* icon */		"a_grenades",
+/* pickup */	"Grenades",
+/* width */		3,
+		5,
+		"grenades",
+		IT_AMMO|IT_WEAPON,
+		WEAP_GRENADES,
+		NULL,
+		AMMO_GRENADES,
+/* precache */ "weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav "
+	},
+
+/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_grenadelauncher",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_GrenadeLauncher,
+		"misc/w_pkup.wav",
+		"models/weapons/g_launch/tris.md2", EF_ROTATE,
+		"models/weapons/v_launch/tris.md2",
+/* icon */		"w_glauncher",
+/* pickup */	"Grenade Launcher",
+		0,
+		1,
+		"Grenades",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_GRENADELAUNCHER,
+		NULL,
+		0,
+/* precache */ "models/objects/grenade/tris.md2 weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav"
+	},
+
+/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_rocketlauncher",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_RocketLauncher,
+		"misc/w_pkup.wav",
+		"models/weapons/g_rocket/tris.md2", EF_ROTATE,
+		"models/weapons/v_rocket/tris.md2",
+/* icon */		"w_rlauncher",
+/* pickup */	"Rocket Launcher",
+		0,
+		1,
+		"Rockets",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_ROCKETLAUNCHER,
+		NULL,
+		0,
+/* precache */ "models/objects/rocket/tris.md2 weapons/rockfly.wav weapons/rocklf1a.wav weapons/rocklr1b.wav models/objects/debris2/tris.md2"
+	},
+
+/*QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_hyperblaster", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_HyperBlaster,
+		"misc/w_pkup.wav",
+		"models/weapons/g_hyperb/tris.md2", EF_ROTATE,
+		"models/weapons/v_hyperb/tris.md2",
+/* icon */		"w_hyperblaster",
+/* pickup */	"HyperBlaster",
+		0,
+		1,
+		"Cells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_HYPERBLASTER,
+		NULL,
+		0,
+/* precache */ "weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav"
+	},
+
+/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_railgun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Railgun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_rail/tris.md2", EF_ROTATE,
+		"models/weapons/v_rail/tris.md2",
+/* icon */		"w_railgun",
+/* pickup */	"Railgun",
+		0,
+		1,
+		"Slugs",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_RAILGUN,
+		NULL,
+		0,
+/* precache */ "weapons/rg_hum.wav"
+	},
+
+/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_bfg",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_BFG,
+		"misc/w_pkup.wav",
+		"models/weapons/g_bfg/tris.md2", EF_ROTATE,
+		"models/weapons/v_bfg/tris.md2",
+/* icon */		"w_bfg",
+/* pickup */	"BFG10K",
+		0,
+		50,
+		"Cells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_BFG,
+		NULL,
+		0,
+/* precache */ "sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav"
+	},
+
+#if 0
+//ZOID
+/*QUAKED weapon_laser (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_laser",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Laser,
+		"misc/w_pkup.wav",
+		"models/weapons/g_laser/tris.md2", EF_ROTATE,
+		"models/weapons/v_laser/tris.md2",
+/* icon */		"w_bfg",
+/* pickup */	"Flashlight Laser",
+		0,
+		1,
+		"Cells",
+		IT_WEAPON,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+#endif
+
+	//
+	// AMMO ITEMS
+	//
+
+/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_shells",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/shells/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_shells",
+/* pickup */	"Shells",
+/* width */		3,
+		10,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_SHELLS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_bullets",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/bullets/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_bullets",
+/* pickup */	"Bullets",
+/* width */		3,
+		50,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_BULLETS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_cells",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/cells/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_cells",
+/* pickup */	"Cells",
+/* width */		3,
+		50,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_CELLS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_rockets",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/rockets/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_rockets",
+/* pickup */	"Rockets",
+/* width */		3,
+		5,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_ROCKETS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_slugs",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/slugs/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_slugs",
+/* pickup */	"Slugs",
+/* width */		3,
+		10,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_SLUGS,
+/* precache */ ""
+	},
+
+
+	//
+	// POWERUP ITEMS
+	//
+/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_quad", 
+		Pickup_Powerup,
+		Use_Quad,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/quaddama/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_quad",
+/* pickup */	"Quad Damage",
+/* width */		2,
+		60,
+		NULL,
+		IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/damage.wav items/damage2.wav items/damage3.wav"
+	},
+
+/*QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_invulnerability",
+		Pickup_Powerup,
+		Use_Invulnerability,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/invulner/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_invulnerability",
+/* pickup */	"Invulnerability",
+/* width */		2,
+		300,
+		NULL,
+		IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/protect.wav items/protect2.wav items/protect4.wav"
+	},
+
+/*QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_silencer",
+		Pickup_Powerup,
+		Use_Silencer,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/silencer/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_silencer",
+/* pickup */	"Silencer",
+/* width */		2,
+		60,
+		NULL,
+		IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_breather",
+		Pickup_Powerup,
+		Use_Breather,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/breather/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_rebreather",
+/* pickup */	"Rebreather",
+/* width */		2,
+		60,
+		NULL,
+		IT_STAY_COOP|IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/airout.wav"
+	},
+
+/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_enviro",
+		Pickup_Powerup,
+		Use_Envirosuit,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/enviro/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_envirosuit",
+/* pickup */	"Environment Suit",
+/* width */		2,
+		60,
+		NULL,
+		IT_STAY_COOP|IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/airout.wav"
+	},
+
+/*QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16)
+Special item that gives +2 to maximum health
+*/
+	{
+		"item_ancient_head",
+		Pickup_AncientHead,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/c_head/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_fixme",
+/* pickup */	"Ancient Head",
+/* width */		2,
+		60,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16)
+gives +1 to maximum health
+*/
+	{
+		"item_adrenaline",
+		Pickup_Adrenaline,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/adrenal/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_adrenaline",
+/* pickup */	"Adrenaline",
+/* width */		2,
+		60,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_bandolier",
+		Pickup_Bandolier,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/band/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_bandolier",
+/* pickup */	"Bandolier",
+/* width */		2,
+		60,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_pack",
+		Pickup_Pack,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/pack/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_pack",
+/* pickup */	"Ammo Pack",
+/* width */		2,
+		180,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+	//
+	// KEYS
+	//
+/*QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16)
+key for computer centers
+*/
+	{
+		"key_data_cd",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/data_cd/tris.md2", EF_ROTATE,
+		NULL,
+		"k_datacd",
+		"Data CD",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_power_cube (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN NO_TOUCH
+warehouse circuits
+*/
+	{
+		"key_power_cube",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/power/tris.md2", EF_ROTATE,
+		NULL,
+		"k_powercube",
+		"Power Cube",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16)
+key for the entrance of jail3
+*/
+	{
+		"key_pyramid",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/pyramid/tris.md2", EF_ROTATE,
+		NULL,
+		"k_pyramid",
+		"Pyramid Key",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16)
+key for the city computer
+*/
+	{
+		"key_data_spinner",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/spinner/tris.md2", EF_ROTATE,
+		NULL,
+		"k_dataspin",
+		"Data Spinner",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16)
+security pass for the security level
+*/
+	{
+		"key_pass",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/pass/tris.md2", EF_ROTATE,
+		NULL,
+		"k_security",
+		"Security Pass",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16)
+normal door key - blue
+*/
+	{
+		"key_blue_key",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/key/tris.md2", EF_ROTATE,
+		NULL,
+		"k_bluekey",
+		"Blue Key",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16)
+normal door key - red
+*/
+	{
+		"key_red_key",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/red_key/tris.md2", EF_ROTATE,
+		NULL,
+		"k_redkey",
+		"Red Key",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16)
+tank commander's head
+*/
+	{
+		"key_commander_head",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/monsters/commandr/head/tris.md2", EF_GIB,
+		NULL,
+/* icon */		"k_comhead",
+/* pickup */	"Commander's Head",
+/* width */		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16)
+tank commander's head
+*/
+	{
+		"key_airstrike_target",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/target/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_airstrike",
+/* pickup */	"Airstrike Marker",
+/* width */		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+	{
+		NULL,
+		Pickup_Health,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		NULL, 0,
+		NULL,
+/* icon */		"i_health",
+/* pickup */	"Health",
+/* width */		3,
+		0,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ "items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"
+	},
+
+
+//ZOID
+/*QUAKED item_flag_team1 (1 0.2 0) (-16 -16 -24) (16 16 32)
+*/
+	{
+		"item_flag_team1",
+		CTFPickup_Flag,
+		NULL,
+		CTFDrop_Flag, //Should this be null if we don't want players to drop it manually?
+		NULL,
+		"ctf/flagtk.wav",
+		"players/male/flag1.md2", EF_FLAG1,
+		NULL,
+/* icon */		"i_ctf1",
+/* pickup */	"Red Flag",
+/* width */		2,
+		0,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ "ctf/flagcap.wav"
+	},
+
+/*QUAKED item_flag_team2 (1 0.2 0) (-16 -16 -24) (16 16 32)
+*/
+	{
+		"item_flag_team2",
+		CTFPickup_Flag,
+		NULL,
+		CTFDrop_Flag, //Should this be null if we don't want players to drop it manually?
+		NULL,
+		"ctf/flagtk.wav",
+		"players/male/flag2.md2", EF_FLAG2,
+		NULL,
+/* icon */		"i_ctf2",
+/* pickup */	"Blue Flag",
+/* width */		2,
+		0,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ "ctf/flagcap.wav"
+	},
+
+/* Resistance Tech */
+	{
+		"item_tech1",
+		CTFPickup_Tech,
+		NULL,
+		CTFDrop_Tech, //Should this be null if we don't want players to drop it manually?
+		NULL,
+		"items/pkup.wav",
+		"models/ctf/resistance/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"tech1",
+/* pickup */	"Disruptor Shield",
+/* width */		2,
+		0,
+		NULL,
+		IT_TECH,
+		0,
+		NULL,
+		0,
+/* precache */ "ctf/tech1.wav"
+	},
+
+/* Strength Tech */
+	{
+		"item_tech2",
+		CTFPickup_Tech,
+		NULL,
+		CTFDrop_Tech, //Should this be null if we don't want players to drop it manually?
+		NULL,
+		"items/pkup.wav",
+		"models/ctf/strength/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"tech2",
+/* pickup */	"Power Amplifier",
+/* width */		2,
+		0,
+		NULL,
+		IT_TECH,
+		0,
+		NULL,
+		0,
+/* precache */ "ctf/tech2.wav ctf/tech2x.wav"
+	},
+
+/* Haste Tech */
+	{
+		"item_tech3",
+		CTFPickup_Tech,
+		NULL,
+		CTFDrop_Tech, //Should this be null if we don't want players to drop it manually?
+		NULL,
+		"items/pkup.wav",
+		"models/ctf/haste/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"tech3",
+/* pickup */	"Time Accel",
+/* width */		2,
+		0,
+		NULL,
+		IT_TECH,
+		0,
+		NULL,
+		0,
+/* precache */ "ctf/tech3.wav"
+	},
+
+/* Regeneration Tech */
+	{
+		"item_tech4",
+		CTFPickup_Tech,
+		NULL,
+		CTFDrop_Tech, //Should this be null if we don't want players to drop it manually?
+		NULL,
+		"items/pkup.wav",
+		"models/ctf/regeneration/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"tech4",
+/* pickup */	"AutoDoc",
+/* width */		2,
+		0,
+		NULL,
+		IT_TECH,
+		0,
+		NULL,
+		0,
+/* precache */ "ctf/tech4.wav"
+	},
+
+//ZOID
+
+	// end of list marker
+	{NULL}
+};
+
+
+/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/healing/medium/tris.md2";
+	self->count = 10;
+	SpawnItem (self, FindItem ("Health"));
+	gi.soundindex ("items/n_health.wav");
+}
+
+/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health_small (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/healing/stimpack/tris.md2";
+	self->count = 2;
+	SpawnItem (self, FindItem ("Health"));
+	self->style = HEALTH_IGNORE_MAX;
+	gi.soundindex ("items/s_health.wav");
+}
+
+/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health_large (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/healing/large/tris.md2";
+	self->count = 25;
+	SpawnItem (self, FindItem ("Health"));
+	gi.soundindex ("items/l_health.wav");
+}
+
+/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health_mega (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/mega_h/tris.md2";
+	self->count = 100;
+	SpawnItem (self, FindItem ("Health"));
+	gi.soundindex ("items/m_health.wav");
+	self->style = HEALTH_IGNORE_MAX|HEALTH_TIMED;
+}
+
+
+void InitItems (void)
+{
+	game.num_items = sizeof(itemlist)/sizeof(itemlist[0]) - 1;
+}
+
+
+
+/*
+===============
+SetItemNames
+
+Called by worldspawn
+===============
+*/
+void SetItemNames (void)
+{
+	int		i;
+	gitem_t	*it;
+
+	for (i=0 ; i<game.num_items ; i++)
+	{
+		it = &itemlist[i];
+		gi.configstring (CS_ITEMS+i, it->pickup_name);
+	}
+
+	jacket_armor_index = ITEM_INDEX(FindItem("Jacket Armor"));
+	combat_armor_index = ITEM_INDEX(FindItem("Combat Armor"));
+	body_armor_index   = ITEM_INDEX(FindItem("Body Armor"));
+	power_screen_index = ITEM_INDEX(FindItem("Power Screen"));
+	power_shield_index = ITEM_INDEX(FindItem("Power Shield"));
+}
--- /dev/null
+++ b/ctf/g_local.h
@@ -1,0 +1,1145 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_local.h -- local definitions for game module
+
+#include "q_shared.h"
+
+// define GAME_INCLUDE so that game.h does not define the
+// short, server-visible gclient_t and edict_t structures,
+// because we define the full size ones in this file
+#define	GAME_INCLUDE
+#include "game.h"
+
+//ZOID
+#include "p_menu.h"
+//ZOID
+
+// the "gameversion" client command will print this plus compile date
+#define	GAMEVERSION	"baseq2"
+
+// protocol bytes that can be directly added to messages
+#define	svc_muzzleflash		1
+#define	svc_muzzleflash2	2
+#define	svc_temp_entity		3
+#define	svc_layout			4
+#define	svc_inventory		5
+
+//==================================================================
+
+// view pitching times
+#define DAMAGE_TIME		0.5
+#define	FALL_TIME		0.3
+
+
+// edict->spawnflags
+// these are set with checkboxes on each entity in the map editor
+#define	SPAWNFLAG_NOT_EASY			0x00000100
+#define	SPAWNFLAG_NOT_MEDIUM		0x00000200
+#define	SPAWNFLAG_NOT_HARD			0x00000400
+#define	SPAWNFLAG_NOT_DEATHMATCH	0x00000800
+#define	SPAWNFLAG_NOT_COOP			0x00001000
+
+// edict->flags
+#define	FL_FLY					0x00000001
+#define	FL_SWIM					0x00000002	// implied immunity to drowining
+#define FL_IMMUNE_LASER			0x00000004
+#define	FL_INWATER				0x00000008
+#define	FL_GODMODE				0x00000010
+#define	FL_NOTARGET				0x00000020
+#define FL_IMMUNE_SLIME			0x00000040
+#define FL_IMMUNE_LAVA			0x00000080
+#define	FL_PARTIALGROUND		0x00000100	// not all corners are valid
+#define	FL_WATERJUMP			0x00000200	// player jumping out of water
+#define	FL_TEAMSLAVE			0x00000400	// not the first on the team
+#define FL_NO_KNOCKBACK			0x00000800
+#define FL_POWER_ARMOR			0x00001000	// power armor (if any) is active
+#define FL_RESPAWN				0x80000000	// used for item respawning
+
+
+#define	FRAMETIME		0.1
+
+// memory tags to allow dynamic memory to be cleaned up
+#define	TAG_GAME	765		// clear when unloading the dll
+#define	TAG_LEVEL	766		// clear when loading a new level
+
+
+#define MELEE_DISTANCE	80
+
+#define BODY_QUEUE_SIZE		8
+
+typedef enum
+{
+	DAMAGE_NO,
+	DAMAGE_YES,			// will take damage if hit
+	DAMAGE_AIM			// auto targeting recognizes this
+} damage_t;
+
+typedef enum 
+{
+	WEAPON_READY, 
+	WEAPON_ACTIVATING,
+	WEAPON_DROPPING,
+	WEAPON_FIRING
+} weaponstate_t;
+
+typedef enum
+{
+	AMMO_BULLETS,
+	AMMO_SHELLS,
+	AMMO_ROCKETS,
+	AMMO_GRENADES,
+	AMMO_CELLS,
+	AMMO_SLUGS
+} ammo_t;
+
+
+//deadflag
+#define DEAD_NO					0
+#define DEAD_DYING				1
+#define DEAD_DEAD				2
+#define DEAD_RESPAWNABLE		3
+
+//range
+#define RANGE_MELEE				0
+#define RANGE_NEAR				1
+#define RANGE_MID				2
+#define RANGE_FAR				3
+
+//gib types
+#define GIB_ORGANIC				0
+#define GIB_METALLIC			1
+
+//monster ai flags
+#define AI_STAND_GROUND			0x00000001
+#define AI_TEMP_STAND_GROUND	0x00000002
+#define AI_SOUND_TARGET			0x00000004
+#define AI_LOST_SIGHT			0x00000008
+#define AI_PURSUIT_LAST_SEEN	0x00000010
+#define AI_PURSUE_NEXT			0x00000020
+#define AI_PURSUE_TEMP			0x00000040
+#define AI_HOLD_FRAME			0x00000080
+#define AI_GOOD_GUY				0x00000100
+#define AI_BRUTAL				0x00000200
+#define AI_NOSTEP				0x00000400
+#define AI_DUCKED				0x00000800
+#define AI_COMBAT_POINT			0x00001000
+#define AI_MEDIC				0x00002000
+#define AI_RESURRECTING			0x00004000
+
+//monster attack state
+#define AS_STRAIGHT				1
+#define AS_SLIDING				2
+#define	AS_MELEE				3
+#define	AS_MISSILE				4
+
+// armor types
+#define ARMOR_NONE				0
+#define ARMOR_JACKET			1
+#define ARMOR_COMBAT			2
+#define ARMOR_BODY				3
+#define ARMOR_SHARD				4
+
+// power armor types
+#define POWER_ARMOR_NONE		0
+#define POWER_ARMOR_SCREEN		1
+#define POWER_ARMOR_SHIELD		2
+
+// handedness values
+#define RIGHT_HANDED			0
+#define LEFT_HANDED				1
+#define CENTER_HANDED			2
+
+
+// game.serverflags values
+#define SFL_CROSS_TRIGGER_1		0x00000001
+#define SFL_CROSS_TRIGGER_2		0x00000002
+#define SFL_CROSS_TRIGGER_3		0x00000004
+#define SFL_CROSS_TRIGGER_4		0x00000008
+#define SFL_CROSS_TRIGGER_5		0x00000010
+#define SFL_CROSS_TRIGGER_6		0x00000020
+#define SFL_CROSS_TRIGGER_7		0x00000040
+#define SFL_CROSS_TRIGGER_8		0x00000080
+#define SFL_CROSS_TRIGGER_MASK	0x000000ff
+
+
+// noise types for PlayerNoise
+#define PNOISE_SELF				0
+#define PNOISE_WEAPON			1
+#define PNOISE_IMPACT			2
+
+
+// edict->movetype values
+typedef enum
+{
+MOVETYPE_NONE,			// never moves
+MOVETYPE_NOCLIP,		// origin and angles change with no interaction
+MOVETYPE_PUSH,			// no clip to world, push on box contact
+MOVETYPE_STOP,			// no clip to world, stops on box contact
+
+MOVETYPE_WALK,			// gravity
+MOVETYPE_STEP,			// gravity, special edge handling
+MOVETYPE_FLY,
+MOVETYPE_TOSS,			// gravity
+MOVETYPE_FLYMISSILE,	// extra size to monsters
+MOVETYPE_BOUNCE
+} movetype_t;
+
+
+
+typedef struct
+{
+	int		base_count;
+	int		max_count;
+	float	normal_protection;
+	float	energy_protection;
+	int		armor;
+} gitem_armor_t;
+
+
+// gitem_t->flags
+#define	IT_WEAPON		1		// use makes active weapon
+#define	IT_AMMO			2
+#define IT_ARMOR		4
+#define IT_STAY_COOP	8
+#define IT_KEY			16
+#define IT_POWERUP		32
+//ZOID
+#define IT_TECH			64
+//ZOID
+
+// gitem_t->weapmodel for weapons indicates model index
+#define WEAP_BLASTER			1 
+#define WEAP_SHOTGUN			2 
+#define WEAP_SUPERSHOTGUN		3 
+#define WEAP_MACHINEGUN			4 
+#define WEAP_CHAINGUN			5 
+#define WEAP_GRENADES			6 
+#define WEAP_GRENADELAUNCHER	7 
+#define WEAP_ROCKETLAUNCHER		8 
+#define WEAP_HYPERBLASTER		9 
+#define WEAP_RAILGUN			10
+#define WEAP_BFG				11
+#define WEAP_GRAPPLE			12
+
+typedef struct gitem_s
+{
+	char		*classname;	// spawning name
+	qboolean	(*pickup)(struct edict_s *ent, struct edict_s *other);
+	void		(*use)(struct edict_s *ent, struct gitem_s *item);
+	void		(*drop)(struct edict_s *ent, struct gitem_s *item);
+	void		(*weaponthink)(struct edict_s *ent);
+	char		*pickup_sound;
+	char		*world_model;
+	int			world_model_flags;
+	char		*view_model;
+
+	// client side info
+	char		*icon;
+	char		*pickup_name;	// for printing on pickup
+	int			count_width;		// number of digits to display by icon
+
+	int			quantity;		// for ammo how much, for weapons how much is used per shot
+	char		*ammo;			// for weapons
+	int			flags;			// IT_* flags
+
+	int			weapmodel;		// weapon model index (for weapons)
+
+	void		*info;
+	int			tag;
+
+	char		*precaches;		// string of all models, sounds, and images this item will use
+} gitem_t;
+
+
+
+//
+// this structure is left intact through an entire game
+// it should be initialized at dll load time, and read/written to
+// the server.ssv file for savegames
+//
+typedef struct
+{
+	char		helpmessage1[512];
+	char		helpmessage2[512];
+	int			helpchanged;	// flash F1 icon if non 0, play sound
+								// and increment only if 1, 2, or 3
+
+	gclient_t	*clients;		// [maxclients]
+
+	// can't store spawnpoint in level, because
+	// it would get overwritten by the savegame restore
+	char		spawnpoint[512];	// needed for coop respawns
+
+	// store latched cvars here that we want to get at often
+	int			maxclients;
+	int			maxentities;
+
+	// cross level triggers
+	int			serverflags;
+
+	// items
+	int			num_items;
+
+	qboolean	autosaved;
+} game_locals_t;
+
+
+//
+// this structure is cleared as each map is entered
+// it is read/written to the level.sav file for savegames
+//
+typedef struct
+{
+	int			framenum;
+	float		time;
+
+	char		level_name[MAX_QPATH];	// the descriptive name (Outer Base, etc)
+	char		mapname[MAX_QPATH];		// the server name (base1, etc)
+	char		nextmap[MAX_QPATH];		// go here when fraglimit is hit
+	char		forcemap[MAX_QPATH];	// go here
+
+	// intermission state
+	float		intermissiontime;		// time the intermission was started
+	char		*changemap;
+	int			exitintermission;
+	vec3_t		intermission_origin;
+	vec3_t		intermission_angle;
+
+	edict_t		*sight_client;	// changed once each frame for coop games
+
+	edict_t		*sight_entity;
+	int			sight_entity_framenum;
+	edict_t		*sound_entity;
+	int			sound_entity_framenum;
+	edict_t		*sound2_entity;
+	int			sound2_entity_framenum;
+
+	int			pic_health;
+
+	int			total_secrets;
+	int			found_secrets;
+
+	int			total_goals;
+	int			found_goals;
+
+	int			total_monsters;
+	int			killed_monsters;
+
+	edict_t		*current_entity;	// entity running from G_RunFrame
+	int			body_que;			// dead bodies
+
+	int			power_cubes;		// ugly necessity for coop
+} level_locals_t;
+
+
+// spawn_temp_t is only used to hold entity field values that
+// can be set from the editor, but aren't actualy present
+// in edict_t during gameplay
+typedef struct
+{
+	// world vars
+	char		*sky;
+	float		skyrotate;
+	vec3_t		skyaxis;
+	char		*nextmap;
+
+	int			lip;
+	int			distance;
+	int			height;
+	char		*noise;
+	float		pausetime;
+	char		*item;
+	char		*gravity;
+
+	float		minyaw;
+	float		maxyaw;
+	float		minpitch;
+	float		maxpitch;
+} spawn_temp_t;
+
+
+typedef struct
+{
+	// fixed data
+	vec3_t		start_origin;
+	vec3_t		start_angles;
+	vec3_t		end_origin;
+	vec3_t		end_angles;
+
+	int			sound_start;
+	int			sound_middle;
+	int			sound_end;
+
+	float		accel;
+	float		speed;
+	float		decel;
+	float		distance;
+
+	float		wait;
+
+	// state data
+	int			state;
+	vec3_t		dir;
+	float		current_speed;
+	float		move_speed;
+	float		next_speed;
+	float		remaining_distance;
+	float		decel_distance;
+	void		(*endfunc)(edict_t *);
+} moveinfo_t;
+
+
+typedef struct
+{
+	void	(*aifunc)(edict_t *self, float dist);
+	float	dist;
+	void	(*thinkfunc)(edict_t *self);
+} mframe_t;
+
+typedef struct
+{
+	int			firstframe;
+	int			lastframe;
+	mframe_t	*frame;
+	void		(*endfunc)(edict_t *self);
+} mmove_t;
+
+typedef struct
+{
+	mmove_t		*currentmove;
+	int			aiflags;
+	int			nextframe;
+	float		scale;
+
+	void		(*stand)(edict_t *self);
+	void		(*idle)(edict_t *self);
+	void		(*search)(edict_t *self);
+	void		(*walk)(edict_t *self);
+	void		(*run)(edict_t *self);
+	void		(*dodge)(edict_t *self, edict_t *other, float eta);
+	void		(*attack)(edict_t *self);
+	void		(*melee)(edict_t *self);
+	void		(*sight)(edict_t *self, edict_t *other);
+	qboolean	(*checkattack)(edict_t *self);
+
+	float		pausetime;
+	float		attack_finished;
+
+	vec3_t		saved_goal;
+	float		search_time;
+	float		trail_time;
+	vec3_t		last_sighting;
+	int			attack_state;
+	int			lefty;
+	float		idle_time;
+	int			linkcount;
+
+	int			power_armor_type;
+	int			power_armor_power;
+} monsterinfo_t;
+
+
+
+extern	game_locals_t	game;
+extern	level_locals_t	level;
+extern	game_import_t	gi;
+extern	game_export_t	globals;
+extern	spawn_temp_t	st;
+
+extern	int	sm_meat_index;
+extern	int	snd_fry;
+
+extern	int	jacket_armor_index;
+extern	int	combat_armor_index;
+extern	int	body_armor_index;
+
+
+// means of death
+#define MOD_UNKNOWN			0
+#define MOD_BLASTER			1
+#define MOD_SHOTGUN			2
+#define MOD_SSHOTGUN		3
+#define MOD_MACHINEGUN		4
+#define MOD_CHAINGUN		5
+#define MOD_GRENADE			6
+#define MOD_G_SPLASH		7
+#define MOD_ROCKET			8
+#define MOD_R_SPLASH		9
+#define MOD_HYPERBLASTER	10
+#define MOD_RAILGUN			11
+#define MOD_BFG_LASER		12
+#define MOD_BFG_BLAST		13
+#define MOD_BFG_EFFECT		14
+#define MOD_HANDGRENADE		15
+#define MOD_HG_SPLASH		16
+#define MOD_WATER			17
+#define MOD_SLIME			18
+#define MOD_LAVA			19
+#define MOD_CRUSH			20
+#define MOD_TELEFRAG		21
+#define MOD_FALLING			22
+#define MOD_SUICIDE			23
+#define MOD_HELD_GRENADE	24
+#define MOD_EXPLOSIVE		25
+#define MOD_BARREL			26
+#define MOD_BOMB			27
+#define MOD_EXIT			28
+#define MOD_SPLASH			29
+#define MOD_TARGET_LASER	30
+#define MOD_TRIGGER_HURT	31
+#define MOD_HIT				32
+#define MOD_TARGET_BLASTER	33
+#define MOD_GRAPPLE			34
+#define MOD_FRIENDLY_FIRE	0x8000000
+
+extern	int	meansOfDeath;
+
+
+extern	edict_t			*g_edicts;
+
+#define	FOFS(x) (int)&(((edict_t *)0)->x)
+#define	STOFS(x) (int)&(((spawn_temp_t *)0)->x)
+#define	LLOFS(x) (int)&(((level_locals_t *)0)->x)
+#define	CLOFS(x) (int)&(((gclient_t *)0)->x)
+
+#define random()	((rand () & 0x7fff) / ((float)0x7fff))
+#define crandom()	(2.0 * (random() - 0.5))
+
+extern	cvar_t	*maxentities;
+extern	cvar_t	*deathmatch;
+extern	cvar_t	*coop;
+extern	cvar_t	*dmflags;
+extern	cvar_t	*skill;
+extern	cvar_t	*fraglimit;
+extern	cvar_t	*timelimit;
+//ZOID
+extern	cvar_t	*capturelimit;
+extern	cvar_t	*instantweap;
+//ZOID
+extern	cvar_t	*password;
+extern	cvar_t	*g_select_empty;
+extern	cvar_t	*dedicated;
+
+extern	cvar_t	*sv_gravity;
+extern	cvar_t	*sv_maxvelocity;
+
+extern	cvar_t	*gun_x, *gun_y, *gun_z;
+extern	cvar_t	*sv_rollspeed;
+extern	cvar_t	*sv_rollangle;
+
+extern	cvar_t	*run_pitch;
+extern	cvar_t	*run_roll;
+extern	cvar_t	*bob_up;
+extern	cvar_t	*bob_pitch;
+extern	cvar_t	*bob_roll;
+
+extern	cvar_t	*sv_cheats;
+extern	cvar_t	*maxclients;
+
+extern	cvar_t	*flood_msgs;
+extern	cvar_t	*flood_persecond;
+extern	cvar_t	*flood_waitdelay;
+
+extern	cvar_t	*sv_maplist;
+
+//ZOID
+extern	qboolean	is_quad;
+//ZOID
+
+#define world	(&g_edicts[0])
+
+// item spawnflags
+#define ITEM_TRIGGER_SPAWN		0x00000001
+#define ITEM_NO_TOUCH			0x00000002
+// 6 bits reserved for editor flags
+// 8 bits used as power cube id bits for coop games
+#define DROPPED_ITEM			0x00010000
+#define	DROPPED_PLAYER_ITEM		0x00020000
+#define ITEM_TARGETS_USED		0x00040000
+
+//
+// fields are needed for spawning from the entity string
+// and saving / loading games
+//
+#define FFL_SPAWNTEMP		1
+
+typedef enum {
+	F_INT, 
+	F_FLOAT,
+	F_LSTRING,			// string on disk, pointer in memory, TAG_LEVEL
+	F_GSTRING,			// string on disk, pointer in memory, TAG_GAME
+	F_VECTOR,
+	F_ANGLEHACK,
+	F_EDICT,			// index on disk, pointer in memory
+	F_ITEM,				// index on disk, pointer in memory
+	F_CLIENT,			// index on disk, pointer in memory
+	F_IGNORE
+} fieldtype_t;
+
+typedef struct
+{
+	char	*name;
+	int		ofs;
+	fieldtype_t	type;
+	int		flags;
+} field_t;
+
+
+extern	field_t fields[];
+extern	gitem_t	itemlist[];
+
+
+//
+// g_cmds.c
+//
+qboolean CheckFlood(edict_t *ent);
+void Cmd_Help_f (edict_t *ent);
+void Cmd_Score_f (edict_t *ent);
+
+//
+// g_items.c
+//
+void PrecacheItem (gitem_t *it);
+void InitItems (void);
+void SetItemNames (void);
+gitem_t	*FindItem (char *pickup_name);
+gitem_t	*FindItemByClassname (char *classname);
+#define	ITEM_INDEX(x) ((x)-itemlist)
+edict_t *Drop_Item (edict_t *ent, gitem_t *item);
+void SetRespawn (edict_t *ent, float delay);
+void ChangeWeapon (edict_t *ent);
+void SpawnItem (edict_t *ent, gitem_t *item);
+void Think_Weapon (edict_t *ent);
+int ArmorIndex (edict_t *ent);
+int PowerArmorType (edict_t *ent);
+gitem_t	*GetItemByIndex (int index);
+qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count);
+void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
+
+//
+// g_utils.c
+//
+qboolean	KillBox (edict_t *ent);
+void	G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
+edict_t *G_Find (edict_t *from, int fieldofs, char *match);
+edict_t *findradius (edict_t *from, vec3_t org, float rad);
+edict_t *G_PickTarget (char *targetname);
+void	G_UseTargets (edict_t *ent, edict_t *activator);
+void	G_SetMovedir (vec3_t angles, vec3_t movedir);
+
+void	G_InitEdict (edict_t *e);
+edict_t	*G_Spawn (void);
+void	G_FreeEdict (edict_t *e);
+
+void	G_TouchTriggers (edict_t *ent);
+void	G_TouchSolids (edict_t *ent);
+
+char	*G_CopyString (char *in);
+
+float	*tv (float x, float y, float z);
+char	*vtos (vec3_t v);
+
+float vectoyaw (vec3_t vec);
+void vectoangles (vec3_t vec, vec3_t angles);
+
+//
+// g_combat.c
+//
+qboolean OnSameTeam (edict_t *ent1, edict_t *ent2);
+qboolean CanDamage (edict_t *targ, edict_t *inflictor);
+qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker);
+void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod);
+void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod);
+
+// damage flags
+#define DAMAGE_RADIUS			0x00000001	// damage was indirect
+#define DAMAGE_NO_ARMOR			0x00000002	// armour does not protect from this damage
+#define DAMAGE_ENERGY			0x00000004	// damage is from an energy based weapon
+#define DAMAGE_NO_KNOCKBACK		0x00000008	// do not affect velocity, just view angles
+#define DAMAGE_BULLET			0x00000010  // damage is from a bullet (used for ricochets)
+#define DAMAGE_NO_PROTECTION	0x00000020  // armor, shields, invulnerability, and godmode have no effect
+
+#define DEFAULT_BULLET_HSPREAD	300
+#define DEFAULT_BULLET_VSPREAD	500
+#define DEFAULT_SHOTGUN_HSPREAD	1000
+#define DEFAULT_SHOTGUN_VSPREAD	500
+#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT	12
+#define DEFAULT_SHOTGUN_COUNT	12
+#define DEFAULT_SSHOTGUN_COUNT	20
+
+//
+// g_monster.c
+//
+void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype);
+void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype);
+void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect);
+void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype);
+void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype);
+void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype);
+void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype);
+void M_droptofloor (edict_t *ent);
+void monster_think (edict_t *self);
+void walkmonster_start (edict_t *self);
+void swimmonster_start (edict_t *self);
+void flymonster_start (edict_t *self);
+void AttackFinished (edict_t *self, float time);
+void monster_death_use (edict_t *self);
+void M_CatagorizePosition (edict_t *ent);
+qboolean M_CheckAttack (edict_t *self);
+void M_FlyCheck (edict_t *self);
+void M_CheckGround (edict_t *ent);
+
+//
+// g_misc.c
+//
+void ThrowHead (edict_t *self, char *gibname, int damage, int type);
+void ThrowClientHead (edict_t *self, int damage);
+void ThrowGib (edict_t *self, char *gibname, int damage, int type);
+void BecomeExplosion1(edict_t *self);
+
+//
+// g_ai.c
+//
+void AI_SetSightClient (void);
+
+void ai_stand (edict_t *self, float dist);
+void ai_move (edict_t *self, float dist);
+void ai_walk (edict_t *self, float dist);
+void ai_turn (edict_t *self, float dist);
+void ai_run (edict_t *self, float dist);
+void ai_charge (edict_t *self, float dist);
+int range (edict_t *self, edict_t *other);
+
+void FoundTarget (edict_t *self);
+qboolean infront (edict_t *self, edict_t *other);
+qboolean visible (edict_t *self, edict_t *other);
+qboolean FacingIdeal(edict_t *self);
+
+//
+// g_weapon.c
+//
+void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
+qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick);
+void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod);
+void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod);
+void fire_blaster (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect, qboolean hyper);
+void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius);
+void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held);
+void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage);
+void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
+void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius);
+
+//
+// g_ptrail.c
+//
+void PlayerTrail_Init (void);
+void PlayerTrail_Add (vec3_t spot);
+void PlayerTrail_New (vec3_t spot);
+edict_t *PlayerTrail_PickFirst (edict_t *self);
+edict_t *PlayerTrail_PickNext (edict_t *self);
+edict_t	*PlayerTrail_LastSpot (void);
+
+
+//
+// g_client.c
+//
+void respawn (edict_t *ent);
+void BeginIntermission (edict_t *targ);
+void PutClientInServer (edict_t *ent);
+void InitClientPersistant (gclient_t *client);
+void InitClientResp (gclient_t *client);
+void InitBodyQue (void);
+void ClientBeginServerFrame (edict_t *ent);
+
+//
+// g_player.c
+//
+void player_pain (edict_t *self, edict_t *other, float kick, int damage);
+void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+
+//
+// g_svcmds.c
+//
+void	ServerCommand (void);
+
+//
+// p_view.c
+//
+void ClientEndServerFrame (edict_t *ent);
+
+//
+// p_hud.c
+//
+void MoveClientToIntermission (edict_t *client);
+void G_SetStats (edict_t *ent);
+void ValidateSelectedItem (edict_t *ent);
+void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer);
+
+//
+// g_pweapon.c
+//
+void PlayerNoise(edict_t *who, vec3_t where, int type);
+void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
+void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent));
+
+//
+// m_move.c
+//
+qboolean M_CheckBottom (edict_t *ent);
+qboolean M_walkmove (edict_t *ent, float yaw, float dist);
+void M_MoveToGoal (edict_t *ent, float dist);
+void M_ChangeYaw (edict_t *ent);
+
+//
+// g_phys.c
+//
+void G_RunEntity (edict_t *ent);
+
+//
+// g_main.c
+//
+void SaveClientData (void);
+void FetchClientEntData (edict_t *ent);
+void EndDMLevel (void);
+
+
+//============================================================================
+
+// client_t->anim_priority
+#define	ANIM_BASIC		0		// stand / run
+#define	ANIM_WAVE		1
+#define	ANIM_JUMP		2
+#define	ANIM_PAIN		3
+#define	ANIM_ATTACK		4
+#define	ANIM_DEATH		5
+#define	ANIM_REVERSE	6
+
+
+// client data that stays across multiple level loads
+typedef struct
+{
+	char		userinfo[MAX_INFO_STRING];
+	char		netname[16];
+	int			hand;
+
+	qboolean	connected;			// a loadgame will leave valid entities that
+									// just don't have a connection yet
+
+	// values saved and restored from edicts when changing levels
+	int			health;
+	int			max_health;
+	qboolean	powerArmorActive;
+
+	int			selected_item;
+	int			inventory[MAX_ITEMS];
+
+	// ammo capacities
+	int			max_bullets;
+	int			max_shells;
+	int			max_rockets;
+	int			max_grenades;
+	int			max_cells;
+	int			max_slugs;
+
+	gitem_t		*weapon;
+	gitem_t		*lastweapon;
+
+	int			power_cubes;	// used for tracking the cubes in coop games
+	int			score;			// for calculating total unit score in coop games
+} client_persistant_t;
+
+// client data that stays across deathmatch respawns
+typedef struct
+{
+	client_persistant_t	coop_respawn;	// what to set client->pers to on a respawn
+	int			enterframe;			// level.framenum the client entered the game
+	int			score;				// frags, etc
+//ZOID
+	int			ctf_team;			// CTF team
+	int			ctf_state;
+	float		ctf_lasthurtcarrier;
+	float		ctf_lastreturnedflag;
+	float		ctf_flagsince;
+	float		ctf_lastfraggedcarrier;
+	qboolean	id_state;
+	qboolean	voted; // for elections
+	qboolean	ready;
+	qboolean	admin;
+	struct ghost_s *ghost; // for ghost codes
+//ZOID
+	vec3_t		cmd_angles;			// angles sent over in the last command
+	int			game_helpchanged;
+	int			helpchanged;
+} client_respawn_t;
+
+// this structure is cleared on each PutClientInServer(),
+// except for 'client->pers'
+struct gclient_s
+{
+	// known to server
+	player_state_t	ps;				// communicated by server to clients
+	int				ping;
+
+	// private to game
+	client_persistant_t	pers;
+	client_respawn_t	resp;
+	pmove_state_t		old_pmove;	// for detecting out-of-pmove changes
+
+	qboolean	showscores;			// set layout stat
+//ZOID
+	qboolean	inmenu;				// in menu
+	pmenuhnd_t	*menu;				// current menu
+//ZOID
+	qboolean	showinventory;		// set layout stat
+	qboolean	showhelp;
+	qboolean	showhelpicon;
+
+	int			ammo_index;
+
+	int			buttons;
+	int			oldbuttons;
+	int			latched_buttons;
+
+	qboolean	weapon_thunk;
+
+	gitem_t		*newweapon;
+
+	// sum up damage over an entire frame, so
+	// shotgun blasts give a single big kick
+	int			damage_armor;		// damage absorbed by armor
+	int			damage_parmor;		// damage absorbed by power armor
+	int			damage_blood;		// damage taken out of health
+	int			damage_knockback;	// impact damage
+	vec3_t		damage_from;		// origin for vector calculation
+
+	float		killer_yaw;			// when dead, look at killer
+
+	weaponstate_t	weaponstate;
+	vec3_t		kick_angles;	// weapon kicks
+	vec3_t		kick_origin;
+	float		v_dmg_roll, v_dmg_pitch, v_dmg_time;	// damage kicks
+	float		fall_time, fall_value;		// for view drop on fall
+	float		damage_alpha;
+	float		bonus_alpha;
+	vec3_t		damage_blend;
+	vec3_t		v_angle;			// aiming direction
+	float		bobtime;			// so off-ground doesn't change it
+	vec3_t		oldviewangles;
+	vec3_t		oldvelocity;
+
+	float		next_drown_time;
+	int			old_waterlevel;
+	int			breather_sound;
+
+	int			machinegun_shots;	// for weapon raising
+
+	// animation vars
+	int			anim_end;
+	int			anim_priority;
+	qboolean	anim_duck;
+	qboolean	anim_run;
+
+	// powerup timers
+	float		quad_framenum;
+	float		invincible_framenum;
+	float		breather_framenum;
+	float		enviro_framenum;
+
+	qboolean	grenade_blew_up;
+	float		grenade_time;
+	int			silencer_shots;
+	int			weapon_sound;
+
+	float		pickup_msg_time;
+
+	float		flood_locktill;		// locked from talking
+	float		flood_when[10];		// when messages were said
+	int			flood_whenhead;		// head pointer for when said
+
+	float		respawn_time;		// can respawn when time > this
+
+//ZOID
+	void		*ctf_grapple;		// entity of grapple
+	int			ctf_grapplestate;		// true if pulling
+	float		ctf_grapplereleasetime;	// time of grapple release
+	float		ctf_regentime;		// regen tech
+	float		ctf_techsndtime;
+	float		ctf_lasttechmsg;
+	edict_t		*chase_target;
+	qboolean	update_chase;
+	float		menutime;			// time to update menu
+	qboolean	menudirty;
+//ZOID
+};
+
+
+struct edict_s
+{
+	entity_state_t	s;
+	struct gclient_s	*client;	// NULL if not a player
+									// the server expects the first part
+									// of gclient_s to be a player_state_t
+									// but the rest of it is opaque
+
+	qboolean	inuse;
+	int			linkcount;
+
+	// FIXME: move these fields to a server private sv_entity_t
+	link_t		area;				// linked to a division node or leaf
+	
+	int			num_clusters;		// if -1, use headnode instead
+	int			clusternums[MAX_ENT_CLUSTERS];
+	int			headnode;			// unused if num_clusters != -1
+	int			areanum, areanum2;
+
+	//================================
+
+	int			svflags;
+	vec3_t		mins, maxs;
+	vec3_t		absmin, absmax, size;
+	solid_t		solid;
+	int			clipmask;
+	edict_t		*owner;
+
+
+	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
+	// EXPECTS THE FIELDS IN THAT ORDER!
+
+	//================================
+	int			movetype;
+	int			flags;
+
+	char		*model;
+	float		freetime;			// sv.time when the object was freed
+	
+	//
+	// only used locally in game, not by server
+	//
+	char		*message;
+	char		*classname;
+	int			spawnflags;
+
+	float		timestamp;
+
+	float		angle;			// set in qe3, -1 = up, -2 = down
+	char		*target;
+	char		*targetname;
+	char		*killtarget;
+	char		*team;
+	char		*pathtarget;
+	char		*deathtarget;
+	char		*combattarget;
+	edict_t		*target_ent;
+
+	float		speed, accel, decel;
+	vec3_t		movedir;
+	vec3_t		pos1, pos2;
+
+	vec3_t		velocity;
+	vec3_t		avelocity;
+	int			mass;
+	float		air_finished;
+	float		gravity;		// per entity gravity multiplier (1.0 is normal)
+								// use for lowgrav artifact, flares
+
+	edict_t		*goalentity;
+	edict_t		*movetarget;
+	float		yaw_speed;
+	float		ideal_yaw;
+
+	float		nextthink;
+	void		(*prethink) (edict_t *ent);
+	void		(*think)(edict_t *self);
+	void		(*blocked)(edict_t *self, edict_t *other);	//move to moveinfo?
+	void		(*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
+	void		(*use)(edict_t *self, edict_t *other, edict_t *activator);
+	void		(*pain)(edict_t *self, edict_t *other, float kick, int damage);
+	void		(*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+
+	float		touch_debounce_time;		// are all these legit?  do we need more/less of them?
+	float		pain_debounce_time;
+	float		damage_debounce_time;
+	float		fly_sound_debounce_time;	//move to clientinfo
+	float		last_move_time;
+
+	int			health;
+	int			max_health;
+	int			gib_health;
+	int			deadflag;
+	qboolean	show_hostile;
+
+	float		powerarmor_time;
+
+	char		*map;			// target_changelevel
+
+	int			viewheight;		// height above origin where eyesight is determined
+	int			takedamage;
+	int			dmg;
+	int			radius_dmg;
+	float		dmg_radius;
+	int			sounds;			//make this a spawntemp var?
+	int			count;
+
+	edict_t		*chain;
+	edict_t		*enemy;
+	edict_t		*oldenemy;
+	edict_t		*activator;
+	edict_t		*groundentity;
+	int			groundentity_linkcount;
+	edict_t		*teamchain;
+	edict_t		*teammaster;
+
+	edict_t		*mynoise;		// can go in client only
+	edict_t		*mynoise2;
+
+	int			noise_index;
+	int			noise_index2;
+	float		volume;
+	float		attenuation;
+
+	// timing variables
+	float		wait;
+	float		delay;			// before firing targets
+	float		random;
+
+	float		teleport_time;
+
+	int			watertype;
+	int			waterlevel;
+
+	vec3_t		move_origin;
+	vec3_t		move_angles;
+
+	// move this to clientinfo?
+	int			light_level;
+
+	int			style;			// also used as areaportal number
+
+	gitem_t		*item;			// for bonus items
+
+	// common data blocks
+	moveinfo_t		moveinfo;
+	monsterinfo_t	monsterinfo;
+};
+
+//ZOID
+#include "g_ctf.h"
+//ZOID
+
--- /dev/null
+++ b/ctf/g_main.c
@@ -1,0 +1,427 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+game_locals_t	game;
+level_locals_t	level;
+game_import_t	gi;
+game_export_t	globals;
+spawn_temp_t	st;
+
+int	sm_meat_index;
+int	snd_fry;
+int meansOfDeath;
+
+edict_t		*g_edicts;
+
+cvar_t	*deathmatch;
+cvar_t	*coop;
+cvar_t	*dmflags;
+cvar_t	*skill;
+cvar_t	*fraglimit;
+cvar_t	*timelimit;
+//ZOID
+cvar_t	*capturelimit;
+cvar_t	*instantweap;
+//ZOID
+cvar_t	*password;
+cvar_t	*maxclients;
+cvar_t	*maxentities;
+cvar_t	*g_select_empty;
+cvar_t	*dedicated;
+
+cvar_t	*sv_maxvelocity;
+cvar_t	*sv_gravity;
+
+cvar_t	*sv_rollspeed;
+cvar_t	*sv_rollangle;
+cvar_t	*gun_x;
+cvar_t	*gun_y;
+cvar_t	*gun_z;
+
+cvar_t	*run_pitch;
+cvar_t	*run_roll;
+cvar_t	*bob_up;
+cvar_t	*bob_pitch;
+cvar_t	*bob_roll;
+
+cvar_t	*sv_cheats;
+
+cvar_t	*flood_msgs;
+cvar_t	*flood_persecond;
+cvar_t	*flood_waitdelay;
+
+cvar_t	*sv_maplist;
+
+void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
+void ClientThink (edict_t *ent, usercmd_t *cmd);
+qboolean ClientConnect (edict_t *ent, char *userinfo);
+void ClientUserinfoChanged (edict_t *ent, char *userinfo);
+void ClientDisconnect (edict_t *ent);
+void ClientBegin (edict_t *ent);
+void ClientCommand (edict_t *ent);
+void RunEntity (edict_t *ent);
+void WriteGame (char *filename, qboolean autosave);
+void ReadGame (char *filename);
+void WriteLevel (char *filename);
+void ReadLevel (char *filename);
+void InitGame (void);
+void G_RunFrame (void);
+
+
+//===================================================================
+
+
+void ShutdownGame (void)
+{
+	gi.dprintf ("==== ShutdownGame ====\n");
+
+	gi.FreeTags (TAG_LEVEL);
+	gi.FreeTags (TAG_GAME);
+}
+
+
+/*
+=================
+GetGameAPI
+
+Returns a pointer to the structure with all entry points
+and global variables
+=================
+*/
+game_export_t *GetGameAPI (game_import_t *import)
+{
+	gi = *import;
+
+	globals.apiversion = GAME_API_VERSION;
+	globals.Init = InitGame;
+	globals.Shutdown = ShutdownGame;
+	globals.SpawnEntities = SpawnEntities;
+
+	globals.WriteGame = WriteGame;
+	globals.ReadGame = ReadGame;
+	globals.WriteLevel = WriteLevel;
+	globals.ReadLevel = ReadLevel;
+
+	globals.ClientThink = ClientThink;
+	globals.ClientConnect = ClientConnect;
+	globals.ClientUserinfoChanged = ClientUserinfoChanged;
+	globals.ClientDisconnect = ClientDisconnect;
+	globals.ClientBegin = ClientBegin;
+	globals.ClientCommand = ClientCommand;
+
+	globals.RunFrame = G_RunFrame;
+
+	globals.ServerCommand = ServerCommand;
+
+	globals.edict_size = sizeof(edict_t);
+
+	return &globals;
+}
+
+#ifndef GAME_HARD_LINKED
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, error);
+	vsprintf (text, error, argptr);
+	va_end (argptr);
+
+	gi.error (ERR_FATAL, "%s", text);
+}
+
+void Com_Printf (char *msg, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, msg);
+	vsprintf (text, msg, argptr);
+	va_end (argptr);
+
+	gi.dprintf ("%s", text);
+}
+
+#endif
+
+//======================================================================
+
+
+/*
+=================
+ClientEndServerFrames
+=================
+*/
+void ClientEndServerFrames (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	// calc the player views now that all pushing
+	// and damage has been added
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = g_edicts + 1 + i;
+		if (!ent->inuse || !ent->client)
+			continue;
+		ClientEndServerFrame (ent);
+	}
+
+}
+
+/*
+=================
+CreateTargetChangeLevel
+
+Returns the created target changelevel
+=================
+*/
+edict_t *CreateTargetChangeLevel(char *map)
+{
+	edict_t *ent;
+
+	ent = G_Spawn ();
+	ent->classname = "target_changelevel";
+	Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
+	ent->map = level.nextmap;
+	return ent;
+}
+
+/*
+=================
+EndDMLevel
+
+The timelimit or fraglimit has been exceeded
+=================
+*/
+void EndDMLevel (void)
+{
+	edict_t		*ent;
+	char *s, *t, *f;
+	static const char *seps = " ,\n\r";
+
+	// stay on same level flag
+	if ((int)dmflags->value & DF_SAME_LEVEL)
+	{
+		BeginIntermission (CreateTargetChangeLevel (level.mapname) );
+		return;
+	}
+
+	if (*level.forcemap) {
+		BeginIntermission (CreateTargetChangeLevel (level.forcemap) );
+		return;
+	}
+
+	// see if it's in the map list
+	if (*sv_maplist->string) {
+		s = strdup(sv_maplist->string);
+		f = NULL;
+		t = strtok(s, seps);
+		while (t != NULL) {
+			if (Q_stricmp(t, level.mapname) == 0) {
+				// it's in the list, go to the next one
+				t = strtok(NULL, seps);
+				if (t == NULL) { // end of list, go to first one
+					if (f == NULL) // there isn't a first one, same level
+						BeginIntermission (CreateTargetChangeLevel (level.mapname) );
+					else
+						BeginIntermission (CreateTargetChangeLevel (f) );
+				} else
+					BeginIntermission (CreateTargetChangeLevel (t) );
+				free(s);
+				return;
+			}
+			if (!f)
+				f = t;
+			t = strtok(NULL, seps);
+		}
+		free(s);
+	}
+
+	if (level.nextmap[0]) // go to a specific map
+		BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
+	else {	// search for a changelevel
+		ent = G_Find (NULL, FOFS(classname), "target_changelevel");
+		if (!ent)
+		{	// the map designer didn't include a changelevel,
+			// so create a fake ent that goes back to the same level
+			BeginIntermission (CreateTargetChangeLevel (level.mapname) );
+			return;
+		}
+		BeginIntermission (ent);
+	}
+}
+
+/*
+=================
+CheckDMRules
+=================
+*/
+void CheckDMRules (void)
+{
+	int			i;
+	gclient_t	*cl;
+
+	if (level.intermissiontime)
+		return;
+
+	if (!deathmatch->value)
+		return;
+
+//ZOID
+	if (ctf->value && CTFCheckRules()) {
+		EndDMLevel ();
+		return;
+	}
+	if (CTFInMatch())
+		return; // no checking in match mode
+//ZOID
+
+	if (timelimit->value)
+	{
+		if (level.time >= timelimit->value*60)
+		{
+			gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
+			EndDMLevel ();
+			return;
+		}
+	}
+
+	if (fraglimit->value)
+		for (i=0 ; i<maxclients->value ; i++)
+		{
+			cl = game.clients + i;
+			if (!g_edicts[i+1].inuse)
+				continue;
+
+			if (cl->resp.score >= fraglimit->value)
+			{
+				gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
+				EndDMLevel ();
+				return;
+			}
+		}
+}
+
+
+/*
+=============
+ExitLevel
+=============
+*/
+void ExitLevel (void)
+{
+	int		i;
+	edict_t	*ent;
+	char	command [256];
+
+	level.exitintermission = 0;
+	level.intermissiontime = 0;
+
+	if (CTFNextMap())
+		return;
+
+	Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
+	gi.AddCommandString (command);
+	ClientEndServerFrames ();
+
+	level.changemap = NULL;
+
+	// clear some things before going to next level
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = g_edicts + 1 + i;
+		if (!ent->inuse)
+			continue;
+		if (ent->health > ent->client->pers.max_health)
+			ent->health = ent->client->pers.max_health;
+	}
+}
+
+/*
+================
+G_RunFrame
+
+Advances the world by 0.1 seconds
+================
+*/
+void G_RunFrame (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	level.framenum++;
+	level.time = level.framenum*FRAMETIME;
+
+	// choose a client for monsters to target this frame
+	AI_SetSightClient ();
+
+	// exit intermissions
+
+	if (level.exitintermission)
+	{
+		ExitLevel ();
+		return;
+	}
+
+	//
+	// treat each object in turn
+	// even the world gets a chance to think
+	//
+	ent = &g_edicts[0];
+	for (i=0 ; i<globals.num_edicts ; i++, ent++)
+	{
+		if (!ent->inuse)
+			continue;
+
+		level.current_entity = ent;
+
+		VectorCopy (ent->s.origin, ent->s.old_origin);
+
+		// if the ground entity moved, make sure we are still on it
+		if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
+		{
+			ent->groundentity = NULL;
+			if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
+			{
+				M_CheckGround (ent);
+			}
+		}
+
+		if (i > 0 && i <= maxclients->value)
+		{
+			ClientBeginServerFrame (ent);
+			continue;
+		}
+
+		G_RunEntity (ent);
+	}
+
+	// see if it is time to end a deathmatch
+	CheckDMRules ();
+
+	// build the playerstate_t structures for all players
+	ClientEndServerFrames ();
+}
+
--- /dev/null
+++ b/ctf/g_misc.c
@@ -1,0 +1,1909 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_misc.c
+
+#include "g_local.h"
+
+
+/*QUAKED func_group (0 0 0) ?
+Used to group brushes together just for editor convenience.
+*/
+
+//=====================================================
+
+void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	ent->count ^= 1;		// toggle state
+//	gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
+	gi.SetAreaPortalState (ent->style, ent->count);
+}
+
+/*QUAKED func_areaportal (0 0 0) ?
+
+This is a non-visible object that divides the world into
+areas that are seperated when this portal is not activated.
+Usually enclosed in the middle of a door.
+*/
+void SP_func_areaportal (edict_t *ent)
+{
+	ent->use = Use_Areaportal;
+	ent->count = 0;		// allways start closed;
+}
+
+//=====================================================
+
+
+/*
+=================
+Misc functions
+=================
+*/
+void VelocityForDamage (int damage, vec3_t v)
+{
+	v[0] = 100.0 * crandom();
+	v[1] = 100.0 * crandom();
+	v[2] = 200.0 + 100.0 * random();
+
+	if (damage < 50)
+		VectorScale (v, 0.7, v);
+	else 
+		VectorScale (v, 1.2, v);
+}
+
+void ClipGibVelocity (edict_t *ent)
+{
+	if (ent->velocity[0] < -300)
+		ent->velocity[0] = -300;
+	else if (ent->velocity[0] > 300)
+		ent->velocity[0] = 300;
+	if (ent->velocity[1] < -300)
+		ent->velocity[1] = -300;
+	else if (ent->velocity[1] > 300)
+		ent->velocity[1] = 300;
+	if (ent->velocity[2] < 200)
+		ent->velocity[2] = 200;	// always some upwards
+	else if (ent->velocity[2] > 500)
+		ent->velocity[2] = 500;
+}
+
+
+/*
+=================
+gibs
+=================
+*/
+void gib_think (edict_t *self)
+{
+	self->s.frame++;
+	self->nextthink = level.time + FRAMETIME;
+
+	if (self->s.frame == 10)
+	{
+		self->think = G_FreeEdict;
+		self->nextthink = level.time + 8 + random()*10;
+	}
+}
+
+void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t	normal_angles, right;
+
+	if (!self->groundentity)
+		return;
+
+	self->touch = NULL;
+
+	if (plane)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
+
+		vectoangles (plane->normal, normal_angles);
+		AngleVectors (normal_angles, NULL, right, NULL);
+		vectoangles (right, self->s.angles);
+
+		if (self->s.modelindex == sm_meat_index)
+		{
+			self->s.frame++;
+			self->think = gib_think;
+			self->nextthink = level.time + FRAMETIME;
+		}
+	}
+}
+
+void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	G_FreeEdict (self);
+}
+
+void ThrowGib (edict_t *self, char *gibname, int damage, int type)
+{
+	edict_t *gib;
+	vec3_t	vd;
+	vec3_t	origin;
+	vec3_t	size;
+	float	vscale;
+
+	gib = G_Spawn();
+
+	VectorScale (self->size, 0.5, size);
+	VectorAdd (self->absmin, size, origin);
+	gib->s.origin[0] = origin[0] + crandom() * size[0];
+	gib->s.origin[1] = origin[1] + crandom() * size[1];
+	gib->s.origin[2] = origin[2] + crandom() * size[2];
+
+	gi.setmodel (gib, gibname);
+	gib->solid = SOLID_NOT;
+	gib->s.effects |= EF_GIB;
+	gib->flags |= FL_NO_KNOCKBACK;
+	gib->takedamage = DAMAGE_YES;
+	gib->die = gib_die;
+
+	if (type == GIB_ORGANIC)
+	{
+		gib->movetype = MOVETYPE_TOSS;
+		gib->touch = gib_touch;
+		vscale = 0.5;
+	}
+	else
+	{
+		gib->movetype = MOVETYPE_BOUNCE;
+		vscale = 1.0;
+	}
+
+	VelocityForDamage (damage, vd);
+	VectorMA (self->velocity, vscale, vd, gib->velocity);
+	ClipGibVelocity (gib);
+	gib->avelocity[0] = random()*600;
+	gib->avelocity[1] = random()*600;
+	gib->avelocity[2] = random()*600;
+
+	gib->think = G_FreeEdict;
+	gib->nextthink = level.time + 10 + random()*10;
+
+	gi.linkentity (gib);
+}
+
+void ThrowHead (edict_t *self, char *gibname, int damage, int type)
+{
+	vec3_t	vd;
+	float	vscale;
+
+	self->s.skinnum = 0;
+	self->s.frame = 0;
+	VectorClear (self->mins);
+	VectorClear (self->maxs);
+
+	self->s.modelindex2 = 0;
+	gi.setmodel (self, gibname);
+	self->solid = SOLID_NOT;
+	self->s.effects |= EF_GIB;
+	self->s.effects &= ~EF_FLIES;
+	self->s.sound = 0;
+	self->flags |= FL_NO_KNOCKBACK;
+	self->svflags &= ~SVF_MONSTER;
+	self->takedamage = DAMAGE_YES;
+	self->die = gib_die;
+
+	if (type == GIB_ORGANIC)
+	{
+		self->movetype = MOVETYPE_TOSS;
+		self->touch = gib_touch;
+		vscale = 0.5;
+	}
+	else
+	{
+		self->movetype = MOVETYPE_BOUNCE;
+		vscale = 1.0;
+	}
+
+	VelocityForDamage (damage, vd);
+	VectorMA (self->velocity, vscale, vd, self->velocity);
+	ClipGibVelocity (self);
+
+	self->avelocity[YAW] = crandom()*600;
+
+	self->think = G_FreeEdict;
+	self->nextthink = level.time + 10 + random()*10;
+
+	gi.linkentity (self);
+}
+
+
+void ThrowClientHead (edict_t *self, int damage)
+{
+	vec3_t	vd;
+	char	*gibname;
+
+	if (rand()&1)
+	{
+		gibname = "models/objects/gibs/head2/tris.md2";
+		self->s.skinnum = 1;		// second skin is player
+	}
+	else
+	{
+		gibname = "models/objects/gibs/skull/tris.md2";
+		self->s.skinnum = 0;
+	}
+
+	self->s.origin[2] += 32;
+	self->s.frame = 0;
+	gi.setmodel (self, gibname);
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 16);
+
+	self->takedamage = DAMAGE_NO;
+	self->solid = SOLID_NOT;
+	self->s.effects = EF_GIB;
+	self->s.sound = 0;
+	self->flags |= FL_NO_KNOCKBACK;
+
+	self->movetype = MOVETYPE_BOUNCE;
+	VelocityForDamage (damage, vd);
+	VectorAdd (self->velocity, vd, self->velocity);
+
+	if (self->client)	// bodies in the queue don't have a client anymore
+	{
+		self->client->anim_priority = ANIM_DEATH;
+		self->client->anim_end = self->s.frame;
+	}
+
+	gi.linkentity (self);
+}
+
+
+/*
+=================
+debris
+=================
+*/
+void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	G_FreeEdict (self);
+}
+
+void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
+{
+	edict_t	*chunk;
+	vec3_t	v;
+
+	chunk = G_Spawn();
+	VectorCopy (origin, chunk->s.origin);
+	gi.setmodel (chunk, modelname);
+	v[0] = 100 * crandom();
+	v[1] = 100 * crandom();
+	v[2] = 100 + 100 * crandom();
+	VectorMA (self->velocity, speed, v, chunk->velocity);
+	chunk->movetype = MOVETYPE_BOUNCE;
+	chunk->solid = SOLID_NOT;
+	chunk->avelocity[0] = random()*600;
+	chunk->avelocity[1] = random()*600;
+	chunk->avelocity[2] = random()*600;
+	chunk->think = G_FreeEdict;
+	chunk->nextthink = level.time + 5 + random()*5;
+	chunk->s.frame = 0;
+	chunk->flags = 0;
+	chunk->classname = "debris";
+	chunk->takedamage = DAMAGE_YES;
+	chunk->die = debris_die;
+	gi.linkentity (chunk);
+}
+
+
+void BecomeExplosion1 (edict_t *self)
+{
+//ZOID
+	//flags are important
+	if (strcmp(self->classname, "item_flag_team1") == 0) {
+		CTFResetFlag(CTF_TEAM1); // this will free self!
+		gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
+			CTFTeamName(CTF_TEAM1));
+		return;
+	}
+	if (strcmp(self->classname, "item_flag_team2") == 0) {
+		CTFResetFlag(CTF_TEAM2); // this will free self!
+		gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
+			CTFTeamName(CTF_TEAM1));
+		return;
+	}
+	// techs are important too
+	if (self->item && (self->item->flags & IT_TECH)) {
+		CTFRespawnTech(self); // this frees self!
+		return;
+	}
+//ZOID
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION1);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	G_FreeEdict (self);
+}
+
+
+void BecomeExplosion2 (edict_t *self)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION2);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	G_FreeEdict (self);
+}
+
+
+/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
+Target: next path corner
+Pathtarget: gets used when an entity that has
+	this path_corner targeted touches it
+*/
+
+void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t		v;
+	edict_t		*next;
+
+	if (other->movetarget != self)
+		return;
+	
+	if (other->enemy)
+		return;
+
+	if (self->pathtarget)
+	{
+		char *savetarget;
+
+		savetarget = self->target;
+		self->target = self->pathtarget;
+		G_UseTargets (self, other);
+		self->target = savetarget;
+	}
+
+	if (self->target)
+		next = G_PickTarget(self->target);
+	else
+		next = NULL;
+
+	if ((next) && (next->spawnflags & 1))
+	{
+		VectorCopy (next->s.origin, v);
+		v[2] += next->mins[2];
+		v[2] -= other->mins[2];
+		VectorCopy (v, other->s.origin);
+		next = G_PickTarget(next->target);
+	}
+
+	other->goalentity = other->movetarget = next;
+
+	if (self->wait)
+	{
+		other->monsterinfo.pausetime = level.time + self->wait;
+		other->monsterinfo.stand (other);
+		return;
+	}
+
+	if (!other->movetarget)
+	{
+		other->monsterinfo.pausetime = level.time + 100000000;
+		other->monsterinfo.stand (other);
+	}
+	else
+	{
+		VectorSubtract (other->goalentity->s.origin, other->s.origin, v);
+		other->ideal_yaw = vectoyaw (v);
+	}
+}
+
+void SP_path_corner (edict_t *self)
+{
+	if (!self->targetname)
+	{
+		gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->solid = SOLID_TRIGGER;
+	self->touch = path_corner_touch;
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+	self->svflags |= SVF_NOCLIENT;
+	gi.linkentity (self);
+}
+
+
+/*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
+Makes this the target of a monster and it will head here
+when first activated before going after the activator.  If
+hold is selected, it will stay here.
+*/
+void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	edict_t	*activator;
+
+	if (other->movetarget != self)
+		return;
+
+	if (self->target)
+	{
+		other->target = self->target;
+		other->goalentity = other->movetarget = G_PickTarget(other->target);
+		if (!other->goalentity)
+		{
+			gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target);
+			other->movetarget = self;
+		}
+		self->target = NULL;
+	}
+	else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY)))
+	{
+		other->monsterinfo.pausetime = level.time + 100000000;
+		other->monsterinfo.aiflags |= AI_STAND_GROUND;
+		other->monsterinfo.stand (other);
+	}
+
+	if (other->movetarget == self)
+	{
+		other->target = NULL;
+		other->movetarget = NULL;
+		other->goalentity = other->enemy;
+		other->monsterinfo.aiflags &= ~AI_COMBAT_POINT;
+	}
+
+	if (self->pathtarget)
+	{
+		char *savetarget;
+
+		savetarget = self->target;
+		self->target = self->pathtarget;
+		if (other->enemy && other->enemy->client)
+			activator = other->enemy;
+		else if (other->oldenemy && other->oldenemy->client)
+			activator = other->oldenemy;
+		else if (other->activator && other->activator->client)
+			activator = other->activator;
+		else
+			activator = other;
+		G_UseTargets (self, activator);
+		self->target = savetarget;
+	}
+}
+
+void SP_point_combat (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+	self->solid = SOLID_TRIGGER;
+	self->touch = point_combat_touch;
+	VectorSet (self->mins, -8, -8, -16);
+	VectorSet (self->maxs, 8, 8, 16);
+	self->svflags = SVF_NOCLIENT;
+	gi.linkentity (self);
+};
+
+
+/*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
+Just for the debugging level.  Don't use
+*/
+static int robotron[4];
+
+void TH_viewthing(edict_t *ent)
+{
+	ent->s.frame = (ent->s.frame + 1) % 7;
+//	ent->s.frame = (ent->s.frame + 1) % 9;
+	ent->nextthink = level.time + FRAMETIME;
+//	return;
+
+	if (ent->spawnflags)
+	{
+		if (ent->s.frame == 0)
+		{
+			ent->spawnflags = (ent->spawnflags + 1) % 4 + 1;
+			ent->s.modelindex = robotron[ent->spawnflags - 1];
+		}
+	}
+}
+
+void SP_viewthing(edict_t *ent)
+{
+	gi.dprintf ("viewthing spawned\n");
+
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.renderfx = RF_FRAMELERP;
+	VectorSet (ent->mins, -16, -16, -24);
+	VectorSet (ent->maxs, 16, 16, 32);
+//	ent->s.modelindex = gi.modelindex ("models/player_y/tris.md2");
+	ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
+	gi.linkentity (ent);
+	ent->nextthink = level.time + 0.5;
+	ent->think = TH_viewthing;
+	return;
+}
+
+
+/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for spotlights, etc.
+*/
+void SP_info_null (edict_t *self)
+{
+	G_FreeEdict (self);
+};
+
+
+/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for lightning.
+*/
+void SP_info_notnull (edict_t *self)
+{
+	VectorCopy (self->s.origin, self->absmin);
+	VectorCopy (self->s.origin, self->absmax);
+};
+
+
+/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
+Non-displayed light.
+Default light value is 300.
+Default style is 0.
+If targeted, will toggle between on and off.
+Default _cone value is 10 (used to set size of light for spotlights)
+*/
+
+#define START_OFF	1
+
+static void light_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->spawnflags & START_OFF)
+	{
+		gi.configstring (CS_LIGHTS+self->style, "m");
+		self->spawnflags &= ~START_OFF;
+	}
+	else
+	{
+		gi.configstring (CS_LIGHTS+self->style, "a");
+		self->spawnflags |= START_OFF;
+	}
+}
+
+void SP_light (edict_t *self)
+{
+	// no targeted lights in deathmatch, because they cause global messages
+	if (!self->targetname || deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (self->style >= 32)
+	{
+		self->use = light_use;
+		if (self->spawnflags & START_OFF)
+			gi.configstring (CS_LIGHTS+self->style, "a");
+		else
+			gi.configstring (CS_LIGHTS+self->style, "m");
+	}
+}
+
+
+/*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST
+This is just a solid wall if not inhibited
+
+TRIGGER_SPAWN	the wall will not be present until triggered
+				it will then blink in to existance; it will
+				kill anything that was in it's way
+
+TOGGLE			only valid for TRIGGER_SPAWN walls
+				this allows the wall to be turned on and off
+
+START_ON		only valid for TRIGGER_SPAWN walls
+				the wall will initially be present
+*/
+
+void func_wall_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->solid == SOLID_NOT)
+	{
+		self->solid = SOLID_BSP;
+		self->svflags &= ~SVF_NOCLIENT;
+		KillBox (self);
+	}
+	else
+	{
+		self->solid = SOLID_NOT;
+		self->svflags |= SVF_NOCLIENT;
+	}
+	gi.linkentity (self);
+
+	if (!(self->spawnflags & 2))
+		self->use = NULL;
+}
+
+void SP_func_wall (edict_t *self)
+{
+	self->movetype = MOVETYPE_PUSH;
+	gi.setmodel (self, self->model);
+
+	if (self->spawnflags & 8)
+		self->s.effects |= EF_ANIM_ALL;
+	if (self->spawnflags & 16)
+		self->s.effects |= EF_ANIM_ALLFAST;
+
+	// just a wall
+	if ((self->spawnflags & 7) == 0)
+	{
+		self->solid = SOLID_BSP;
+		gi.linkentity (self);
+		return;
+	}
+
+	// it must be TRIGGER_SPAWN
+	if (!(self->spawnflags & 1))
+	{
+//		gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
+		self->spawnflags |= 1;
+	}
+
+	// yell if the spawnflags are odd
+	if (self->spawnflags & 4)
+	{
+		if (!(self->spawnflags & 2))
+		{
+			gi.dprintf("func_wall START_ON without TOGGLE\n");
+			self->spawnflags |= 2;
+		}
+	}
+
+	self->use = func_wall_use;
+	if (self->spawnflags & 4)
+	{
+		self->solid = SOLID_BSP;
+	}
+	else
+	{
+		self->solid = SOLID_NOT;
+		self->svflags |= SVF_NOCLIENT;
+	}
+	gi.linkentity (self);
+}
+
+
+/*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
+This is solid bmodel that will fall if it's support it removed.
+*/
+
+void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	// only squash thing we fall on top of
+	if (!plane)
+		return;
+	if (plane->normal[2] < 1.0)
+		return;
+	if (other->takedamage == DAMAGE_NO)
+		return;
+	T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void func_object_release (edict_t *self)
+{
+	self->movetype = MOVETYPE_TOSS;
+	self->touch = func_object_touch;
+}
+
+void func_object_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->solid = SOLID_BSP;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = NULL;
+	KillBox (self);
+	func_object_release (self);
+}
+
+void SP_func_object (edict_t *self)
+{
+	gi.setmodel (self, self->model);
+
+	self->mins[0] += 1;
+	self->mins[1] += 1;
+	self->mins[2] += 1;
+	self->maxs[0] -= 1;
+	self->maxs[1] -= 1;
+	self->maxs[2] -= 1;
+
+	if (!self->dmg)
+		self->dmg = 100;
+
+	if (self->spawnflags == 0)
+	{
+		self->solid = SOLID_BSP;
+		self->movetype = MOVETYPE_PUSH;
+		self->think = func_object_release;
+		self->nextthink = level.time + 2 * FRAMETIME;
+	}
+	else
+	{
+		self->solid = SOLID_NOT;
+		self->movetype = MOVETYPE_PUSH;
+		self->use = func_object_use;
+		self->svflags |= SVF_NOCLIENT;
+	}
+
+	if (self->spawnflags & 2)
+		self->s.effects |= EF_ANIM_ALL;
+	if (self->spawnflags & 4)
+		self->s.effects |= EF_ANIM_ALLFAST;
+
+	self->clipmask = MASK_MONSTERSOLID;
+
+	gi.linkentity (self);
+}
+
+
+/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
+Any brush that you want to explode or break apart.  If you want an
+ex0plosion, set dmg and it will do a radius explosion of that amount
+at the center of the bursh.
+
+If targeted it will not be shootable.
+
+health defaults to 100.
+
+mass defaults to 75.  This determines how much debris is emitted when
+it explodes.  You get one large chunk per 100 of mass (up to 8) and
+one small chunk per 25 of mass (up to 16).  So 800 gives the most.
+*/
+void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	vec3_t	origin;
+	vec3_t	chunkorigin;
+	vec3_t	size;
+	int		count;
+	int		mass;
+
+	// bmodel origins are (0 0 0), we need to adjust that here
+	VectorScale (self->size, 0.5, size);
+	VectorAdd (self->absmin, size, origin);
+	VectorCopy (origin, self->s.origin);
+
+	self->takedamage = DAMAGE_NO;
+
+	if (self->dmg)
+		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
+
+	VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
+	VectorNormalize (self->velocity);
+	VectorScale (self->velocity, 150, self->velocity);
+
+	// start chunks towards the center
+	VectorScale (size, 0.5, size);
+
+	mass = self->mass;
+	if (!mass)
+		mass = 75;
+
+	// big chunks
+	if (mass >= 100)
+	{
+		count = mass / 100;
+		if (count > 8)
+			count = 8;
+		while(count--)
+		{
+			chunkorigin[0] = origin[0] + crandom() * size[0];
+			chunkorigin[1] = origin[1] + crandom() * size[1];
+			chunkorigin[2] = origin[2] + crandom() * size[2];
+			ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
+		}
+	}
+
+	// small chunks
+	count = mass / 25;
+	if (count > 16)
+		count = 16;
+	while(count--)
+	{
+		chunkorigin[0] = origin[0] + crandom() * size[0];
+		chunkorigin[1] = origin[1] + crandom() * size[1];
+		chunkorigin[2] = origin[2] + crandom() * size[2];
+		ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
+	}
+
+	G_UseTargets (self, attacker);
+
+	if (self->dmg)
+		BecomeExplosion1 (self);
+	else
+		G_FreeEdict (self);
+}
+
+void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
+{
+	func_explosive_explode (self, self, other, self->health, vec3_origin);
+}
+
+void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->solid = SOLID_BSP;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = NULL;
+	KillBox (self);
+	gi.linkentity (self);
+}
+
+void SP_func_explosive (edict_t *self)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->movetype = MOVETYPE_PUSH;
+
+	gi.modelindex ("models/objects/debris1/tris.md2");
+	gi.modelindex ("models/objects/debris2/tris.md2");
+
+	gi.setmodel (self, self->model);
+
+	if (self->spawnflags & 1)
+	{
+		self->svflags |= SVF_NOCLIENT;
+		self->solid = SOLID_NOT;
+		self->use = func_explosive_spawn;
+	}
+	else
+	{
+		self->solid = SOLID_BSP;
+		if (self->targetname)
+			self->use = func_explosive_use;
+	}
+
+	if (self->spawnflags & 2)
+		self->s.effects |= EF_ANIM_ALL;
+	if (self->spawnflags & 4)
+		self->s.effects |= EF_ANIM_ALLFAST;
+
+	if (self->use != func_explosive_use)
+	{
+		if (!self->health)
+			self->health = 100;
+		self->die = func_explosive_explode;
+		self->takedamage = DAMAGE_YES;
+	}
+
+	gi.linkentity (self);
+}
+
+
+/*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
+Large exploding box.  You can override its mass (100),
+health (80), and dmg (150).
+*/
+
+void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+
+{
+	float	ratio;
+	vec3_t	v;
+
+	if ((!other->groundentity) || (other->groundentity == self))
+		return;
+
+	ratio = (float)other->mass / (float)self->mass;
+	VectorSubtract (self->s.origin, other->s.origin, v);
+	M_walkmove (self, vectoyaw(v), 20 * ratio * FRAMETIME);
+}
+
+void barrel_explode (edict_t *self)
+{
+	vec3_t	org;
+	float	spd;
+	vec3_t	save;
+
+	T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL);
+
+	VectorCopy (self->s.origin, save);
+	VectorMA (self->absmin, 0.5, self->size, self->s.origin);
+
+	// a few big chunks
+	spd = 1.5 * (float)self->dmg / 200.0;
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
+
+	// bottom corners
+	spd = 1.75 * (float)self->dmg / 200.0;
+	VectorCopy (self->absmin, org);
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+	VectorCopy (self->absmin, org);
+	org[0] += self->size[0];
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+	VectorCopy (self->absmin, org);
+	org[1] += self->size[1];
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+	VectorCopy (self->absmin, org);
+	org[0] += self->size[0];
+	org[1] += self->size[1];
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+
+	// a bunch of little chunks
+	spd = 2 * self->dmg / 200;
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+
+	VectorCopy (save, self->s.origin);
+	if (self->groundentity)
+		BecomeExplosion2 (self);
+	else
+		BecomeExplosion1 (self);
+}
+
+void barrel_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	self->takedamage = DAMAGE_NO;
+	self->nextthink = level.time + 2 * FRAMETIME;
+	self->think = barrel_explode;
+	self->activator = attacker;
+}
+
+void SP_misc_explobox (edict_t *self)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (self);
+		return;
+	}
+
+	gi.modelindex ("models/objects/debris1/tris.md2");
+	gi.modelindex ("models/objects/debris2/tris.md2");
+	gi.modelindex ("models/objects/debris3/tris.md2");
+
+	self->solid = SOLID_BBOX;
+	self->movetype = MOVETYPE_STEP;
+
+	self->model = "models/objects/barrels/tris.md2";
+	self->s.modelindex = gi.modelindex (self->model);
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 40);
+
+	if (!self->mass)
+		self->mass = 400;
+	if (!self->health)
+		self->health = 10;
+	if (!self->dmg)
+		self->dmg = 150;
+
+	self->die = barrel_delay;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.aiflags = AI_NOSTEP;
+
+	self->touch = barrel_touch;
+
+	self->think = M_droptofloor;
+	self->nextthink = level.time + 2 * FRAMETIME;
+
+	gi.linkentity (self);
+}
+
+
+//
+// miscellaneous specialty items
+//
+
+/*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8)
+*/
+
+void misc_blackhole_use (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	/*
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_BOSSTPORT);
+	gi.WritePosition (ent->s.origin);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+	*/
+	G_FreeEdict (ent);
+}
+
+void misc_blackhole_think (edict_t *self)
+{
+	if (++self->s.frame < 19)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 0;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_blackhole (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	VectorSet (ent->mins, -64, -64, 0);
+	VectorSet (ent->maxs, 64, 64, 8);
+	ent->s.modelindex = gi.modelindex ("models/objects/black/tris.md2");
+	ent->s.renderfx = RF_TRANSLUCENT;
+	ent->use = misc_blackhole_use;
+	ent->think = misc_blackhole_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32)
+*/
+
+void misc_eastertank_think (edict_t *self)
+{
+	if (++self->s.frame < 293)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 254;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_eastertank (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -32, -32, -16);
+	VectorSet (ent->maxs, 32, 32, 32);
+	ent->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
+	ent->s.frame = 254;
+	ent->think = misc_eastertank_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32)
+*/
+
+
+void misc_easterchick_think (edict_t *self)
+{
+	if (++self->s.frame < 247)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 208;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_easterchick (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -32, -32, 0);
+	VectorSet (ent->maxs, 32, 32, 32);
+	ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
+	ent->s.frame = 208;
+	ent->think = misc_easterchick_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32)
+*/
+
+
+void misc_easterchick2_think (edict_t *self)
+{
+	if (++self->s.frame < 287)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 248;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_easterchick2 (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -32, -32, 0);
+	VectorSet (ent->maxs, 32, 32, 32);
+	ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
+	ent->s.frame = 248;
+	ent->think = misc_easterchick2_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48)
+Not really a monster, this is the Tank Commander's decapitated body.
+There should be a item_commander_head that has this as it's target.
+*/
+
+void commander_body_think (edict_t *self)
+{
+	if (++self->s.frame < 24)
+		self->nextthink = level.time + FRAMETIME;
+	else
+		self->nextthink = 0;
+
+	if (self->s.frame == 22)
+		gi.sound (self, CHAN_BODY, gi.soundindex ("tank/thud.wav"), 1, ATTN_NORM, 0);
+}
+
+void commander_body_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->think = commander_body_think;
+	self->nextthink = level.time + FRAMETIME;
+	gi.sound (self, CHAN_BODY, gi.soundindex ("tank/pain.wav"), 1, ATTN_NORM, 0);
+}
+
+void commander_body_drop (edict_t *self)
+{
+	self->movetype = MOVETYPE_TOSS;
+	self->s.origin[2] += 2;
+}
+
+void SP_monster_commander_body (edict_t *self)
+{
+	self->movetype = MOVETYPE_NONE;
+	self->solid = SOLID_BBOX;
+	self->model = "models/monsters/commandr/tris.md2";
+	self->s.modelindex = gi.modelindex (self->model);
+	VectorSet (self->mins, -32, -32, 0);
+	VectorSet (self->maxs, 32, 32, 48);
+	self->use = commander_body_use;
+	self->takedamage = DAMAGE_YES;
+	self->flags = FL_GODMODE;
+	self->s.renderfx |= RF_FRAMELERP;
+	gi.linkentity (self);
+
+	gi.soundindex ("tank/thud.wav");
+	gi.soundindex ("tank/pain.wav");
+
+	self->think = commander_body_drop;
+	self->nextthink = level.time + 5 * FRAMETIME;
+}
+
+
+/*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4)
+The origin is the bottom of the banner.
+The banner is 128 tall.
+*/
+void misc_banner_think (edict_t *ent)
+{
+	ent->s.frame = (ent->s.frame + 1) % 16;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void SP_misc_banner (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
+	ent->s.frame = rand() % 16;
+	gi.linkentity (ent);
+
+	ent->think = misc_banner_think;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+/*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED
+This is the dead player model. Comes in 6 exciting different poses!
+*/
+void misc_deadsoldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	if (self->health > -80)
+		return;
+
+	gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+	for (n= 0; n < 4; n++)
+		ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+	ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+}
+
+void SP_misc_deadsoldier (edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.modelindex=gi.modelindex ("models/deadbods/dude/tris.md2");
+
+	// Defaults to frame 0
+	if (ent->spawnflags & 2)
+		ent->s.frame = 1;
+	else if (ent->spawnflags & 4)
+		ent->s.frame = 2;
+	else if (ent->spawnflags & 8)
+		ent->s.frame = 3;
+	else if (ent->spawnflags & 16)
+		ent->s.frame = 4;
+	else if (ent->spawnflags & 32)
+		ent->s.frame = 5;
+	else
+		ent->s.frame = 0;
+
+	VectorSet (ent->mins, -16, -16, 0);
+	VectorSet (ent->maxs, 16, 16, 16);
+	ent->deadflag = DEAD_DEAD;
+	ent->takedamage = DAMAGE_YES;
+	ent->svflags |= SVF_MONSTER|SVF_DEADMONSTER;
+	ent->die = misc_deadsoldier_die;
+	ent->monsterinfo.aiflags |= AI_GOOD_GUY;
+
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32)
+This is the Viper for the flyby bombing.
+It is trigger_spawned, so you must have something use it for it to show up.
+There must be a path for it to follow once it is activated.
+
+"speed"		How fast the Viper should fly
+*/
+
+extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
+extern void func_train_find (edict_t *self);
+
+void misc_viper_use  (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = train_use;
+	train_use (self, other, activator);
+}
+
+void SP_misc_viper (edict_t *ent)
+{
+	if (!ent->target)
+	{
+		gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!ent->speed)
+		ent->speed = 300;
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2");
+	VectorSet (ent->mins, -16, -16, 0);
+	VectorSet (ent->maxs, 16, 16, 32);
+
+	ent->think = func_train_find;
+	ent->nextthink = level.time + FRAMETIME;
+	ent->use = misc_viper_use;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
+
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72) 
+This is a large stationary viper as seen in Paul's intro
+*/
+void SP_misc_bigviper (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -176, -120, -24);
+	VectorSet (ent->maxs, 176, 120, 72);
+	ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8)
+"dmg"	how much boom should the bomb make?
+*/
+void misc_viper_bomb_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	G_UseTargets (self, self->activator);
+
+	self->s.origin[2] = self->absmin[2] + 1;
+	T_RadiusDamage (self, self, self->dmg, NULL, self->dmg+40, MOD_BOMB);
+	BecomeExplosion2 (self);
+}
+
+void misc_viper_bomb_prethink (edict_t *self)
+{
+	vec3_t	v;
+	float	diff;
+
+	self->groundentity = NULL;
+
+	diff = self->timestamp - level.time;
+	if (diff < -1.0)
+		diff = -1.0;
+
+	VectorScale (self->moveinfo.dir, 1.0 + diff, v);
+	v[2] = diff;
+
+	diff = self->s.angles[2];
+	vectoangles (v, self->s.angles);
+	self->s.angles[2] = diff + 10;
+}
+
+void misc_viper_bomb_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t	*viper;
+
+	self->solid = SOLID_BBOX;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->s.effects |= EF_ROCKET;
+	self->use = NULL;
+	self->movetype = MOVETYPE_TOSS;
+	self->prethink = misc_viper_bomb_prethink;
+	self->touch = misc_viper_bomb_touch;
+	self->activator = activator;
+
+	viper = G_Find (NULL, FOFS(classname), "misc_viper");
+	VectorScale (viper->moveinfo.dir, viper->moveinfo.speed, self->velocity);
+
+	self->timestamp = level.time;
+	VectorCopy (viper->moveinfo.dir, self->moveinfo.dir);
+}
+
+void SP_misc_viper_bomb (edict_t *self)
+{
+	self->movetype = MOVETYPE_NONE;
+	self->solid = SOLID_NOT;
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+
+	self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2");
+
+	if (!self->dmg)
+		self->dmg = 1000;
+
+	self->use = misc_viper_bomb_use;
+	self->svflags |= SVF_NOCLIENT;
+
+	gi.linkentity (self);
+}
+
+
+/*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32)
+This is a Storgg ship for the flybys.
+It is trigger_spawned, so you must have something use it for it to show up.
+There must be a path for it to follow once it is activated.
+
+"speed"		How fast it should fly
+*/
+
+extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
+extern void func_train_find (edict_t *self);
+
+void misc_strogg_ship_use  (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = train_use;
+	train_use (self, other, activator);
+}
+
+void SP_misc_strogg_ship (edict_t *ent)
+{
+	if (!ent->target)
+	{
+		gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!ent->speed)
+		ent->speed = 300;
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/ships/strogg1/tris.md2");
+	VectorSet (ent->mins, -16, -16, 0);
+	VectorSet (ent->maxs, 16, 16, 32);
+
+	ent->think = func_train_find;
+	ent->nextthink = level.time + FRAMETIME;
+	ent->use = misc_strogg_ship_use;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
+
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128)
+*/
+void misc_satellite_dish_think (edict_t *self)
+{
+	self->s.frame++;
+	if (self->s.frame < 38)
+		self->nextthink = level.time + FRAMETIME;
+}
+
+void misc_satellite_dish_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->s.frame = 0;
+	self->think = misc_satellite_dish_think;
+	self->nextthink = level.time + FRAMETIME;
+}
+
+void SP_misc_satellite_dish (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -64, -64, 0);
+	VectorSet (ent->maxs, 64, 64, 128);
+	ent->s.modelindex = gi.modelindex ("models/objects/satellite/tris.md2");
+	ent->use = misc_satellite_dish_use;
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
+*/
+void SP_light_mine1 (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.modelindex = gi.modelindex ("models/objects/minelite/light1/tris.md2");
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
+*/
+void SP_light_mine2 (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.modelindex = gi.modelindex ("models/objects/minelite/light2/tris.md2");
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
+Intended for use with the target_spawner
+*/
+void SP_misc_gib_arm (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/gibs/arm/tris.md2");
+	ent->solid = SOLID_NOT;
+	ent->s.effects |= EF_GIB;
+	ent->takedamage = DAMAGE_YES;
+	ent->die = gib_die;
+	ent->movetype = MOVETYPE_TOSS;
+	ent->svflags |= SVF_MONSTER;
+	ent->deadflag = DEAD_DEAD;
+	ent->avelocity[0] = random()*200;
+	ent->avelocity[1] = random()*200;
+	ent->avelocity[2] = random()*200;
+	ent->think = G_FreeEdict;
+	ent->nextthink = level.time + 30;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
+Intended for use with the target_spawner
+*/
+void SP_misc_gib_leg (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/gibs/leg/tris.md2");
+	ent->solid = SOLID_NOT;
+	ent->s.effects |= EF_GIB;
+	ent->takedamage = DAMAGE_YES;
+	ent->die = gib_die;
+	ent->movetype = MOVETYPE_TOSS;
+	ent->svflags |= SVF_MONSTER;
+	ent->deadflag = DEAD_DEAD;
+	ent->avelocity[0] = random()*200;
+	ent->avelocity[1] = random()*200;
+	ent->avelocity[2] = random()*200;
+	ent->think = G_FreeEdict;
+	ent->nextthink = level.time + 30;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
+Intended for use with the target_spawner
+*/
+void SP_misc_gib_head (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/gibs/head/tris.md2");
+	ent->solid = SOLID_NOT;
+	ent->s.effects |= EF_GIB;
+	ent->takedamage = DAMAGE_YES;
+	ent->die = gib_die;
+	ent->movetype = MOVETYPE_TOSS;
+	ent->svflags |= SVF_MONSTER;
+	ent->deadflag = DEAD_DEAD;
+	ent->avelocity[0] = random()*200;
+	ent->avelocity[1] = random()*200;
+	ent->avelocity[2] = random()*200;
+	ent->think = G_FreeEdict;
+	ent->nextthink = level.time + 30;
+	gi.linkentity (ent);
+}
+
+//=====================================================
+
+/*QUAKED target_character (0 0 1) ?
+used with target_string (must be on same "team")
+"count" is position in the string (starts at 1)
+*/
+
+void SP_target_character (edict_t *self)
+{
+	self->movetype = MOVETYPE_PUSH;
+	gi.setmodel (self, self->model);
+	self->solid = SOLID_BSP;
+	self->s.frame = 12;
+	gi.linkentity (self);
+	return;
+}
+
+
+/*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
+*/
+
+void target_string_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t *e;
+	int		n, l;
+	char	c;
+
+	l = strlen(self->message);
+	for (e = self->teammaster; e; e = e->teamchain)
+	{
+		if (!e->count)
+			continue;
+		n = e->count - 1;
+		if (n > l)
+		{
+			e->s.frame = 12;
+			continue;
+		}
+
+		c = self->message[n];
+		if (c >= '0' && c <= '9')
+			e->s.frame = c - '0';
+		else if (c == '-')
+			e->s.frame = 10;
+		else if (c == ':')
+			e->s.frame = 11;
+		else
+			e->s.frame = 12;
+	}
+}
+
+void SP_target_string (edict_t *self)
+{
+	if (!self->message)
+		self->message = "";
+	self->use = target_string_use;
+}
+
+
+/*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
+target a target_string with this
+
+The default is to be a time of day clock
+
+TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
+If START_OFF, this entity must be used before it starts
+
+"style"		0 "xx"
+			1 "xx:xx"
+			2 "xx:xx:xx"
+*/
+
+#define	CLOCK_MESSAGE_SIZE	16
+
+// don't let field width of any clock messages change, or it
+// could cause an overwrite after a game load
+
+static void func_clock_reset (edict_t *self)
+{
+	self->activator = NULL;
+	if (self->spawnflags & 1)
+	{
+		self->health = 0;
+		self->wait = self->count;
+	}
+	else if (self->spawnflags & 2)
+	{
+		self->health = self->count;
+		self->wait = 0;
+	}
+}
+
+static void func_clock_format_countdown (edict_t *self)
+{
+	if (self->style == 0)
+	{
+		Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health);
+		return;
+	}
+
+	if (self->style == 1)
+	{
+		Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60);
+		if (self->message[3] == ' ')
+			self->message[3] = '0';
+		return;
+	}
+
+	if (self->style == 2)
+	{
+		Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60);
+		if (self->message[3] == ' ')
+			self->message[3] = '0';
+		if (self->message[6] == ' ')
+			self->message[6] = '0';
+		return;
+	}
+}
+
+void func_clock_think (edict_t *self)
+{
+	if (!self->enemy)
+	{
+		self->enemy = G_Find (NULL, FOFS(targetname), self->target);
+		if (!self->enemy)
+			return;
+	}
+
+	if (self->spawnflags & 1)
+	{
+		func_clock_format_countdown (self);
+		self->health++;
+	}
+	else if (self->spawnflags & 2)
+	{
+		func_clock_format_countdown (self);
+		self->health--;
+	}
+	else
+	{
+		struct tm	*ltime;
+		time_t		gmtime;
+
+		time(&gmtime);
+		ltime = localtime(&gmtime);
+		Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
+		if (self->message[3] == ' ')
+			self->message[3] = '0';
+		if (self->message[6] == ' ')
+			self->message[6] = '0';
+	}
+
+	self->enemy->message = self->message;
+	self->enemy->use (self->enemy, self, self);
+
+	if (((self->spawnflags & 1) && (self->health > self->wait)) ||
+		((self->spawnflags & 2) && (self->health < self->wait)))
+	{
+		if (self->pathtarget)
+		{
+			char *savetarget;
+			char *savemessage;
+
+			savetarget = self->target;
+			savemessage = self->message;
+			self->target = self->pathtarget;
+			self->message = NULL;
+			G_UseTargets (self, self->activator);
+			self->target = savetarget;
+			self->message = savemessage;
+		}
+
+		if (!(self->spawnflags & 8))
+			return;
+
+		func_clock_reset (self);
+
+		if (self->spawnflags & 4)
+			return;
+	}
+
+	self->nextthink = level.time + 1;
+}
+
+void func_clock_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (!(self->spawnflags & 8))
+		self->use = NULL;
+	if (self->activator)
+		return;
+	self->activator = activator;
+	self->think (self);
+}
+
+void SP_func_clock (edict_t *self)
+{
+	if (!self->target)
+	{
+		gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if ((self->spawnflags & 2) && (!self->count))
+	{
+		gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if ((self->spawnflags & 1) && (!self->count))
+		self->count = 60*60;;
+
+	func_clock_reset (self);
+
+	self->message = gi.TagMalloc (CLOCK_MESSAGE_SIZE, TAG_LEVEL);
+
+	self->think = func_clock_think;
+
+	if (self->spawnflags & 4)
+		self->use = func_clock_use;
+	else
+		self->nextthink = level.time + 1;
+}
+
+//=================================================================================
+
+void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	edict_t		*dest;
+	int			i;
+
+	if (!other->client)
+		return;
+	dest = G_Find (NULL, FOFS(targetname), self->target);
+	if (!dest)
+	{
+		gi.dprintf ("Couldn't find destination\n");
+		return;
+	}
+
+//ZOID
+	CTFPlayerResetGrapple(other);
+//ZOID
+
+	// unlink to make sure it can't possibly interfere with KillBox
+	gi.unlinkentity (other);
+
+	VectorCopy (dest->s.origin, other->s.origin);
+	VectorCopy (dest->s.origin, other->s.old_origin);
+	other->s.origin[2] += 10;
+
+	// clear the velocity and hold them in place briefly
+	VectorClear (other->velocity);
+	other->client->ps.pmove.pm_time = 160>>3;		// hold time
+	other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
+
+	// draw the teleport splash at source and on the player
+	self->owner->s.event = EV_PLAYER_TELEPORT;
+	other->s.event = EV_PLAYER_TELEPORT;
+
+	// set angles
+	for (i=0 ; i<3 ; i++)
+		other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
+
+	VectorClear (other->s.angles);
+	VectorClear (other->client->ps.viewangles);
+	VectorClear (other->client->v_angle);
+
+	// kill anything at the destination
+	KillBox (other);
+
+	gi.linkentity (other);
+}
+
+/*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
+Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
+*/
+void SP_misc_teleporter (edict_t *ent)
+{
+	edict_t		*trig;
+
+	if (!ent->target)
+	{
+		gi.dprintf ("teleporter without a target.\n");
+		G_FreeEdict (ent);
+		return;
+	}
+
+	gi.setmodel (ent, "models/objects/dmspot/tris.md2");
+	ent->s.skinnum = 1;
+	ent->s.effects = EF_TELEPORTER;
+	ent->s.sound = gi.soundindex ("world/amb10.wav");
+	ent->solid = SOLID_BBOX;
+
+	VectorSet (ent->mins, -32, -32, -24);
+	VectorSet (ent->maxs, 32, 32, -16);
+	gi.linkentity (ent);
+
+	trig = G_Spawn ();
+	trig->touch = teleporter_touch;
+	trig->solid = SOLID_TRIGGER;
+	trig->target = ent->target;
+	trig->owner = ent;
+	VectorCopy (ent->s.origin, trig->s.origin);
+	VectorSet (trig->mins, -8, -8, 8);
+	VectorSet (trig->maxs, 8, 8, 24);
+	gi.linkentity (trig);
+	
+}
+
+/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
+Point teleporters at these.
+*/
+void SP_misc_teleporter_dest (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/dmspot/tris.md2");
+	ent->s.skinnum = 0;
+	ent->solid = SOLID_BBOX;
+//	ent->s.effects |= EF_FLIES;
+	VectorSet (ent->mins, -32, -32, -24);
+	VectorSet (ent->maxs, 32, 32, -16);
+	gi.linkentity (ent);
+}
+
--- /dev/null
+++ b/ctf/g_monster.c
@@ -1,0 +1,740 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+//
+// monster weapons
+//
+
+//FIXME mosnters should call these with a totally accurate direction
+// and we can mess it up based on skill.  Spread should be for normal
+// and we can tighten or loosen based on skill.  We could muck with
+// the damages too, but I'm not sure that's such a good idea.
+void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
+{
+	fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
+{
+	fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
+{
+	fire_blaster (self, start, dir, damage, speed, effect, false);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}	
+
+void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
+{
+	fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
+{
+	fire_rocket (self, start, dir, damage, speed, damage+20, damage);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}	
+
+void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
+{
+	fire_rail (self, start, aimdir, damage, kick);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
+{
+	fire_bfg (self, start, aimdir, damage, speed, damage_radius);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+
+
+//
+// Monster utility functions
+//
+
+static void M_FliesOff (edict_t *self)
+{
+	self->s.effects &= ~EF_FLIES;
+	self->s.sound = 0;
+}
+
+static void M_FliesOn (edict_t *self)
+{
+	if (self->waterlevel)
+		return;
+	self->s.effects |= EF_FLIES;
+	self->s.sound = gi.soundindex ("infantry/inflies1.wav");
+	self->think = M_FliesOff;
+	self->nextthink = level.time + 60;
+}
+
+void M_FlyCheck (edict_t *self)
+{
+	if (self->waterlevel)
+		return;
+
+	if (random() > 0.5)
+		return;
+
+	self->think = M_FliesOn;
+	self->nextthink = level.time + 5 + 10 * random();
+}
+
+void AttackFinished (edict_t *self, float time)
+{
+	self->monsterinfo.attack_finished = level.time + time;
+}
+
+
+void M_CheckGround (edict_t *ent)
+{
+	vec3_t		point;
+	trace_t		trace;
+
+	if (ent->flags & (FL_SWIM|FL_FLY))
+		return;
+
+	if (ent->velocity[2] > 100)
+	{
+		ent->groundentity = NULL;
+		return;
+	}
+
+// if the hull point one-quarter unit down is solid the entity is on ground
+	point[0] = ent->s.origin[0];
+	point[1] = ent->s.origin[1];
+	point[2] = ent->s.origin[2] - 0.25;
+
+	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
+
+	// check steepness
+	if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
+	{
+		ent->groundentity = NULL;
+		return;
+	}
+
+//	ent->groundentity = trace.ent;
+//	ent->groundentity_linkcount = trace.ent->linkcount;
+//	if (!trace.startsolid && !trace.allsolid)
+//		VectorCopy (trace.endpos, ent->s.origin);
+	if (!trace.startsolid && !trace.allsolid)
+	{
+		VectorCopy (trace.endpos, ent->s.origin);
+		ent->groundentity = trace.ent;
+		ent->groundentity_linkcount = trace.ent->linkcount;
+		ent->velocity[2] = 0;
+	}
+}
+
+
+void M_CatagorizePosition (edict_t *ent)
+{
+	vec3_t		point;
+	int			cont;
+
+//
+// get waterlevel
+//
+	point[0] = ent->s.origin[0];
+	point[1] = ent->s.origin[1];
+	point[2] = ent->s.origin[2] + ent->mins[2] + 1;	
+	cont = gi.pointcontents (point);
+
+	if (!(cont & MASK_WATER))
+	{
+		ent->waterlevel = 0;
+		ent->watertype = 0;
+		return;
+	}
+
+	ent->watertype = cont;
+	ent->waterlevel = 1;
+	point[2] += 26;
+	cont = gi.pointcontents (point);
+	if (!(cont & MASK_WATER))
+		return;
+
+	ent->waterlevel = 2;
+	point[2] += 22;
+	cont = gi.pointcontents (point);
+	if (cont & MASK_WATER)
+		ent->waterlevel = 3;
+}
+
+
+void M_WorldEffects (edict_t *ent)
+{
+	int		dmg;
+
+	if (ent->health > 0)
+	{
+		if (!(ent->flags & FL_SWIM))
+		{
+			if (ent->waterlevel < 3)
+			{
+				ent->air_finished = level.time + 12;
+			}
+			else if (ent->air_finished < level.time)
+			{	// drown!
+				if (ent->pain_debounce_time < level.time)
+				{
+					dmg = 2 + 2 * floor(level.time - ent->air_finished);
+					if (dmg > 15)
+						dmg = 15;
+					T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
+					ent->pain_debounce_time = level.time + 1;
+				}
+			}
+		}
+		else
+		{
+			if (ent->waterlevel > 0)
+			{
+				ent->air_finished = level.time + 9;
+			}
+			else if (ent->air_finished < level.time)
+			{	// suffocate!
+				if (ent->pain_debounce_time < level.time)
+				{
+					dmg = 2 + 2 * floor(level.time - ent->air_finished);
+					if (dmg > 15)
+						dmg = 15;
+					T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
+					ent->pain_debounce_time = level.time + 1;
+				}
+			}
+		}
+	}
+	
+	if (ent->waterlevel == 0)
+	{
+		if (ent->flags & FL_INWATER)
+		{	
+			gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
+			ent->flags &= ~FL_INWATER;
+		}
+		return;
+	}
+
+	if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
+	{
+		if (ent->damage_debounce_time < level.time)
+		{
+			ent->damage_debounce_time = level.time + 0.2;
+			T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
+		}
+	}
+	if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
+	{
+		if (ent->damage_debounce_time < level.time)
+		{
+			ent->damage_debounce_time = level.time + 1;
+			T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
+		}
+	}
+	
+	if ( !(ent->flags & FL_INWATER) )
+	{	
+		if (!(ent->svflags & SVF_DEADMONSTER))
+		{
+			if (ent->watertype & CONTENTS_LAVA)
+				if (random() <= 0.5)
+					gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
+			else if (ent->watertype & CONTENTS_SLIME)
+				gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+			else if (ent->watertype & CONTENTS_WATER)
+				gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+		}
+
+		ent->flags |= FL_INWATER;
+		ent->damage_debounce_time = 0;
+	}
+}
+
+
+void M_droptofloor (edict_t *ent)
+{
+	vec3_t		end;
+	trace_t		trace;
+
+	ent->s.origin[2] += 1;
+	VectorCopy (ent->s.origin, end);
+	end[2] -= 256;
+	
+	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
+
+	if (trace.fraction == 1 || trace.allsolid)
+		return;
+
+	VectorCopy (trace.endpos, ent->s.origin);
+
+	gi.linkentity (ent);
+	M_CheckGround (ent);
+	M_CatagorizePosition (ent);
+}
+
+
+void M_SetEffects (edict_t *ent)
+{
+	ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
+	ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
+
+	if (ent->monsterinfo.aiflags & AI_RESURRECTING)
+	{
+		ent->s.effects |= EF_COLOR_SHELL;
+		ent->s.renderfx |= RF_SHELL_RED;
+	}
+
+	if (ent->health <= 0)
+		return;
+
+	if (ent->powerarmor_time > level.time)
+	{
+		if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
+		{
+			ent->s.effects |= EF_POWERSCREEN;
+		}
+		else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
+		{
+			ent->s.effects |= EF_COLOR_SHELL;
+			ent->s.renderfx |= RF_SHELL_GREEN;
+		}
+	}
+}
+
+
+void M_MoveFrame (edict_t *self)
+{
+	mmove_t	*move;
+	int		index;
+
+	move = self->monsterinfo.currentmove;
+	self->nextthink = level.time + FRAMETIME;
+
+	if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
+	{
+		self->s.frame = self->monsterinfo.nextframe;
+		self->monsterinfo.nextframe = 0;
+	}
+	else
+	{
+		if (self->s.frame == move->lastframe)
+		{
+			if (move->endfunc)
+			{
+				move->endfunc (self);
+
+				// regrab move, endfunc is very likely to change it
+				move = self->monsterinfo.currentmove;
+
+				// check for death
+				if (self->svflags & SVF_DEADMONSTER)
+					return;
+			}
+		}
+
+		if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
+		{
+			self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+			self->s.frame = move->firstframe;
+		}
+		else
+		{
+			if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
+			{
+				self->s.frame++;
+				if (self->s.frame > move->lastframe)
+					self->s.frame = move->firstframe;
+			}
+		}
+	}
+
+	index = self->s.frame - move->firstframe;
+	if (move->frame[index].aifunc)
+		if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
+			move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
+		else
+			move->frame[index].aifunc (self, 0);
+
+	if (move->frame[index].thinkfunc)
+		move->frame[index].thinkfunc (self);
+}
+
+
+void monster_think (edict_t *self)
+{
+	M_MoveFrame (self);
+	if (self->linkcount != self->monsterinfo.linkcount)
+	{
+		self->monsterinfo.linkcount = self->linkcount;
+		M_CheckGround (self);
+	}
+	M_CatagorizePosition (self);
+	M_WorldEffects (self);
+	M_SetEffects (self);
+}
+
+
+/*
+================
+monster_use
+
+Using a monster makes it angry at the current activator
+================
+*/
+void monster_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->enemy)
+		return;
+	if (self->health <= 0)
+		return;
+	if (activator->flags & FL_NOTARGET)
+		return;
+	if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
+		return;
+	
+// delay reaction so if the monster is teleported, its sound is still heard
+	self->enemy = activator;
+	FoundTarget (self);
+}
+
+
+void monster_start_go (edict_t *self);
+
+
+void monster_triggered_spawn (edict_t *self)
+{
+	self->s.origin[2] += 1;
+	KillBox (self);
+
+	self->solid = SOLID_BBOX;
+	self->movetype = MOVETYPE_STEP;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->air_finished = level.time + 12;
+	gi.linkentity (self);
+
+	monster_start_go (self);
+
+	if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
+	{
+		FoundTarget (self);
+	}
+	else
+	{
+		self->enemy = NULL;
+	}
+}
+
+void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	// we have a one frame delay here so we don't telefrag the guy who activated us
+	self->think = monster_triggered_spawn;
+	self->nextthink = level.time + FRAMETIME;
+	if (activator->client)
+		self->enemy = activator;
+	self->use = monster_use;
+}
+
+void monster_triggered_start (edict_t *self)
+{
+	self->solid = SOLID_NOT;
+	self->movetype = MOVETYPE_NONE;
+	self->svflags |= SVF_NOCLIENT;
+	self->nextthink = 0;
+	self->use = monster_triggered_spawn_use;
+}
+
+
+/*
+================
+monster_death_use
+
+When a monster dies, it fires all of its targets with the current
+enemy as activator.
+================
+*/
+void monster_death_use (edict_t *self)
+{
+	self->flags &= ~(FL_FLY|FL_SWIM);
+	self->monsterinfo.aiflags &= AI_GOOD_GUY;
+
+	if (self->item)
+	{
+		Drop_Item (self, self->item);
+		self->item = NULL;
+	}
+
+	if (self->deathtarget)
+		self->target = self->deathtarget;
+
+	if (!self->target)
+		return;
+
+	G_UseTargets (self, self->enemy);
+}
+
+
+//============================================================================
+
+qboolean monster_start (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return false;
+	}
+
+	if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
+	{
+		self->spawnflags &= ~4;
+		self->spawnflags |= 1;
+//		gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
+	}
+
+	if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
+		level.total_monsters++;
+
+	self->nextthink = level.time + FRAMETIME;
+	self->svflags |= SVF_MONSTER;
+	self->s.renderfx |= RF_FRAMELERP;
+	self->takedamage = DAMAGE_AIM;
+	self->air_finished = level.time + 12;
+	self->use = monster_use;
+	self->max_health = self->health;
+	self->clipmask = MASK_MONSTERSOLID;
+
+	self->s.skinnum = 0;
+	self->deadflag = DEAD_NO;
+	self->svflags &= ~SVF_DEADMONSTER;
+
+	if (!self->monsterinfo.checkattack)
+		self->monsterinfo.checkattack = M_CheckAttack;
+	VectorCopy (self->s.origin, self->s.old_origin);
+
+	if (st.item)
+	{
+		self->item = FindItemByClassname (st.item);
+		if (!self->item)
+			gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
+	}
+
+	// randomize what frame they start on
+	if (self->monsterinfo.currentmove)
+		self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
+
+	return true;
+}
+
+void monster_start_go (edict_t *self)
+{
+	vec3_t	v;
+
+	if (self->health <= 0)
+		return;
+
+	// check for target to combat_point and change to combattarget
+	if (self->target)
+	{
+		qboolean	notcombat;
+		qboolean	fixup;
+		edict_t		*target;
+
+		target = NULL;
+		notcombat = false;
+		fixup = false;
+		while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
+		{
+			if (strcmp(target->classname, "point_combat") == 0)
+			{
+				self->combattarget = self->target;
+				fixup = true;
+			}
+			else
+			{
+				notcombat = true;
+			}
+		}
+		if (notcombat && self->combattarget)
+			gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
+		if (fixup)
+			self->target = NULL;
+	}
+
+	// validate combattarget
+	if (self->combattarget)
+	{
+		edict_t		*target;
+
+		target = NULL;
+		while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
+		{
+			if (strcmp(target->classname, "point_combat") != 0)
+			{
+				gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
+					self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
+					self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
+					(int)target->s.origin[2]);
+			}
+		}
+	}
+
+	if (self->target)
+	{
+		self->goalentity = self->movetarget = G_PickTarget(self->target);
+		if (!self->movetarget)
+		{
+			gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
+			self->target = NULL;
+			self->monsterinfo.pausetime = 100000000;
+			self->monsterinfo.stand (self);
+		}
+		else if (strcmp (self->movetarget->classname, "path_corner") == 0)
+		{
+			VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+			self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
+			self->monsterinfo.walk (self);
+			self->target = NULL;
+		}
+		else
+		{
+			self->goalentity = self->movetarget = NULL;
+			self->monsterinfo.pausetime = 100000000;
+			self->monsterinfo.stand (self);
+		}
+	}
+	else
+	{
+		self->monsterinfo.pausetime = 100000000;
+		self->monsterinfo.stand (self);
+	}
+
+	self->think = monster_think;
+	self->nextthink = level.time + FRAMETIME;
+}
+
+
+void walkmonster_start_go (edict_t *self)
+{
+	if (!(self->spawnflags & 2) && level.time < 1)
+	{
+		M_droptofloor (self);
+
+		if (self->groundentity)
+			if (!M_walkmove (self, 0, 0))
+				gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
+	}
+	
+	if (!self->yaw_speed)
+		self->yaw_speed = 20;
+	self->viewheight = 25;
+
+	monster_start_go (self);
+
+	if (self->spawnflags & 2)
+		monster_triggered_start (self);
+}
+
+void walkmonster_start (edict_t *self)
+{
+	self->think = walkmonster_start_go;
+	monster_start (self);
+}
+
+
+void flymonster_start_go (edict_t *self)
+{
+	if (!M_walkmove (self, 0, 0))
+		gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
+
+	if (!self->yaw_speed)
+		self->yaw_speed = 10;
+	self->viewheight = 25;
+
+	monster_start_go (self);
+
+	if (self->spawnflags & 2)
+		monster_triggered_start (self);
+}
+
+
+void flymonster_start (edict_t *self)
+{
+	self->flags |= FL_FLY;
+	self->think = flymonster_start_go;
+	monster_start (self);
+}
+
+
+void swimmonster_start_go (edict_t *self)
+{
+	if (!self->yaw_speed)
+		self->yaw_speed = 10;
+	self->viewheight = 10;
+
+	monster_start_go (self);
+
+	if (self->spawnflags & 2)
+		monster_triggered_start (self);
+}
+
+void swimmonster_start (edict_t *self)
+{
+	self->flags |= FL_SWIM;
+	self->think = swimmonster_start_go;
+	monster_start (self);
+}
--- /dev/null
+++ b/ctf/g_phys.c
@@ -1,0 +1,959 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_phys.c
+
+#include "g_local.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.
+
+*/
+
+
+/*
+============
+SV_TestEntityPosition
+
+============
+*/
+edict_t	*SV_TestEntityPosition (edict_t *ent)
+{
+	trace_t	trace;
+	int		mask;
+
+	
+	if (ent->clipmask)
+		mask = ent->clipmask;
+	else
+		mask = MASK_SOLID;
+	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
+
+	if (trace.startsolid)
+		return g_edicts;
+		
+	return NULL;
+}
+
+
+/*
+================
+SV_CheckVelocity
+================
+*/
+void SV_CheckVelocity (edict_t *ent)
+{
+	int		i;
+
+//
+// bound velocity
+//
+	for (i=0 ; i<3 ; i++)
+	{
+		if (ent->velocity[i] > sv_maxvelocity->value)
+			ent->velocity[i] = sv_maxvelocity->value;
+		else if (ent->velocity[i] < -sv_maxvelocity->value)
+			ent->velocity[i] = -sv_maxvelocity->value;
+	}
+}
+
+/*
+=============
+SV_RunThink
+
+Runs thinking code for this frame if necessary
+=============
+*/
+qboolean SV_RunThink (edict_t *ent)
+{
+	float	thinktime;
+
+	thinktime = ent->nextthink;
+	if (thinktime <= 0)
+		return true;
+	if (thinktime > level.time+0.001)
+		return true;
+	
+	ent->nextthink = 0;
+	if (!ent->think)
+		gi.error ("NULL ent->think");
+	ent->think (ent);
+
+	return false;
+}
+
+/*
+==================
+SV_Impact
+
+Two entities have touched, so run their touch functions
+==================
+*/
+void SV_Impact (edict_t *e1, trace_t *trace)
+{
+	edict_t		*e2;
+//	cplane_t	backplane;
+
+	e2 = trace->ent;
+
+	if (e1->touch && e1->solid != SOLID_NOT)
+		e1->touch (e1, e2, &trace->plane, trace->surface);
+	
+	if (e2->touch && e2->solid != SOLID_NOT)
+		e2->touch (e2, e1, NULL, NULL);
+}
+
+
+/*
+==================
+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
+============
+*/
+#define	MAX_CLIP_PLANES	5
+int SV_FlyMove (edict_t *ent, float time, int mask)
+{
+	edict_t		*hit;
+	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->velocity, original_velocity);
+	VectorCopy (ent->velocity, primal_velocity);
+	numplanes = 0;
+	
+	time_left = time;
+
+	ent->groundentity = NULL;
+	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+	{
+		for (i=0 ; i<3 ; i++)
+			end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
+
+		trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
+
+		if (trace.allsolid)
+		{	// entity is trapped in another solid
+			VectorCopy (vec3_origin, ent->velocity);
+			return 3;
+		}
+
+		if (trace.fraction > 0)
+		{	// actually covered some distance
+			VectorCopy (trace.endpos, ent->s.origin);
+			VectorCopy (ent->velocity, original_velocity);
+			numplanes = 0;
+		}
+
+		if (trace.fraction == 1)
+			 break;		// moved the entire distance
+
+		hit = trace.ent;
+
+		if (trace.plane.normal[2] > 0.7)
+		{
+			blocked |= 1;		// floor
+			if ( hit->solid == SOLID_BSP)
+			{
+				ent->groundentity = hit;
+				ent->groundentity_linkcount = hit->linkcount;
+			}
+		}
+		if (!trace.plane.normal[2])
+		{
+			blocked |= 2;		// step
+		}
+
+//
+// run the impact function
+//
+		SV_Impact (ent, &trace);
+		if (!ent->inuse)
+			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->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->velocity);
+		}
+		else
+		{	// go along the crease
+			if (numplanes != 2)
+			{
+//				gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
+				VectorCopy (vec3_origin, ent->velocity);
+				return 7;
+			}
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, ent->velocity);
+			VectorScale (dir, d, ent->velocity);
+		}
+
+//
+// if original velocity is against the original velocity, stop dead
+// to avoid tiny occilations in sloping corners
+//
+		if (DotProduct (ent->velocity, primal_velocity) <= 0)
+		{
+			VectorCopy (vec3_origin, ent->velocity);
+			return blocked;
+		}
+	}
+
+	return blocked;
+}
+
+
+/*
+============
+SV_AddGravity
+
+============
+*/
+void SV_AddGravity (edict_t *ent)
+{
+	ent->velocity[2] -= ent->gravity * sv_gravity->value * 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	start;
+	vec3_t	end;
+	int		mask;
+
+	VectorCopy (ent->s.origin, start);
+	VectorAdd (start, push, end);
+
+retry:
+	if (ent->clipmask)
+		mask = ent->clipmask;
+	else
+		mask = MASK_SOLID;
+
+	trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
+	
+	VectorCopy (trace.endpos, ent->s.origin);
+	gi.linkentity (ent);
+
+	if (trace.fraction != 1.0)
+	{
+		SV_Impact (ent, &trace);
+
+		// if the pushed entity went away and the pusher is still there
+		if (!trace.ent->inuse && ent->inuse)
+		{
+			// move the pusher back and try again
+			VectorCopy (start, ent->s.origin);
+			gi.linkentity (ent);
+			goto retry;
+		}
+	}
+
+	if (ent->inuse)
+		G_TouchTriggers (ent);
+
+	return trace;
+}					
+
+
+typedef struct
+{
+	edict_t	*ent;
+	vec3_t	origin;
+	vec3_t	angles;
+	float	deltayaw;
+} pushed_t;
+pushed_t	pushed[MAX_EDICTS], *pushed_p;
+
+edict_t	*obstacle;
+
+/*
+============
+SV_Push
+
+Objects need to be moved back on a failed push,
+otherwise riders would continue to slide.
+============
+*/
+qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
+{
+	int			i, e;
+	edict_t		*check, *block;
+	vec3_t		mins, maxs;
+	pushed_t	*p;
+	vec3_t		org, org2, move2, forward, right, up;
+
+	// clamp the move to 1/8 units, so the position will
+	// be accurate for client side prediction
+	for (i=0 ; i<3 ; i++)
+	{
+		float	temp;
+		temp = move[i]*8.0;
+		if (temp > 0.0)
+			temp += 0.5;
+		else
+			temp -= 0.5;
+		move[i] = 0.125 * (int)temp;
+	}
+
+	// find the bounding box
+	for (i=0 ; i<3 ; i++)
+	{
+		mins[i] = pusher->absmin[i] + move[i];
+		maxs[i] = pusher->absmax[i] + move[i];
+	}
+
+// we need this for pushing things later
+	VectorSubtract (vec3_origin, amove, org);
+	AngleVectors (org, forward, right, up);
+
+// save the pusher's original position
+	pushed_p->ent = pusher;
+	VectorCopy (pusher->s.origin, pushed_p->origin);
+	VectorCopy (pusher->s.angles, pushed_p->angles);
+	if (pusher->client)
+		pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
+	pushed_p++;
+
+// move the pusher to it's final position
+	VectorAdd (pusher->s.origin, move, pusher->s.origin);
+	VectorAdd (pusher->s.angles, amove, pusher->s.angles);
+	gi.linkentity (pusher);
+
+// see if any solid entities are inside the final position
+	check = g_edicts+1;
+	for (e = 1; e < globals.num_edicts; e++, check++)
+	{
+		if (!check->inuse)
+			continue;
+		if (check->movetype == MOVETYPE_PUSH
+		|| check->movetype == MOVETYPE_STOP
+		|| check->movetype == MOVETYPE_NONE
+		|| check->movetype == MOVETYPE_NOCLIP)
+			continue;
+
+		if (!check->area.prev)
+			continue;		// not linked in anywhere
+
+	// if the entity is standing on the pusher, it will definitely be moved
+		if (check->groundentity != pusher)
+		{
+			// see if the ent needs to be tested
+			if ( check->absmin[0] >= maxs[0]
+			|| check->absmin[1] >= maxs[1]
+			|| check->absmin[2] >= maxs[2]
+			|| check->absmax[0] <= mins[0]
+			|| check->absmax[1] <= mins[1]
+			|| check->absmax[2] <= mins[2] )
+				continue;
+
+			// see if the ent's bbox is inside the pusher's final position
+			if (!SV_TestEntityPosition (check))
+				continue;
+		}
+
+		if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
+		{
+			// move this entity
+			pushed_p->ent = check;
+			VectorCopy (check->s.origin, pushed_p->origin);
+			VectorCopy (check->s.angles, pushed_p->angles);
+			pushed_p++;
+
+			// try moving the contacted entity 
+			VectorAdd (check->s.origin, move, check->s.origin);
+			if (check->client)
+			{	// FIXME: doesn't rotate monsters?
+				check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
+			}
+
+			// figure movement due to the pusher's amove
+			VectorSubtract (check->s.origin, pusher->s.origin, org);
+			org2[0] = DotProduct (org, forward);
+			org2[1] = -DotProduct (org, right);
+			org2[2] = DotProduct (org, up);
+			VectorSubtract (org2, org, move2);
+			VectorAdd (check->s.origin, move2, check->s.origin);
+
+			// may have pushed them off an edge
+			if (check->groundentity != pusher)
+				check->groundentity = NULL;
+
+			block = SV_TestEntityPosition (check);
+			if (!block)
+			{	// pushed ok
+				gi.linkentity (check);
+				// impact?
+				continue;
+			}
+
+			// if it is ok to leave in the old position, do it
+			// this is only relevent for riding entities, not pushed
+			// FIXME: this doesn't acount for rotation
+			VectorSubtract (check->s.origin, move, check->s.origin);
+			block = SV_TestEntityPosition (check);
+			if (!block)
+			{
+				pushed_p--;
+				continue;
+			}
+		}
+		
+		// save off the obstacle so we can call the block function
+		obstacle = check;
+
+		// move back any entities we already moved
+		// go backwards, so if the same entity was pushed
+		// twice, it goes back to the original position
+		for (p=pushed_p-1 ; p>=pushed ; p--)
+		{
+			VectorCopy (p->origin, p->ent->s.origin);
+			VectorCopy (p->angles, p->ent->s.angles);
+			if (p->ent->client)
+			{
+				p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
+			}
+			gi.linkentity (p->ent);
+		}
+		return false;
+	}
+
+//FIXME: is there a better way to handle this?
+	// see if anything we moved has touched a trigger
+	for (p=pushed_p-1 ; p>=pushed ; p--)
+		G_TouchTriggers (p->ent);
+
+	return true;
+}
+
+/*
+================
+SV_Physics_Pusher
+
+Bmodel objects don't interact with each other, but
+push all box objects
+================
+*/
+void SV_Physics_Pusher (edict_t *ent)
+{
+	vec3_t		move, amove;
+	edict_t		*part, *mv;
+
+	// if not a team captain, so movement will be handled elsewhere
+	if ( ent->flags & FL_TEAMSLAVE)
+		return;
+
+	// make sure all team slaves can move before commiting
+	// any moves or calling any think functions
+	// if the move is blocked, all moved objects will be backed out
+//retry:
+	pushed_p = pushed;
+	for (part = ent ; part ; part=part->teamchain)
+	{
+		if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
+			part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
+			)
+		{	// object is moving
+			VectorScale (part->velocity, FRAMETIME, move);
+			VectorScale (part->avelocity, FRAMETIME, amove);
+
+			if (!SV_Push (part, move, amove))
+				break;	// move was blocked
+		}
+	}
+	if (pushed_p > &pushed[MAX_EDICTS])
+		gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
+
+	if (part)
+	{
+		// the move failed, bump all nextthink times and back out moves
+		for (mv = ent ; mv ; mv=mv->teamchain)
+		{
+			if (mv->nextthink > 0)
+				mv->nextthink += FRAMETIME;
+		}
+
+		// if the pusher has a "blocked" function, call it
+		// otherwise, just stay in place until the obstacle is gone
+		if (part->blocked)
+			part->blocked (part, obstacle);
+#if 0
+		// if the pushed entity went away and the pusher is still there
+		if (!obstacle->inuse && part->inuse)
+			goto retry;
+#endif
+	}
+	else
+	{
+		// the move succeeded, so call all think functions
+		for (part = ent ; part ; part=part->teamchain)
+		{
+			SV_RunThink (part);
+		}
+	}
+}
+
+//==================================================================
+
+/*
+=============
+SV_Physics_None
+
+Non moving objects can only think
+=============
+*/
+void SV_Physics_None (edict_t *ent)
+{
+// regular thinking
+	SV_RunThink (ent);
+}
+
+/*
+=============
+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->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
+	VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
+
+	gi.linkentity (ent);
+}
+
+/*
+==============================================================================
+
+TOSS / BOUNCE
+
+==============================================================================
+*/
+
+/*
+=============
+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;
+	edict_t		*slave;
+	qboolean	wasinwater;
+	qboolean	isinwater;
+	vec3_t		old_origin;
+
+// regular thinking
+	SV_RunThink (ent);
+
+	// if not a team captain, so movement will be handled elsewhere
+	if ( ent->flags & FL_TEAMSLAVE)
+		return;
+
+	if (ent->velocity[2] > 0)
+		ent->groundentity = NULL;
+
+// check for the groundentity going away
+	if (ent->groundentity)
+		if (!ent->groundentity->inuse)
+			ent->groundentity = NULL;
+
+// if onground, return without moving
+	if ( ent->groundentity )
+		return;
+
+	VectorCopy (ent->s.origin, old_origin);
+
+	SV_CheckVelocity (ent);
+
+// add gravity
+	if (ent->movetype != MOVETYPE_FLY
+	&& ent->movetype != MOVETYPE_FLYMISSILE)
+		SV_AddGravity (ent);
+
+// move angles
+	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
+
+// move origin
+	VectorScale (ent->velocity, FRAMETIME, move);
+	trace = SV_PushEntity (ent, move);
+	if (!ent->inuse)
+		return;
+
+	if (trace.fraction < 1)
+	{
+		if (ent->movetype == MOVETYPE_BOUNCE)
+			backoff = 1.5;
+		else
+			backoff = 1;
+
+		ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
+
+	// stop if on ground
+		if (trace.plane.normal[2] > 0.7)
+		{		
+			if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
+			{
+				ent->groundentity = trace.ent;
+				ent->groundentity_linkcount = trace.ent->linkcount;
+				VectorCopy (vec3_origin, ent->velocity);
+				VectorCopy (vec3_origin, ent->avelocity);
+			}
+		}
+
+//		if (ent->touch)
+//			ent->touch (ent, trace.ent, &trace.plane, trace.surface);
+	}
+	
+// check for water transition
+	wasinwater = (ent->watertype & MASK_WATER);
+	ent->watertype = gi.pointcontents (ent->s.origin);
+	isinwater = ent->watertype & MASK_WATER;
+
+	if (isinwater)
+		ent->waterlevel = 1;
+	else
+		ent->waterlevel = 0;
+
+	if (!wasinwater && isinwater)
+		gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
+	else if (wasinwater && !isinwater)
+		gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
+
+// move teamslaves
+	for (slave = ent->teamchain; slave; slave = slave->teamchain)
+	{
+		VectorCopy (ent->s.origin, slave->s.origin);
+		gi.linkentity (slave);
+	}
+}
+
+/*
+===============================================================================
+
+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.
+FIXME: is this true?
+=============
+*/
+
+//FIXME: hacked in for E3 demo
+#define	sv_stopspeed		100
+#define sv_friction			6
+#define sv_waterfriction	1
+
+void SV_AddRotationalFriction (edict_t *ent)
+{
+	int		n;
+	float	adjustment;
+
+	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
+	adjustment = FRAMETIME * sv_stopspeed * sv_friction;
+	for (n = 0; n < 3; n++)
+	{
+		if (ent->avelocity[n] > 0)
+		{
+			ent->avelocity[n] -= adjustment;
+			if (ent->avelocity[n] < 0)
+				ent->avelocity[n] = 0;
+		}
+		else
+		{
+			ent->avelocity[n] += adjustment;
+			if (ent->avelocity[n] > 0)
+				ent->avelocity[n] = 0;
+		}
+	}
+}
+
+void SV_Physics_Step (edict_t *ent)
+{
+	qboolean	wasonground;
+	qboolean	hitsound = false;
+	float		*vel;
+	float		speed, newspeed, control;
+	float		friction;
+	edict_t		*groundentity;
+	int			mask;
+
+	// airborn monsters should always check for ground
+	if (!ent->groundentity)
+		M_CheckGround (ent);
+
+	groundentity = ent->groundentity;
+
+	SV_CheckVelocity (ent);
+
+	if (groundentity)
+		wasonground = true;
+	else
+		wasonground = false;
+		
+	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
+		SV_AddRotationalFriction (ent);
+
+	// add gravity except:
+	//   flying monsters
+	//   swimming monsters who are in the water
+	if (! wasonground)
+		if (!(ent->flags & FL_FLY))
+			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
+			{
+				if (ent->velocity[2] < sv_gravity->value*-0.1)
+					hitsound = true;
+				if (ent->waterlevel == 0)
+					SV_AddGravity (ent);
+			}
+
+	// friction for flying monsters that have been given vertical velocity
+	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
+	{
+		speed = fabs(ent->velocity[2]);
+		control = speed < sv_stopspeed ? sv_stopspeed : speed;
+		friction = sv_friction/3;
+		newspeed = speed - (FRAMETIME * control * friction);
+		if (newspeed < 0)
+			newspeed = 0;
+		newspeed /= speed;
+		ent->velocity[2] *= newspeed;
+	}
+
+	// friction for flying monsters that have been given vertical velocity
+	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
+	{
+		speed = fabs(ent->velocity[2]);
+		control = speed < sv_stopspeed ? sv_stopspeed : speed;
+		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
+		if (newspeed < 0)
+			newspeed = 0;
+		newspeed /= speed;
+		ent->velocity[2] *= newspeed;
+	}
+
+	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
+	{
+		// apply friction
+		// let dead monsters who aren't completely onground slide
+		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
+			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
+			{
+				vel = ent->velocity;
+				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
+				if (speed)
+				{
+					friction = sv_friction;
+
+					control = speed < sv_stopspeed ? sv_stopspeed : speed;
+					newspeed = speed - FRAMETIME*control*friction;
+
+					if (newspeed < 0)
+						newspeed = 0;
+					newspeed /= speed;
+
+					vel[0] *= newspeed;
+					vel[1] *= newspeed;
+				}
+			}
+
+		if (ent->svflags & SVF_MONSTER)
+			mask = MASK_MONSTERSOLID;
+		else
+			mask = MASK_SOLID;
+		SV_FlyMove (ent, FRAMETIME, mask);
+
+		gi.linkentity (ent);
+		G_TouchTriggers (ent);
+
+		if (ent->groundentity)
+			if (!wasonground)
+				if (hitsound)
+					gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
+	}
+
+// regular thinking
+	SV_RunThink (ent);
+}
+
+//============================================================================
+/*
+================
+G_RunEntity
+
+================
+*/
+void G_RunEntity (edict_t *ent)
+{
+	if (ent->prethink)
+		ent->prethink (ent);
+
+	switch ( (int)ent->movetype)
+	{
+	case MOVETYPE_PUSH:
+	case MOVETYPE_STOP:
+		SV_Physics_Pusher (ent);
+		break;
+	case MOVETYPE_NONE:
+		SV_Physics_None (ent);
+		break;
+	case MOVETYPE_NOCLIP:
+		SV_Physics_Noclip (ent);
+		break;
+	case MOVETYPE_STEP:
+		SV_Physics_Step (ent);
+		break;
+	case MOVETYPE_TOSS:
+	case MOVETYPE_BOUNCE:
+	case MOVETYPE_FLY:
+	case MOVETYPE_FLYMISSILE:
+		SV_Physics_Toss (ent);
+		break;
+	default:
+		gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);			
+	}
+}
--- /dev/null
+++ b/ctf/g_save.c
@@ -1,0 +1,743 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+field_t fields[] = {
+	{"classname", FOFS(classname), F_LSTRING},
+	{"origin", FOFS(s.origin), F_VECTOR},
+	{"model", FOFS(model), F_LSTRING},
+	{"spawnflags", FOFS(spawnflags), F_INT},
+	{"speed", FOFS(speed), F_FLOAT},
+	{"accel", FOFS(accel), F_FLOAT},
+	{"decel", FOFS(decel), F_FLOAT},
+	{"target", FOFS(target), F_LSTRING},
+	{"targetname", FOFS(targetname), F_LSTRING},
+	{"pathtarget", FOFS(pathtarget), F_LSTRING},
+	{"deathtarget", FOFS(deathtarget), F_LSTRING},
+	{"killtarget", FOFS(killtarget), F_LSTRING},
+	{"combattarget", FOFS(combattarget), F_LSTRING},
+	{"message", FOFS(message), F_LSTRING},
+	{"team", FOFS(team), F_LSTRING},
+	{"wait", FOFS(wait), F_FLOAT},
+	{"delay", FOFS(delay), F_FLOAT},
+	{"random", FOFS(random), F_FLOAT},
+	{"move_origin", FOFS(move_origin), F_VECTOR},
+	{"move_angles", FOFS(move_angles), F_VECTOR},
+	{"style", FOFS(style), F_INT},
+	{"count", FOFS(count), F_INT},
+	{"health", FOFS(health), F_INT},
+	{"sounds", FOFS(sounds), F_INT},
+	{"light", 0, F_IGNORE},
+	{"dmg", FOFS(dmg), F_INT},
+	{"angles", FOFS(s.angles), F_VECTOR},
+	{"angle", FOFS(s.angles), F_ANGLEHACK},
+	{"mass", FOFS(mass), F_INT},
+	{"volume", FOFS(volume), F_FLOAT},
+	{"attenuation", FOFS(attenuation), F_FLOAT},
+	{"map", FOFS(map), F_LSTRING},
+
+	// temp spawn vars -- only valid when the spawn function is called
+	{"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
+	{"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
+	{"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
+	{"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
+	{"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
+	{"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
+	{"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
+	{"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
+	{"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
+	{"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
+	{"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
+	{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
+	{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
+	{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
+	{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}
+};
+
+// -------- just for savegames ----------
+// all pointer fields should be listed here, or savegames
+// won't work properly (they will crash and burn).
+// this wasn't just tacked on to the fields array, because
+// these don't need names, we wouldn't want map fields using
+// some of these, and if one were accidentally present twice
+// it would double swizzle (fuck) the pointer.
+
+field_t		savefields[] =
+{
+	{"", FOFS(classname), F_LSTRING},
+	{"", FOFS(target), F_LSTRING},
+	{"", FOFS(targetname), F_LSTRING},
+	{"", FOFS(killtarget), F_LSTRING},
+	{"", FOFS(team), F_LSTRING},
+	{"", FOFS(pathtarget), F_LSTRING},
+	{"", FOFS(deathtarget), F_LSTRING},
+	{"", FOFS(combattarget), F_LSTRING},
+	{"", FOFS(model), F_LSTRING},
+	{"", FOFS(map), F_LSTRING},
+	{"", FOFS(message), F_LSTRING},
+
+	{"", FOFS(client), F_CLIENT},
+	{"", FOFS(item), F_ITEM},
+
+	{"", FOFS(goalentity), F_EDICT},
+	{"", FOFS(movetarget), F_EDICT},
+	{"", FOFS(enemy), F_EDICT},
+	{"", FOFS(oldenemy), F_EDICT},
+	{"", FOFS(activator), F_EDICT},
+	{"", FOFS(groundentity), F_EDICT},
+	{"", FOFS(teamchain), F_EDICT},
+	{"", FOFS(teammaster), F_EDICT},
+	{"", FOFS(owner), F_EDICT},
+	{"", FOFS(mynoise), F_EDICT},
+	{"", FOFS(mynoise2), F_EDICT},
+	{"", FOFS(target_ent), F_EDICT},
+	{"", FOFS(chain), F_EDICT},
+
+	{NULL, 0, F_INT}
+};
+
+field_t		levelfields[] =
+{
+	{"", LLOFS(changemap), F_LSTRING},
+
+	{"", LLOFS(sight_client), F_EDICT},
+	{"", LLOFS(sight_entity), F_EDICT},
+	{"", LLOFS(sound_entity), F_EDICT},
+	{"", LLOFS(sound2_entity), F_EDICT},
+
+	{NULL, 0, F_INT}
+};
+
+field_t		clientfields[] =
+{
+	{"", CLOFS(pers.weapon), F_ITEM},
+	{"", CLOFS(pers.lastweapon), F_ITEM},
+	{"", CLOFS(newweapon), F_ITEM},
+
+	{NULL, 0, F_INT}
+};
+
+/*
+============
+InitGame
+
+This will be called when the dll is first loaded, which
+only happens when a new game is started or a save game
+is loaded.
+============
+*/
+void InitGame (void)
+{
+	gi.dprintf ("==== InitGame ====\n");
+
+	gun_x = gi.cvar ("gun_x", "0", 0);
+	gun_y = gi.cvar ("gun_y", "0", 0);
+	gun_z = gi.cvar ("gun_z", "0", 0);
+
+	//FIXME: sv_ prefix is wrong for these
+	sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
+	sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
+	sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
+	sv_gravity = gi.cvar ("sv_gravity", "800", 0);
+
+	// noset vars
+	dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
+
+	// latched vars
+	sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
+	gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
+	gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
+
+	maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
+	deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
+	coop = gi.cvar ("coop", "0", CVAR_LATCH);
+	skill = gi.cvar ("skill", "1", CVAR_LATCH);
+	maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
+
+//ZOID
+//This game.dll only supports deathmatch
+	if (!deathmatch->value) {
+		gi.dprintf("Forcing deathmatch.");
+		gi.cvar_set("deathmatch", "1");
+	}
+	//force coop off
+	if (coop->value)
+		gi.cvar_set("coop", "0");
+//ZOID
+
+
+	// change anytime vars
+	dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
+	fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
+	timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
+//ZOID
+	capturelimit = gi.cvar ("capturelimit", "0", CVAR_SERVERINFO);
+	instantweap = gi.cvar ("instantweap", "0", CVAR_SERVERINFO);
+//ZOID
+ 	password = gi.cvar ("password", "", CVAR_USERINFO);
+
+	g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
+
+	run_pitch = gi.cvar ("run_pitch", "0.002", 0);
+	run_roll = gi.cvar ("run_roll", "0.005", 0);
+	bob_up  = gi.cvar ("bob_up", "0.005", 0);
+	bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
+	bob_roll = gi.cvar ("bob_roll", "0.002", 0);
+
+	// flood control
+	flood_msgs = gi.cvar ("flood_msgs", "4", 0);
+	flood_persecond = gi.cvar ("flood_persecond", "4", 0);
+	flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
+
+	// dm map list
+	sv_maplist = gi.cvar ("sv_maplist", "", 0);
+
+	// items
+	InitItems ();
+
+	Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
+
+	Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
+
+	// initialize all entities for this game
+	game.maxentities = maxentities->value;
+	g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
+	globals.edicts = g_edicts;
+	globals.max_edicts = game.maxentities;
+
+	// initialize all clients for this game
+	game.maxclients = maxclients->value;
+	game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
+	globals.num_edicts = game.maxclients+1;
+
+//ZOID
+	CTFInit();
+//ZOID
+}
+
+//=========================================================
+
+void WriteField1 (FILE *f, field_t *field, byte *base)
+{
+	void		*p;
+	int			len;
+	int			index;
+
+	p = (void *)(base + field->ofs);
+	switch (field->type)
+	{
+	case F_INT:
+	case F_FLOAT:
+	case F_ANGLEHACK:
+	case F_VECTOR:
+	case F_IGNORE:
+		break;
+
+	case F_LSTRING:
+	case F_GSTRING:
+		if ( *(char **)p )
+			len = strlen(*(char **)p) + 1;
+		else
+			len = 0;
+		*(int *)p = len;
+		break;
+	case F_EDICT:
+		if ( *(edict_t **)p == NULL)
+			index = -1;
+		else
+			index = *(edict_t **)p - g_edicts;
+		*(int *)p = index;
+		break;
+	case F_CLIENT:
+		if ( *(gclient_t **)p == NULL)
+			index = -1;
+		else
+			index = *(gclient_t **)p - game.clients;
+		*(int *)p = index;
+		break;
+	case F_ITEM:
+		if ( *(edict_t **)p == NULL)
+			index = -1;
+		else
+			index = *(gitem_t **)p - itemlist;
+		*(int *)p = index;
+		break;
+
+	default:
+		gi.error ("WriteEdict: unknown field type");
+	}
+}
+
+void WriteField2 (FILE *f, field_t *field, byte *base)
+{
+	int			len;
+	void		*p;
+
+	p = (void *)(base + field->ofs);
+	switch (field->type)
+	{
+	case F_LSTRING:
+	case F_GSTRING:
+		if ( *(char **)p )
+		{
+			len = strlen(*(char **)p) + 1;
+			fwrite (*(char **)p, len, 1, f);
+		}
+		break;
+	}
+}
+
+void ReadField (FILE *f, field_t *field, byte *base)
+{
+	void		*p;
+	int			len;
+	int			index;
+
+	p = (void *)(base + field->ofs);
+	switch (field->type)
+	{
+	case F_INT:
+	case F_FLOAT:
+	case F_ANGLEHACK:
+	case F_VECTOR:
+	case F_IGNORE:
+		break;
+
+	case F_LSTRING:
+		len = *(int *)p;
+		if (!len)
+			*(char **)p = NULL;
+		else
+		{
+			*(char **)p = gi.TagMalloc (len, TAG_LEVEL);
+			fread (*(char **)p, len, 1, f);
+		}
+		break;
+	case F_GSTRING:
+		len = *(int *)p;
+		if (!len)
+			*(char **)p = NULL;
+		else
+		{
+			*(char **)p = gi.TagMalloc (len, TAG_GAME);
+			fread (*(char **)p, len, 1, f);
+		}
+		break;
+	case F_EDICT:
+		index = *(int *)p;
+		if ( index == -1 )
+			*(edict_t **)p = NULL;
+		else
+			*(edict_t **)p = &g_edicts[index];
+		break;
+	case F_CLIENT:
+		index = *(int *)p;
+		if ( index == -1 )
+			*(gclient_t **)p = NULL;
+		else
+			*(gclient_t **)p = &game.clients[index];
+		break;
+	case F_ITEM:
+		index = *(int *)p;
+		if ( index == -1 )
+			*(gitem_t **)p = NULL;
+		else
+			*(gitem_t **)p = &itemlist[index];
+		break;
+
+	default:
+		gi.error ("ReadEdict: unknown field type");
+	}
+}
+
+//=========================================================
+
+/*
+==============
+WriteClient
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void WriteClient (FILE *f, gclient_t *client)
+{
+	field_t		*field;
+	gclient_t	temp;
+	
+	// all of the ints, floats, and vectors stay as they are
+	temp = *client;
+
+	// change the pointers to lengths or indexes
+	for (field=clientfields ; field->name ; field++)
+	{
+		WriteField1 (f, field, (byte *)&temp);
+	}
+
+	// write the block
+	fwrite (&temp, sizeof(temp), 1, f);
+
+	// now write any allocated data following the edict
+	for (field=clientfields ; field->name ; field++)
+	{
+		WriteField2 (f, field, (byte *)client);
+	}
+}
+
+/*
+==============
+ReadClient
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void ReadClient (FILE *f, gclient_t *client)
+{
+	field_t		*field;
+
+	fread (client, sizeof(*client), 1, f);
+
+	for (field=clientfields ; field->name ; field++)
+	{
+		ReadField (f, field, (byte *)client);
+	}
+}
+
+/*
+============
+WriteGame
+
+This will be called whenever the game goes to a new level,
+and when the user explicitly saves the game.
+
+Game information include cross level data, like multi level
+triggers, help computer info, and all client states.
+
+A single player death will automatically restore from the
+last save position.
+============
+*/
+void WriteGame (char *filename, qboolean autosave)
+{
+	FILE	*f;
+	int		i;
+	char	str[16];
+
+	if (!autosave)
+		SaveClientData ();
+
+	f = fopen (filename, "wb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	memset (str, 0, sizeof(str));
+	strcpy (str, __DATE__);
+	fwrite (str, sizeof(str), 1, f);
+
+	game.autosaved = autosave;
+	fwrite (&game, sizeof(game), 1, f);
+	game.autosaved = false;
+
+	for (i=0 ; i<game.maxclients ; i++)
+		WriteClient (f, &game.clients[i]);
+
+	fclose (f);
+}
+
+void ReadGame (char *filename)
+{
+	FILE	*f;
+	int		i;
+	char	str[16];
+
+	gi.FreeTags (TAG_GAME);
+
+	f = fopen (filename, "rb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	fread (str, sizeof(str), 1, f);
+	if (strcmp (str, __DATE__))
+	{
+		fclose (f);
+		gi.error ("Savegame from an older version.\n");
+	}
+
+	g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
+	globals.edicts = g_edicts;
+
+	fread (&game, sizeof(game), 1, f);
+	game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
+	for (i=0 ; i<game.maxclients ; i++)
+		ReadClient (f, &game.clients[i]);
+
+	fclose (f);
+}
+
+//==========================================================
+
+
+/*
+==============
+WriteEdict
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void WriteEdict (FILE *f, edict_t *ent)
+{
+	field_t		*field;
+	edict_t		temp;
+
+	// all of the ints, floats, and vectors stay as they are
+	temp = *ent;
+
+	// change the pointers to lengths or indexes
+	for (field=savefields ; field->name ; field++)
+	{
+		WriteField1 (f, field, (byte *)&temp);
+	}
+
+	// write the block
+	fwrite (&temp, sizeof(temp), 1, f);
+
+	// now write any allocated data following the edict
+	for (field=savefields ; field->name ; field++)
+	{
+		WriteField2 (f, field, (byte *)ent);
+	}
+
+}
+
+/*
+==============
+WriteLevelLocals
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void WriteLevelLocals (FILE *f)
+{
+	field_t		*field;
+	level_locals_t		temp;
+
+	// all of the ints, floats, and vectors stay as they are
+	temp = level;
+
+	// change the pointers to lengths or indexes
+	for (field=levelfields ; field->name ; field++)
+	{
+		WriteField1 (f, field, (byte *)&temp);
+	}
+
+	// write the block
+	fwrite (&temp, sizeof(temp), 1, f);
+
+	// now write any allocated data following the edict
+	for (field=levelfields ; field->name ; field++)
+	{
+		WriteField2 (f, field, (byte *)&level);
+	}
+}
+
+
+/*
+==============
+ReadEdict
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void ReadEdict (FILE *f, edict_t *ent)
+{
+	field_t		*field;
+
+	fread (ent, sizeof(*ent), 1, f);
+
+	for (field=savefields ; field->name ; field++)
+	{
+		ReadField (f, field, (byte *)ent);
+	}
+}
+
+/*
+==============
+ReadLevelLocals
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void ReadLevelLocals (FILE *f)
+{
+	field_t		*field;
+
+	fread (&level, sizeof(level), 1, f);
+
+	for (field=levelfields ; field->name ; field++)
+	{
+		ReadField (f, field, (byte *)&level);
+	}
+}
+
+/*
+=================
+WriteLevel
+
+=================
+*/
+void WriteLevel (char *filename)
+{
+	int		i;
+	edict_t	*ent;
+	FILE	*f;
+	void	*base;
+
+	f = fopen (filename, "wb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	// write out edict size for checking
+	i = sizeof(edict_t);
+	fwrite (&i, sizeof(i), 1, f);
+
+	// write out a function pointer for checking
+	base = (void *)InitGame;
+	fwrite (&base, sizeof(base), 1, f);
+
+	// write out level_locals_t
+	WriteLevelLocals (f);
+
+	// write out all the entities
+	for (i=0 ; i<globals.num_edicts ; i++)
+	{
+		ent = &g_edicts[i];
+		if (!ent->inuse)
+			continue;
+		fwrite (&i, sizeof(i), 1, f);
+		WriteEdict (f, ent);
+	}
+	i = -1;
+	fwrite (&i, sizeof(i), 1, f);
+
+	fclose (f);
+}
+
+
+/*
+=================
+ReadLevel
+
+SpawnEntities will allready have been called on the
+level the same way it was when the level was saved.
+
+That is necessary to get the baselines
+set up identically.
+
+The server will have cleared all of the world links before
+calling ReadLevel.
+
+No clients are connected yet.
+=================
+*/
+void ReadLevel (char *filename)
+{
+	int		entnum;
+	FILE	*f;
+	int		i;
+	void	*base;
+	edict_t	*ent;
+
+	f = fopen (filename, "rb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	// free any dynamic memory allocated by loading the level
+	// base state
+	gi.FreeTags (TAG_LEVEL);
+
+	// wipe all the entities
+	memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
+	globals.num_edicts = maxclients->value+1;
+
+	// check edict size
+	fread (&i, sizeof(i), 1, f);
+	if (i != sizeof(edict_t))
+	{
+		fclose (f);
+		gi.error ("ReadLevel: mismatched edict size");
+	}
+
+	// check function pointer base address
+	fread (&base, sizeof(base), 1, f);
+	if (base != (void *)InitGame)
+	{
+		fclose (f);
+		gi.error ("ReadLevel: function pointers have moved");
+	}
+
+	// load the level locals
+	ReadLevelLocals (f);
+
+	// load all the entities
+	while (1)
+	{
+		if (fread (&entnum, sizeof(entnum), 1, f) != 1)
+		{
+			fclose (f);
+			gi.error ("ReadLevel: failed to read entnum");
+		}
+		if (entnum == -1)
+			break;
+		if (entnum >= globals.num_edicts)
+			globals.num_edicts = entnum+1;
+
+		ent = &g_edicts[entnum];
+		ReadEdict (f, ent);
+
+		// let the server rebuild world links for this ent
+		memset (&ent->area, 0, sizeof(ent->area));
+		gi.linkentity (ent);
+	}
+
+	fclose (f);
+
+	// mark all clients as unconnected
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = &g_edicts[i+1];
+		ent->client = game.clients + i;
+		ent->client->pers.connected = false;
+	}
+
+	// do any load time things at this point
+	for (i=0 ; i<globals.num_edicts ; i++)
+	{
+		ent = &g_edicts[i];
+
+		if (!ent->inuse)
+			continue;
+
+		// fire any cross-level triggers
+		if (ent->classname)
+			if (strcmp(ent->classname, "target_crosslevel_target") == 0)
+				ent->nextthink = level.time + ent->delay;
+	}
+}
+
--- /dev/null
+++ b/ctf/g_spawn.c
@@ -1,0 +1,998 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+typedef struct
+{
+	char	*name;
+	void	(*spawn)(edict_t *ent);
+} spawn_t;
+
+
+void SP_item_health (edict_t *self);
+void SP_item_health_small (edict_t *self);
+void SP_item_health_large (edict_t *self);
+void SP_item_health_mega (edict_t *self);
+
+void SP_info_player_start (edict_t *ent);
+void SP_info_player_deathmatch (edict_t *ent);
+void SP_info_player_coop (edict_t *ent);
+void SP_info_player_intermission (edict_t *ent);
+
+void SP_func_plat (edict_t *ent);
+void SP_func_rotating (edict_t *ent);
+void SP_func_button (edict_t *ent);
+void SP_func_door (edict_t *ent);
+void SP_func_door_secret (edict_t *ent);
+void SP_func_door_rotating (edict_t *ent);
+void SP_func_water (edict_t *ent);
+void SP_func_train (edict_t *ent);
+void SP_func_conveyor (edict_t *self);
+void SP_func_wall (edict_t *self);
+void SP_func_object (edict_t *self);
+void SP_func_explosive (edict_t *self);
+void SP_func_timer (edict_t *self);
+void SP_func_areaportal (edict_t *ent);
+void SP_func_clock (edict_t *ent);
+void SP_func_killbox (edict_t *ent);
+
+void SP_trigger_always (edict_t *ent);
+void SP_trigger_once (edict_t *ent);
+void SP_trigger_multiple (edict_t *ent);
+void SP_trigger_relay (edict_t *ent);
+void SP_trigger_push (edict_t *ent);
+void SP_trigger_hurt (edict_t *ent);
+void SP_trigger_key (edict_t *ent);
+void SP_trigger_counter (edict_t *ent);
+void SP_trigger_elevator (edict_t *ent);
+void SP_trigger_gravity (edict_t *ent);
+void SP_trigger_monsterjump (edict_t *ent);
+
+void SP_target_temp_entity (edict_t *ent);
+void SP_target_speaker (edict_t *ent);
+void SP_target_explosion (edict_t *ent);
+void SP_target_changelevel (edict_t *ent);
+void SP_target_secret (edict_t *ent);
+void SP_target_goal (edict_t *ent);
+void SP_target_splash (edict_t *ent);
+void SP_target_spawner (edict_t *ent);
+void SP_target_blaster (edict_t *ent);
+void SP_target_crosslevel_trigger (edict_t *ent);
+void SP_target_crosslevel_target (edict_t *ent);
+void SP_target_laser (edict_t *self);
+void SP_target_help (edict_t *ent);
+void SP_target_actor (edict_t *ent);
+void SP_target_lightramp (edict_t *self);
+void SP_target_earthquake (edict_t *ent);
+void SP_target_character (edict_t *ent);
+void SP_target_string (edict_t *ent);
+
+void SP_worldspawn (edict_t *ent);
+void SP_viewthing (edict_t *ent);
+
+void SP_light (edict_t *self);
+void SP_light_mine1 (edict_t *ent);
+void SP_light_mine2 (edict_t *ent);
+void SP_info_null (edict_t *self);
+void SP_info_notnull (edict_t *self);
+void SP_path_corner (edict_t *self);
+void SP_point_combat (edict_t *self);
+
+void SP_misc_explobox (edict_t *self);
+void SP_misc_banner (edict_t *self);
+void SP_misc_satellite_dish (edict_t *self);
+void SP_misc_actor (edict_t *self);
+void SP_misc_gib_arm (edict_t *self);
+void SP_misc_gib_leg (edict_t *self);
+void SP_misc_gib_head (edict_t *self);
+void SP_misc_insane (edict_t *self);
+void SP_misc_deadsoldier (edict_t *self);
+void SP_misc_viper (edict_t *self);
+void SP_misc_viper_bomb (edict_t *self);
+void SP_misc_bigviper (edict_t *self);
+void SP_misc_strogg_ship (edict_t *self);
+void SP_misc_teleporter (edict_t *self);
+void SP_misc_teleporter_dest (edict_t *self);
+void SP_misc_blackhole (edict_t *self);
+void SP_misc_eastertank (edict_t *self);
+void SP_misc_easterchick (edict_t *self);
+void SP_misc_easterchick2 (edict_t *self);
+
+void SP_monster_berserk (edict_t *self);
+void SP_monster_gladiator (edict_t *self);
+void SP_monster_gunner (edict_t *self);
+void SP_monster_infantry (edict_t *self);
+void SP_monster_soldier_light (edict_t *self);
+void SP_monster_soldier (edict_t *self);
+void SP_monster_soldier_ss (edict_t *self);
+void SP_monster_tank (edict_t *self);
+void SP_monster_medic (edict_t *self);
+void SP_monster_flipper (edict_t *self);
+void SP_monster_chick (edict_t *self);
+void SP_monster_parasite (edict_t *self);
+void SP_monster_flyer (edict_t *self);
+void SP_monster_brain (edict_t *self);
+void SP_monster_floater (edict_t *self);
+void SP_monster_hover (edict_t *self);
+void SP_monster_mutant (edict_t *self);
+void SP_monster_supertank (edict_t *self);
+void SP_monster_boss2 (edict_t *self);
+void SP_monster_jorg (edict_t *self);
+void SP_monster_boss3_stand (edict_t *self);
+
+void SP_monster_commander_body (edict_t *self);
+
+void SP_turret_breach (edict_t *self);
+void SP_turret_base (edict_t *self);
+void SP_turret_driver (edict_t *self);
+
+
+spawn_t	spawns[] = {
+	{"item_health", SP_item_health},
+	{"item_health_small", SP_item_health_small},
+	{"item_health_large", SP_item_health_large},
+	{"item_health_mega", SP_item_health_mega},
+
+	{"info_player_start", SP_info_player_start},
+	{"info_player_deathmatch", SP_info_player_deathmatch},
+	{"info_player_coop", SP_info_player_coop},
+	{"info_player_intermission", SP_info_player_intermission},
+//ZOID
+	{"info_player_team1", SP_info_player_team1},
+	{"info_player_team2", SP_info_player_team2},
+//ZOID
+
+	{"func_plat", SP_func_plat},
+	{"func_button", SP_func_button},
+	{"func_door", SP_func_door},
+	{"func_door_secret", SP_func_door_secret},
+	{"func_door_rotating", SP_func_door_rotating},
+	{"func_rotating", SP_func_rotating},
+	{"func_train", SP_func_train},
+	{"func_water", SP_func_water},
+	{"func_conveyor", SP_func_conveyor},
+	{"func_areaportal", SP_func_areaportal},
+	{"func_clock", SP_func_clock},
+	{"func_wall", SP_func_wall},
+	{"func_object", SP_func_object},
+	{"func_timer", SP_func_timer},
+	{"func_explosive", SP_func_explosive},
+	{"func_killbox", SP_func_killbox},
+
+	{"trigger_always", SP_trigger_always},
+	{"trigger_once", SP_trigger_once},
+	{"trigger_multiple", SP_trigger_multiple},
+	{"trigger_relay", SP_trigger_relay},
+	{"trigger_push", SP_trigger_push},
+	{"trigger_hurt", SP_trigger_hurt},
+	{"trigger_key", SP_trigger_key},
+	{"trigger_counter", SP_trigger_counter},
+	{"trigger_elevator", SP_trigger_elevator},
+	{"trigger_gravity", SP_trigger_gravity},
+	{"trigger_monsterjump", SP_trigger_monsterjump},
+
+	{"target_temp_entity", SP_target_temp_entity},
+	{"target_speaker", SP_target_speaker},
+	{"target_explosion", SP_target_explosion},
+	{"target_changelevel", SP_target_changelevel},
+	{"target_secret", SP_target_secret},
+	{"target_goal", SP_target_goal},
+	{"target_splash", SP_target_splash},
+	{"target_spawner", SP_target_spawner},
+	{"target_blaster", SP_target_blaster},
+	{"target_crosslevel_trigger", SP_target_crosslevel_trigger},
+	{"target_crosslevel_target", SP_target_crosslevel_target},
+	{"target_laser", SP_target_laser},
+	{"target_help", SP_target_help},
+#if 0 // remove monster code
+	{"target_actor", SP_target_actor},
+#endif
+	{"target_lightramp", SP_target_lightramp},
+	{"target_earthquake", SP_target_earthquake},
+	{"target_character", SP_target_character},
+	{"target_string", SP_target_string},
+
+	{"worldspawn", SP_worldspawn},
+	{"viewthing", SP_viewthing},
+
+	{"light", SP_light},
+	{"light_mine1", SP_light_mine1},
+	{"light_mine2", SP_light_mine2},
+	{"info_null", SP_info_null},
+	{"func_group", SP_info_null},
+	{"info_notnull", SP_info_notnull},
+	{"path_corner", SP_path_corner},
+	{"point_combat", SP_point_combat},
+
+	{"misc_explobox", SP_misc_explobox},
+	{"misc_banner", SP_misc_banner},
+//ZOID
+	{"misc_ctf_banner", SP_misc_ctf_banner},
+	{"misc_ctf_small_banner", SP_misc_ctf_small_banner},
+//ZOID
+	{"misc_satellite_dish", SP_misc_satellite_dish},
+#if 0 // remove monster code
+	{"misc_actor", SP_misc_actor},
+#endif
+	{"misc_gib_arm", SP_misc_gib_arm},
+	{"misc_gib_leg", SP_misc_gib_leg},
+	{"misc_gib_head", SP_misc_gib_head},
+#if 0 // remove monster code
+	{"misc_insane", SP_misc_insane},
+#endif
+	{"misc_deadsoldier", SP_misc_deadsoldier},
+	{"misc_viper", SP_misc_viper},
+	{"misc_viper_bomb", SP_misc_viper_bomb},
+	{"misc_bigviper", SP_misc_bigviper},
+	{"misc_strogg_ship", SP_misc_strogg_ship},
+	{"misc_teleporter", SP_misc_teleporter},
+	{"misc_teleporter_dest", SP_misc_teleporter_dest},
+//ZOID
+	{"trigger_teleport", SP_trigger_teleport},
+	{"info_teleport_destination", SP_info_teleport_destination},
+//ZOID
+	{"misc_blackhole", SP_misc_blackhole},
+	{"misc_eastertank", SP_misc_eastertank},
+	{"misc_easterchick", SP_misc_easterchick},
+	{"misc_easterchick2", SP_misc_easterchick2},
+
+#if 0 // remove monster code
+	{"monster_berserk", SP_monster_berserk},
+	{"monster_gladiator", SP_monster_gladiator},
+	{"monster_gunner", SP_monster_gunner},
+	{"monster_infantry", SP_monster_infantry},
+	{"monster_soldier_light", SP_monster_soldier_light},
+	{"monster_soldier", SP_monster_soldier},
+	{"monster_soldier_ss", SP_monster_soldier_ss},
+	{"monster_tank", SP_monster_tank},
+	{"monster_tank_commander", SP_monster_tank},
+	{"monster_medic", SP_monster_medic},
+	{"monster_flipper", SP_monster_flipper},
+	{"monster_chick", SP_monster_chick},
+	{"monster_parasite", SP_monster_parasite},
+	{"monster_flyer", SP_monster_flyer},
+	{"monster_brain", SP_monster_brain},
+	{"monster_floater", SP_monster_floater},
+	{"monster_hover", SP_monster_hover},
+	{"monster_mutant", SP_monster_mutant},
+	{"monster_supertank", SP_monster_supertank},
+	{"monster_boss2", SP_monster_boss2},
+	{"monster_boss3_stand", SP_monster_boss3_stand},
+	{"monster_jorg", SP_monster_jorg},
+
+	{"monster_commander_body", SP_monster_commander_body},
+
+	{"turret_breach", SP_turret_breach},
+	{"turret_base", SP_turret_base},
+	{"turret_driver", SP_turret_driver},
+#endif
+
+	{NULL, NULL}
+};
+
+/*
+===============
+ED_CallSpawn
+
+Finds the spawn function for the entity and calls it
+===============
+*/
+void ED_CallSpawn (edict_t *ent)
+{
+	spawn_t	*s;
+	gitem_t	*item;
+	int		i;
+
+	if (!ent->classname)
+	{
+		gi.dprintf ("ED_CallSpawn: NULL classname\n");
+		return;
+	}
+
+	// check item spawn functions
+	for (i=0,item=itemlist ; i<game.num_items ; i++,item++)
+	{
+		if (!item->classname)
+			continue;
+		if (!strcmp(item->classname, ent->classname))
+		{	// found it
+			SpawnItem (ent, item);
+			return;
+		}
+	}
+
+	// check normal spawn functions
+	for (s=spawns ; s->name ; s++)
+	{
+		if (!strcmp(s->name, ent->classname))
+		{	// found it
+			s->spawn (ent);
+			return;
+		}
+	}
+	gi.dprintf ("%s doesn't have a spawn function\n", ent->classname);
+}
+
+/*
+=============
+ED_NewString
+=============
+*/
+char *ED_NewString (char *string)
+{
+	char	*newb, *new_p;
+	int		i,l;
+	
+	l = strlen(string) + 1;
+
+	newb = gi.TagMalloc (l, TAG_LEVEL);
+
+	new_p = newb;
+
+	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 newb;
+}
+
+
+
+
+/*
+===============
+ED_ParseField
+
+Takes a key/value pair and sets the binary values
+in an edict
+===============
+*/
+void ED_ParseField (char *key, char *value, edict_t *ent)
+{
+	field_t	*f;
+	byte	*b;
+	float	v;
+	vec3_t	vec;
+
+	for (f=fields ; f->name ; f++)
+	{
+		if (!Q_stricmp(f->name, key))
+		{	// found it
+			if (f->flags & FFL_SPAWNTEMP)
+				b = (byte *)&st;
+			else
+				b = (byte *)ent;
+
+			switch (f->type)
+			{
+			case F_LSTRING:
+				*(char **)(b+f->ofs) = ED_NewString (value);
+				break;
+			case F_VECTOR:
+				sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
+				((float *)(b+f->ofs))[0] = vec[0];
+				((float *)(b+f->ofs))[1] = vec[1];
+				((float *)(b+f->ofs))[2] = vec[2];
+				break;
+			case F_INT:
+				*(int *)(b+f->ofs) = atoi(value);
+				break;
+			case F_FLOAT:
+				*(float *)(b+f->ofs) = atof(value);
+				break;
+			case F_ANGLEHACK:
+				v = atof(value);
+				((float *)(b+f->ofs))[0] = 0;
+				((float *)(b+f->ofs))[1] = v;
+				((float *)(b+f->ofs))[2] = 0;
+				break;
+			case F_IGNORE:
+				break;
+			}
+			return;
+		}
+	}
+	gi.dprintf ("%s is not a field\n", key);
+}
+
+/*
+====================
+ED_ParseEdict
+
+Parses an edict out of the given string, returning the new position
+ed should be a properly initialized empty edict.
+====================
+*/
+char *ED_ParseEdict (char *data, edict_t *ent)
+{
+	qboolean	init;
+	char		keyname[256];
+	char		*com_token;
+
+	init = false;
+	memset (&st, 0, sizeof(st));
+
+// go through all the dictionary pairs
+	while (1)
+	{	
+	// parse key
+		com_token = COM_Parse (&data);
+		if (com_token[0] == '}')
+			break;
+		if (!data)
+			gi.error ("ED_ParseEntity: EOF without closing brace");
+
+		strncpy (keyname, com_token, sizeof(keyname)-1);
+		
+	// parse value	
+		com_token = COM_Parse (&data);
+		if (!data)
+			gi.error ("ED_ParseEntity: EOF without closing brace");
+
+		if (com_token[0] == '}')
+			gi.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;
+
+		ED_ParseField (keyname, com_token, ent);
+	}
+
+	if (!init)
+		memset (ent, 0, sizeof(*ent));
+
+	return data;
+}
+
+
+/*
+================
+G_FindTeams
+
+Chain together all entities with a matching team field.
+
+All but the first will have the FL_TEAMSLAVE flag set.
+All but the last will have the teamchain field set to the next one
+================
+*/
+void G_FindTeams (void)
+{
+	edict_t	*e, *e2, *chain;
+	int		i, j;
+	int		c, c2;
+
+	c = 0;
+	c2 = 0;
+	for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
+	{
+		if (!e->inuse)
+			continue;
+		if (!e->team)
+			continue;
+		if (e->flags & FL_TEAMSLAVE)
+			continue;
+		chain = e;
+		e->teammaster = e;
+		c++;
+		c2++;
+		for (j=i+1, e2=e+1 ; j < globals.num_edicts ; j++,e2++)
+		{
+			if (!e2->inuse)
+				continue;
+			if (!e2->team)
+				continue;
+			if (e2->flags & FL_TEAMSLAVE)
+				continue;
+			if (!strcmp(e->team, e2->team))
+			{
+				c2++;
+				chain->teamchain = e2;
+				e2->teammaster = e;
+				chain = e2;
+				e2->flags |= FL_TEAMSLAVE;
+			}
+		}
+	}
+
+	gi.dprintf ("%i teams with %i entities\n", c, c2);
+}
+
+/*
+==============
+SpawnEntities
+
+Creates a server's entity / program execution context by
+parsing textual entity definitions out of an ent file.
+==============
+*/
+void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
+{
+	edict_t		*ent;
+	int			inhibit;
+	char		*com_token;
+	int			i;
+	float		skill_level;
+
+	skill_level = floor (skill->value);
+	if (skill_level < 0)
+		skill_level = 0;
+	if (skill_level > 3)
+		skill_level = 3;
+	if (skill->value != skill_level)
+		gi.cvar_forceset("skill", va("%f", skill_level));
+
+	SaveClientData ();
+
+	gi.FreeTags (TAG_LEVEL);
+
+	memset (&level, 0, sizeof(level));
+	memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));
+
+	strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
+	strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);
+
+	// set client fields on player ents
+	for (i=0 ; i<game.maxclients ; i++)
+		g_edicts[i+1].client = game.clients + i;
+
+	ent = NULL;
+	inhibit = 0;
+
+// parse ents
+	while (1)
+	{
+		// parse the opening brace	
+		com_token = COM_Parse (&entities);
+		if (!entities)
+			break;
+		if (com_token[0] != '{')
+			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);
+
+		if (!ent)
+			ent = g_edicts;
+		else
+			ent = G_Spawn ();
+		entities = ED_ParseEdict (entities, ent);
+		
+		// yet another map hack
+		if (!stricmp(level.mapname, "command") && !stricmp(ent->classname, "trigger_once") && !stricmp(ent->model, "*27"))
+			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;
+
+		// remove things (except the world) from different skill levels or deathmatch
+		if (ent != g_edicts)
+		{
+			if (deathmatch->value)
+			{
+				if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
+				{
+					G_FreeEdict (ent);	
+					inhibit++;
+					continue;
+				}
+			}
+			else
+			{
+				if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */
+					((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
+					((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
+					(((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))
+					)
+					{
+						G_FreeEdict (ent);	
+						inhibit++;
+						continue;
+					}
+			}
+
+			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
+		}
+
+		ED_CallSpawn (ent);
+	}	
+
+	gi.dprintf ("%i entities inhibited\n", inhibit);
+
+	G_FindTeams ();
+
+	PlayerTrail_Init ();
+
+//ZOID
+	CTFSpawn();
+//ZOID
+}
+
+
+//===================================================================
+
+#if 0
+	// cursor positioning
+	xl <value>
+	xr <value>
+	yb <value>
+	yt <value>
+	xv <value>
+	yv <value>
+
+	// drawing
+	statpic <name>
+	pic <stat>
+	num <fieldwidth> <stat>
+	string <stat>
+
+	// control
+	if <stat>
+	ifeq <stat> <value>
+	ifbit <stat> <value>
+	endif
+
+#endif
+
+char *single_statusbar = 
+"yb	-24 "
+
+// health
+"xv	0 "
+"hnum "
+"xv	50 "
+"pic 0 "
+
+// ammo
+"if 2 "
+"	xv	100 "
+"	anum "
+"	xv	150 "
+"	pic 2 "
+"endif "
+
+// armor
+"if 4 "
+"	xv	200 "
+"	rnum "
+"	xv	250 "
+"	pic 4 "
+"endif "
+
+// selected item
+"if 6 "
+"	xv	296 "
+"	pic 6 "
+"endif "
+
+"yb	-50 "
+
+// picked up item
+"if 7 "
+"	xv	0 "
+"	pic 7 "
+"	xv	26 "
+"	yb	-42 "
+"	stat_string 8 "
+"	yb	-50 "
+"endif "
+
+// timer
+"if 9 "
+"	xv	262 "
+"	num	2	10 "
+"	xv	296 "
+"	pic	9 "
+"endif "
+
+//  help / weapon icon 
+"if 11 "
+"	xv	148 "
+"	pic	11 "
+"endif "
+;
+
+char *dm_statusbar =
+"yb	-24 "
+
+// health
+"xv	0 "
+"hnum "
+"xv	50 "
+"pic 0 "
+
+// ammo
+"if 2 "
+"	xv	100 "
+"	anum "
+"	xv	150 "
+"	pic 2 "
+"endif "
+
+// armor
+"if 4 "
+"	xv	200 "
+"	rnum "
+"	xv	250 "
+"	pic 4 "
+"endif "
+
+// selected item
+"if 6 "
+"	xv	296 "
+"	pic 6 "
+"endif "
+
+"yb	-50 "
+
+// picked up item
+"if 7 "
+"	xv	0 "
+"	pic 7 "
+"	xv	26 "
+"	yb	-42 "
+"	stat_string 8 "
+"	yb	-50 "
+"endif "
+
+// timer
+"if 9 "
+"	xv	246 "
+"	num	2	10 "
+"	xv	296 "
+"	pic	9 "
+"endif "
+
+//  help / weapon icon 
+"if 11 "
+"	xv	148 "
+"	pic	11 "
+"endif "
+
+//  frags
+"xr	-50 "
+"yt 2 "
+"num 3 14"
+;
+
+
+/*QUAKED worldspawn (0 0 0) ?
+
+Only used for the world.
+"sky"	environment map name
+"skyaxis"	vector axis for rotating sky
+"skyrotate"	speed of rotation in degrees/second
+"sounds"	music cd track number
+"gravity"	800 is default gravity
+"message"	text to print at user logon
+*/
+void SP_worldspawn (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	ent->inuse = true;			// since the world doesn't use G_Spawn()
+	ent->s.modelindex = 1;		// world model is always index 1
+
+	//---------------
+
+	// reserve some spots for dead player bodies for coop / deathmatch
+	InitBodyQue ();
+
+	// set configstrings for items
+	SetItemNames ();
+
+	if (st.nextmap)
+		strcpy (level.nextmap, st.nextmap);
+
+	// make some data visible to the server
+
+	if (ent->message && ent->message[0])
+	{
+		gi.configstring (CS_NAME, ent->message);
+		strncpy (level.level_name, ent->message, sizeof(level.level_name));
+	}
+	else
+		strncpy (level.level_name, level.mapname, sizeof(level.level_name));
+
+	if (st.sky && st.sky[0])
+		gi.configstring (CS_SKY, st.sky);
+	else
+		gi.configstring (CS_SKY, "unit1_");
+
+	gi.configstring (CS_SKYROTATE, va("%f", st.skyrotate) );
+
+	gi.configstring (CS_SKYAXIS, va("%f %f %f",
+		st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]) );
+
+	gi.configstring (CS_CDTRACK, va("%i", ent->sounds) );
+
+	gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) );
+
+	// status bar program
+	if (deathmatch->value)
+//ZOID
+		if (ctf->value) {
+			gi.configstring (CS_STATUSBAR, ctf_statusbar);
+			//precaches
+			gi.imageindex("i_ctf1");
+			gi.imageindex("i_ctf2");
+			gi.imageindex("i_ctf1d");
+			gi.imageindex("i_ctf2d");
+			gi.imageindex("i_ctf1t");
+			gi.imageindex("i_ctf2t");
+			gi.imageindex("i_ctfj");
+		} else
+//ZOID
+		gi.configstring (CS_STATUSBAR, dm_statusbar);
+	else
+		gi.configstring (CS_STATUSBAR, single_statusbar);
+
+	//---------------
+
+
+	// help icon for statusbar
+	gi.imageindex ("i_help");
+	level.pic_health = gi.imageindex ("i_health");
+	gi.imageindex ("help");
+	gi.imageindex ("field_3");
+
+	if (!st.gravity)
+		gi.cvar_set("sv_gravity", "800");
+	else
+		gi.cvar_set("sv_gravity", st.gravity);
+
+	snd_fry = gi.soundindex ("player/fry.wav");	// standing in lava / slime
+
+	PrecacheItem (FindItem ("Blaster"));
+
+	gi.soundindex ("player/lava1.wav");
+	gi.soundindex ("player/lava2.wav");
+
+	gi.soundindex ("misc/pc_up.wav");
+	gi.soundindex ("misc/talk1.wav");
+
+	gi.soundindex ("misc/udeath.wav");
+
+	// gibs
+	gi.soundindex ("items/respawn1.wav");
+
+	// sexed sounds
+	gi.soundindex ("*death1.wav");
+	gi.soundindex ("*death2.wav");
+	gi.soundindex ("*death3.wav");
+	gi.soundindex ("*death4.wav");
+	gi.soundindex ("*fall1.wav");
+	gi.soundindex ("*fall2.wav");	
+	gi.soundindex ("*gurp1.wav");		// drowning damage
+	gi.soundindex ("*gurp2.wav");	
+	gi.soundindex ("*jump1.wav");		// player jump
+	gi.soundindex ("*pain25_1.wav");
+	gi.soundindex ("*pain25_2.wav");
+	gi.soundindex ("*pain50_1.wav");
+	gi.soundindex ("*pain50_2.wav");
+	gi.soundindex ("*pain75_1.wav");
+	gi.soundindex ("*pain75_2.wav");
+	gi.soundindex ("*pain100_1.wav");
+	gi.soundindex ("*pain100_2.wav");
+
+#if 0 //DISABLED
+	// sexed models
+	// THIS ORDER MUST MATCH THE DEFINES IN g_local.h
+	// you can add more, max 15
+	gi.modelindex ("#w_blaster.md2");
+	gi.modelindex ("#w_shotgun.md2");
+	gi.modelindex ("#w_sshotgun.md2");
+	gi.modelindex ("#w_machinegun.md2");
+	gi.modelindex ("#w_chaingun.md2");
+	gi.modelindex ("#a_grenades.md2");
+	gi.modelindex ("#w_glauncher.md2");
+	gi.modelindex ("#w_rlauncher.md2");
+	gi.modelindex ("#w_hyperblaster.md2");
+	gi.modelindex ("#w_railgun.md2");
+	gi.modelindex ("#w_bfg.md2");
+	gi.modelindex ("#w_grapple.md2");
+#endif
+
+	//-------------------
+
+	gi.soundindex ("player/gasp1.wav");		// gasping for air
+	gi.soundindex ("player/gasp2.wav");		// head breaking surface, not gasping
+
+	gi.soundindex ("player/watr_in.wav");	// feet hitting water
+	gi.soundindex ("player/watr_out.wav");	// feet leaving water
+
+	gi.soundindex ("player/watr_un.wav");	// head going underwater
+	
+	gi.soundindex ("player/u_breath1.wav");
+	gi.soundindex ("player/u_breath2.wav");
+
+	gi.soundindex ("items/pkup.wav");		// bonus item pickup
+	gi.soundindex ("world/land.wav");		// landing thud
+	gi.soundindex ("misc/h2ohit1.wav");		// landing splash
+
+	gi.soundindex ("items/damage.wav");
+	gi.soundindex ("items/protect.wav");
+	gi.soundindex ("items/protect4.wav");
+	gi.soundindex ("weapons/noammo.wav");
+
+	gi.soundindex ("infantry/inflies1.wav");
+
+	sm_meat_index = gi.modelindex ("models/objects/gibs/sm_meat/tris.md2");
+	gi.modelindex ("models/objects/gibs/arm/tris.md2");
+	gi.modelindex ("models/objects/gibs/bone/tris.md2");
+	gi.modelindex ("models/objects/gibs/bone2/tris.md2");
+	gi.modelindex ("models/objects/gibs/chest/tris.md2");
+	gi.modelindex ("models/objects/gibs/skull/tris.md2");
+	gi.modelindex ("models/objects/gibs/head2/tris.md2");
+
+//
+// Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
+//
+
+	// 0 normal
+	gi.configstring(CS_LIGHTS+0, "m");
+	
+	// 1 FLICKER (first variety)
+	gi.configstring(CS_LIGHTS+1, "mmnmmommommnonmmonqnmmo");
+	
+	// 2 SLOW STRONG PULSE
+	gi.configstring(CS_LIGHTS+2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
+	
+	// 3 CANDLE (first variety)
+	gi.configstring(CS_LIGHTS+3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
+	
+	// 4 FAST STROBE
+	gi.configstring(CS_LIGHTS+4, "mamamamamama");
+	
+	// 5 GENTLE PULSE 1
+	gi.configstring(CS_LIGHTS+5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
+	
+	// 6 FLICKER (second variety)
+	gi.configstring(CS_LIGHTS+6, "nmonqnmomnmomomno");
+	
+	// 7 CANDLE (second variety)
+	gi.configstring(CS_LIGHTS+7, "mmmaaaabcdefgmmmmaaaammmaamm");
+	
+	// 8 CANDLE (third variety)
+	gi.configstring(CS_LIGHTS+8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
+	
+	// 9 SLOW STROBE (fourth variety)
+	gi.configstring(CS_LIGHTS+9, "aaaaaaaazzzzzzzz");
+	
+	// 10 FLUORESCENT FLICKER
+	gi.configstring(CS_LIGHTS+10, "mmamammmmammamamaaamammma");
+
+	// 11 SLOW PULSE NOT FADE TO BLACK
+	gi.configstring(CS_LIGHTS+11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
+	
+	// styles 32-62 are assigned by the light program for switchable lights
+
+	// 63 testing
+	gi.configstring(CS_LIGHTS+63, "a");
+}
+
--- /dev/null
+++ b/ctf/g_svcmds.c
@@ -1,0 +1,48 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+void	Svcmd_Test_f (void)
+{
+	gi.cprintf (NULL, PRINT_HIGH, "Svcmd_Test_f()\n");
+}
+
+/*
+=================
+ServerCommand
+
+ServerCommand will be called when an "sv" command is issued.
+The game can issue gi.argc() / gi.argv() commands to get the rest
+of the parameters
+=================
+*/
+void	ServerCommand (void)
+{
+	char	*cmd;
+
+	cmd = gi.argv(1);
+	if (Q_stricmp (cmd, "test") == 0)
+		Svcmd_Test_f ();
+	else
+		gi.cprintf (NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);
+}
+
--- /dev/null
+++ b/ctf/g_target.c
@@ -1,0 +1,809 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
+Fire an origin based temp entity event to the clients.
+"style"		type byte
+*/
+void Use_Target_Tent (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (ent->style);
+	gi.WritePosition (ent->s.origin);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+}
+
+void SP_target_temp_entity (edict_t *ent)
+{
+	ent->use = Use_Target_Tent;
+}
+
+
+//==========================================================
+
+//==========================================================
+
+/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable
+"noise"		wav file to play
+"attenuation"
+-1 = none, send to whole level
+1 = normal fighting sounds
+2 = idle sound level
+3 = ambient sound level
+"volume"	0.0 to 1.0
+
+Normal sounds play each time the target is used.  The reliable flag can be set for crucial voiceovers.
+
+Looped sounds are allways atten 3 / vol 1, and the use function toggles it on/off.
+Multiple identical looping sounds will just increase volume without any speed cost.
+*/
+void Use_Target_Speaker (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	int		chan;
+
+	if (ent->spawnflags & 3)
+	{	// looping sound toggles
+		if (ent->s.sound)
+			ent->s.sound = 0;	// turn it off
+		else
+			ent->s.sound = ent->noise_index;	// start it
+	}
+	else
+	{	// normal sound
+		if (ent->spawnflags & 4)
+			chan = CHAN_VOICE|CHAN_RELIABLE;
+		else
+			chan = CHAN_VOICE;
+		// use a positioned_sound, because this entity won't normally be
+		// sent to any clients because it is invisible
+		gi.positioned_sound (ent->s.origin, ent, chan, ent->noise_index, ent->volume, ent->attenuation, 0);
+	}
+}
+
+void SP_target_speaker (edict_t *ent)
+{
+	char	buffer[MAX_QPATH];
+
+	if(!st.noise)
+	{
+		gi.dprintf("target_speaker with no noise set at %s\n", vtos(ent->s.origin));
+		return;
+	}
+	if (!strstr (st.noise, ".wav"))
+		Com_sprintf (buffer, sizeof(buffer), "%s.wav", st.noise);
+	else
+		strncpy (buffer, st.noise, sizeof(buffer));
+	ent->noise_index = gi.soundindex (buffer);
+
+	if (!ent->volume)
+		ent->volume = 1.0;
+
+	if (!ent->attenuation)
+		ent->attenuation = 1.0;
+	else if (ent->attenuation == -1)	// use -1 so 0 defaults to 1
+		ent->attenuation = 0;
+
+	// check for prestarted looping sound
+	if (ent->spawnflags & 1)
+		ent->s.sound = ent->noise_index;
+
+	ent->use = Use_Target_Speaker;
+
+	// must link the entity so we get areas and clusters so
+	// the server can determine who to send updates to
+	gi.linkentity (ent);
+}
+
+
+//==========================================================
+
+void Use_Target_Help (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	if (ent->spawnflags & 1)
+		strncpy (game.helpmessage1, ent->message, sizeof(game.helpmessage2)-1);
+	else
+		strncpy (game.helpmessage2, ent->message, sizeof(game.helpmessage1)-1);
+
+	game.helpchanged++;
+}
+
+/*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1
+When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars.
+*/
+void SP_target_help(edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!ent->message)
+	{
+		gi.dprintf ("%s with no message at %s\n", ent->classname, vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+	ent->use = Use_Target_Help;
+}
+
+//==========================================================
+
+/*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8)
+Counts a secret found.
+These are single use targets.
+*/
+void use_target_secret (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
+
+	level.found_secrets++;
+
+	G_UseTargets (ent, activator);
+	G_FreeEdict (ent);
+}
+
+void SP_target_secret (edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->use = use_target_secret;
+	if (!st.noise)
+		st.noise = "misc/secret.wav";
+	ent->noise_index = gi.soundindex (st.noise);
+	ent->svflags = SVF_NOCLIENT;
+	level.total_secrets++;
+	// map bug hack
+	if (!stricmp(level.mapname, "mine3") && ent->s.origin[0] == 280 && ent->s.origin[1] == -2048 && ent->s.origin[2] == -624)
+		ent->message = "You have found a secret area.";
+}
+
+//==========================================================
+
+/*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8)
+Counts a goal completed.
+These are single use targets.
+*/
+void use_target_goal (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
+
+	level.found_goals++;
+
+	if (level.found_goals == level.total_goals)
+		gi.configstring (CS_CDTRACK, "0");
+
+	G_UseTargets (ent, activator);
+	G_FreeEdict (ent);
+}
+
+void SP_target_goal (edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->use = use_target_goal;
+	if (!st.noise)
+		st.noise = "misc/secret.wav";
+	ent->noise_index = gi.soundindex (st.noise);
+	ent->svflags = SVF_NOCLIENT;
+	level.total_goals++;
+}
+
+//==========================================================
+
+
+/*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8)
+Spawns an explosion temporary entity when used.
+
+"delay"		wait this long before going off
+"dmg"		how much radius damage should be done, defaults to 0
+*/
+void target_explosion_explode (edict_t *self)
+{
+	float		save;
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION1);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PHS);
+
+	T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
+
+	save = self->delay;
+	self->delay = 0;
+	G_UseTargets (self, self->activator);
+	self->delay = save;
+}
+
+void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+
+	if (!self->delay)
+	{
+		target_explosion_explode (self);
+		return;
+	}
+
+	self->think = target_explosion_explode;
+	self->nextthink = level.time + self->delay;
+}
+
+void SP_target_explosion (edict_t *ent)
+{
+	ent->use = use_target_explosion;
+	ent->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8)
+Changes level to "map" when fired
+*/
+void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (level.intermissiontime)
+		return;		// allready activated
+
+	if (!deathmatch->value && !coop->value)
+	{
+		if (g_edicts[1].health <= 0)
+			return;
+	}
+
+	// if noexit, do a ton of damage to other
+	if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world)
+	{
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 10 * other->max_health, 1000, 0, MOD_EXIT);
+		return;
+	}
+
+	// if multiplayer, let everyone know who hit the exit
+	if (deathmatch->value)
+	{
+		if (activator && activator->client)
+			gi.bprintf (PRINT_HIGH, "%s exited the level.\n", activator->client->pers.netname);
+	}
+
+	// if going to a new unit, clear cross triggers
+	if (strstr(self->map, "*"))	
+		game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK);
+
+	BeginIntermission (self);
+}
+
+void SP_target_changelevel (edict_t *ent)
+{
+	if (!ent->map)
+	{
+		gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	// ugly hack because *SOMEBODY* screwed up their map
+   if((stricmp(level.mapname, "fact1") == 0) && (stricmp(ent->map, "fact3") == 0))
+	   ent->map = "fact3$secret1";
+
+	ent->use = use_target_changelevel;
+	ent->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8)
+Creates a particle splash effect when used.
+
+Set "sounds" to one of the following:
+  1) sparks
+  2) blue water
+  3) brown water
+  4) slime
+  5) lava
+  6) blood
+
+"count"	how many pixels in the splash
+"dmg"	if set, does a radius damage at this location when it splashes
+		useful for lava/sparks
+*/
+
+void use_target_splash (edict_t *self, edict_t *other, edict_t *activator)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_SPLASH);
+	gi.WriteByte (self->count);
+	gi.WritePosition (self->s.origin);
+	gi.WriteDir (self->movedir);
+	gi.WriteByte (self->sounds);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	if (self->dmg)
+		T_RadiusDamage (self, activator, self->dmg, NULL, self->dmg+40, MOD_SPLASH);
+}
+
+void SP_target_splash (edict_t *self)
+{
+	self->use = use_target_splash;
+	G_SetMovedir (self->s.angles, self->movedir);
+
+	if (!self->count)
+		self->count = 32;
+
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8)
+Set target to the type of entity you want spawned.
+Useful for spawning monsters and gibs in the factory levels.
+
+For monsters:
+	Set direction to the facing you want it to have.
+
+For gibs:
+	Set direction if you want it moving and
+	speed how fast it should be moving otherwise it
+	will just be dropped
+*/
+void ED_CallSpawn (edict_t *ent);
+
+void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t	*ent;
+
+	ent = G_Spawn();
+	ent->classname = self->target;
+	VectorCopy (self->s.origin, ent->s.origin);
+	VectorCopy (self->s.angles, ent->s.angles);
+	ED_CallSpawn (ent);
+	gi.unlinkentity (ent);
+	KillBox (ent);
+	gi.linkentity (ent);
+	if (self->speed)
+		VectorCopy (self->movedir, ent->velocity);
+}
+
+void SP_target_spawner (edict_t *self)
+{
+	self->use = use_target_spawner;
+	self->svflags = SVF_NOCLIENT;
+	if (self->speed)
+	{
+		G_SetMovedir (self->s.angles, self->movedir);
+		VectorScale (self->movedir, self->speed, self->movedir);
+	}
+}
+
+//==========================================================
+
+/*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS
+Fires a blaster bolt in the set direction when triggered.
+
+dmg		default is 15
+speed	default is 1000
+*/
+
+void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator)
+{
+	int effect;
+
+	if (self->spawnflags & 2)
+		effect = 0;
+	else if (self->spawnflags & 1)
+		effect = EF_HYPERBLASTER;
+	else
+		effect = EF_BLASTER;
+
+	fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER, MOD_TARGET_BLASTER);
+	gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0);
+}
+
+void SP_target_blaster (edict_t *self)
+{
+	self->use = use_target_blaster;
+	G_SetMovedir (self->s.angles, self->movedir);
+	self->noise_index = gi.soundindex ("weapons/laser2.wav");
+
+	if (!self->dmg)
+		self->dmg = 15;
+	if (!self->speed)
+		self->speed = 1000;
+
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
+Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit.  It is OK to check multiple triggers.  Message, delay, target, and killtarget also work.
+*/
+void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	game.serverflags |= self->spawnflags;
+	G_FreeEdict (self);
+}
+
+void SP_target_crosslevel_trigger (edict_t *self)
+{
+	self->svflags = SVF_NOCLIENT;
+	self->use = trigger_crosslevel_trigger_use;
+}
+
+/*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
+Triggered by a trigger_crosslevel elsewhere within a unit.  If multiple triggers are checked, all must be true.  Delay, target and
+killtarget also work.
+
+"delay"		delay before using targets if the trigger has been activated (default 1)
+*/
+void target_crosslevel_target_think (edict_t *self)
+{
+	if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags))
+	{
+		G_UseTargets (self, self);
+		G_FreeEdict (self);
+	}
+}
+
+void SP_target_crosslevel_target (edict_t *self)
+{
+	if (! self->delay)
+		self->delay = 1;
+	self->svflags = SVF_NOCLIENT;
+
+	self->think = target_crosslevel_target_think;
+	self->nextthink = level.time + self->delay;
+}
+
+//==========================================================
+
+/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT
+When triggered, fires a laser.  You can either set a target
+or a direction.
+*/
+
+void target_laser_think (edict_t *self)
+{
+	edict_t	*ignore;
+	vec3_t	start;
+	vec3_t	end;
+	trace_t	tr;
+	vec3_t	point;
+	vec3_t	last_movedir;
+	int		count;
+
+	if (self->spawnflags & 0x80000000)
+		count = 8;
+	else
+		count = 4;
+
+	if (self->enemy)
+	{
+		VectorCopy (self->movedir, last_movedir);
+		VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
+		VectorSubtract (point, self->s.origin, self->movedir);
+		VectorNormalize (self->movedir);
+		if (!VectorCompare(self->movedir, last_movedir))
+			self->spawnflags |= 0x80000000;
+	}
+
+	ignore = self;
+	VectorCopy (self->s.origin, start);
+	VectorMA (start, 2048, self->movedir, end);
+	while(1)
+	{
+		tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
+
+		if (!tr.ent)
+			break;
+
+		// hurt it if we can
+		if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
+			T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER);
+
+		// if we hit something that's not a monster or player or is immune to lasers, we're done
+		if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
+		{
+			if (self->spawnflags & 0x80000000)
+			{
+				self->spawnflags &= ~0x80000000;
+				gi.WriteByte (svc_temp_entity);
+				gi.WriteByte (TE_LASER_SPARKS);
+				gi.WriteByte (count);
+				gi.WritePosition (tr.endpos);
+				gi.WriteDir (tr.plane.normal);
+				gi.WriteByte (self->s.skinnum);
+				gi.multicast (tr.endpos, MULTICAST_PVS);
+			}
+			break;
+		}
+
+		ignore = tr.ent;
+		VectorCopy (tr.endpos, start);
+	}
+
+	VectorCopy (tr.endpos, self->s.old_origin);
+
+	self->nextthink = level.time + FRAMETIME;
+}
+
+void target_laser_on (edict_t *self)
+{
+	if (!self->activator)
+		self->activator = self;
+	self->spawnflags |= 0x80000001;
+	self->svflags &= ~SVF_NOCLIENT;
+	target_laser_think (self);
+}
+
+void target_laser_off (edict_t *self)
+{
+	self->spawnflags &= ~1;
+	self->svflags |= SVF_NOCLIENT;
+	self->nextthink = 0;
+}
+
+void target_laser_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+	if (self->spawnflags & 1)
+		target_laser_off (self);
+	else
+		target_laser_on (self);
+}
+
+void target_laser_start (edict_t *self)
+{
+	edict_t *ent;
+
+	self->movetype = MOVETYPE_NONE;
+	self->solid = SOLID_NOT;
+	self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT;
+	self->s.modelindex = 1;			// must be non-zero
+
+	// set the beam diameter
+	if (self->spawnflags & 64)
+		self->s.frame = 16;
+	else
+		self->s.frame = 4;
+
+	// set the color
+	if (self->spawnflags & 2)
+		self->s.skinnum = 0xf2f2f0f0;
+	else if (self->spawnflags & 4)
+		self->s.skinnum = 0xd0d1d2d3;
+	else if (self->spawnflags & 8)
+		self->s.skinnum = 0xf3f3f1f1;
+	else if (self->spawnflags & 16)
+		self->s.skinnum = 0xdcdddedf;
+	else if (self->spawnflags & 32)
+		self->s.skinnum = 0xe0e1e2e3;
+
+	if (!self->enemy)
+	{
+		if (self->target)
+		{
+			ent = G_Find (NULL, FOFS(targetname), self->target);
+			if (!ent)
+				gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
+			self->enemy = ent;
+		}
+		else
+		{
+			G_SetMovedir (self->s.angles, self->movedir);
+		}
+	}
+	self->use = target_laser_use;
+	self->think = target_laser_think;
+
+	if (!self->dmg)
+		self->dmg = 1;
+
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+	gi.linkentity (self);
+
+	if (self->spawnflags & 1)
+		target_laser_on (self);
+	else
+		target_laser_off (self);
+}
+
+void SP_target_laser (edict_t *self)
+{
+	// let everything else get spawned before we start firing
+	self->think = target_laser_start;
+	self->nextthink = level.time + 1;
+}
+
+//==========================================================
+
+/*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE
+speed		How many seconds the ramping will take
+message		two letters; starting lightlevel and ending lightlevel
+*/
+
+void target_lightramp_think (edict_t *self)
+{
+	char	style[2];
+
+	style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2];
+	style[1] = 0;
+	gi.configstring (CS_LIGHTS+self->enemy->style, style);
+
+	if ((level.time - self->timestamp) < self->speed)
+	{
+		self->nextthink = level.time + FRAMETIME;
+	}
+	else if (self->spawnflags & 1)
+	{
+		char	temp;
+
+		temp = self->movedir[0];
+		self->movedir[0] = self->movedir[1];
+		self->movedir[1] = temp;
+		self->movedir[2] *= -1;
+	}
+}
+
+void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (!self->enemy)
+	{
+		edict_t		*e;
+
+		// check all the targets
+		e = NULL;
+		while (1)
+		{
+			e = G_Find (e, FOFS(targetname), self->target);
+			if (!e)
+				break;
+			if (strcmp(e->classname, "light") != 0)
+			{
+				gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin));
+				gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin));
+			}
+			else
+			{
+				self->enemy = e;
+			}
+		}
+
+		if (!self->enemy)
+		{
+			gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin));
+			G_FreeEdict (self);
+			return;
+		}
+	}
+
+	self->timestamp = level.time;
+	target_lightramp_think (self);
+}
+
+void SP_target_lightramp (edict_t *self)
+{
+	if (!self->message || strlen(self->message) != 2 || self->message[0] < 'a' || self->message[0] > 'z' || self->message[1] < 'a' || self->message[1] > 'z' || self->message[0] == self->message[1])
+	{
+		gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (!self->target)
+	{
+		gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->svflags |= SVF_NOCLIENT;
+	self->use = target_lightramp_use;
+	self->think = target_lightramp_think;
+
+	self->movedir[0] = self->message[0] - 'a';
+	self->movedir[1] = self->message[1] - 'a';
+	self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME);
+}
+
+//==========================================================
+
+/*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8)
+When triggered, this initiates a level-wide earthquake.
+All players and monsters are affected.
+"speed"		severity of the quake (default:200)
+"count"		duration of the quake (default:5)
+*/
+
+void target_earthquake_think (edict_t *self)
+{
+	int		i;
+	edict_t	*e;
+
+	if (self->last_move_time < level.time)
+	{
+		gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0);
+		self->last_move_time = level.time + 0.5;
+	}
+
+	for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++)
+	{
+		if (!e->inuse)
+			continue;
+		if (!e->client)
+			continue;
+		if (!e->groundentity)
+			continue;
+
+		e->groundentity = NULL;
+		e->velocity[0] += crandom()* 150;
+		e->velocity[1] += crandom()* 150;
+		e->velocity[2] = self->speed * (100.0 / e->mass);
+	}
+
+	if (level.time < self->timestamp)
+		self->nextthink = level.time + FRAMETIME;
+}
+
+void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->timestamp = level.time + self->count;
+	self->nextthink = level.time + FRAMETIME;
+	self->activator = activator;
+	self->last_move_time = 0;
+}
+
+void SP_target_earthquake (edict_t *self)
+{
+	if (!self->targetname)
+		gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
+
+	if (!self->count)
+		self->count = 5;
+
+	if (!self->speed)
+		self->speed = 200;
+
+	self->svflags |= SVF_NOCLIENT;
+	self->think = target_earthquake_think;
+	self->use = target_earthquake_use;
+
+	self->noise_index = gi.soundindex ("world/quake.wav");
+}
--- /dev/null
+++ b/ctf/g_trigger.c
@@ -1,0 +1,598 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+void InitTrigger (edict_t *self)
+{
+	if (!VectorCompare (self->s.angles, vec3_origin))
+		G_SetMovedir (self->s.angles, self->movedir);
+
+	self->solid = SOLID_TRIGGER;
+	self->movetype = MOVETYPE_NONE;
+	gi.setmodel (self, self->model);
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+// the wait time has passed, so set back up for another activation
+void multi_wait (edict_t *ent)
+{
+	ent->nextthink = 0;
+}
+
+
+// the trigger was just activated
+// ent->activator should be set to the activator so it can be held through a delay
+// so wait for the delay time before firing
+void multi_trigger (edict_t *ent)
+{
+	if (ent->nextthink)
+		return;		// already been triggered
+
+	G_UseTargets (ent, ent->activator);
+
+	if (ent->wait > 0)	
+	{
+		ent->think = multi_wait;
+		ent->nextthink = level.time + ent->wait;
+	}
+	else
+	{	// we can't just remove (self) here, because this is a touch function
+		// called while looping through area links...
+		ent->touch = NULL;
+		ent->nextthink = level.time + FRAMETIME;
+		ent->think = G_FreeEdict;
+	}
+}
+
+void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	ent->activator = activator;
+	multi_trigger (ent);
+}
+
+void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if(other->client)
+	{
+		if (self->spawnflags & 2)
+			return;
+	}
+	else if (other->svflags & SVF_MONSTER)
+	{
+		if (!(self->spawnflags & 1))
+			return;
+	}
+	else
+		return;
+
+	if (!VectorCompare(self->movedir, vec3_origin))
+	{
+		vec3_t	forward;
+
+		AngleVectors(other->s.angles, forward, NULL, NULL);
+		if (_DotProduct(forward, self->movedir) < 0)
+			return;
+	}
+
+	self->activator = other;
+	multi_trigger (self);
+}
+
+/*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
+Variable sized repeatable trigger.  Must be targeted at one or more entities.
+If "delay" is set, the trigger waits some time after activating before firing.
+"wait" : Seconds between triggerings. (.2 default)
+sounds
+1)	secret
+2)	beep beep
+3)	large switch
+4)
+set "message" to text string
+*/
+void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->solid = SOLID_TRIGGER;
+	self->use = Use_Multi;
+	gi.linkentity (self);
+}
+
+void SP_trigger_multiple (edict_t *ent)
+{
+	if (ent->sounds == 1)
+		ent->noise_index = gi.soundindex ("misc/secret.wav");
+	else if (ent->sounds == 2)
+		ent->noise_index = gi.soundindex ("misc/talk.wav");
+	else if (ent->sounds == 3)
+		ent->noise_index = gi.soundindex ("misc/trigger1.wav");
+	
+	if (!ent->wait)
+		ent->wait = 0.2;
+	ent->touch = Touch_Multi;
+	ent->movetype = MOVETYPE_NONE;
+	ent->svflags |= SVF_NOCLIENT;
+
+
+	if (ent->spawnflags & 4)
+	{
+		ent->solid = SOLID_NOT;
+		ent->use = trigger_enable;
+	}
+	else
+	{
+		ent->solid = SOLID_TRIGGER;
+		ent->use = Use_Multi;
+	}
+
+	if (!VectorCompare(ent->s.angles, vec3_origin))
+		G_SetMovedir (ent->s.angles, ent->movedir);
+
+	gi.setmodel (ent, ent->model);
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
+Triggers once, then removes itself.
+You must set the key "target" to the name of another object in the level that has a matching "targetname".
+
+If TRIGGERED, this trigger must be triggered before it is live.
+
+sounds
+ 1)	secret
+ 2)	beep beep
+ 3)	large switch
+ 4)
+
+"message"	string to be displayed when triggered
+*/
+
+void SP_trigger_once(edict_t *ent)
+{
+	// make old maps work because I messed up on flag assignments here
+	// triggered was on bit 1 when it should have been on bit 4
+	if (ent->spawnflags & 1)
+	{
+		vec3_t	v;
+
+		VectorMA (ent->mins, 0.5, ent->size, v);
+		ent->spawnflags &= ~1;
+		ent->spawnflags |= 4;
+		gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
+	}
+
+	ent->wait = -1;
+	SP_trigger_multiple (ent);
+}
+
+/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
+This fixed size trigger cannot be touched, it can only be fired by other events.
+*/
+void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	G_UseTargets (self, activator);
+}
+
+void SP_trigger_relay (edict_t *self)
+{
+	self->use = trigger_relay_use;
+}
+
+
+/*
+==============================================================================
+
+trigger_key
+
+==============================================================================
+*/
+
+/*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
+A relay trigger that only fires it's targets if player has the proper key.
+Use "item" to specify the required key, for example "key_data_cd"
+*/
+void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	int			index;
+
+	if (!self->item)
+		return;
+	if (!activator->client)
+		return;
+
+	index = ITEM_INDEX(self->item);
+	if (!activator->client->pers.inventory[index])
+	{
+		if (level.time < self->touch_debounce_time)
+			return;
+		self->touch_debounce_time = level.time + 5.0;
+		gi.centerprintf (activator, "You need the %s", self->item->pickup_name);
+		gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
+		return;
+	}
+
+	gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
+	if (coop->value)
+	{
+		int		player;
+		edict_t	*ent;
+
+		if (strcmp(self->item->classname, "key_power_cube") == 0)
+		{
+			int	cube;
+
+			for (cube = 0; cube < 8; cube++)
+				if (activator->client->pers.power_cubes & (1 << cube))
+					break;
+			for (player = 1; player <= game.maxclients; player++)
+			{
+				ent = &g_edicts[player];
+				if (!ent->inuse)
+					continue;
+				if (!ent->client)
+					continue;
+				if (ent->client->pers.power_cubes & (1 << cube))
+				{
+					ent->client->pers.inventory[index]--;
+					ent->client->pers.power_cubes &= ~(1 << cube);
+				}
+			}
+		}
+		else
+		{
+			for (player = 1; player <= game.maxclients; player++)
+			{
+				ent = &g_edicts[player];
+				if (!ent->inuse)
+					continue;
+				if (!ent->client)
+					continue;
+				ent->client->pers.inventory[index] = 0;
+			}
+		}
+	}
+	else
+	{
+		activator->client->pers.inventory[index]--;
+	}
+
+	G_UseTargets (self, activator);
+
+	self->use = NULL;
+}
+
+void SP_trigger_key (edict_t *self)
+{
+	if (!st.item)
+	{
+		gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
+		return;
+	}
+	self->item = FindItemByClassname (st.item);
+
+	if (!self->item)
+	{
+		gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
+		return;
+	}
+
+	if (!self->target)
+	{
+		gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
+		return;
+	}
+
+	gi.soundindex ("misc/keytry.wav");
+	gi.soundindex ("misc/keyuse.wav");
+
+	self->use = trigger_key_use;
+}
+
+
+/*
+==============================================================================
+
+trigger_counter
+
+==============================================================================
+*/
+
+/*QUAKED trigger_counter (.5 .5 .5) ? nomessage
+Acts as an intermediary for an action that takes multiple inputs.
+
+If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
+
+After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
+*/
+
+void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->count == 0)
+		return;
+	
+	self->count--;
+
+	if (self->count)
+	{
+		if (! (self->spawnflags & 1))
+		{
+			gi.centerprintf(activator, "%i more to go...", self->count);
+			gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+		}
+		return;
+	}
+	
+	if (! (self->spawnflags & 1))
+	{
+		gi.centerprintf(activator, "Sequence completed!");
+		gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+	}
+	self->activator = activator;
+	multi_trigger (self);
+}
+
+void SP_trigger_counter (edict_t *self)
+{
+	self->wait = -1;
+	if (!self->count)
+		self->count = 2;
+
+	self->use = trigger_counter_use;
+}
+
+
+/*
+==============================================================================
+
+trigger_always
+
+==============================================================================
+*/
+
+/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
+This trigger will always fire.  It is activated by the world.
+*/
+void SP_trigger_always (edict_t *ent)
+{
+	// we must have some delay to make sure our use targets are present
+	if (ent->delay < 0.2)
+		ent->delay = 0.2;
+	G_UseTargets(ent, ent);
+}
+
+
+/*
+==============================================================================
+
+trigger_push
+
+==============================================================================
+*/
+
+#define PUSH_ONCE		1
+
+static int windsound;
+
+void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (strcmp(other->classname, "grenade") == 0)
+	{
+		VectorScale (self->movedir, self->speed * 10, other->velocity);
+	}
+	else if (other->health > 0)
+	{
+		VectorScale (self->movedir, self->speed * 10, other->velocity);
+
+		if (other->client)
+		{
+			// don't take falling damage immediately from this
+			VectorCopy (other->velocity, other->client->oldvelocity);
+			if (other->fly_sound_debounce_time < level.time)
+			{
+				other->fly_sound_debounce_time = level.time + 1.5;
+				gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
+			}
+		}
+	}
+	if (self->spawnflags & PUSH_ONCE)
+		G_FreeEdict (self);
+}
+
+
+/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
+Pushes the player
+"speed"		defaults to 1000
+*/
+void SP_trigger_push (edict_t *self)
+{
+	InitTrigger (self);
+	windsound = gi.soundindex ("misc/windfly.wav");
+	self->touch = trigger_push_touch;
+	if (!self->speed)
+		self->speed = 1000;
+	gi.linkentity (self);
+}
+
+
+/*
+==============================================================================
+
+trigger_hurt
+
+==============================================================================
+*/
+
+/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
+Any entity that touches this will be hurt.
+
+It does dmg points of damage each server frame
+
+SILENT			supresses playing the sound
+SLOW			changes the damage rate to once per second
+NO_PROTECTION	*nothing* stops the damage
+
+"dmg"			default 5 (whole numbers only)
+
+*/
+void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->solid == SOLID_NOT)
+		self->solid = SOLID_TRIGGER;
+	else
+		self->solid = SOLID_NOT;
+	gi.linkentity (self);
+
+	if (!(self->spawnflags & 2))
+		self->use = NULL;
+}
+
+
+void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	int		dflags;
+
+	if (!other->takedamage)
+		return;
+
+	if (self->timestamp > level.time)
+		return;
+
+	if (self->spawnflags & 16)
+		self->timestamp = level.time + 1;
+	else
+		self->timestamp = level.time + FRAMETIME;
+
+	if (!(self->spawnflags & 4))
+	{
+		if ((level.framenum % 10) == 0)
+			gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
+	}
+
+	if (self->spawnflags & 8)
+		dflags = DAMAGE_NO_PROTECTION;
+	else
+		dflags = 0;
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
+}
+
+void SP_trigger_hurt (edict_t *self)
+{
+	InitTrigger (self);
+
+	self->noise_index = gi.soundindex ("world/electro.wav");
+	self->touch = hurt_touch;
+
+	if (!self->dmg)
+		self->dmg = 5;
+
+	if (self->spawnflags & 1)
+		self->solid = SOLID_NOT;
+	else
+		self->solid = SOLID_TRIGGER;
+
+	if (self->spawnflags & 2)
+		self->use = hurt_use;
+
+	gi.linkentity (self);
+}
+
+
+/*
+==============================================================================
+
+trigger_gravity
+
+==============================================================================
+*/
+
+/*QUAKED trigger_gravity (.5 .5 .5) ?
+Changes the touching entites gravity to
+the value of "gravity".  1.0 is standard
+gravity for the level.
+*/
+
+void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	other->gravity = self->gravity;
+}
+
+void SP_trigger_gravity (edict_t *self)
+{
+	if (st.gravity == 0)
+	{
+		gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
+		G_FreeEdict  (self);
+		return;
+	}
+
+	InitTrigger (self);
+	self->gravity = atoi(st.gravity);
+	self->touch = trigger_gravity_touch;
+}
+
+
+/*
+==============================================================================
+
+trigger_monsterjump
+
+==============================================================================
+*/
+
+/*QUAKED trigger_monsterjump (.5 .5 .5) ?
+Walking monsters that touch this will jump in the direction of the trigger's angle
+"speed" default to 200, the speed thrown forward
+"height" default to 200, the speed thrown upwards
+*/
+
+void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other->flags & (FL_FLY | FL_SWIM) )
+		return;
+	if (other->svflags & SVF_DEADMONSTER)
+		return;
+	if ( !(other->svflags & SVF_MONSTER))
+		return;
+
+// set XY even if not on ground, so the jump will clear lips
+	other->velocity[0] = self->movedir[0] * self->speed;
+	other->velocity[1] = self->movedir[1] * self->speed;
+	
+	if (!other->groundentity)
+		return;
+	
+	other->groundentity = NULL;
+	other->velocity[2] = self->movedir[2];
+}
+
+void SP_trigger_monsterjump (edict_t *self)
+{
+	if (!self->speed)
+		self->speed = 200;
+	if (!st.height)
+		st.height = 200;
+	if (self->s.angles[YAW] == 0)
+		self->s.angles[YAW] = 360;
+	InitTrigger (self);
+	self->touch = trigger_monsterjump_touch;
+	self->movedir[2] = st.height;
+}
+
--- /dev/null
+++ b/ctf/g_utils.c
@@ -1,0 +1,570 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_utils.c -- misc utility functions for game module
+
+#include "g_local.h"
+
+
+void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
+{
+	result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
+	result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
+	result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
+}
+
+
+/*
+=============
+G_Find
+
+Searches all active entities for the next one that holds
+the matching string at fieldofs (use the FOFS() macro) in the structure.
+
+Searches beginning at the edict after from, or the beginning if NULL
+NULL will be returned if the end of the list is reached.
+
+=============
+*/
+edict_t *G_Find (edict_t *from, int fieldofs, char *match)
+{
+	char	*s;
+
+	if (!from)
+		from = g_edicts;
+	else
+		from++;
+
+	for ( ; from < &g_edicts[globals.num_edicts] ; from++)
+	{
+		if (!from->inuse)
+			continue;
+		s = *(char **) ((byte *)from + fieldofs);
+		if (!s)
+			continue;
+		if (!Q_stricmp (s, match))
+			return from;
+	}
+
+	return NULL;
+}
+
+
+/*
+=================
+findradius
+
+Returns entities that have origins within a spherical area
+
+findradius (origin, radius)
+=================
+*/
+edict_t *findradius (edict_t *from, vec3_t org, float rad)
+{
+	vec3_t	eorg;
+	int		j;
+
+	if (!from)
+		from = g_edicts;
+	else
+		from++;
+	for ( ; from < &g_edicts[globals.num_edicts]; from++)
+	{
+		if (!from->inuse)
+			continue;
+		if (from->solid == SOLID_NOT)
+			continue;
+		for (j=0 ; j<3 ; j++)
+			eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
+		if (VectorLength(eorg) > rad)
+			continue;
+		return from;
+	}
+
+	return NULL;
+}
+
+
+/*
+=============
+G_PickTarget
+
+Searches all active entities for the next one that holds
+the matching string at fieldofs (use the FOFS() macro) in the structure.
+
+Searches beginning at the edict after from, or the beginning if NULL
+NULL will be returned if the end of the list is reached.
+
+=============
+*/
+#define MAXCHOICES	8
+
+edict_t *G_PickTarget (char *targetname)
+{
+	edict_t	*ent = NULL;
+	int		num_choices = 0;
+	edict_t	*choice[MAXCHOICES];
+
+	if (!targetname)
+	{
+		gi.dprintf("G_PickTarget called with NULL targetname\n");
+		return NULL;
+	}
+
+	while(1)
+	{
+		ent = G_Find (ent, FOFS(targetname), targetname);
+		if (!ent)
+			break;
+		choice[num_choices++] = ent;
+		if (num_choices == MAXCHOICES)
+			break;
+	}
+
+	if (!num_choices)
+	{
+		gi.dprintf("G_PickTarget: target %s not found\n", targetname);
+		return NULL;
+	}
+
+	return choice[rand() % num_choices];
+}
+
+
+
+void Think_Delay (edict_t *ent)
+{
+	G_UseTargets (ent, ent->activator);
+	G_FreeEdict (ent);
+}
+
+/*
+==============================
+G_UseTargets
+
+the global "activator" should be set to the entity that initiated the firing.
+
+If self.delay is set, a DelayedUse entity will be created that will actually
+do the SUB_UseTargets after that many seconds have passed.
+
+Centerprints any self.message to the activator.
+
+Search for (string)targetname in all entities that
+match (string)self.target and call their .use function
+
+==============================
+*/
+void G_UseTargets (edict_t *ent, edict_t *activator)
+{
+	edict_t		*t;
+
+//
+// check for a delay
+//
+	if (ent->delay)
+	{
+	// create a temp object to fire at a later time
+		t = G_Spawn();
+		t->classname = "DelayedUse";
+		t->nextthink = level.time + ent->delay;
+		t->think = Think_Delay;
+		t->activator = activator;
+		if (!activator)
+			gi.dprintf ("Think_Delay with no activator\n");
+		t->message = ent->message;
+		t->target = ent->target;
+		t->killtarget = ent->killtarget;
+		return;
+	}
+	
+	
+//
+// print the message
+//
+	if ((ent->message) && !(activator->svflags & SVF_MONSTER))
+	{
+		gi.centerprintf (activator, "%s", ent->message);
+		if (ent->noise_index)
+			gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
+		else
+			gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+	}
+
+//
+// kill killtargets
+//
+	if (ent->killtarget)
+	{
+		t = NULL;
+		while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
+		{
+			G_FreeEdict (t);
+			if (!ent->inuse)
+			{
+				gi.dprintf("entity was removed while using killtargets\n");
+				return;
+			}
+		}
+	}
+
+//	gi.dprintf("TARGET: activating %s\n", ent->target);
+
+//
+// fire targets
+//
+	if (ent->target)
+	{
+		t = NULL;
+		while ((t = G_Find (t, FOFS(targetname), ent->target)))
+		{
+			// doors fire area portals in a specific way
+			if (!Q_stricmp(t->classname, "func_areaportal") &&
+				(!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
+				continue;
+
+			if (t == ent)
+			{
+				gi.dprintf ("WARNING: Entity used itself.\n");
+			}
+			else
+			{
+				if (t->use)
+					t->use (t, ent, activator);
+			}
+			if (!ent->inuse)
+			{
+				gi.dprintf("entity was removed while using targets\n");
+				return;
+			}
+		}
+	}
+}
+
+
+/*
+=============
+TempVector
+
+This is just a convenience function
+for making temporary vectors for function calls
+=============
+*/
+float	*tv (float x, float y, float z)
+{
+	static	int		index;
+	static	vec3_t	vecs[8];
+	float	*v;
+
+	// use an array so that multiple tempvectors won't collide
+	// for a while
+	v = vecs[index];
+	index = (index + 1)&7;
+
+	v[0] = x;
+	v[1] = y;
+	v[2] = z;
+
+	return v;
+}
+
+
+/*
+=============
+VectorToString
+
+This is just a convenience function
+for printing vectors
+=============
+*/
+char	*vtos (vec3_t v)
+{
+	static	int		index;
+	static	char	str[8][32];
+	char	*s;
+
+	// use an array so that multiple vtos won't collide
+	s = str[index];
+	index = (index + 1)&7;
+
+	Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
+
+	return s;
+}
+
+
+vec3_t VEC_UP		= {0, -1, 0};
+vec3_t MOVEDIR_UP	= {0, 0, 1};
+vec3_t VEC_DOWN		= {0, -2, 0};
+vec3_t MOVEDIR_DOWN	= {0, 0, -1};
+
+void G_SetMovedir (vec3_t angles, vec3_t movedir)
+{
+	if (VectorCompare (angles, VEC_UP))
+	{
+		VectorCopy (MOVEDIR_UP, movedir);
+	}
+	else if (VectorCompare (angles, VEC_DOWN))
+	{
+		VectorCopy (MOVEDIR_DOWN, movedir);
+	}
+	else
+	{
+		AngleVectors (angles, movedir, NULL, NULL);
+	}
+
+	VectorClear (angles);
+}
+
+
+float vectoyaw (vec3_t vec)
+{
+	float	yaw;
+	
+	if (/* vec[YAW] == 0 && */ vec[PITCH] == 0) 
+	{
+		yaw = 0;
+		if (vec[YAW] > 0)
+			yaw = 90;
+		else if (vec[YAW] < 0)
+			yaw = -90;
+	}
+	else
+	{
+		yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
+		if (yaw < 0)
+			yaw += 360;
+	}
+
+	return yaw;
+}
+
+
+void vectoangles (vec3_t value1, vec3_t angles)
+{
+	float	forward;
+	float	yaw, pitch;
+	
+	if (value1[1] == 0 && value1[0] == 0)
+	{
+		yaw = 0;
+		if (value1[2] > 0)
+			pitch = 90;
+		else
+			pitch = 270;
+	}
+	else
+	{
+		if (value1[0])
+			yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
+		else if (value1[1] > 0)
+			yaw = 90;
+		else
+			yaw = -90;
+		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;
+	}
+
+	angles[PITCH] = -pitch;
+	angles[YAW] = yaw;
+	angles[ROLL] = 0;
+}
+
+char *G_CopyString (char *in)
+{
+	char	*out;
+	
+	out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
+	strcpy (out, in);
+	return out;
+}
+
+
+void G_InitEdict (edict_t *e)
+{
+	e->inuse = true;
+	e->classname = "noclass";
+	e->gravity = 1.0;
+	e->s.number = e - g_edicts;
+}
+
+/*
+=================
+G_Spawn
+
+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 *G_Spawn (void)
+{
+	int			i;
+	edict_t		*e;
+
+	e = &g_edicts[(int)maxclients->value+1];
+	for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
+	{
+		// the first couple seconds of server time can involve a lot of
+		// freeing and allocating, so relax the replacement policy
+		if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
+		{
+			G_InitEdict (e);
+			return e;
+		}
+	}
+	
+	if (i == game.maxentities)
+		gi.error ("ED_Alloc: no free edicts");
+		
+	globals.num_edicts++;
+	G_InitEdict (e);
+	return e;
+}
+
+/*
+=================
+G_FreeEdict
+
+Marks the edict as free
+=================
+*/
+void G_FreeEdict (edict_t *ed)
+{
+	gi.unlinkentity (ed);		// unlink from world
+
+	if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
+	{
+//		gi.dprintf("tried to free special edict\n");
+		return;
+	}
+
+	memset (ed, 0, sizeof(*ed));
+	ed->classname = "freed";
+	ed->freetime = level.time;
+	ed->inuse = false;
+}
+
+
+/*
+============
+G_TouchTriggers
+
+============
+*/
+void	G_TouchTriggers (edict_t *ent)
+{
+	int			i, num;
+	edict_t		*touch[MAX_EDICTS], *hit;
+
+	// dead things don't activate triggers!
+	if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
+		return;
+
+	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
+		, MAX_EDICTS, AREA_TRIGGERS);
+
+	// be careful, it is possible to have an entity in this
+	// list removed before we get to it (killtriggered)
+	for (i=0 ; i<num ; i++)
+	{
+		hit = touch[i];
+		if (!hit->inuse)
+			continue;
+		if (!hit->touch)
+			continue;
+		hit->touch (hit, ent, NULL, NULL);
+	}
+}
+
+/*
+============
+G_TouchSolids
+
+Call after linking a new trigger in during gameplay
+to force all entities it covers to immediately touch it
+============
+*/
+void	G_TouchSolids (edict_t *ent)
+{
+	int			i, num;
+	edict_t		*touch[MAX_EDICTS], *hit;
+
+	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
+		, MAX_EDICTS, AREA_SOLID);
+
+	// be careful, it is possible to have an entity in this
+	// list removed before we get to it (killtriggered)
+	for (i=0 ; i<num ; i++)
+	{
+		hit = touch[i];
+		if (!hit->inuse)
+			continue;
+		if (ent->touch)
+			ent->touch (hit, ent, NULL, NULL);
+		if (!ent->inuse)
+			break;
+	}
+}
+
+
+
+
+/*
+==============================================================================
+
+Kill box
+
+==============================================================================
+*/
+
+/*
+=================
+KillBox
+
+Kills all entities that would touch the proposed new positioning
+of ent.  Ent should be unlinked before calling this!
+=================
+*/
+qboolean KillBox (edict_t *ent)
+{
+	trace_t		tr;
+
+	while (1)
+	{
+		tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
+		if (!tr.ent)
+			break;
+
+		// nail it
+		T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
+
+		// if we didn't kill it, fail
+		if (tr.ent->solid)
+			return false;
+	}
+
+	return true;		// all clear
+}
--- /dev/null
+++ b/ctf/g_weapon.c
@@ -1,0 +1,919 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+/*
+=================
+check_dodge
+
+This is a support routine used when a client is firing
+a non-instant attack weapon.  It checks to see if a
+monster's dodge function should be called.
+=================
+*/
+static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed)
+{
+	vec3_t	end;
+	vec3_t	v;
+	trace_t	tr;
+	float	eta;
+
+	// easy mode only ducks one quarter the time
+	if (skill->value == 0)
+	{
+		if (random() > 0.25)
+			return;
+	}
+	VectorMA (start, 8192, dir, end);
+	tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
+	if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self))
+	{
+		VectorSubtract (tr.endpos, start, v);
+		eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
+		tr.ent->monsterinfo.dodge (tr.ent, self, eta);
+	}
+}
+
+
+/*
+=================
+fire_hit
+
+Used for all impact (hit/punch/slash) attacks
+=================
+*/
+qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick)
+{
+	trace_t		tr;
+	vec3_t		forward, right, up;
+	vec3_t		v;
+	vec3_t		point;
+	float		range;
+	vec3_t		dir;
+
+	//see if enemy is in range
+	VectorSubtract (self->enemy->s.origin, self->s.origin, dir);
+	range = VectorLength(dir);
+	if (range > aim[0])
+		return false;
+
+	if (aim[1] > self->mins[0] && aim[1] < self->maxs[0])
+	{
+		// the hit is straight on so back the range up to the edge of their bbox
+		range -= self->enemy->maxs[0];
+	}
+	else
+	{
+		// this is a side hit so adjust the "right" value out to the edge of their bbox
+		if (aim[1] < 0)
+			aim[1] = self->enemy->mins[0];
+		else
+			aim[1] = self->enemy->maxs[0];
+	}
+
+	VectorMA (self->s.origin, range, dir, point);
+
+	tr = gi.trace (self->s.origin, NULL, NULL, point, self, MASK_SHOT);
+	if (tr.fraction < 1)
+	{
+		if (!tr.ent->takedamage)
+			return false;
+		// if it will hit any client/monster then hit the one we wanted to hit
+		if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
+			tr.ent = self->enemy;
+	}
+
+	AngleVectors(self->s.angles, forward, right, up);
+	VectorMA (self->s.origin, range, forward, point);
+	VectorMA (point, aim[1], right, point);
+	VectorMA (point, aim[2], up, point);
+	VectorSubtract (point, self->enemy->s.origin, dir);
+
+	// do the damage
+	T_Damage (tr.ent, self, self, dir, point, vec3_origin, damage, kick/2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
+
+	if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
+		return false;
+
+	// do our special form of knockback here
+	VectorMA (self->enemy->absmin, 0.5, self->enemy->size, v);
+	VectorSubtract (v, point, v);
+	VectorNormalize (v);
+	VectorMA (self->enemy->velocity, kick, v, self->enemy->velocity);
+	if (self->enemy->velocity[2] > 0)
+		self->enemy->groundentity = NULL;
+	return true;
+}
+
+
+/*
+=================
+fire_lead
+
+This is an internal support routine used for bullet/pellet based weapons.
+=================
+*/
+static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
+{
+	trace_t		tr;
+	vec3_t		dir;
+	vec3_t		forward, right, up;
+	vec3_t		end;
+	float		r;
+	float		u;
+	vec3_t		water_start;
+	qboolean	water = false;
+	int			content_mask = MASK_SHOT | MASK_WATER;
+
+	tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
+	if (!(tr.fraction < 1.0))
+	{
+		vectoangles (aimdir, dir);
+		AngleVectors (dir, forward, right, up);
+
+		r = crandom()*hspread;
+		u = crandom()*vspread;
+		VectorMA (start, 8192, forward, end);
+		VectorMA (end, r, right, end);
+		VectorMA (end, u, up, end);
+
+		if (gi.pointcontents (start) & MASK_WATER)
+		{
+			water = true;
+			VectorCopy (start, water_start);
+			content_mask &= ~MASK_WATER;
+		}
+
+		tr = gi.trace (start, NULL, NULL, end, self, content_mask);
+
+		// see if we hit water
+		if (tr.contents & MASK_WATER)
+		{
+			int		color;
+
+			water = true;
+			VectorCopy (tr.endpos, water_start);
+
+			if (!VectorCompare (start, tr.endpos))
+			{
+				if (tr.contents & CONTENTS_WATER)
+				{
+					if (strcmp(tr.surface->name, "*brwater") == 0)
+						color = SPLASH_BROWN_WATER;
+					else
+						color = SPLASH_BLUE_WATER;
+				}
+				else if (tr.contents & CONTENTS_SLIME)
+					color = SPLASH_SLIME;
+				else if (tr.contents & CONTENTS_LAVA)
+					color = SPLASH_LAVA;
+				else
+					color = SPLASH_UNKNOWN;
+
+				if (color != SPLASH_UNKNOWN)
+				{
+					gi.WriteByte (svc_temp_entity);
+					gi.WriteByte (TE_SPLASH);
+					gi.WriteByte (8);
+					gi.WritePosition (tr.endpos);
+					gi.WriteDir (tr.plane.normal);
+					gi.WriteByte (color);
+					gi.multicast (tr.endpos, MULTICAST_PVS);
+				}
+
+				// change bullet's course when it enters water
+				VectorSubtract (end, start, dir);
+				vectoangles (dir, dir);
+				AngleVectors (dir, forward, right, up);
+				r = crandom()*hspread*2;
+				u = crandom()*vspread*2;
+				VectorMA (water_start, 8192, forward, end);
+				VectorMA (end, r, right, end);
+				VectorMA (end, u, up, end);
+			}
+
+			// re-trace ignoring water this time
+			tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT);
+		}
+	}
+
+	// send gun puff / flash
+	if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
+	{
+		if (tr.fraction < 1.0)
+		{
+			if (tr.ent->takedamage)
+			{
+				T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
+			}
+			else
+			{
+				if (strncmp (tr.surface->name, "sky", 3) != 0)
+				{
+					gi.WriteByte (svc_temp_entity);
+					gi.WriteByte (te_impact);
+					gi.WritePosition (tr.endpos);
+					gi.WriteDir (tr.plane.normal);
+					gi.multicast (tr.endpos, MULTICAST_PVS);
+
+					if (self->client)
+						PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
+				}
+			}
+		}
+	}
+
+	// if went through water, determine where the end and make a bubble trail
+	if (water)
+	{
+		vec3_t	pos;
+
+		VectorSubtract (tr.endpos, water_start, dir);
+		VectorNormalize (dir);
+		VectorMA (tr.endpos, -2, dir, pos);
+		if (gi.pointcontents (pos) & MASK_WATER)
+			VectorCopy (pos, tr.endpos);
+		else
+			tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER);
+
+		VectorAdd (water_start, tr.endpos, pos);
+		VectorScale (pos, 0.5, pos);
+
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_BUBBLETRAIL);
+		gi.WritePosition (water_start);
+		gi.WritePosition (tr.endpos);
+		gi.multicast (pos, MULTICAST_PVS);
+	}
+}
+
+
+/*
+=================
+fire_bullet
+
+Fires a single round.  Used for machinegun and chaingun.  Would be fine for
+pistols, rifles, etc....
+=================
+*/
+void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod)
+{
+	fire_lead (self, start, aimdir, damage, kick, TE_GUNSHOT, hspread, vspread, mod);
+}
+
+
+/*
+=================
+fire_shotgun
+
+Shoots shotgun pellets.  Used by shotgun and super shotgun.
+=================
+*/
+void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod)
+{
+	int		i;
+
+	for (i = 0; i < count; i++)
+		fire_lead (self, start, aimdir, damage, kick, TE_SHOTGUN, hspread, vspread, mod);
+}
+
+
+/*
+=================
+fire_blaster
+
+Fires a single blaster bolt.  Used by the blaster and hyper blaster.
+=================
+*/
+void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	int		mod;
+
+	if (other == self->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (self->owner->client)
+		PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
+
+	if (other->takedamage)
+	{
+		if (self->spawnflags & 1)
+			mod = MOD_HYPERBLASTER;
+		else
+			mod = MOD_BLASTER;
+		T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod);
+	}
+	else
+	{
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_BLASTER);
+		gi.WritePosition (self->s.origin);
+		if (!plane)
+			gi.WriteDir (vec3_origin);
+		else
+			gi.WriteDir (plane->normal);
+		gi.multicast (self->s.origin, MULTICAST_PVS);
+	}
+
+	G_FreeEdict (self);
+}
+
+void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, qboolean hyper)
+{
+	edict_t	*bolt;
+	trace_t	tr;
+
+	VectorNormalize (dir);
+
+	bolt = G_Spawn();
+	bolt->svflags = SVF_PROJECTILE; // special net code is used for projectiles
+	VectorCopy (start, bolt->s.origin);
+	VectorCopy (start, bolt->s.old_origin);
+	vectoangles (dir, bolt->s.angles);
+	VectorScale (dir, speed, bolt->velocity);
+	bolt->movetype = MOVETYPE_FLYMISSILE;
+	bolt->clipmask = MASK_SHOT;
+	bolt->solid = SOLID_BBOX;
+	bolt->s.effects |= effect;
+	VectorClear (bolt->mins);
+	VectorClear (bolt->maxs);
+	bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2");
+	bolt->s.sound = gi.soundindex ("misc/lasfly.wav");
+	bolt->owner = self;
+	bolt->touch = blaster_touch;
+	bolt->nextthink = level.time + 2;
+	bolt->think = G_FreeEdict;
+	bolt->dmg = damage;
+	bolt->classname = "bolt";
+	if (hyper)
+		bolt->spawnflags = 1;
+	gi.linkentity (bolt);
+
+	if (self->client)
+		check_dodge (self, bolt->s.origin, dir, speed);
+
+	tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
+	if (tr.fraction < 1.0)
+	{
+		VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
+		bolt->touch (bolt, tr.ent, NULL, NULL);
+	}
+}	
+
+
+/*
+=================
+fire_grenade
+=================
+*/
+static void Grenade_Explode (edict_t *ent)
+{
+	vec3_t		origin;
+	int			mod;
+
+	if (ent->owner->client)
+		PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
+
+	//FIXME: if we are onground then raise our Z just a bit since we are a point?
+	if (ent->enemy)
+	{
+		float	points;
+		vec3_t	v;
+		vec3_t	dir;
+
+		VectorAdd (ent->enemy->mins, ent->enemy->maxs, v);
+		VectorMA (ent->enemy->s.origin, 0.5, v, v);
+		VectorSubtract (ent->s.origin, v, v);
+		points = ent->dmg - 0.5 * VectorLength (v);
+		VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir);
+		if (ent->spawnflags & 1)
+			mod = MOD_HANDGRENADE;
+		else
+			mod = MOD_GRENADE;
+		T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
+	}
+
+	if (ent->spawnflags & 2)
+		mod = MOD_HELD_GRENADE;
+	else if (ent->spawnflags & 1)
+		mod = MOD_HG_SPLASH;
+	else
+		mod = MOD_G_SPLASH;
+	T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
+
+	VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
+	gi.WriteByte (svc_temp_entity);
+	if (ent->waterlevel)
+	{
+		if (ent->groundentity)
+			gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
+		else
+			gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
+	}
+	else
+	{
+		if (ent->groundentity)
+			gi.WriteByte (TE_GRENADE_EXPLOSION);
+		else
+			gi.WriteByte (TE_ROCKET_EXPLOSION);
+	}
+	gi.WritePosition (origin);
+	gi.multicast (ent->s.origin, MULTICAST_PHS);
+
+	G_FreeEdict (ent);
+}
+
+static void Grenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other == ent->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!other->takedamage)
+	{
+		if (ent->spawnflags & 1)
+		{
+			if (random() > 0.5)
+				gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
+			else
+				gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
+		}
+		else
+		{
+			gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
+		}
+		return;
+	}
+
+	ent->enemy = other;
+	Grenade_Explode (ent);
+}
+
+void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
+{
+	edict_t	*grenade;
+	vec3_t	dir;
+	vec3_t	forward, right, up;
+
+	vectoangles (aimdir, dir);
+	AngleVectors (dir, forward, right, up);
+
+	grenade = G_Spawn();
+	VectorCopy (start, grenade->s.origin);
+	VectorScale (aimdir, speed, grenade->velocity);
+	VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
+	VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
+	VectorSet (grenade->avelocity, 300, 300, 300);
+	grenade->movetype = MOVETYPE_BOUNCE;
+	grenade->clipmask = MASK_SHOT;
+	grenade->solid = SOLID_BBOX;
+	grenade->s.effects |= EF_GRENADE;
+	VectorClear (grenade->mins);
+	VectorClear (grenade->maxs);
+	grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2");
+	grenade->owner = self;
+	grenade->touch = Grenade_Touch;
+	grenade->nextthink = level.time + timer;
+	grenade->think = Grenade_Explode;
+	grenade->dmg = damage;
+	grenade->dmg_radius = damage_radius;
+	grenade->classname = "grenade";
+
+	gi.linkentity (grenade);
+}
+
+void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
+{
+	edict_t	*grenade;
+	vec3_t	dir;
+	vec3_t	forward, right, up;
+
+	vectoangles (aimdir, dir);
+	AngleVectors (dir, forward, right, up);
+
+	grenade = G_Spawn();
+	VectorCopy (start, grenade->s.origin);
+	VectorScale (aimdir, speed, grenade->velocity);
+	VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
+	VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
+	VectorSet (grenade->avelocity, 300, 300, 300);
+	grenade->movetype = MOVETYPE_BOUNCE;
+	grenade->clipmask = MASK_SHOT;
+	grenade->solid = SOLID_BBOX;
+	grenade->s.effects |= EF_GRENADE;
+	VectorClear (grenade->mins);
+	VectorClear (grenade->maxs);
+	grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2");
+	grenade->owner = self;
+	grenade->touch = Grenade_Touch;
+	grenade->nextthink = level.time + timer;
+	grenade->think = Grenade_Explode;
+	grenade->dmg = damage;
+	grenade->dmg_radius = damage_radius;
+	grenade->classname = "hgrenade";
+	if (held)
+		grenade->spawnflags = 3;
+	else
+		grenade->spawnflags = 1;
+	grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav");
+
+	if (timer <= 0.0)
+		Grenade_Explode (grenade);
+	else
+	{
+		gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
+		gi.linkentity (grenade);
+	}
+}
+
+
+/*
+=================
+fire_rocket
+=================
+*/
+void rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t		origin;
+	int			n;
+
+	if (other == ent->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (ent->owner->client)
+		PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
+
+	// calculate position for the explosion entity
+	VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
+
+	if (other->takedamage)
+	{
+		T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET);
+	}
+	else
+	{
+		// don't throw any debris in net games
+		if (!deathmatch->value && !coop->value)
+		{
+			if ((surf) && !(surf->flags & (SURF_WARP|SURF_TRANS33|SURF_TRANS66|SURF_FLOWING)))
+			{
+				n = rand() % 5;
+				while(n--)
+					ThrowDebris (ent, "models/objects/debris2/tris.md2", 2, ent->s.origin);
+			}
+		}
+	}
+
+	T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH);
+
+	gi.WriteByte (svc_temp_entity);
+	if (ent->waterlevel)
+		gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
+	else
+		gi.WriteByte (TE_ROCKET_EXPLOSION);
+	gi.WritePosition (origin);
+	gi.multicast (ent->s.origin, MULTICAST_PHS);
+
+	G_FreeEdict (ent);
+}
+
+void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
+{
+	edict_t	*rocket;
+
+	rocket = G_Spawn();
+	VectorCopy (start, rocket->s.origin);
+	VectorCopy (dir, rocket->movedir);
+	vectoangles (dir, rocket->s.angles);
+	VectorScale (dir, speed, rocket->velocity);
+	rocket->movetype = MOVETYPE_FLYMISSILE;
+	rocket->clipmask = MASK_SHOT;
+	rocket->solid = SOLID_BBOX;
+	rocket->s.effects |= EF_ROCKET;
+	VectorClear (rocket->mins);
+	VectorClear (rocket->maxs);
+	rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");
+	rocket->owner = self;
+	rocket->touch = rocket_touch;
+	rocket->nextthink = level.time + 8000/speed;
+	rocket->think = G_FreeEdict;
+	rocket->dmg = damage;
+	rocket->radius_dmg = radius_damage;
+	rocket->dmg_radius = damage_radius;
+	rocket->s.sound = gi.soundindex ("weapons/rockfly.wav");
+	rocket->classname = "rocket";
+
+	if (self->client)
+		check_dodge (self, rocket->s.origin, dir, speed);
+
+	gi.linkentity (rocket);
+}
+
+
+/*
+=================
+fire_rail
+=================
+*/
+void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
+{
+	vec3_t		from;
+	vec3_t		end;
+	trace_t		tr;
+	edict_t		*ignore;
+	int			mask;
+	qboolean	water;
+
+	VectorMA (start, 8192, aimdir, end);
+	VectorCopy (start, from);
+	ignore = self;
+	water = false;
+	mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA;
+	while (ignore)
+	{
+		tr = gi.trace (from, NULL, NULL, end, ignore, mask);
+
+		if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA))
+		{
+			mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA);
+			water = true;
+		}
+		else
+		{
+			if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
+				ignore = tr.ent;
+			else
+				ignore = NULL;
+
+			if ((tr.ent != self) && (tr.ent->takedamage))
+				T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_RAILGUN);
+		}
+
+		VectorCopy (tr.endpos, from);
+	}
+
+	// send gun puff / flash
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_RAILTRAIL);
+	gi.WritePosition (start);
+	gi.WritePosition (tr.endpos);
+	gi.multicast (self->s.origin, MULTICAST_PHS);
+//	gi.multicast (start, MULTICAST_PHS);
+	if (water)
+	{
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_RAILTRAIL);
+		gi.WritePosition (start);
+		gi.WritePosition (tr.endpos);
+		gi.multicast (tr.endpos, MULTICAST_PHS);
+	}
+
+	if (self->client)
+		PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
+}
+
+
+/*
+=================
+fire_bfg
+=================
+*/
+void bfg_explode (edict_t *self)
+{
+	edict_t	*ent;
+	float	points;
+	vec3_t	v;
+	float	dist;
+
+	if (self->s.frame == 0)
+	{
+		// the BFG effect
+		ent = NULL;
+		while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL)
+		{
+			if (!ent->takedamage)
+				continue;
+			if (ent == self->owner)
+				continue;
+			if (!CanDamage (ent, self))
+				continue;
+			if (!CanDamage (ent, self->owner))
+				continue;
+
+			VectorAdd (ent->mins, ent->maxs, v);
+			VectorMA (ent->s.origin, 0.5, v, v);
+			VectorSubtract (self->s.origin, v, v);
+			dist = VectorLength(v);
+			points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius));
+			if (ent == self->owner)
+				points = points * 0.5;
+
+			gi.WriteByte (svc_temp_entity);
+			gi.WriteByte (TE_BFG_EXPLOSION);
+			gi.WritePosition (ent->s.origin);
+			gi.multicast (ent->s.origin, MULTICAST_PHS);
+			T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
+		}
+	}
+
+	self->nextthink = level.time + FRAMETIME;
+	self->s.frame++;
+	if (self->s.frame == 5)
+		self->think = G_FreeEdict;
+}
+
+void bfg_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other == self->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (self->owner->client)
+		PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
+
+	// core explosion - prevents firing it into the wall/floor
+	if (other->takedamage)
+		T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST);
+	T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
+
+	gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
+	self->solid = SOLID_NOT;
+	self->touch = NULL;
+	VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
+	VectorClear (self->velocity);
+	self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2");
+	self->s.frame = 0;
+	self->s.sound = 0;
+	self->s.effects &= ~EF_ANIM_ALLFAST;
+	self->think = bfg_explode;
+	self->nextthink = level.time + FRAMETIME;
+	self->enemy = other;
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_BFG_BIGEXPLOSION);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+}
+
+
+void bfg_think (edict_t *self)
+{
+	edict_t	*ent;
+	edict_t	*ignore;
+	vec3_t	point;
+	vec3_t	dir;
+	vec3_t	start;
+	vec3_t	end;
+	int		dmg;
+	trace_t	tr;
+
+	if (deathmatch->value)
+		dmg = 5;
+	else
+		dmg = 10;
+
+	ent = NULL;
+	while ((ent = findradius(ent, self->s.origin, 256)) != NULL)
+	{
+		if (ent == self)
+			continue;
+
+		if (ent == self->owner)
+			continue;
+
+		if (!ent->takedamage)
+			continue;
+
+		if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
+			continue;
+
+//ZOID
+		//don't target players in CTF
+		if (ctf->value && ent->client &&
+			self->owner->client &&
+			ent->client->resp.ctf_team == self->owner->client->resp.ctf_team)
+			continue;
+//ZOID
+
+		VectorMA (ent->absmin, 0.5, ent->size, point);
+
+		VectorSubtract (point, self->s.origin, dir);
+		VectorNormalize (dir);
+
+		ignore = self;
+		VectorCopy (self->s.origin, start);
+		VectorMA (start, 2048, dir, end);
+		while(1)
+		{
+			tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
+
+			if (!tr.ent)
+				break;
+
+			// hurt it if we can
+			if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner))
+				T_Damage (tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
+
+			// if we hit something that's not a monster or player we're done
+			if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
+			{
+				gi.WriteByte (svc_temp_entity);
+				gi.WriteByte (TE_LASER_SPARKS);
+				gi.WriteByte (4);
+				gi.WritePosition (tr.endpos);
+				gi.WriteDir (tr.plane.normal);
+				gi.WriteByte (self->s.skinnum);
+				gi.multicast (tr.endpos, MULTICAST_PVS);
+				break;
+			}
+
+			ignore = tr.ent;
+			VectorCopy (tr.endpos, start);
+		}
+
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_BFG_LASER);
+		gi.WritePosition (self->s.origin);
+		gi.WritePosition (tr.endpos);
+		gi.multicast (self->s.origin, MULTICAST_PHS);
+	}
+
+	self->nextthink = level.time + FRAMETIME;
+}
+
+
+void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius)
+{
+	edict_t	*bfg;
+
+	bfg = G_Spawn();
+	VectorCopy (start, bfg->s.origin);
+	VectorCopy (dir, bfg->movedir);
+	vectoangles (dir, bfg->s.angles);
+	VectorScale (dir, speed, bfg->velocity);
+	bfg->movetype = MOVETYPE_FLYMISSILE;
+	bfg->clipmask = MASK_SHOT;
+	bfg->solid = SOLID_BBOX;
+	bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST;
+	VectorClear (bfg->mins);
+	VectorClear (bfg->maxs);
+	bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2");
+	bfg->owner = self;
+	bfg->touch = bfg_touch;
+	bfg->nextthink = level.time + 8000/speed;
+	bfg->think = G_FreeEdict;
+	bfg->radius_dmg = damage;
+	bfg->dmg_radius = damage_radius;
+	bfg->classname = "bfg blast";
+	bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav");
+
+	bfg->think = bfg_think;
+	bfg->nextthink = level.time + FRAMETIME;
+	bfg->teammaster = bfg;
+	bfg->teamchain = NULL;
+
+	if (self->client)
+		check_dodge (self, bfg->s.origin, dir, speed);
+
+	gi.linkentity (bfg);
+}
--- /dev/null
+++ b/ctf/game.h
@@ -1,0 +1,242 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+// game.h -- game dll information visible to server
+
+#define	GAME_API_VERSION	3
+
+// edict->svflags
+
+#define	SVF_NOCLIENT			0x00000001	// don't send entity to clients, even if it has effects
+#define	SVF_DEADMONSTER			0x00000002	// treat as CONTENTS_DEADMONSTER for collision
+#define	SVF_MONSTER				0x00000004	// treat as CONTENTS_MONSTER for collision
+//ZOID
+#define SVF_PROJECTILE			0x00000008  // entity is simple projectile, used for network optimization
+// if an entity is projectile, the model index/x/y/z/pitch/yaw are sent, encoded into
+// seven (or eight) bytes.  This is to speed up projectiles.  Currently, only the
+// hyperblaster makes use of this.  use for items that are moving with a constant
+// velocity that don't change direction or model
+//ZOID
+
+// edict->solid values
+
+typedef enum
+{
+SOLID_NOT,			// no interaction with other objects
+SOLID_TRIGGER,		// only touch when inside, after moving
+SOLID_BBOX,			// touch on edge
+SOLID_BSP			// bsp clip, touch on edge
+} solid_t;
+
+//===============================================================
+
+// link_t is only used for entity area links now
+typedef struct link_s
+{
+	struct link_s	*prev, *next;
+} link_t;
+
+#define	MAX_ENT_CLUSTERS	16
+
+
+typedef struct edict_s edict_t;
+typedef struct gclient_s gclient_t;
+
+
+#ifndef GAME_INCLUDE
+
+struct gclient_s
+{
+	player_state_t	ps;		// communicated by server to clients
+	int				ping;
+	// the game dll can add anything it wants after
+	// this point in the structure
+};
+
+
+struct edict_s
+{
+	entity_state_t	s;
+	struct gclient_s	*client;
+	qboolean	inuse;
+	int			linkcount;
+
+	// FIXME: move these fields to a server private sv_entity_t
+	link_t		area;				// linked to a division node or leaf
+	
+	int			num_clusters;		// if -1, use headnode instead
+	int			clusternums[MAX_ENT_CLUSTERS];
+	int			headnode;			// unused if num_clusters != -1
+	int			areanum, areanum2;
+
+	//================================
+
+	int			svflags;			// SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc
+	vec3_t		mins, maxs;
+	vec3_t		absmin, absmax, size;
+	solid_t		solid;
+	int			clipmask;
+	edict_t		*owner;
+
+	// the game dll can add anything it wants after
+	// this point in the structure
+};
+
+#endif		// GAME_INCLUDE
+
+//===============================================================
+
+//
+// functions provided by the main engine
+//
+typedef struct
+{
+	// special messages
+	void	(*bprintf) (int printlevel, char *fmt, ...);
+	void	(*dprintf) (char *fmt, ...);
+	void	(*cprintf) (edict_t *ent, int printlevel, char *fmt, ...);
+	void	(*centerprintf) (edict_t *ent, char *fmt, ...);
+	void	(*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
+	void	(*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
+
+	// config strings hold all the index strings, the lightstyles,
+	// and misc data like the sky definition and cdtrack.
+	// All of the current configstrings are sent to clients when
+	// they connect, and changes are sent to all connected clients.
+	void	(*configstring) (int num, char *string);
+
+	void	(*error) (char *fmt, ...);
+
+	// the *index functions create configstrings and some internal server state
+	int		(*modelindex) (char *name);
+	int		(*soundindex) (char *name);
+	int		(*imageindex) (char *name);
+
+	void	(*setmodel) (edict_t *ent, char *name);
+
+	// collision detection
+	trace_t	(*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
+	int		(*pointcontents) (vec3_t point);
+	qboolean	(*inPVS) (vec3_t p1, vec3_t p2);
+	qboolean	(*inPHS) (vec3_t p1, vec3_t p2);
+	void		(*SetAreaPortalState) (int portalnum, qboolean open);
+	qboolean	(*AreasConnected) (int area1, int area2);
+
+	// an entity will never be sent to a client or used for collision
+	// if it is not passed to linkentity.  If the size, position, or
+	// solidity changes, it must be relinked.
+	void	(*linkentity) (edict_t *ent);
+	void	(*unlinkentity) (edict_t *ent);		// call before removing an interactive edict
+	int		(*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list,	int maxcount, int areatype);
+	void	(*Pmove) (pmove_t *pmove);		// player movement code common with client prediction
+
+	// network messaging
+	void	(*multicast) (vec3_t origin, multicast_t to);
+	void	(*unicast) (edict_t *ent, qboolean reliable);
+	void	(*WriteChar) (int c);
+	void	(*WriteByte) (int c);
+	void	(*WriteShort) (int c);
+	void	(*WriteLong) (int c);
+	void	(*WriteFloat) (float f);
+	void	(*WriteString) (char *s);
+	void	(*WritePosition) (vec3_t pos);	// some fractional bits
+	void	(*WriteDir) (vec3_t pos);		// single byte encoded, very coarse
+	void	(*WriteAngle) (float f);
+
+	// managed memory allocation
+	void	*(*TagMalloc) (int size, int tag);
+	void	(*TagFree) (void *block);
+	void	(*FreeTags) (int tag);
+
+	// console variable interaction
+	cvar_t	*(*cvar) (char *var_name, char *value, int flags);
+	cvar_t	*(*cvar_set) (char *var_name, char *value);
+	cvar_t	*(*cvar_forceset) (char *var_name, char *value);
+
+	// ClientCommand and ServerCommand parameter access
+	int		(*argc) (void);
+	char	*(*argv) (int n);
+	char	*(*args) (void);	// concatenation of all argv >= 1
+
+	// add commands to the server console as if they were typed in
+	// for map changing, etc
+	void	(*AddCommandString) (char *text);
+
+	void	(*DebugGraph) (float value, int color);
+} game_import_t;
+
+//
+// functions exported by the game subsystem
+//
+typedef struct
+{
+	int			apiversion;
+
+	// the init function will only be called when a game starts,
+	// not each time a level is loaded.  Persistant data for clients
+	// and the server can be allocated in init
+	void		(*Init) (void);
+	void		(*Shutdown) (void);
+
+	// each new level entered will cause a call to SpawnEntities
+	void		(*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
+
+	// Read/Write Game is for storing persistant cross level information
+	// about the world state and the clients.
+	// WriteGame is called every time a level is exited.
+	// ReadGame is called on a loadgame.
+	void		(*WriteGame) (char *filename, qboolean autosave);
+	void		(*ReadGame) (char *filename);
+
+	// ReadLevel is called after the default map information has been
+	// loaded with SpawnEntities
+	void		(*WriteLevel) (char *filename);
+	void		(*ReadLevel) (char *filename);
+
+	qboolean	(*ClientConnect) (edict_t *ent, char *userinfo);
+	void		(*ClientBegin) (edict_t *ent);
+	void		(*ClientUserinfoChanged) (edict_t *ent, char *userinfo);
+	void		(*ClientDisconnect) (edict_t *ent);
+	void		(*ClientCommand) (edict_t *ent);
+	void		(*ClientThink) (edict_t *ent, usercmd_t *cmd);
+
+	void		(*RunFrame) (void);
+
+	// ServerCommand will be called when an "sv <command>" command is issued on the
+	// server console.
+	// The game can issue gi.argc() / gi.argv() commands to get the rest
+	// of the parameters
+	void		(*ServerCommand) (void);
+
+	//
+	// global variables shared between game and server
+	//
+
+	// The edict array is allocated in the game dll so it
+	// can vary in size from one game to another.
+	// 
+	// The size will be fixed when ge->Init() is called
+	struct edict_s	*edicts;
+	int			edict_size;
+	int			num_edicts;		// current number, <= max_edicts
+	int			max_edicts;
+} game_export_t;
+
+game_export_t *GetGameApi (game_import_t *import);
--- /dev/null
+++ b/ctf/layout.txt
@@ -1,0 +1,12 @@
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+
+Name             Score Kills Deaths BaseDef CarrierDef Efficiency
+0123456789012345 01234 01234 012345 0123456 0123456789 0123456789
+>BC>Zoid           110    40     10       5         10        75%
+
+Name            |Score|Kills|Deaths|BaseDef|CarrierDef|Efficiency|
+----------------+-----+-----+------+-------+----------+----------+
+0123456789012345|01234|01234|012345|0123456|0123456789|0123456789|
+>BC>Zoid        |  110|   40|    10|      5|        10|       75%|
+
+%-16.16s|%5d|%5d|%6d|%7d|%10d|%10d|
--- /dev/null
+++ b/ctf/m_move.c
@@ -1,0 +1,556 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// m_move.c -- monster movement
+
+#include "g_local.h"
+
+#define	STEPSIZE	18
+
+/*
+=============
+M_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 M_CheckBottom (edict_t *ent)
+{
+	vec3_t	mins, maxs, start, stop;
+	trace_t	trace;
+	int		x, y;
+	float	mid, bottom;
+	
+	VectorAdd (ent->s.origin, ent->mins, mins);
+	VectorAdd (ent->s.origin, ent->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 (gi.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 = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
+
+	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 = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
+			
+			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
+=============
+*/
+//FIXME since we need to test end position contents here, can we avoid doing
+//it again later in catagorize position?
+qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
+{
+	float		dz;
+	vec3_t		oldorg, neworg, end;
+	trace_t		trace;
+	int			i;
+	float		stepsize;
+	vec3_t		test;
+	int			contents;
+
+// try the move	
+	VectorCopy (ent->s.origin, oldorg);
+	VectorAdd (ent->s.origin, move, neworg);
+
+// flying monsters don't step up
+	if ( ent->flags & (FL_SWIM | FL_FLY) )
+	{
+	// try one move with vertical motion, then one without
+		for (i=0 ; i<2 ; i++)
+		{
+			VectorAdd (ent->s.origin, move, neworg);
+			if (i == 0 && ent->enemy)
+			{
+				if (!ent->goalentity)
+					ent->goalentity = ent->enemy;
+				dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
+				if (ent->goalentity->client)
+				{
+					if (dz > 40)
+						neworg[2] -= 8;
+					if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
+						if (dz < 30)
+							neworg[2] += 8;
+				}
+				else
+				{
+					if (dz > 8)
+						neworg[2] -= 8;
+					else if (dz > 0)
+						neworg[2] -= dz;
+					else if (dz < -8)
+						neworg[2] += 8;
+					else
+						neworg[2] += dz;
+				}
+			}
+			trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
+	
+			// fly monsters don't enter water voluntarily
+			if (ent->flags & FL_FLY)
+			{
+				if (!ent->waterlevel)
+				{
+					test[0] = trace.endpos[0];
+					test[1] = trace.endpos[1];
+					test[2] = trace.endpos[2] + ent->mins[2] + 1;
+					contents = gi.pointcontents(test);
+					if (contents & MASK_WATER)
+						return false;
+				}
+			}
+
+			// swim monsters don't exit water voluntarily
+			if (ent->flags & FL_SWIM)
+			{
+				if (ent->waterlevel < 2)
+				{
+					test[0] = trace.endpos[0];
+					test[1] = trace.endpos[1];
+					test[2] = trace.endpos[2] + ent->mins[2] + 1;
+					contents = gi.pointcontents(test);
+					if (!(contents & MASK_WATER))
+						return false;
+				}
+			}
+
+			if (trace.fraction == 1)
+			{
+				VectorCopy (trace.endpos, ent->s.origin);
+				if (relink)
+				{
+					gi.linkentity (ent);
+					G_TouchTriggers (ent);
+				}
+				return true;
+			}
+			
+			if (!ent->enemy)
+				break;
+		}
+		
+		return false;
+	}
+
+// push down from a step height above the wished position
+	if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
+		stepsize = STEPSIZE;
+	else
+		stepsize = 1;
+
+	neworg[2] += stepsize;
+	VectorCopy (neworg, end);
+	end[2] -= stepsize*2;
+
+	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
+
+	if (trace.allsolid)
+		return false;
+
+	if (trace.startsolid)
+	{
+		neworg[2] -= stepsize;
+		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
+		if (trace.allsolid || trace.startsolid)
+			return false;
+	}
+
+
+	// don't go in to water
+	if (ent->waterlevel == 0)
+	{
+		test[0] = trace.endpos[0];
+		test[1] = trace.endpos[1];
+		test[2] = trace.endpos[2] + ent->mins[2] + 1;	
+		contents = gi.pointcontents(test);
+
+		if (contents & MASK_WATER)
+			return false;
+	}
+
+	if (trace.fraction == 1)
+	{
+	// if monster had the ground pulled out, go ahead and fall
+		if ( ent->flags & FL_PARTIALGROUND )
+		{
+			VectorAdd (ent->s.origin, move, ent->s.origin);
+			if (relink)
+			{
+				gi.linkentity (ent);
+				G_TouchTriggers (ent);
+			}
+			ent->groundentity = NULL;
+			return true;
+		}
+	
+		return false;		// walked off an edge
+	}
+
+// check point traces down for dangling corners
+	VectorCopy (trace.endpos, ent->s.origin);
+	
+	if (!M_CheckBottom (ent))
+	{
+		if ( ent->flags & FL_PARTIALGROUND )
+		{	// entity had floor mostly pulled out from underneath it
+			// and is trying to correct
+			if (relink)
+			{
+				gi.linkentity (ent);
+				G_TouchTriggers (ent);
+			}
+			return true;
+		}
+		VectorCopy (oldorg, ent->s.origin);
+		return false;
+	}
+
+	if ( ent->flags & FL_PARTIALGROUND )
+	{
+		ent->flags &= ~FL_PARTIALGROUND;
+	}
+	ent->groundentity = trace.ent;
+	ent->groundentity_linkcount = trace.ent->linkcount;
+
+// the move is ok
+	if (relink)
+	{
+		gi.linkentity (ent);
+		G_TouchTriggers (ent);
+	}
+	return true;
+}
+
+
+//============================================================================
+
+/*
+===============
+M_ChangeYaw
+
+===============
+*/
+void M_ChangeYaw (edict_t *ent)
+{
+	float	ideal;
+	float	current;
+	float	move;
+	float	speed;
+	
+	current = anglemod(ent->s.angles[YAW]);
+	ideal = ent->ideal_yaw;
+
+	if (current == ideal)
+		return;
+
+	move = ideal - current;
+	speed = ent->yaw_speed;
+	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->s.angles[YAW] = anglemod (current + move);
+}
+
+
+/*
+======================
+SV_StepDirection
+
+Turns to the movement direction, and walks the current distance if
+facing it.
+
+======================
+*/
+qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
+{
+	vec3_t		move, oldorigin;
+	float		delta;
+	
+	ent->ideal_yaw = yaw;
+	M_ChangeYaw (ent);
+	
+	yaw = yaw*M_PI*2 / 360;
+	move[0] = cos(yaw)*dist;
+	move[1] = sin(yaw)*dist;
+	move[2] = 0;
+
+	VectorCopy (ent->s.origin, oldorigin);
+	if (SV_movestep (ent, move, false))
+	{
+		delta = ent->s.angles[YAW] - ent->ideal_yaw;
+		if (delta > 45 && delta < 315)
+		{		// not turned far enough, so don't take the step
+			VectorCopy (oldorigin, ent->s.origin);
+		}
+		gi.linkentity (ent);
+		G_TouchTriggers (ent);
+		return true;
+	}
+	gi.linkentity (ent);
+	G_TouchTriggers (ent);
+	return false;
+}
+
+/*
+======================
+SV_FixCheckBottom
+
+======================
+*/
+void SV_FixCheckBottom (edict_t *ent)
+{
+	ent->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;
+
+	//FIXME: how did we get here with no enemy
+	if (!enemy)
+		return;
+
+	olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
+	turnaround = anglemod(olddir - 180);
+
+	deltax = enemy->s.origin[0] - actor->s.origin[0];
+	deltay = enemy->s.origin[1] - actor->s.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->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 (!M_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->absmin[i] > ent->absmax[i] + dist)
+			return false;
+		if (goal->absmax[i] < ent->absmin[i] - dist)
+			return false;
+	}
+	return true;
+}
+
+
+/*
+======================
+M_MoveToGoal
+======================
+*/
+void M_MoveToGoal (edict_t *ent, float dist)
+{
+	edict_t		*goal;
+	
+	goal = ent->goalentity;
+
+	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
+		return;
+
+// if the next step hits the enemy, return immediately
+	if (ent->enemy &&  SV_CloseEnough (ent, ent->enemy, dist) )
+		return;
+
+// bump around...
+	if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
+	{
+		if (ent->inuse)
+			SV_NewChaseDir (ent, goal, dist);
+	}
+}
+
+
+/*
+===============
+M_walkmove
+===============
+*/
+qboolean M_walkmove (edict_t *ent, float yaw, float dist)
+{
+	vec3_t	move;
+	
+	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
+		return false;
+
+	yaw = yaw*M_PI*2 / 360;
+	
+	move[0] = cos(yaw)*dist;
+	move[1] = sin(yaw)*dist;
+	move[2] = 0;
+
+	return SV_movestep(ent, move, true);
+}
--- /dev/null
+++ b/ctf/m_player.h
@@ -1,0 +1,225 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/player_x/frames
+
+// This file generated by qdata - Do NOT Modify
+
+#define FRAME_stand01         	0
+#define FRAME_stand02         	1
+#define FRAME_stand03         	2
+#define FRAME_stand04         	3
+#define FRAME_stand05         	4
+#define FRAME_stand06         	5
+#define FRAME_stand07         	6
+#define FRAME_stand08         	7
+#define FRAME_stand09         	8
+#define FRAME_stand10         	9
+#define FRAME_stand11         	10
+#define FRAME_stand12         	11
+#define FRAME_stand13         	12
+#define FRAME_stand14         	13
+#define FRAME_stand15         	14
+#define FRAME_stand16         	15
+#define FRAME_stand17         	16
+#define FRAME_stand18         	17
+#define FRAME_stand19         	18
+#define FRAME_stand20         	19
+#define FRAME_stand21         	20
+#define FRAME_stand22         	21
+#define FRAME_stand23         	22
+#define FRAME_stand24         	23
+#define FRAME_stand25         	24
+#define FRAME_stand26         	25
+#define FRAME_stand27         	26
+#define FRAME_stand28         	27
+#define FRAME_stand29         	28
+#define FRAME_stand30         	29
+#define FRAME_stand31         	30
+#define FRAME_stand32         	31
+#define FRAME_stand33         	32
+#define FRAME_stand34         	33
+#define FRAME_stand35         	34
+#define FRAME_stand36         	35
+#define FRAME_stand37         	36
+#define FRAME_stand38         	37
+#define FRAME_stand39         	38
+#define FRAME_stand40         	39
+#define FRAME_run1            	40
+#define FRAME_run2            	41
+#define FRAME_run3            	42
+#define FRAME_run4            	43
+#define FRAME_run5            	44
+#define FRAME_run6            	45
+#define FRAME_attack1         	46
+#define FRAME_attack2         	47
+#define FRAME_attack3         	48
+#define FRAME_attack4         	49
+#define FRAME_attack5         	50
+#define FRAME_attack6         	51
+#define FRAME_attack7         	52
+#define FRAME_attack8         	53
+#define FRAME_pain101         	54
+#define FRAME_pain102         	55
+#define FRAME_pain103         	56
+#define FRAME_pain104         	57
+#define FRAME_pain201         	58
+#define FRAME_pain202         	59
+#define FRAME_pain203         	60
+#define FRAME_pain204         	61
+#define FRAME_pain301         	62
+#define FRAME_pain302         	63
+#define FRAME_pain303         	64
+#define FRAME_pain304         	65
+#define FRAME_jump1           	66
+#define FRAME_jump2           	67
+#define FRAME_jump3           	68
+#define FRAME_jump4           	69
+#define FRAME_jump5           	70
+#define FRAME_jump6           	71
+#define FRAME_flip01          	72
+#define FRAME_flip02          	73
+#define FRAME_flip03          	74
+#define FRAME_flip04          	75
+#define FRAME_flip05          	76
+#define FRAME_flip06          	77
+#define FRAME_flip07          	78
+#define FRAME_flip08          	79
+#define FRAME_flip09          	80
+#define FRAME_flip10          	81
+#define FRAME_flip11          	82
+#define FRAME_flip12          	83
+#define FRAME_salute01        	84
+#define FRAME_salute02        	85
+#define FRAME_salute03        	86
+#define FRAME_salute04        	87
+#define FRAME_salute05        	88
+#define FRAME_salute06        	89
+#define FRAME_salute07        	90
+#define FRAME_salute08        	91
+#define FRAME_salute09        	92
+#define FRAME_salute10        	93
+#define FRAME_salute11        	94
+#define FRAME_taunt01         	95
+#define FRAME_taunt02         	96
+#define FRAME_taunt03         	97
+#define FRAME_taunt04         	98
+#define FRAME_taunt05         	99
+#define FRAME_taunt06         	100
+#define FRAME_taunt07         	101
+#define FRAME_taunt08         	102
+#define FRAME_taunt09         	103
+#define FRAME_taunt10         	104
+#define FRAME_taunt11         	105
+#define FRAME_taunt12         	106
+#define FRAME_taunt13         	107
+#define FRAME_taunt14         	108
+#define FRAME_taunt15         	109
+#define FRAME_taunt16         	110
+#define FRAME_taunt17         	111
+#define FRAME_wave01          	112
+#define FRAME_wave02          	113
+#define FRAME_wave03          	114
+#define FRAME_wave04          	115
+#define FRAME_wave05          	116
+#define FRAME_wave06          	117
+#define FRAME_wave07          	118
+#define FRAME_wave08          	119
+#define FRAME_wave09          	120
+#define FRAME_wave10          	121
+#define FRAME_wave11          	122
+#define FRAME_point01         	123
+#define FRAME_point02         	124
+#define FRAME_point03         	125
+#define FRAME_point04         	126
+#define FRAME_point05         	127
+#define FRAME_point06         	128
+#define FRAME_point07         	129
+#define FRAME_point08         	130
+#define FRAME_point09         	131
+#define FRAME_point10         	132
+#define FRAME_point11         	133
+#define FRAME_point12         	134
+#define FRAME_crstnd01        	135
+#define FRAME_crstnd02        	136
+#define FRAME_crstnd03        	137
+#define FRAME_crstnd04        	138
+#define FRAME_crstnd05        	139
+#define FRAME_crstnd06        	140
+#define FRAME_crstnd07        	141
+#define FRAME_crstnd08        	142
+#define FRAME_crstnd09        	143
+#define FRAME_crstnd10        	144
+#define FRAME_crstnd11        	145
+#define FRAME_crstnd12        	146
+#define FRAME_crstnd13        	147
+#define FRAME_crstnd14        	148
+#define FRAME_crstnd15        	149
+#define FRAME_crstnd16        	150
+#define FRAME_crstnd17        	151
+#define FRAME_crstnd18        	152
+#define FRAME_crstnd19        	153
+#define FRAME_crwalk1         	154
+#define FRAME_crwalk2         	155
+#define FRAME_crwalk3         	156
+#define FRAME_crwalk4         	157
+#define FRAME_crwalk5         	158
+#define FRAME_crwalk6         	159
+#define FRAME_crattak1        	160
+#define FRAME_crattak2        	161
+#define FRAME_crattak3        	162
+#define FRAME_crattak4        	163
+#define FRAME_crattak5        	164
+#define FRAME_crattak6        	165
+#define FRAME_crattak7        	166
+#define FRAME_crattak8        	167
+#define FRAME_crattak9        	168
+#define FRAME_crpain1         	169
+#define FRAME_crpain2         	170
+#define FRAME_crpain3         	171
+#define FRAME_crpain4         	172
+#define FRAME_crdeath1        	173
+#define FRAME_crdeath2        	174
+#define FRAME_crdeath3        	175
+#define FRAME_crdeath4        	176
+#define FRAME_crdeath5        	177
+#define FRAME_death101        	178
+#define FRAME_death102        	179
+#define FRAME_death103        	180
+#define FRAME_death104        	181
+#define FRAME_death105        	182
+#define FRAME_death106        	183
+#define FRAME_death201        	184
+#define FRAME_death202        	185
+#define FRAME_death203        	186
+#define FRAME_death204        	187
+#define FRAME_death205        	188
+#define FRAME_death206        	189
+#define FRAME_death301        	190
+#define FRAME_death302        	191
+#define FRAME_death303        	192
+#define FRAME_death304        	193
+#define FRAME_death305        	194
+#define FRAME_death306        	195
+#define FRAME_death307        	196
+#define FRAME_death308        	197
+
+#define MODEL_SCALE		1.000000
+
+
--- /dev/null
+++ b/ctf/p_client.c
@@ -1,0 +1,1726 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+void ClientUserinfoChanged (edict_t *ent, char *userinfo);
+
+void SP_misc_teleporter_dest (edict_t *ent);
+
+//
+// Gross, ugly, disgustuing hack section
+//
+
+// this function is an ugly as hell hack to fix some map flaws
+//
+// the coop spawn spots on some maps are SNAFU.  There are coop spots
+// with the wrong targetname as well as spots with no name at all
+//
+// we use carnal knowledge of the maps to fix the coop spot targetnames to match
+// that of the nearest named single player spot
+
+static void SP_FixCoopSpots (edict_t *self)
+{
+	edict_t	*spot;
+	vec3_t	d;
+
+	spot = NULL;
+
+	while(1)
+	{
+		spot = G_Find(spot, FOFS(classname), "info_player_start");
+		if (!spot)
+			return;
+		if (!spot->targetname)
+			continue;
+		VectorSubtract(self->s.origin, spot->s.origin, d);
+		if (VectorLength(d) < 384)
+		{
+			if ((!self->targetname) || stricmp(self->targetname, spot->targetname) != 0)
+			{
+//				gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
+				self->targetname = spot->targetname;
+			}
+			return;
+		}
+	}
+}
+
+// now if that one wasn't ugly enough for you then try this one on for size
+// some maps don't have any coop spots at all, so we need to create them
+// where they should have been
+
+static void SP_CreateCoopSpots (edict_t *self)
+{
+	edict_t	*spot;
+
+	if(stricmp(level.mapname, "security") == 0)
+	{
+		spot = G_Spawn();
+		spot->classname = "info_player_coop";
+		spot->s.origin[0] = 188 - 64;
+		spot->s.origin[1] = -164;
+		spot->s.origin[2] = 80;
+		spot->targetname = "jail3";
+		spot->s.angles[1] = 90;
+
+		spot = G_Spawn();
+		spot->classname = "info_player_coop";
+		spot->s.origin[0] = 188 + 64;
+		spot->s.origin[1] = -164;
+		spot->s.origin[2] = 80;
+		spot->targetname = "jail3";
+		spot->s.angles[1] = 90;
+
+		spot = G_Spawn();
+		spot->classname = "info_player_coop";
+		spot->s.origin[0] = 188 + 128;
+		spot->s.origin[1] = -164;
+		spot->s.origin[2] = 80;
+		spot->targetname = "jail3";
+		spot->s.angles[1] = 90;
+
+		return;
+	}
+}
+
+
+/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
+The normal starting point for a level.
+*/
+void SP_info_player_start(edict_t *self)
+{
+	if (!coop->value)
+		return;
+	if(stricmp(level.mapname, "security") == 0)
+	{
+		// invoke one of our gross, ugly, disgusting hacks
+		self->think = SP_CreateCoopSpots;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
+potential spawning position for deathmatch games
+*/
+void SP_info_player_deathmatch(edict_t *self)
+{
+	if (!deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+	SP_misc_teleporter_dest (self);
+}
+
+/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
+potential spawning position for coop games
+*/
+
+void SP_info_player_coop(edict_t *self)
+{
+	if (!coop->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if((stricmp(level.mapname, "jail2") == 0)   ||
+	   (stricmp(level.mapname, "jail4") == 0)   ||
+	   (stricmp(level.mapname, "mine1") == 0)   ||
+	   (stricmp(level.mapname, "mine2") == 0)   ||
+	   (stricmp(level.mapname, "mine3") == 0)   ||
+	   (stricmp(level.mapname, "mine4") == 0)   ||
+	   (stricmp(level.mapname, "lab") == 0)     ||
+	   (stricmp(level.mapname, "boss1") == 0)   ||
+	   (stricmp(level.mapname, "fact3") == 0)   ||
+	   (stricmp(level.mapname, "biggun") == 0)  ||
+	   (stricmp(level.mapname, "space") == 0)   ||
+	   (stricmp(level.mapname, "command") == 0) ||
+	   (stricmp(level.mapname, "power2") == 0) ||
+	   (stricmp(level.mapname, "strike") == 0))
+	{
+		// invoke one of our gross, ugly, disgusting hacks
+		self->think = SP_FixCoopSpots;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+
+/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
+The deathmatch intermission point will be at one of these
+Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw.  'pitch yaw roll'
+*/
+void SP_info_player_intermission(void)
+{
+}
+
+
+//=======================================================================
+
+
+void player_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	// player pain is handled at the end of the frame in P_DamageFeedback
+}
+
+
+qboolean IsFemale (edict_t *ent)
+{
+	char		*info;
+
+	if (!ent->client)
+		return false;
+
+	info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
+	if (info[0] == 'f' || info[0] == 'F')
+		return true;
+	return false;
+}
+
+
+void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
+{
+	int			mod;
+	char		*message;
+	char		*message2;
+	qboolean	ff;
+
+
+	if (coop->value && attacker->client)
+		meansOfDeath |= MOD_FRIENDLY_FIRE;
+
+	if (deathmatch->value || coop->value)
+	{
+		ff = meansOfDeath & MOD_FRIENDLY_FIRE;
+		mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
+		message = NULL;
+		message2 = "";
+
+		switch (mod)
+		{
+		case MOD_SUICIDE:
+			message = "suicides";
+			break;
+		case MOD_FALLING:
+			message = "cratered";
+			break;
+		case MOD_CRUSH:
+			message = "was squished";
+			break;
+		case MOD_WATER:
+			message = "sank like a rock";
+			break;
+		case MOD_SLIME:
+			message = "melted";
+			break;
+		case MOD_LAVA:
+			message = "does a back flip into the lava";
+			break;
+		case MOD_EXPLOSIVE:
+		case MOD_BARREL:
+			message = "blew up";
+			break;
+		case MOD_EXIT:
+			message = "found a way out";
+			break;
+		case MOD_TARGET_LASER:
+			message = "saw the light";
+			break;
+		case MOD_TARGET_BLASTER:
+			message = "got blasted";
+			break;
+		case MOD_BOMB:
+		case MOD_SPLASH:
+		case MOD_TRIGGER_HURT:
+			message = "was in the wrong place";
+			break;
+		}
+		if (attacker == self)
+		{
+			switch (mod)
+			{
+			case MOD_HELD_GRENADE:
+				message = "tried to put the pin back in";
+				break;
+			case MOD_HG_SPLASH:
+			case MOD_G_SPLASH:
+				if (IsFemale(self))
+					message = "tripped on her own grenade";
+				else
+					message = "tripped on his own grenade";
+				break;
+			case MOD_R_SPLASH:
+				if (IsFemale(self))
+					message = "blew herself up";
+				else
+					message = "blew himself up";
+				break;
+			case MOD_BFG_BLAST:
+				message = "should have used a smaller gun";
+				break;
+			default:
+				if (IsFemale(self))
+					message = "killed herself";
+				else
+					message = "killed himself";
+				break;
+			}
+		}
+		if (message)
+		{
+			gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message);
+			if (deathmatch->value)
+			self->client->resp.score--;
+			self->enemy = NULL;
+			return;
+		}
+
+		self->enemy = attacker;
+		if (attacker && attacker->client)
+		{
+			switch (mod)
+			{
+			case MOD_BLASTER:
+				message = "was blasted by";
+				break;
+			case MOD_SHOTGUN:
+				message = "was gunned down by";
+				break;
+			case MOD_SSHOTGUN:
+				message = "was blown away by";
+				message2 = "'s super shotgun";
+				break;
+			case MOD_MACHINEGUN:
+				message = "was machinegunned by";
+				break;
+			case MOD_CHAINGUN:
+				message = "was cut in half by";
+				message2 = "'s chaingun";
+				break;
+			case MOD_GRENADE:
+				message = "was popped by";
+				message2 = "'s grenade";
+				break;
+			case MOD_G_SPLASH:
+				message = "was shredded by";
+				message2 = "'s shrapnel";
+				break;
+			case MOD_ROCKET:
+				message = "ate";
+				message2 = "'s rocket";
+				break;
+			case MOD_R_SPLASH:
+				message = "almost dodged";
+				message2 = "'s rocket";
+				break;
+			case MOD_HYPERBLASTER:
+				message = "was melted by";
+				message2 = "'s hyperblaster";
+				break;
+			case MOD_RAILGUN:
+				message = "was railed by";
+				break;
+			case MOD_BFG_LASER:
+				message = "saw the pretty lights from";
+				message2 = "'s BFG";
+				break;
+			case MOD_BFG_BLAST:
+				message = "was disintegrated by";
+				message2 = "'s BFG blast";
+				break;
+			case MOD_BFG_EFFECT:
+				message = "couldn't hide from";
+				message2 = "'s BFG";
+				break;
+			case MOD_HANDGRENADE:
+				message = "caught";
+				message2 = "'s handgrenade";
+				break;
+			case MOD_HG_SPLASH:
+				message = "didn't see";
+				message2 = "'s handgrenade";
+				break;
+			case MOD_HELD_GRENADE:
+				message = "feels";
+				message2 = "'s pain";
+				break;
+			case MOD_TELEFRAG:
+				message = "tried to invade";
+				message2 = "'s personal space";
+				break;
+//ZOID
+			case MOD_GRAPPLE:
+				message = "was caught by";
+				message2 = "'s grapple";
+				break;
+//ZOID
+
+			}
+			if (message)
+			{
+				gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
+				if (deathmatch->value)
+				{
+					if (ff)
+						attacker->client->resp.score--;
+					else
+						attacker->client->resp.score++;
+				}
+				return;
+			}
+		}
+	}
+
+	gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
+	if (deathmatch->value)
+	self->client->resp.score--;
+}
+
+
+void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
+
+void TossClientWeapon (edict_t *self)
+{
+	gitem_t		*item;
+	edict_t		*drop;
+	qboolean	quad;
+	float		spread;
+
+	if (!deathmatch->value)
+		return;
+
+	item = self->client->pers.weapon;
+	if (! self->client->pers.inventory[self->client->ammo_index] )
+		item = NULL;
+	if (item && (strcmp (item->pickup_name, "Blaster") == 0))
+		item = NULL;
+
+	if (!((int)(dmflags->value) & DF_QUAD_DROP))
+		quad = false;
+	else
+		quad = (self->client->quad_framenum > (level.framenum + 10));
+
+	if (item && quad)
+		spread = 22.5;
+	else
+		spread = 0.0;
+
+	if (item)
+	{
+		self->client->v_angle[YAW] -= spread;
+		drop = Drop_Item (self, item);
+		self->client->v_angle[YAW] += spread;
+		drop->spawnflags = DROPPED_PLAYER_ITEM;
+	}
+
+	if (quad)
+	{
+		self->client->v_angle[YAW] += spread;
+		drop = Drop_Item (self, FindItemByClassname ("item_quad"));
+		self->client->v_angle[YAW] -= spread;
+		drop->spawnflags |= DROPPED_PLAYER_ITEM;
+
+		drop->touch = Touch_Item;
+		drop->nextthink = level.time + (self->client->quad_framenum - level.framenum) * FRAMETIME;
+		drop->think = G_FreeEdict;
+	}
+}
+
+
+/*
+==================
+LookAtKiller
+==================
+*/
+void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
+{
+	vec3_t		dir;
+
+	if (attacker && attacker != world && attacker != self)
+	{
+		VectorSubtract (attacker->s.origin, self->s.origin, dir);
+	}
+	else if (inflictor && inflictor != world && inflictor != self)
+	{
+		VectorSubtract (inflictor->s.origin, self->s.origin, dir);
+	}
+	else
+	{
+		self->client->killer_yaw = self->s.angles[YAW];
+		return;
+	}
+
+	if (dir[0])
+		self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
+	else {
+		self->client->killer_yaw = 0;
+		if (dir[1] > 0)
+			self->client->killer_yaw = 90;
+		else if (dir[1] < 0)
+			self->client->killer_yaw = -90;
+	}
+	if (self->client->killer_yaw < 0)
+		self->client->killer_yaw += 360;
+}
+
+/*
+==================
+player_die
+==================
+*/
+void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	VectorClear (self->avelocity);
+
+	self->takedamage = DAMAGE_YES;
+	self->movetype = MOVETYPE_TOSS;
+
+	self->s.modelindex2 = 0;	// remove linked weapon model
+//ZOID
+	self->s.modelindex3 = 0;	// remove linked ctf flag
+//ZOID
+
+	self->s.angles[0] = 0;
+	self->s.angles[2] = 0;
+
+	self->s.sound = 0;
+	self->client->weapon_sound = 0;
+
+	self->maxs[2] = -8;
+
+//	self->solid = SOLID_NOT;
+	self->svflags |= SVF_DEADMONSTER;
+
+	if (!self->deadflag)
+	{
+		self->client->respawn_time = level.time + 1.0;
+		LookAtKiller (self, inflictor, attacker);
+		self->client->ps.pmove.pm_type = PM_DEAD;
+		ClientObituary (self, inflictor, attacker);
+//ZOID
+		// if at start and same team, clear
+		if (ctf->value && meansOfDeath == MOD_TELEFRAG &&
+			self->client->resp.ctf_state < 2 &&
+			self->client->resp.ctf_team == attacker->client->resp.ctf_team) {
+			attacker->client->resp.score--;
+			self->client->resp.ctf_state = 0;
+		}
+
+		CTFFragBonuses(self, inflictor, attacker);
+//ZOID
+		TossClientWeapon (self);
+//ZOID
+		CTFPlayerResetGrapple(self);
+		CTFDeadDropFlag(self);
+		CTFDeadDropTech(self);
+//ZOID
+		if (deathmatch->value && !self->client->showscores)
+			Cmd_Help_f (self);		// show scores
+	}
+
+	// remove powerups
+	self->client->quad_framenum = 0;
+	self->client->invincible_framenum = 0;
+	self->client->breather_framenum = 0;
+	self->client->enviro_framenum = 0;
+
+	// clear inventory
+	memset(self->client->pers.inventory, 0, sizeof(self->client->pers.inventory));
+
+	if (self->health < -40)
+	{	// gib
+		gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowClientHead (self, damage);
+//ZOID
+		self->client->anim_priority = ANIM_DEATH;
+		self->client->anim_end = 0;
+//ZOID
+		self->takedamage = DAMAGE_NO;
+	}
+	else
+	{	// normal death
+		if (!self->deadflag)
+		{
+			static int i;
+
+			i = (i+1)%3;
+			// start a death animation
+			self->client->anim_priority = ANIM_DEATH;
+			if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				self->s.frame = FRAME_crdeath1-1;
+				self->client->anim_end = FRAME_crdeath5;
+			}
+			else switch (i)
+			{
+			case 0:
+				self->s.frame = FRAME_death101-1;
+				self->client->anim_end = FRAME_death106;
+				break;
+			case 1:
+				self->s.frame = FRAME_death201-1;
+				self->client->anim_end = FRAME_death206;
+				break;
+			case 2:
+				self->s.frame = FRAME_death301-1;
+				self->client->anim_end = FRAME_death308;
+				break;
+			}
+			gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
+		}
+	}
+
+	self->deadflag = DEAD_DEAD;
+
+	gi.linkentity (self);
+}
+
+//=======================================================================
+
+/*
+==============
+InitClientPersistant
+
+This is only called when the game first initializes in single player,
+but is called after each death and level change in deathmatch
+==============
+*/
+void InitClientPersistant (gclient_t *client)
+{
+	gitem_t		*item;
+
+	memset (&client->pers, 0, sizeof(client->pers));
+
+	item = FindItem("Blaster");
+	client->pers.selected_item = ITEM_INDEX(item);
+	client->pers.inventory[client->pers.selected_item] = 1;
+
+	client->pers.weapon = item;
+//ZOID
+	client->pers.lastweapon = item;
+//ZOID
+
+//ZOID
+	item = FindItem("Grapple");
+	client->pers.inventory[ITEM_INDEX(item)] = 1;
+//ZOID
+
+	client->pers.health			= 100;
+	client->pers.max_health		= 100;
+
+	client->pers.max_bullets	= 200;
+	client->pers.max_shells		= 100;
+	client->pers.max_rockets	= 50;
+	client->pers.max_grenades	= 50;
+	client->pers.max_cells		= 200;
+	client->pers.max_slugs		= 50;
+
+	client->pers.connected = true;
+}
+
+
+void InitClientResp (gclient_t *client)
+{
+//ZOID
+	int ctf_team = client->resp.ctf_team;
+	qboolean id_state = client->resp.id_state;
+//ZOID
+
+	memset (&client->resp, 0, sizeof(client->resp));
+	
+//ZOID
+	client->resp.ctf_team = ctf_team;
+	client->resp.id_state = id_state;
+//ZOID
+
+	client->resp.enterframe = level.framenum;
+	client->resp.coop_respawn = client->pers;
+ 
+//ZOID
+	if (ctf->value && client->resp.ctf_team < CTF_TEAM1)
+		CTFAssignTeam(client);
+//ZOID
+}
+
+/*
+==================
+SaveClientData
+
+Some information that should be persistant, like health, 
+is still stored in the edict structure, so it needs to
+be mirrored out to the client structure before all the
+edicts are wiped.
+==================
+*/
+void SaveClientData (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	for (i=0 ; i<game.maxclients ; i++)
+	{
+		ent = &g_edicts[1+i];
+		if (!ent->inuse)
+			continue;
+		game.clients[i].pers.health = ent->health;
+		game.clients[i].pers.max_health = ent->max_health;
+		game.clients[i].pers.powerArmorActive = (ent->flags & FL_POWER_ARMOR);
+		if (coop->value)
+			game.clients[i].pers.score = ent->client->resp.score;
+	}
+}
+
+void FetchClientEntData (edict_t *ent)
+{
+	ent->health = ent->client->pers.health;
+	ent->max_health = ent->client->pers.max_health;
+	if (ent->client->pers.powerArmorActive)
+		ent->flags |= FL_POWER_ARMOR;
+	if (coop->value)
+		ent->client->resp.score = ent->client->pers.score;
+}
+
+
+
+/*
+=======================================================================
+
+  SelectSpawnPoint
+
+=======================================================================
+*/
+
+/*
+================
+PlayersRangeFromSpot
+
+Returns the distance to the nearest player from the given spot
+================
+*/
+float	PlayersRangeFromSpot (edict_t *spot)
+{
+	edict_t	*player;
+	float	bestplayerdistance;
+	vec3_t	v;
+	int		n;
+	float	playerdistance;
+
+
+	bestplayerdistance = 9999999;
+
+	for (n = 1; n <= maxclients->value; n++)
+	{
+		player = &g_edicts[n];
+
+		if (!player->inuse)
+			continue;
+
+		if (player->health <= 0)
+			continue;
+
+		VectorSubtract (spot->s.origin, player->s.origin, v);
+		playerdistance = VectorLength (v);
+
+		if (playerdistance < bestplayerdistance)
+			bestplayerdistance = playerdistance;
+	}
+
+	return bestplayerdistance;
+}
+
+/*
+================
+SelectRandomDeathmatchSpawnPoint
+
+go to a random point, but NOT the two points closest
+to other players
+================
+*/
+edict_t *SelectRandomDeathmatchSpawnPoint (void)
+{
+	edict_t	*spot, *spot1, *spot2;
+	int		count = 0;
+	int		selection;
+	float	range, range1, range2;
+
+	spot = NULL;
+	range1 = range2 = 99999;
+	spot1 = spot2 = NULL;
+
+	while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
+	{
+		count++;
+		range = PlayersRangeFromSpot(spot);
+		if (range < range1)
+		{
+			range1 = range;
+			spot1 = spot;
+		}
+		else if (range < range2)
+		{
+			range2 = range;
+			spot2 = spot;
+		}
+	}
+
+	if (!count)
+		return NULL;
+
+	if (count <= 2)
+	{
+		spot1 = spot2 = NULL;
+	}
+	else
+		count -= 2;
+
+	selection = rand() % count;
+
+	spot = NULL;
+	do
+	{
+		spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
+		if (spot == spot1 || spot == spot2)
+			selection++;
+	} while(selection--);
+
+	return spot;
+}
+
+/*
+================
+SelectFarthestDeathmatchSpawnPoint
+
+================
+*/
+edict_t *SelectFarthestDeathmatchSpawnPoint (void)
+{
+	edict_t	*bestspot;
+	float	bestdistance, bestplayerdistance;
+	edict_t	*spot;
+
+
+	spot = NULL;
+	bestspot = NULL;
+	bestdistance = 0;
+	while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
+	{
+		bestplayerdistance = PlayersRangeFromSpot (spot);
+
+		if (bestplayerdistance > bestdistance)
+		{
+			bestspot = spot;
+			bestdistance = bestplayerdistance;
+		}
+	}
+
+	if (bestspot)
+	{
+		return bestspot;
+	}
+
+	// if there is a player just spawned on each and every start spot
+	// we have no choice to turn one into a telefrag meltdown
+	spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
+
+	return spot;
+}
+
+edict_t *SelectDeathmatchSpawnPoint (void)
+{
+	if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
+		return SelectFarthestDeathmatchSpawnPoint ();
+	else
+		return SelectRandomDeathmatchSpawnPoint ();
+}
+
+
+edict_t *SelectCoopSpawnPoint (edict_t *ent)
+{
+	int		index;
+	edict_t	*spot = NULL;
+	char	*target;
+
+	index = ent->client - game.clients;
+
+	// player 0 starts in normal player spawn point
+	if (!index)
+		return NULL;
+
+	spot = NULL;
+
+	// assume there are four coop spots at each spawnpoint
+	while (1)
+	{
+		spot = G_Find (spot, FOFS(classname), "info_player_coop");
+		if (!spot)
+			return NULL;	// we didn't have enough...
+
+		target = spot->targetname;
+		if (!target)
+			target = "";
+		if ( Q_stricmp(game.spawnpoint, target) == 0 )
+		{	// this is a coop spawn point for one of the clients here
+			index--;
+			if (!index)
+				return spot;		// this is it
+		}
+	}
+
+
+	return spot;
+}
+
+
+/*
+===========
+SelectSpawnPoint
+
+Chooses a player start, deathmatch start, coop start, etc
+============
+*/
+void	SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
+{
+	edict_t	*spot = NULL;
+
+	if (deathmatch->value)
+//ZOID
+		if (ctf->value)
+			spot = SelectCTFSpawnPoint(ent);
+		else
+//ZOID
+			spot = SelectDeathmatchSpawnPoint ();
+	else if (coop->value)
+		spot = SelectCoopSpawnPoint (ent);
+
+	// find a single player start spot
+	if (!spot)
+	{
+		while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
+		{
+			if (!game.spawnpoint[0] && !spot->targetname)
+				break;
+
+			if (!game.spawnpoint[0] || !spot->targetname)
+				continue;
+
+			if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
+				break;
+		}
+
+		if (!spot)
+		{
+			if (!game.spawnpoint[0])
+			{	// there wasn't a spawnpoint without a target, so use any
+				spot = G_Find (spot, FOFS(classname), "info_player_start");
+			}
+			if (!spot)
+				gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
+		}
+	}
+
+	VectorCopy (spot->s.origin, origin);
+	origin[2] += 9;
+	VectorCopy (spot->s.angles, angles);
+}
+
+//======================================================================
+
+
+void InitBodyQue (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	level.body_que = 0;
+	for (i=0; i<BODY_QUEUE_SIZE ; i++)
+	{
+		ent = G_Spawn();
+		ent->classname = "bodyque";
+	}
+}
+
+void body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int	n;
+
+	if (self->health < -40)
+	{
+		gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		self->s.origin[2] -= 48;
+		ThrowClientHead (self, damage);
+		self->takedamage = DAMAGE_NO;
+	}
+}
+
+void CopyToBodyQue (edict_t *ent)
+{
+	edict_t		*body;
+
+
+	// grab a body que and cycle to the next one
+	body = &g_edicts[(int)maxclients->value + level.body_que + 1];
+	level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
+
+	// FIXME: send an effect on the removed body
+
+	gi.unlinkentity (ent);
+
+	gi.unlinkentity (body);
+	body->s = ent->s;
+	body->s.number = body - g_edicts;
+
+	body->svflags = ent->svflags;
+	VectorCopy (ent->mins, body->mins);
+	VectorCopy (ent->maxs, body->maxs);
+	VectorCopy (ent->absmin, body->absmin);
+	VectorCopy (ent->absmax, body->absmax);
+	VectorCopy (ent->size, body->size);
+	body->solid = ent->solid;
+	body->clipmask = ent->clipmask;
+	body->owner = ent->owner;
+	body->movetype = ent->movetype;
+
+	body->die = body_die;
+	body->takedamage = DAMAGE_YES;
+
+	gi.linkentity (body);
+}
+
+
+void respawn (edict_t *self)
+{
+	if (deathmatch->value || coop->value)
+	{
+		if (self->movetype != MOVETYPE_NOCLIP)
+			CopyToBodyQue (self);
+		self->svflags &= ~SVF_NOCLIENT;
+		PutClientInServer (self);
+
+		// add a teleportation effect
+		self->s.event = EV_PLAYER_TELEPORT;
+
+		// hold in place briefly
+		self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+		self->client->ps.pmove.pm_time = 14;
+
+		self->client->respawn_time = level.time;
+
+		return;
+	}
+
+	// restart the entire server
+	gi.AddCommandString ("menu_loadgame\n");
+}
+
+//==============================================================
+
+
+/*
+===========
+PutClientInServer
+
+Called when a player connects to a server or respawns in
+a deathmatch.
+============
+*/
+void PutClientInServer (edict_t *ent)
+{
+	vec3_t	mins = {-16, -16, -24};
+	vec3_t	maxs = {16, 16, 32};
+	int		index;
+	vec3_t	spawn_origin, spawn_angles;
+	gclient_t	*client;
+	int		i;
+	client_persistant_t	saved;
+	client_respawn_t	resp;
+
+	// find a spawn point
+	// do it before setting health back up, so farthest
+	// ranging doesn't count this client
+	SelectSpawnPoint (ent, spawn_origin, spawn_angles);
+
+	index = ent-g_edicts-1;
+	client = ent->client;
+
+	// deathmatch wipes most client data every spawn
+	if (deathmatch->value)
+	{
+		char		userinfo[MAX_INFO_STRING];
+
+		resp = client->resp;
+		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
+		InitClientPersistant (client);
+		ClientUserinfoChanged (ent, userinfo);
+	}
+	else if (coop->value)
+	{
+		int			n;
+		char		userinfo[MAX_INFO_STRING];
+
+		resp = client->resp;
+		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
+		// this is kind of ugly, but it's how we want to handle keys in coop
+		for (n = 0; n < MAX_ITEMS; n++)
+		{
+			if (itemlist[n].flags & IT_KEY)
+				resp.coop_respawn.inventory[n] = client->pers.inventory[n];
+		}
+		client->pers = resp.coop_respawn;
+		ClientUserinfoChanged (ent, userinfo);
+		if (resp.score > client->pers.score)
+			client->pers.score = resp.score;
+	}
+	else
+	{
+		memset (&resp, 0, sizeof(resp));
+	}
+
+	// clear everything but the persistant data
+	saved = client->pers;
+	memset (client, 0, sizeof(*client));
+	client->pers = saved;
+	if (client->pers.health <= 0)
+		InitClientPersistant(client);
+	client->resp = resp;
+
+	// copy some data from the client to the entity
+	FetchClientEntData (ent);
+
+	// clear entity values
+	ent->groundentity = NULL;
+	ent->client = &game.clients[index];
+	ent->takedamage = DAMAGE_AIM;
+	ent->movetype = MOVETYPE_WALK;
+	ent->viewheight = 22;
+	ent->inuse = true;
+	ent->classname = "player";
+	ent->mass = 200;
+	ent->solid = SOLID_BBOX;
+	ent->deadflag = DEAD_NO;
+	ent->air_finished = level.time + 12;
+	ent->clipmask = MASK_PLAYERSOLID;
+	ent->model = "players/male/tris.md2";
+	ent->pain = player_pain;
+	ent->die = player_die;
+	ent->waterlevel = 0;
+	ent->watertype = 0;
+	ent->flags &= ~FL_NO_KNOCKBACK;
+	ent->svflags &= ~SVF_DEADMONSTER;
+
+	VectorCopy (mins, ent->mins);
+	VectorCopy (maxs, ent->maxs);
+	VectorClear (ent->velocity);
+
+	// clear playerstate values
+	memset (&ent->client->ps, 0, sizeof(client->ps));
+
+	client->ps.pmove.origin[0] = spawn_origin[0]*8;
+	client->ps.pmove.origin[1] = spawn_origin[1]*8;
+	client->ps.pmove.origin[2] = spawn_origin[2]*8;
+//ZOID
+	client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
+//ZOID
+
+	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
+	{
+		client->ps.fov = 90;
+	}
+	else
+	{
+		client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
+		if (client->ps.fov < 1)
+			client->ps.fov = 90;
+		else if (client->ps.fov > 160)
+			client->ps.fov = 160;
+	}
+
+	client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
+
+	// clear entity state values
+	ent->s.effects = 0;
+	ent->s.skinnum = ent - g_edicts - 1;
+	ent->s.modelindex = 255;		// will use the skin specified model
+	ent->s.modelindex2 = 255;		// custom gun model
+	// sknum is player num and weapon number
+	// weapon number will be added in changeweapon
+	ent->s.skinnum = ent - g_edicts - 1;
+
+	ent->s.frame = 0;
+	VectorCopy (spawn_origin, ent->s.origin);
+	ent->s.origin[2] += 1;	// make sure off ground
+	VectorCopy (ent->s.origin, ent->s.old_origin);
+
+	// set the delta angle
+	for (i=0 ; i<3 ; i++)
+		client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
+
+	ent->s.angles[PITCH] = 0;
+	ent->s.angles[YAW] = spawn_angles[YAW];
+	ent->s.angles[ROLL] = 0;
+	VectorCopy (ent->s.angles, client->ps.viewangles);
+	VectorCopy (ent->s.angles, client->v_angle);
+
+//ZOID
+	if (CTFStartClient(ent))
+		return;
+//ZOID
+
+	if (!KillBox (ent))
+	{	// could't spawn in?
+	}
+
+	gi.linkentity (ent);
+
+	// force the current weapon up
+	client->newweapon = client->pers.weapon;
+	ChangeWeapon (ent);
+}
+
+/*
+=====================
+ClientBeginDeathmatch
+
+A client has just connected to the server in 
+deathmatch mode, so clear everything out before starting them.
+=====================
+*/
+void ClientBeginDeathmatch (edict_t *ent)
+{
+	G_InitEdict (ent);
+
+	InitClientResp (ent->client);
+
+	// locate ent at a spawn point
+	PutClientInServer (ent);
+
+	// send effect
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_LOGIN);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
+
+	// make sure all view stuff is valid
+	ClientEndServerFrame (ent);
+}
+
+
+/*
+===========
+ClientBegin
+
+called when a client has finished connecting, and is ready
+to be placed into the game.  This will happen every level load.
+============
+*/
+void ClientBegin (edict_t *ent)
+{
+	int		i;
+
+	ent->client = game.clients + (ent - g_edicts - 1);
+
+	if (deathmatch->value)
+	{
+		ClientBeginDeathmatch (ent);
+		return;
+	}
+
+	// if there is already a body waiting for us (a loadgame), just
+	// take it, otherwise spawn one from scratch
+	if (ent->inuse == true)
+	{
+		// the client has cleared the client side viewangles upon
+		// connecting to the server, which is different than the
+		// state when the game is saved, so we need to compensate
+		// with deltaangles
+		for (i=0 ; i<3 ; i++)
+			ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
+	}
+	else
+	{
+		// a spawn point will completely reinitialize the entity
+		// except for the persistant data that was initialized at
+		// ClientConnect() time
+		G_InitEdict (ent);
+		ent->classname = "player";
+		InitClientResp (ent->client);
+		PutClientInServer (ent);
+	}
+
+	if (level.intermissiontime)
+	{
+		MoveClientToIntermission (ent);
+	}
+	else
+	{
+		// send effect if in a multiplayer game
+		if (game.maxclients > 1)
+		{
+			gi.WriteByte (svc_muzzleflash);
+			gi.WriteShort (ent-g_edicts);
+			gi.WriteByte (MZ_LOGIN);
+			gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+			gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
+		}
+	}
+
+	// make sure all view stuff is valid
+	ClientEndServerFrame (ent);
+}
+
+/*
+===========
+ClientUserInfoChanged
+
+called whenever the player updates a userinfo variable.
+
+The game can override any of the settings in place
+(forcing skins or names, etc) before copying it off.
+============
+*/
+void ClientUserinfoChanged (edict_t *ent, char *userinfo)
+{
+	char	*s;
+	int		playernum;
+
+	// check for malformed or illegal info strings
+	if (!Info_Validate(userinfo))
+	{
+		strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
+	}
+
+	// set name
+	s = Info_ValueForKey (userinfo, "name");
+	strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
+
+	// set skin
+	s = Info_ValueForKey (userinfo, "skin");
+
+	playernum = ent-g_edicts-1;
+
+	// combine name and skin into a configstring
+//ZOID
+	if (ctf->value)
+		CTFAssignSkin(ent, s);
+	else
+//ZOID
+		gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );
+
+	// fov
+	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
+	{
+		ent->client->ps.fov = 90;
+	}
+	else
+	{
+		ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov"));
+		if (ent->client->ps.fov < 1)
+			ent->client->ps.fov = 90;
+		else if (ent->client->ps.fov > 160)
+			ent->client->ps.fov = 160;
+	}
+
+	// handedness
+	s = Info_ValueForKey (userinfo, "hand");
+	if (strlen(s))
+	{
+		ent->client->pers.hand = atoi(s);
+	}
+
+	// save off the userinfo in case we want to check something later
+	strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
+}
+
+
+/*
+===========
+ClientConnect
+
+Called when a player begins connecting to the server.
+The game can refuse entrance to a client by returning false.
+If the client is allowed, the connection process will continue
+and eventually get to ClientBegin()
+Changing levels will NOT cause this to be called again, but
+loadgames will.
+============
+*/
+qboolean ClientConnect (edict_t *ent, char *userinfo)
+{
+	char	*value;
+
+	// check to see if they are on the banned IP list
+	value = Info_ValueForKey (userinfo, "ip");
+
+	// check for a password
+	value = Info_ValueForKey (userinfo, "password");
+	if (*password->string && strcmp(password->string, "none") && 
+		strcmp(password->string, value)) {
+		Info_SetValueForKey(userinfo, "rejmsg", "Password required or incorrect.");
+		return false;
+	}
+
+	// they can connect
+	ent->client = game.clients + (ent - g_edicts - 1);
+
+	// if there is already a body waiting for us (a loadgame), just
+	// take it, otherwise spawn one from scratch
+	if (ent->inuse == false)
+	{
+		// clear the respawning variables
+//ZOID -- force team join
+		ent->client->resp.ctf_team = -1;
+		ent->client->resp.id_state = false; 
+//ZOID
+		InitClientResp (ent->client);
+		if (!game.autosaved || !ent->client->pers.weapon)
+			InitClientPersistant (ent->client);
+	}
+
+	ClientUserinfoChanged (ent, userinfo);
+
+	if (game.maxclients > 1)
+		gi.dprintf ("%s connected\n", ent->client->pers.netname);
+
+	ent->client->pers.connected = true;
+	return true;
+}
+
+/*
+===========
+ClientDisconnect
+
+Called when a player drops from the server.
+Will not be called between levels.
+============
+*/
+void ClientDisconnect (edict_t *ent)
+{
+	int		playernum;
+
+	if (!ent->client)
+		return;
+
+	gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
+
+//ZOID
+	CTFDeadDropFlag(ent);
+	CTFDeadDropTech(ent);
+//ZOID
+
+	// send effect
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_LOGOUT);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	gi.unlinkentity (ent);
+	ent->s.modelindex = 0;
+	ent->solid = SOLID_NOT;
+	ent->inuse = false;
+	ent->classname = "disconnected";
+	ent->client->pers.connected = false;
+
+	playernum = ent-g_edicts-1;
+	gi.configstring (CS_PLAYERSKINS+playernum, "");
+}
+
+
+//==============================================================
+
+
+edict_t	*pm_passent;
+
+// pmove doesn't need to know about passent and contentmask
+trace_t	PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+	if (pm_passent->health > 0)
+		return gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
+	else
+		return gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
+}
+
+unsigned CheckBlock (void *b, int c)
+{
+	int	v,i;
+	v = 0;
+	for (i=0 ; i<c ; i++)
+		v+= ((byte *)b)[i];
+	return v;
+}
+void PrintPmove (pmove_t *pm)
+{
+	unsigned	c1, c2;
+
+	c1 = CheckBlock (&pm->s, sizeof(pm->s));
+	c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd));
+	Com_Printf ("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2);
+}
+
+/*
+==============
+ClientThink
+
+This will be called once for each client frame, which will
+usually be a couple times for each server frame.
+==============
+*/
+void ClientThink (edict_t *ent, usercmd_t *ucmd)
+{
+	gclient_t	*client;
+	edict_t	*other;
+	int		i, j;
+	pmove_t	pm;
+
+	level.current_entity = ent;
+	client = ent->client;
+
+	if (level.intermissiontime)
+	{
+		client->ps.pmove.pm_type = PM_FREEZE;
+		// can exit intermission after five seconds
+		if (level.time > level.intermissiontime + 5.0 
+			&& (ucmd->buttons & BUTTON_ANY) )
+			level.exitintermission = true;
+		return;
+	}
+
+	pm_passent = ent;
+
+//ZOID
+	if (ent->client->chase_target) {
+		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
+		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
+		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
+		return;
+	}
+//ZOID
+
+	// set up for pmove
+	memset (&pm, 0, sizeof(pm));
+
+	if (ent->movetype == MOVETYPE_NOCLIP)
+		client->ps.pmove.pm_type = PM_SPECTATOR;
+	else if (ent->s.modelindex != 255)
+		client->ps.pmove.pm_type = PM_GIB;
+	else if (ent->deadflag)
+		client->ps.pmove.pm_type = PM_DEAD;
+	else
+		client->ps.pmove.pm_type = PM_NORMAL;
+
+	client->ps.pmove.gravity = sv_gravity->value;
+	pm.s = client->ps.pmove;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		pm.s.origin[i] = ent->s.origin[i]*8;
+		pm.s.velocity[i] = ent->velocity[i]*8;
+	}
+
+	if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
+	{
+		pm.snapinitial = true;
+//		gi.dprintf ("pmove changed!\n");
+	}
+
+	pm.cmd = *ucmd;
+
+	pm.trace = PM_trace;	// adds default parms
+	pm.pointcontents = gi.pointcontents;
+
+	// perform a pmove
+	gi.Pmove (&pm);
+
+	// save results of pmove
+	client->ps.pmove = pm.s;
+	client->old_pmove = pm.s;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		ent->s.origin[i] = pm.s.origin[i]*0.125;
+		ent->velocity[i] = pm.s.velocity[i]*0.125;
+	}
+
+	VectorCopy (pm.mins, ent->mins);
+	VectorCopy (pm.maxs, ent->maxs);
+
+	client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
+	client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
+	client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
+
+	if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
+	{
+		gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
+		PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
+	}
+
+	ent->viewheight = pm.viewheight;
+	ent->waterlevel = pm.waterlevel;
+	ent->watertype = pm.watertype;
+	ent->groundentity = pm.groundentity;
+	if (pm.groundentity)
+		ent->groundentity_linkcount = pm.groundentity->linkcount;
+
+	if (ent->deadflag)
+	{
+		client->ps.viewangles[ROLL] = 40;
+		client->ps.viewangles[PITCH] = -15;
+		client->ps.viewangles[YAW] = client->killer_yaw;
+	}
+	else
+	{
+		VectorCopy (pm.viewangles, client->v_angle);
+		VectorCopy (pm.viewangles, client->ps.viewangles);
+	}
+
+//ZOID
+	if (client->ctf_grapple)
+		CTFGrapplePull(client->ctf_grapple);
+//ZOID
+
+	gi.linkentity (ent);
+
+	if (ent->movetype != MOVETYPE_NOCLIP)
+		G_TouchTriggers (ent);
+
+	// touch other objects
+	for (i=0 ; i<pm.numtouch ; i++)
+	{
+		other = pm.touchents[i];
+		for (j=0 ; j<i ; j++)
+			if (pm.touchents[j] == other)
+				break;
+		if (j != i)
+			continue;	// duplicated
+		if (!other->touch)
+			continue;
+		other->touch (other, ent, NULL, NULL);
+	}
+
+
+	client->oldbuttons = client->buttons;
+	client->buttons = ucmd->buttons;
+	client->latched_buttons |= client->buttons & ~client->oldbuttons;
+
+	// save light level the player is standing on for
+	// monster sighting AI
+	ent->light_level = ucmd->lightlevel;
+
+	// fire weapon from final position if needed
+	if (client->latched_buttons & BUTTON_ATTACK
+//ZOID
+		&& ent->movetype != MOVETYPE_NOCLIP
+//ZOID
+		)
+	{
+		if (!client->weapon_thunk)
+		{
+			client->weapon_thunk = true;
+			Think_Weapon (ent);
+		}
+	}
+
+//ZOID
+//regen tech
+	CTFApplyRegeneration(ent);
+//ZOID
+
+//ZOID
+	for (i = 1; i <= maxclients->value; i++) {
+		other = g_edicts + i;
+		if (other->inuse && other->client->chase_target == ent)
+			UpdateChaseCam(other);
+	}
+
+	if (client->menudirty && client->menutime <= level.time) {
+		PMenu_Do_Update(ent);
+		gi.unicast (ent, true);
+		client->menutime = level.time;
+		client->menudirty = false;
+	}
+//ZOID
+}
+
+
+/*
+==============
+ClientBeginServerFrame
+
+This will be called once for each server frame, before running
+any other entities in the world.
+==============
+*/
+void ClientBeginServerFrame (edict_t *ent)
+{
+	gclient_t	*client;
+	int			buttonMask;
+
+	if (level.intermissiontime)
+		return;
+
+	client = ent->client;
+
+	// run weapon animations if it hasn't been done by a ucmd_t
+	if (!client->weapon_thunk
+//ZOID
+		&& ent->movetype != MOVETYPE_NOCLIP
+//ZOID
+		)
+		Think_Weapon (ent);
+	else
+		client->weapon_thunk = false;
+
+	if (ent->deadflag)
+	{
+		// wait for any button just going down
+		if ( level.time > client->respawn_time)
+		{
+			// in deathmatch, only wait for attack button
+			if (deathmatch->value)
+				buttonMask = BUTTON_ATTACK;
+			else
+				buttonMask = -1;
+
+			if ( ( client->latched_buttons & buttonMask ) ||
+				(deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) ||
+				CTFMatchOn())
+			{
+				respawn(ent);
+				client->latched_buttons = 0;
+			}
+		}
+		return;
+	}
+
+	// add player trail so monsters can follow
+	if (!deathmatch->value)
+		if (!visible (ent, PlayerTrail_LastSpot() ) )
+			PlayerTrail_Add (ent->s.old_origin);
+
+	client->latched_buttons = 0;
+}
--- /dev/null
+++ b/ctf/p_hud.c
@@ -1,0 +1,544 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+
+/*
+======================================================================
+
+INTERMISSION
+
+======================================================================
+*/
+
+void MoveClientToIntermission (edict_t *ent)
+{
+	if (deathmatch->value || coop->value)
+		ent->client->showscores = true;
+	VectorCopy (level.intermission_origin, ent->s.origin);
+	ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8;
+	ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8;
+	ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8;
+	VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
+	ent->client->ps.pmove.pm_type = PM_FREEZE;
+	ent->client->ps.gunindex = 0;
+	ent->client->ps.blend[3] = 0;
+	ent->client->ps.rdflags &= ~RDF_UNDERWATER;
+
+	// clean up powerup info
+	ent->client->quad_framenum = 0;
+	ent->client->invincible_framenum = 0;
+	ent->client->breather_framenum = 0;
+	ent->client->enviro_framenum = 0;
+	ent->client->grenade_blew_up = false;
+	ent->client->grenade_time = 0;
+
+	ent->viewheight = 0;
+	ent->s.modelindex = 0;
+	ent->s.modelindex2 = 0;
+	ent->s.modelindex3 = 0;
+	ent->s.modelindex = 0;
+	ent->s.effects = 0;
+	ent->s.sound = 0;
+	ent->solid = SOLID_NOT;
+
+	// add the layout
+
+	if (deathmatch->value || coop->value)
+	{
+		DeathmatchScoreboardMessage (ent, NULL);
+		gi.unicast (ent, true);
+	}
+
+}
+
+void BeginIntermission (edict_t *targ)
+{
+	int		i, n;
+	edict_t	*ent, *client;
+
+	if (level.intermissiontime)
+		return;		// allready activated
+
+//ZOID
+	if (deathmatch->value && ctf->value)
+		CTFCalcScores();
+//ZOID
+
+	game.autosaved = false;
+
+	// respawn any dead clients
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		client = g_edicts + 1 + i;
+		if (!client->inuse)
+			continue;
+		if (client->health <= 0)
+			respawn(client);
+	}
+
+	level.intermissiontime = level.time;
+	level.changemap = targ->map;
+
+	if (strstr(level.changemap, "*"))
+	{
+		if (coop->value)
+		{
+			for (i=0 ; i<maxclients->value ; i++)
+			{
+				client = g_edicts + 1 + i;
+				if (!client->inuse)
+					continue;
+				// strip players of all keys between units
+				for (n = 0; n < MAX_ITEMS; n++)
+				{
+					if (itemlist[n].flags & IT_KEY)
+						client->client->pers.inventory[n] = 0;
+				}
+			}
+		}
+	}
+	else
+	{
+		if (!deathmatch->value)
+		{
+			level.exitintermission = 1;		// go immediately to the next level
+			return;
+		}
+	}
+
+	level.exitintermission = 0;
+
+	// find an intermission spot
+	ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
+	if (!ent)
+	{	// the map creator forgot to put in an intermission point...
+		ent = G_Find (NULL, FOFS(classname), "info_player_start");
+		if (!ent)
+			ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
+	}
+	else
+	{	// chose one of four spots
+		i = rand() & 3;
+		while (i--)
+		{
+			ent = G_Find (ent, FOFS(classname), "info_player_intermission");
+			if (!ent)	// wrap around the list
+				ent = G_Find (ent, FOFS(classname), "info_player_intermission");
+		}
+	}
+
+	VectorCopy (ent->s.origin, level.intermission_origin);
+	VectorCopy (ent->s.angles, level.intermission_angle);
+
+	// move all clients to the intermission point
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		client = g_edicts + 1 + i;
+		if (!client->inuse)
+			continue;
+		MoveClientToIntermission (client);
+	}
+}
+
+
+/*
+==================
+DeathmatchScoreboardMessage
+
+==================
+*/
+void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer)
+{
+	char	entry[1024];
+	char	string[1400];
+	int		stringlength;
+	int		i, j, k;
+	int		sorted[MAX_CLIENTS];
+	int		sortedscores[MAX_CLIENTS];
+	int		score, total;
+	int		picnum;
+	int		x, y;
+	gclient_t	*cl;
+	edict_t		*cl_ent;
+	char	*tag;
+
+//ZOID
+	if (ctf->value) {
+		CTFScoreboardMessage (ent, killer);
+		return;
+	}
+//ZOID
+
+	// sort the clients by score
+	total = 0;
+	for (i=0 ; i<game.maxclients ; i++)
+	{
+		cl_ent = g_edicts + 1 + i;
+		if (!cl_ent->inuse)
+			continue;
+		score = game.clients[i].resp.score;
+		for (j=0 ; j<total ; j++)
+		{
+			if (score > sortedscores[j])
+				break;
+		}
+		for (k=total ; k>j ; k--)
+		{
+			sorted[k] = sorted[k-1];
+			sortedscores[k] = sortedscores[k-1];
+		}
+		sorted[j] = i;
+		sortedscores[j] = score;
+		total++;
+	}
+
+	// print level name and exit rules
+	string[0] = 0;
+
+	stringlength = strlen(string);
+
+	// add the clients in sorted order
+	if (total > 12)
+		total = 12;
+
+	for (i=0 ; i<total ; i++)
+	{
+		cl = &game.clients[sorted[i]];
+		cl_ent = g_edicts + 1 + sorted[i];
+
+		picnum = gi.imageindex ("i_fixme");
+		x = (i>=6) ? 160 : 0;
+		y = 32 + 32 * (i%6);
+
+		// add a dogtag
+		if (cl_ent == ent)
+			tag = "tag1";
+		else if (cl_ent == killer)
+			tag = "tag2";
+		else
+			tag = NULL;
+		if (tag)
+		{
+			Com_sprintf (entry, sizeof(entry),
+				"xv %i yv %i picn %s ",x+32, y, tag);
+			j = strlen(entry);
+			if (stringlength + j > 1024)
+				break;
+			strcpy (string + stringlength, entry);
+			stringlength += j;
+		}
+
+		// send the layout
+		Com_sprintf (entry, sizeof(entry),
+			"client %i %i %i %i %i %i ",
+			x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe)/600);
+		j = strlen(entry);
+		if (stringlength + j > 1024)
+			break;
+		strcpy (string + stringlength, entry);
+		stringlength += j;
+	}
+
+	gi.WriteByte (svc_layout);
+	gi.WriteString (string);
+}
+
+
+/*
+==================
+DeathmatchScoreboard
+
+Draw instead of help message.
+Note that it isn't that hard to overflow the 1400 byte message limit!
+==================
+*/
+void DeathmatchScoreboard (edict_t *ent)
+{
+	DeathmatchScoreboardMessage (ent, ent->enemy);
+	gi.unicast (ent, true);
+}
+
+
+/*
+==================
+Cmd_Score_f
+
+Display the scoreboard
+==================
+*/
+void Cmd_Score_f (edict_t *ent)
+{
+	ent->client->showinventory = false;
+	ent->client->showhelp = false;
+//ZOID
+	if (ent->client->menu)
+		PMenu_Close(ent);
+//ZOID
+
+	if (!deathmatch->value && !coop->value)
+		return;
+
+	if (ent->client->showscores)
+	{
+		ent->client->showscores = false;
+		ent->client->update_chase = true;
+		return;
+	}
+
+	ent->client->showscores = true;
+
+	DeathmatchScoreboard (ent);
+}
+
+
+/*
+==================
+HelpComputer
+
+Draw help computer.
+==================
+*/
+void HelpComputer (edict_t *ent)
+{
+	char	string[1024];
+	char	*sk;
+
+	if (skill->value == 0)
+		sk = "easy";
+	else if (skill->value == 1)
+		sk = "medium";
+	else if (skill->value == 2)
+		sk = "hard";
+	else
+		sk = "hard+";
+
+	// send the layout
+	Com_sprintf (string, sizeof(string),
+		"xv 32 yv 8 picn help "			// background
+		"xv 202 yv 12 string2 \"%s\" "		// skill
+		"xv 0 yv 24 cstring2 \"%s\" "		// level name
+		"xv 0 yv 54 cstring2 \"%s\" "		// help 1
+		"xv 0 yv 110 cstring2 \"%s\" "		// help 2
+		"xv 50 yv 164 string2 \" kills     goals    secrets\" "
+		"xv 50 yv 172 string2 \"%3i/%3i     %i/%i       %i/%i\" ", 
+		sk,
+		level.level_name,
+		game.helpmessage1,
+		game.helpmessage2,
+		level.killed_monsters, level.total_monsters, 
+		level.found_goals, level.total_goals,
+		level.found_secrets, level.total_secrets);
+
+	gi.WriteByte (svc_layout);
+	gi.WriteString (string);
+	gi.unicast (ent, true);
+}
+
+
+/*
+==================
+Cmd_Help_f
+
+Display the current help message
+==================
+*/
+void Cmd_Help_f (edict_t *ent)
+{
+	// this is for backwards compatability
+	if (deathmatch->value)
+	{
+		Cmd_Score_f (ent);
+		return;
+	}
+
+	ent->client->showinventory = false;
+	ent->client->showscores = false;
+
+	if (ent->client->showhelp && (ent->client->resp.game_helpchanged == game.helpchanged))
+	{
+		ent->client->showhelp = false;
+		return;
+	}
+
+	ent->client->showhelp = true;
+	ent->client->resp.helpchanged = 0;
+	HelpComputer (ent);
+}
+
+
+//=======================================================================
+
+/*
+===============
+G_SetStats
+===============
+*/
+void G_SetStats (edict_t *ent)
+{
+	gitem_t		*item;
+	int			index, cells;
+	int			power_armor_type;
+
+	//
+	// health
+	//
+	ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
+	ent->client->ps.stats[STAT_HEALTH] = ent->health;
+
+	//
+	// ammo
+	//
+	if (!ent->client->ammo_index /* || !ent->client->pers.inventory[ent->client->ammo_index] */)
+	{
+		ent->client->ps.stats[STAT_AMMO_ICON] = 0;
+		ent->client->ps.stats[STAT_AMMO] = 0;
+	}
+	else
+	{
+		item = &itemlist[ent->client->ammo_index];
+		ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex (item->icon);
+		ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index];
+	}
+	
+	//
+	// armor
+	//
+	power_armor_type = PowerArmorType (ent);
+	if (power_armor_type)
+	{
+		cells = ent->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
+		if (cells == 0)
+		{	// ran out of cells for power armor
+			ent->flags &= ~FL_POWER_ARMOR;
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
+			power_armor_type = 0;;
+		}
+	}
+
+	index = ArmorIndex (ent);
+	if (power_armor_type && (!index || (level.framenum & 8) ) )
+	{	// flash between power armor and other armor icon
+		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
+		ent->client->ps.stats[STAT_ARMOR] = cells;
+	}
+	else if (index)
+	{
+		item = GetItemByIndex (index);
+		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex (item->icon);
+		ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index];
+	}
+	else
+	{
+		ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
+		ent->client->ps.stats[STAT_ARMOR] = 0;
+	}
+
+	//
+	// pickup message
+	//
+	if (level.time > ent->client->pickup_msg_time)
+	{
+		ent->client->ps.stats[STAT_PICKUP_ICON] = 0;
+		ent->client->ps.stats[STAT_PICKUP_STRING] = 0;
+	}
+
+	//
+	// timers
+	//
+	if (ent->client->quad_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
+	}
+	else if (ent->client->invincible_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_invulnerability");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum)/10;
+	}
+	else if (ent->client->enviro_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_envirosuit");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum)/10;
+	}
+	else if (ent->client->breather_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_rebreather");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum)/10;
+	}
+	else
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = 0;
+		ent->client->ps.stats[STAT_TIMER] = 0;
+	}
+
+	//
+	// selected item
+	//
+	if (ent->client->pers.selected_item == -1)
+		ent->client->ps.stats[STAT_SELECTED_ICON] = 0;
+	else
+		ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex (itemlist[ent->client->pers.selected_item].icon);
+
+	ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item;
+
+	//
+	// layouts
+	//
+	ent->client->ps.stats[STAT_LAYOUTS] = 0;
+
+	if (deathmatch->value)
+	{
+		if (ent->client->pers.health <= 0 || level.intermissiontime
+			|| ent->client->showscores)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
+		if (ent->client->showinventory && ent->client->pers.health > 0)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
+	}
+	else
+	{
+		if (ent->client->showscores || ent->client->showhelp)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
+		if (ent->client->showinventory && ent->client->pers.health > 0)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
+	}
+
+	//
+	// frags
+	//
+	ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score;
+
+	//
+	// help icon / current weapon if not shown
+	//
+	if (ent->client->resp.helpchanged && (level.framenum&8) )
+		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex ("i_help");
+	else if ( (ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91)
+		&& ent->client->pers.weapon)
+		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon);
+	else
+		ent->client->ps.stats[STAT_HELPICON] = 0;
+
+//ZOID
+	SetCTFStats(ent);
+//ZOID
+}
+
--- /dev/null
+++ b/ctf/p_menu.c
@@ -1,0 +1,256 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+// Note that the pmenu entries are duplicated
+// this is so that a static set of pmenu entries can be used
+// for multiple clients and changed without interference
+// note that arg will be freed when the menu is closed, it must be allocated memory
+pmenuhnd_t *PMenu_Open(edict_t *ent, pmenu_t *entries, int cur, int num, void *arg)
+{
+	pmenuhnd_t *hnd;
+	pmenu_t *p;
+	int i;
+
+	if (!ent->client)
+		return NULL;
+
+	if (ent->client->menu) {
+		gi.dprintf("warning, ent already has a menu\n");
+		PMenu_Close(ent);
+	}
+
+	hnd = malloc(sizeof(*hnd));
+
+	hnd->arg = arg;
+	hnd->entries = malloc(sizeof(pmenu_t) * num);
+	memcpy(hnd->entries, entries, sizeof(pmenu_t) * num);
+	// duplicate the strings since they may be from static memory
+	for (i = 0; i < num; i++)
+		if (entries[i].text)
+			hnd->entries[i].text = strdup(entries[i].text);
+
+	hnd->num = num;
+
+	if (cur < 0 || !entries[cur].SelectFunc) {
+		for (i = 0, p = entries; i < num; i++, p++)
+			if (p->SelectFunc)
+				break;
+	} else
+		i = cur;
+
+	if (i >= num)
+		hnd->cur = -1;
+	else
+		hnd->cur = i;
+
+	ent->client->showscores = true;
+	ent->client->inmenu = true;
+	ent->client->menu = hnd;
+
+	PMenu_Do_Update(ent);
+	gi.unicast (ent, true);
+
+	return hnd;
+}
+
+void PMenu_Close(edict_t *ent)
+{
+	int i;
+	pmenuhnd_t *hnd;
+
+	if (!ent->client->menu)
+		return;
+
+	hnd = ent->client->menu;
+	for (i = 0; i < hnd->num; i++)
+		if (hnd->entries[i].text)
+			free(hnd->entries[i].text);
+	free(hnd->entries);
+	if (hnd->arg)
+		free(hnd->arg);
+	free(hnd);
+	ent->client->menu = NULL;
+	ent->client->showscores = false;
+}
+
+// only use on pmenu's that have been called with PMenu_Open
+void PMenu_UpdateEntry(pmenu_t *entry, const char *text, int align, SelectFunc_t SelectFunc)
+{
+	if (entry->text)
+		free(entry->text);
+	entry->text = strdup(text);
+	entry->align = align;
+	entry->SelectFunc = SelectFunc;
+}
+
+void PMenu_Do_Update(edict_t *ent)
+{
+	char string[1400];
+	int i;
+	pmenu_t *p;
+	int x;
+	pmenuhnd_t *hnd;
+	char *t;
+	qboolean alt = false;
+
+	if (!ent->client->menu) {
+		gi.dprintf("warning:  ent has no menu\n");
+		return;
+	}
+
+	hnd = ent->client->menu;
+
+	strcpy(string, "xv 32 yv 8 picn inventory ");
+
+	for (i = 0, p = hnd->entries; i < hnd->num; i++, p++) {
+		if (!p->text || !*(p->text))
+			continue; // blank line
+		t = p->text;
+		if (*t == '*') {
+			alt = true;
+			t++;
+		}
+		sprintf(string + strlen(string), "yv %d ", 32 + i * 8);
+		if (p->align == PMENU_ALIGN_CENTER)
+			x = 196/2 - strlen(t)*4 + 64;
+		else if (p->align == PMENU_ALIGN_RIGHT)
+			x = 64 + (196 - strlen(t)*8);
+		else
+			x = 64;
+
+		sprintf(string + strlen(string), "xv %d ",
+			x - ((hnd->cur == i) ? 8 : 0));
+
+		if (hnd->cur == i)
+			sprintf(string + strlen(string), "string2 \"\x0d%s\" ", t);
+		else if (alt)
+			sprintf(string + strlen(string), "string2 \"%s\" ", t);
+		else
+			sprintf(string + strlen(string), "string \"%s\" ", t);
+		alt = false;
+	}
+
+	gi.WriteByte (svc_layout);
+	gi.WriteString (string);
+}
+
+void PMenu_Update(edict_t *ent)
+{
+	if (!ent->client->menu) {
+		gi.dprintf("warning:  ent has no menu\n");
+		return;
+	}
+
+	if (level.time - ent->client->menutime >= 1.0) {
+		// been a second or more since last update, update now
+		PMenu_Do_Update(ent);
+		gi.unicast (ent, true);
+		ent->client->menutime = level.time;
+		ent->client->menudirty = false;
+	}
+	ent->client->menutime = level.time + 0.2;
+	ent->client->menudirty = true;
+}
+
+void PMenu_Next(edict_t *ent)
+{
+	pmenuhnd_t *hnd;
+	int i;
+	pmenu_t *p;
+
+	if (!ent->client->menu) {
+		gi.dprintf("warning:  ent has no menu\n");
+		return;
+	}
+
+	hnd = ent->client->menu;
+
+	if (hnd->cur < 0)
+		return; // no selectable entries
+
+	i = hnd->cur;
+	p = hnd->entries + hnd->cur;
+	do {
+		i++, p++;
+		if (i == hnd->num)
+			i = 0, p = hnd->entries;
+		if (p->SelectFunc)
+			break;
+	} while (i != hnd->cur);
+
+	hnd->cur = i;
+
+	PMenu_Update(ent);
+}
+
+void PMenu_Prev(edict_t *ent)
+{
+	pmenuhnd_t *hnd;
+	int i;
+	pmenu_t *p;
+
+	if (!ent->client->menu) {
+		gi.dprintf("warning:  ent has no menu\n");
+		return;
+	}
+
+	hnd = ent->client->menu;
+
+	if (hnd->cur < 0)
+		return; // no selectable entries
+
+	i = hnd->cur;
+	p = hnd->entries + hnd->cur;
+	do {
+		if (i == 0) {
+			i = hnd->num - 1;
+			p = hnd->entries + i;
+		} else
+			i--, p--;
+		if (p->SelectFunc)
+			break;
+	} while (i != hnd->cur);
+
+	hnd->cur = i;
+
+	PMenu_Update(ent);
+}
+
+void PMenu_Select(edict_t *ent)
+{
+	pmenuhnd_t *hnd;
+	pmenu_t *p;
+
+	if (!ent->client->menu) {
+		gi.dprintf("warning:  ent has no menu\n");
+		return;
+	}
+
+	hnd = ent->client->menu;
+
+	if (hnd->cur < 0)
+		return; // no selectable entries
+
+	p = hnd->entries + hnd->cur;
+
+	if (p->SelectFunc)
+		p->SelectFunc(ent, hnd);
+}
--- /dev/null
+++ b/ctf/p_menu.h
@@ -1,0 +1,49 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+enum {
+	PMENU_ALIGN_LEFT,
+	PMENU_ALIGN_CENTER,
+	PMENU_ALIGN_RIGHT
+};
+
+typedef struct pmenuhnd_s {
+	struct pmenu_s *entries;
+	int cur;
+	int num;
+	void *arg;
+} pmenuhnd_t;
+
+typedef void (*SelectFunc_t)(edict_t *ent, pmenuhnd_t *hnd);
+
+typedef struct pmenu_s {
+	char *text;
+	int align;
+	SelectFunc_t SelectFunc;
+} pmenu_t;
+
+pmenuhnd_t *PMenu_Open(edict_t *ent, pmenu_t *entries, int cur, int num, void *arg);
+void PMenu_Close(edict_t *ent);
+void PMenu_UpdateEntry(pmenu_t *entry, const char *text, int align, SelectFunc_t SelectFunc);
+void PMenu_Do_Update(edict_t *ent);
+void PMenu_Update(edict_t *ent);
+void PMenu_Next(edict_t *ent);
+void PMenu_Prev(edict_t *ent);
+void PMenu_Select(edict_t *ent);
--- /dev/null
+++ b/ctf/p_trail.c
@@ -1,0 +1,146 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+/*
+==============================================================================
+
+PLAYER TRAIL
+
+==============================================================================
+
+This is a circular list containing the a list of points of where
+the player has been recently.  It is used by monsters for pursuit.
+
+.origin		the spot
+.owner		forward link
+.aiment		backward link
+*/
+
+
+#define	TRAIL_LENGTH	8
+
+edict_t		*trail[TRAIL_LENGTH];
+int			trail_head;
+qboolean	trail_active = false;
+
+#define NEXT(n)		(((n) + 1) & (TRAIL_LENGTH - 1))
+#define PREV(n)		(((n) - 1) & (TRAIL_LENGTH - 1))
+
+
+void PlayerTrail_Init (void)
+{
+	int		n;
+
+	if (deathmatch->value /* FIXME || coop */)
+		return;
+
+	for (n = 0; n < TRAIL_LENGTH; n++)
+	{
+		trail[n] = G_Spawn();
+		trail[n]->classname = "player_trail";
+	}
+
+	trail_head = 0;
+	trail_active = true;
+}
+
+
+void PlayerTrail_Add (vec3_t spot)
+{
+	vec3_t	temp;
+
+	if (!trail_active)
+		return;
+
+	VectorCopy (spot, trail[trail_head]->s.origin);
+
+	trail[trail_head]->timestamp = level.time;
+
+	VectorSubtract (spot, trail[PREV(trail_head)]->s.origin, temp);
+	trail[trail_head]->s.angles[1] = vectoyaw (temp);
+
+	trail_head = NEXT(trail_head);
+}
+
+
+void PlayerTrail_New (vec3_t spot)
+{
+	if (!trail_active)
+		return;
+
+	PlayerTrail_Init ();
+	PlayerTrail_Add (spot);
+}
+
+
+edict_t *PlayerTrail_PickFirst (edict_t *self)
+{
+	int		marker;
+	int		n;
+
+	if (!trail_active)
+		return NULL;
+
+	for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
+	{
+		if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
+			marker = NEXT(marker);
+		else
+			break;
+	}
+
+	if (visible(self, trail[marker]))
+	{
+		return trail[marker];
+	}
+
+	if (visible(self, trail[PREV(marker)]))
+	{
+		return trail[PREV(marker)];
+	}
+
+	return trail[marker];
+}
+
+edict_t *PlayerTrail_PickNext (edict_t *self)
+{
+	int		marker;
+	int		n;
+
+	if (!trail_active)
+		return NULL;
+
+	for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
+	{
+		if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
+			marker = NEXT(marker);
+		else
+			break;
+	}
+
+	return trail[marker];
+}
+
+edict_t *PlayerTrail_LastSpot (void)
+{
+	return trail[PREV(trail_head)];
+}
--- /dev/null
+++ b/ctf/p_view.c
@@ -1,0 +1,1135 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+
+
+static	edict_t		*current_player;
+static	gclient_t	*current_client;
+
+static	vec3_t	forward, right, up;
+float	xyspeed;
+
+float	bobmove;
+int		bobcycle;		// odd cycles are right foot going forward
+float	bobfracsin;		// sin(bobfrac*M_PI)
+
+/*
+===============
+SV_CalcRoll
+
+===============
+*/
+float SV_CalcRoll (vec3_t angles, vec3_t velocity)
+{
+	float	sign;
+	float	side;
+	float	value;
+	
+	side = DotProduct (velocity, right);
+	sign = side < 0 ? -1 : 1;
+	side = fabs(side);
+	
+	value = sv_rollangle->value;
+
+	if (side < sv_rollspeed->value)
+		side = side * value / sv_rollspeed->value;
+	else
+		side = value;
+	
+	return side*sign;
+	
+}
+
+
+/*
+===============
+P_DamageFeedback
+
+Handles color blends and view kicks
+===============
+*/
+void P_DamageFeedback (edict_t *player)
+{
+	gclient_t	*client;
+	float	side;
+	float	realcount, count, kick;
+	vec3_t	v;
+	int		r, l;
+	static	vec3_t	power_color = {0.0, 1.0, 0.0};
+	static	vec3_t	acolor = {1.0, 1.0, 1.0};
+	static	vec3_t	bcolor = {1.0, 0.0, 0.0};
+
+	client = player->client;
+
+	// flash the backgrounds behind the status numbers
+	client->ps.stats[STAT_FLASHES] = 0;
+	if (client->damage_blood)
+		client->ps.stats[STAT_FLASHES] |= 1;
+	if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
+		client->ps.stats[STAT_FLASHES] |= 2;
+
+	// total points of damage shot at the player this frame
+	count = (client->damage_blood + client->damage_armor + client->damage_parmor);
+	if (count == 0)
+		return;		// didn't take any damage
+
+	// start a pain animation if still in the player model
+	if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255)
+	{
+		static int		i;
+
+		client->anim_priority = ANIM_PAIN;
+		if (client->ps.pmove.pm_flags & PMF_DUCKED)
+		{
+			player->s.frame = FRAME_crpain1-1;
+			client->anim_end = FRAME_crpain4;
+		}
+		else
+		{
+			i = (i+1)%3;
+			switch (i)
+			{
+			case 0:
+				player->s.frame = FRAME_pain101-1;
+				client->anim_end = FRAME_pain104;
+				break;
+			case 1:
+				player->s.frame = FRAME_pain201-1;
+				client->anim_end = FRAME_pain204;
+				break;
+			case 2:
+				player->s.frame = FRAME_pain301-1;
+				client->anim_end = FRAME_pain304;
+				break;
+			}
+		}
+	}
+
+	realcount = count;
+	if (count < 10)
+		count = 10;	// allways make a visible effect
+
+	// play an apropriate pain sound
+	if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
+	{
+		r = 1 + (rand()&1);
+		player->pain_debounce_time = level.time + 0.7;
+		if (player->health < 25)
+			l = 25;
+		else if (player->health < 50)
+			l = 50;
+		else if (player->health < 75)
+			l = 75;
+		else
+			l = 100;
+		gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
+	}
+
+	// the total alpha of the blend is allways proportional to count
+	if (client->damage_alpha < 0)
+		client->damage_alpha = 0;
+	client->damage_alpha += count*0.01;
+	if (client->damage_alpha < 0.2)
+		client->damage_alpha = 0.2;
+	if (client->damage_alpha > 0.6)
+		client->damage_alpha = 0.6;		// don't go too saturated
+
+	// the color of the blend will vary based on how much was absorbed
+	// by different armors
+	VectorClear (v);
+	if (client->damage_parmor)
+		VectorMA (v, (float)client->damage_parmor/realcount, power_color, v);
+	if (client->damage_armor)
+		VectorMA (v, (float)client->damage_armor/realcount,  acolor, v);
+	if (client->damage_blood)
+		VectorMA (v, (float)client->damage_blood/realcount,  bcolor, v);
+	VectorCopy (v, client->damage_blend);
+
+
+	//
+	// calculate view angle kicks
+	//
+	kick = abs(client->damage_knockback);
+	if (kick && player->health > 0)	// kick of 0 means no view adjust at all
+	{
+		kick = kick * 100 / player->health;
+
+		if (kick < count*0.5)
+			kick = count*0.5;
+		if (kick > 50)
+			kick = 50;
+
+		VectorSubtract (client->damage_from, player->s.origin, v);
+		VectorNormalize (v);
+		
+		side = DotProduct (v, right);
+		client->v_dmg_roll = kick*side*0.3;
+		
+		side = -DotProduct (v, forward);
+		client->v_dmg_pitch = kick*side*0.3;
+
+		client->v_dmg_time = level.time + DAMAGE_TIME;
+	}
+
+	//
+	// clear totals
+	//
+	client->damage_blood = 0;
+	client->damage_armor = 0;
+	client->damage_parmor = 0;
+	client->damage_knockback = 0;
+}
+
+
+
+
+/*
+===============
+SV_CalcViewOffset
+
+Auto pitching on slopes?
+
+  fall from 128: 400 = 160000
+  fall from 256: 580 = 336400
+  fall from 384: 720 = 518400
+  fall from 512: 800 = 640000
+  fall from 640: 960 = 
+
+  damage = deltavelocity*deltavelocity  * 0.0001
+
+===============
+*/
+void SV_CalcViewOffset (edict_t *ent)
+{
+	float		*angles;
+	float		bob;
+	float		ratio;
+	float		delta;
+	vec3_t		v;
+
+
+//===================================
+
+	// base angles
+	angles = ent->client->ps.kick_angles;
+
+	// if dead, fix the angle and don't add any kick
+	if (ent->deadflag)
+	{
+		VectorClear (angles);
+
+		ent->client->ps.viewangles[ROLL] = 40;
+		ent->client->ps.viewangles[PITCH] = -15;
+		ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
+	}
+	else
+	{
+		// add angles based on weapon kick
+
+		VectorCopy (ent->client->kick_angles, angles);
+
+		// add angles based on damage kick
+
+		ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME;
+		if (ratio < 0)
+		{
+			ratio = 0;
+			ent->client->v_dmg_pitch = 0;
+			ent->client->v_dmg_roll = 0;
+		}
+		angles[PITCH] += ratio * ent->client->v_dmg_pitch;
+		angles[ROLL] += ratio * ent->client->v_dmg_roll;
+
+		// add pitch based on fall kick
+
+		ratio = (ent->client->fall_time - level.time) / FALL_TIME;
+		if (ratio < 0)
+			ratio = 0;
+		angles[PITCH] += ratio * ent->client->fall_value;
+
+		// add angles based on velocity
+
+		delta = DotProduct (ent->velocity, forward);
+		angles[PITCH] += delta*run_pitch->value;
+		
+		delta = DotProduct (ent->velocity, right);
+		angles[ROLL] += delta*run_roll->value;
+
+		// add angles based on bob
+
+		delta = bobfracsin * bob_pitch->value * xyspeed;
+		if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			delta *= 6;		// crouching
+		angles[PITCH] += delta;
+		delta = bobfracsin * bob_roll->value * xyspeed;
+		if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			delta *= 6;		// crouching
+		if (bobcycle & 1)
+			delta = -delta;
+		angles[ROLL] += delta;
+	}
+
+//===================================
+
+	// base origin
+
+	VectorClear (v);
+
+	// add view height
+
+	v[2] += ent->viewheight;
+
+	// add fall height
+
+	ratio = (ent->client->fall_time - level.time) / FALL_TIME;
+	if (ratio < 0)
+		ratio = 0;
+	v[2] -= ratio * ent->client->fall_value * 0.4;
+
+	// add bob height
+
+	bob = bobfracsin * xyspeed * bob_up->value;
+	if (bob > 6)
+		bob = 6;
+	//gi.DebugGraph (bob *2, 255);
+	v[2] += bob;
+
+	// add kick offset
+
+	VectorAdd (v, ent->client->kick_origin, v);
+
+	// absolutely bound offsets
+	// so the view can never be outside the player box
+
+	if (v[0] < -14)
+		v[0] = -14;
+	else if (v[0] > 14)
+		v[0] = 14;
+	if (v[1] < -14)
+		v[1] = -14;
+	else if (v[1] > 14)
+		v[1] = 14;
+	if (v[2] < -22)
+		v[2] = -22;
+	else if (v[2] > 30)
+		v[2] = 30;
+
+	VectorCopy (v, ent->client->ps.viewoffset);
+}
+
+/*
+==============
+SV_CalcGunOffset
+==============
+*/
+void SV_CalcGunOffset (edict_t *ent)
+{
+	int		i;
+	float	delta;
+
+	// gun angles from bobbing
+	ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
+	ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
+	if (bobcycle & 1)
+	{
+		ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
+		ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
+	}
+
+	ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
+
+	// gun angles from delta movement
+	for (i=0 ; i<3 ; i++)
+	{
+		delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
+		if (delta > 180)
+			delta -= 360;
+		if (delta < -180)
+			delta += 360;
+		if (delta > 45)
+			delta = 45;
+		if (delta < -45)
+			delta = -45;
+		if (i == YAW)
+			ent->client->ps.gunangles[ROLL] += 0.1*delta;
+		ent->client->ps.gunangles[i] += 0.2 * delta;
+	}
+
+	// gun height
+	VectorClear (ent->client->ps.gunoffset);
+//	ent->ps->gunorigin[2] += bob;
+
+	// gun_x / gun_y / gun_z are development tools
+	for (i=0 ; i<3 ; i++)
+	{
+		ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value);
+		ent->client->ps.gunoffset[i] += right[i]*gun_x->value;
+		ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value);
+	}
+}
+
+
+/*
+=============
+SV_AddBlend
+=============
+*/
+void SV_AddBlend (float r, float g, float b, float a, float *v_blend)
+{
+	float	a2, a3;
+
+	if (a <= 0)
+		return;
+	a2 = v_blend[3] + (1-v_blend[3])*a;	// new total alpha
+	a3 = v_blend[3]/a2;		// fraction of color from old
+
+	v_blend[0] = v_blend[0]*a3 + r*(1-a3);
+	v_blend[1] = v_blend[1]*a3 + g*(1-a3);
+	v_blend[2] = v_blend[2]*a3 + b*(1-a3);
+	v_blend[3] = a2;
+}
+
+
+/*
+=============
+SV_CalcBlend
+=============
+*/
+void SV_CalcBlend (edict_t *ent)
+{
+	int		contents;
+	vec3_t	vieworg;
+	int		remaining;
+
+	ent->client->ps.blend[0] = ent->client->ps.blend[1] = 
+		ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0;
+
+	// add for contents
+	VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg);
+	contents = gi.pointcontents (vieworg);
+	if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
+		ent->client->ps.rdflags |= RDF_UNDERWATER;
+	else
+		ent->client->ps.rdflags &= ~RDF_UNDERWATER;
+
+	if (contents & (CONTENTS_SOLID|CONTENTS_LAVA))
+		SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend);
+	else if (contents & CONTENTS_SLIME)
+		SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend);
+	else if (contents & CONTENTS_WATER)
+		SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend);
+
+	// add for powerups
+	if (ent->client->quad_framenum > level.framenum)
+	{
+		remaining = ent->client->quad_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
+	}
+	else if (ent->client->invincible_framenum > level.framenum)
+	{
+		remaining = ent->client->invincible_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend);
+	}
+	else if (ent->client->enviro_framenum > level.framenum)
+	{
+		remaining = ent->client->enviro_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend);
+	}
+	else if (ent->client->breather_framenum > level.framenum)
+	{
+		remaining = ent->client->breather_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend);
+	}
+
+	// add for damage
+	if (ent->client->damage_alpha > 0)
+		SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1]
+		,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend);
+
+	if (ent->client->bonus_alpha > 0)
+		SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend);
+
+	// drop the damage value
+	ent->client->damage_alpha -= 0.06;
+	if (ent->client->damage_alpha < 0)
+		ent->client->damage_alpha = 0;
+
+	// drop the bonus value
+	ent->client->bonus_alpha -= 0.1;
+	if (ent->client->bonus_alpha < 0)
+		ent->client->bonus_alpha = 0;
+}
+
+
+/*
+=================
+P_FallingDamage
+=================
+*/
+void P_FallingDamage (edict_t *ent)
+{
+	float	delta;
+	int		damage;
+	vec3_t	dir;
+
+	if (ent->s.modelindex != 255)
+		return;		// not in the player model
+
+ 	if (ent->movetype == MOVETYPE_NOCLIP)
+		return;
+
+	if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity))
+	{
+		delta = ent->client->oldvelocity[2];
+	}
+	else
+	{
+		if (!ent->groundentity)
+			return;
+		delta = ent->velocity[2] - ent->client->oldvelocity[2];
+	}
+	delta = delta*delta * 0.0001;
+
+//ZOID
+	// never take damage if just release grapple or on grapple
+	if (level.time - ent->client->ctf_grapplereleasetime <= FRAMETIME * 2 ||
+		(ent->client->ctf_grapple && 
+		ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY))
+		return;
+//ZOID
+
+	// never take falling damage if completely underwater
+	if (ent->waterlevel == 3)
+		return;
+	if (ent->waterlevel == 2)
+		delta *= 0.25;
+	if (ent->waterlevel == 1)
+		delta *= 0.5;
+
+	if (delta < 1)
+		return;
+
+	if (delta < 15)
+	{
+		ent->s.event = EV_FOOTSTEP;
+		return;
+	}
+
+	ent->client->fall_value = delta*0.5;
+	if (ent->client->fall_value > 40)
+		ent->client->fall_value = 40;
+	ent->client->fall_time = level.time + FALL_TIME;
+
+	if (delta > 30)
+	{
+		if (ent->health > 0)
+		{
+			if (delta >= 55)
+				ent->s.event = EV_FALLFAR;
+			else
+				ent->s.event = EV_FALL;
+		}
+		ent->pain_debounce_time = level.time;	// no normal pain sound
+		damage = (delta-30)/2;
+		if (damage < 1)
+			damage = 1;
+		VectorSet (dir, 0, 0, 1);
+
+		if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) )
+			T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
+	}
+	else
+	{
+		ent->s.event = EV_FALLSHORT;
+		return;
+	}
+}
+
+
+
+/*
+=============
+P_WorldEffects
+=============
+*/
+void P_WorldEffects (void)
+{
+	qboolean	breather;
+	qboolean	envirosuit;
+	int			waterlevel, old_waterlevel;
+
+	if (current_player->movetype == MOVETYPE_NOCLIP)
+	{
+		current_player->air_finished = level.time + 12;	// don't need air
+		return;
+	}
+
+	waterlevel = current_player->waterlevel;
+	old_waterlevel = current_client->old_waterlevel;
+	current_client->old_waterlevel = waterlevel;
+
+	breather = current_client->breather_framenum > level.framenum;
+	envirosuit = current_client->enviro_framenum > level.framenum;
+
+	//
+	// if just entered a water volume, play a sound
+	//
+	if (!old_waterlevel && waterlevel)
+	{
+		PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+		if (current_player->watertype & CONTENTS_LAVA)
+			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
+		else if (current_player->watertype & CONTENTS_SLIME)
+			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+		else if (current_player->watertype & CONTENTS_WATER)
+			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+		current_player->flags |= FL_INWATER;
+
+		// clear damage_debounce, so the pain sound will play immediately
+		current_player->damage_debounce_time = level.time - 1;
+	}
+
+	//
+	// if just completely exited a water volume, play a sound
+	//
+	if (old_waterlevel && ! waterlevel)
+	{
+		PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+		gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
+		current_player->flags &= ~FL_INWATER;
+	}
+
+	//
+	// check for head just going under water
+	//
+	if (old_waterlevel != 3 && waterlevel == 3)
+	{
+		gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
+	}
+
+	//
+	// check for head just coming out of water
+	//
+	if (old_waterlevel == 3 && waterlevel != 3)
+	{
+		if (current_player->air_finished < level.time)
+		{	// gasp for air
+			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
+			PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+		}
+		else  if (current_player->air_finished < level.time + 11)
+		{	// just break surface
+			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
+		}
+	}
+
+	//
+	// check for drowning
+	//
+	if (waterlevel == 3)
+	{
+		// breather or envirosuit give air
+		if (breather || envirosuit)
+		{
+			current_player->air_finished = level.time + 10;
+
+			if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
+			{
+				if (!current_client->breather_sound)
+					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
+				current_client->breather_sound ^= 1;
+				PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+				//FIXME: release a bubble?
+			}
+		}
+
+		// if out of air, start drowning
+		if (current_player->air_finished < level.time)
+		{	// drown!
+			if (current_player->client->next_drown_time < level.time 
+				&& current_player->health > 0)
+			{
+				current_player->client->next_drown_time = level.time + 1;
+
+				// take more damage the longer underwater
+				current_player->dmg += 2;
+				if (current_player->dmg > 15)
+					current_player->dmg = 15;
+
+				// play a gurp sound instead of a normal pain sound
+				if (current_player->health <= current_player->dmg)
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
+				else if (rand()&1)
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
+
+				current_player->pain_debounce_time = level.time;
+
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
+			}
+		}
+	}
+	else
+	{
+		current_player->air_finished = level.time + 12;
+		current_player->dmg = 2;
+	}
+
+	//
+	// check for sizzle damage
+	//
+	if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
+	{
+		if (current_player->watertype & CONTENTS_LAVA)
+		{
+			if (current_player->health > 0
+				&& current_player->pain_debounce_time <= level.time
+				&& current_client->invincible_framenum < level.framenum)
+			{
+				if (rand()&1)
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
+				current_player->pain_debounce_time = level.time + 1;
+			}
+
+			if (envirosuit)	// take 1/3 damage with envirosuit
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
+			else
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
+		}
+
+		if (current_player->watertype & CONTENTS_SLIME)
+		{
+			if (!envirosuit)
+			{	// no damage from slime with envirosuit
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
+			}
+		}
+	}
+}
+
+
+/*
+===============
+G_SetClientEffects
+===============
+*/
+void G_SetClientEffects (edict_t *ent)
+{
+	int		pa_type;
+	int		remaining;
+
+	ent->s.effects = 0;
+	ent->s.renderfx = 0;
+
+	if (ent->health <= 0 || level.intermissiontime)
+		return;
+
+	if (ent->powerarmor_time > level.time)
+	{
+		pa_type = PowerArmorType (ent);
+		if (pa_type == POWER_ARMOR_SCREEN)
+		{
+			ent->s.effects |= EF_POWERSCREEN;
+		}
+		else if (pa_type == POWER_ARMOR_SHIELD)
+		{
+			ent->s.effects |= EF_COLOR_SHELL;
+			ent->s.renderfx |= RF_SHELL_GREEN;
+		}
+	}
+
+//ZOID
+	CTFEffects(ent);
+//ZOID
+
+	if (ent->client->quad_framenum > level.framenum
+//ZOID
+		&& (level.framenum & 8)
+//ZOID
+		)
+	{
+		remaining = ent->client->quad_framenum - level.framenum;
+		if (remaining > 30 || (remaining & 4) )
+			ent->s.effects |= EF_QUAD;
+	}
+
+	if (ent->client->invincible_framenum > level.framenum
+//ZOID
+		&& (level.framenum & 8)
+//ZOID
+		)
+	{
+		remaining = ent->client->invincible_framenum - level.framenum;
+		if (remaining > 30 || (remaining & 4) )
+			ent->s.effects |= EF_PENT;
+	}
+
+	// show cheaters!!!
+	if (ent->flags & FL_GODMODE)
+	{
+		ent->s.effects |= EF_COLOR_SHELL;
+		ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
+	}
+}
+
+
+/*
+===============
+G_SetClientEvent
+===============
+*/
+void G_SetClientEvent (edict_t *ent)
+{
+	if (ent->s.event)
+		return;
+
+	if ( ent->groundentity && xyspeed > 225)
+	{
+		if ( (int)(current_client->bobtime+bobmove) != bobcycle )
+			ent->s.event = EV_FOOTSTEP;
+	}
+}
+
+/*
+===============
+G_SetClientSound
+===============
+*/
+void G_SetClientSound (edict_t *ent)
+{
+	char	*weap;
+
+	if (ent->client->resp.game_helpchanged != game.helpchanged)
+	{
+		ent->client->resp.game_helpchanged = game.helpchanged;
+		ent->client->resp.helpchanged = 1;
+	}
+
+	// help beep (no more than three times)
+	if (ent->client->resp.helpchanged && ent->client->resp.helpchanged <= 3 && !(level.framenum&63) )
+	{
+		ent->client->resp.helpchanged++;
+		gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
+	}
+
+
+	if (ent->client->pers.weapon)
+		weap = ent->client->pers.weapon->classname;
+	else
+		weap = "";
+
+	if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
+		ent->s.sound = snd_fry;
+	else if (strcmp(weap, "weapon_railgun") == 0)
+		ent->s.sound = gi.soundindex("weapons/rg_hum.wav");
+	else if (strcmp(weap, "weapon_bfg") == 0)
+		ent->s.sound = gi.soundindex("weapons/bfg_hum.wav");
+	else if (ent->client->weapon_sound)
+		ent->s.sound = ent->client->weapon_sound;
+	else
+		ent->s.sound = 0;
+}
+
+/*
+===============
+G_SetClientFrame
+===============
+*/
+void G_SetClientFrame (edict_t *ent)
+{
+	gclient_t	*client;
+	qboolean	duck, run;
+
+	if (ent->s.modelindex != 255)
+		return;		// not in the player model
+
+	client = ent->client;
+
+	if (client->ps.pmove.pm_flags & PMF_DUCKED)
+		duck = true;
+	else
+		duck = false;
+	if (xyspeed)
+		run = true;
+	else
+		run = false;
+
+	// check for stand/duck and stop/go transitions
+	if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH)
+		goto newanim;
+	if (run != client->anim_run && client->anim_priority == ANIM_BASIC)
+		goto newanim;
+	if (!ent->groundentity && client->anim_priority <= ANIM_WAVE)
+		goto newanim;
+
+	if(client->anim_priority == ANIM_REVERSE)
+	{
+		if(ent->s.frame > client->anim_end)
+		{
+			ent->s.frame--;
+			return;
+		}
+	}
+	else if (ent->s.frame < client->anim_end)
+	{	// continue an animation
+		ent->s.frame++;
+		return;
+	}
+
+	if (client->anim_priority == ANIM_DEATH)
+		return;		// stay there
+	if (client->anim_priority == ANIM_JUMP)
+	{
+		if (!ent->groundentity)
+			return;		// stay there
+		ent->client->anim_priority = ANIM_WAVE;
+		ent->s.frame = FRAME_jump3;
+		ent->client->anim_end = FRAME_jump6;
+		return;
+	}
+
+newanim:
+	// return to either a running or standing frame
+	client->anim_priority = ANIM_BASIC;
+	client->anim_duck = duck;
+	client->anim_run = run;
+
+	if (!ent->groundentity)
+	{
+//ZOID: if on grapple, don't go into jump frame, go into standing
+//frame
+		if (client->ctf_grapple) {
+			ent->s.frame = FRAME_stand01;
+			client->anim_end = FRAME_stand40;
+		} else {
+//ZOID
+		client->anim_priority = ANIM_JUMP;
+		if (ent->s.frame != FRAME_jump2)
+			ent->s.frame = FRAME_jump1;
+		client->anim_end = FRAME_jump2;
+	}
+	}
+	else if (run)
+	{	// running
+		if (duck)
+		{
+			ent->s.frame = FRAME_crwalk1;
+			client->anim_end = FRAME_crwalk6;
+		}
+		else
+		{
+			ent->s.frame = FRAME_run1;
+			client->anim_end = FRAME_run6;
+		}
+	}
+	else
+	{	// standing
+		if (duck)
+		{
+			ent->s.frame = FRAME_crstnd01;
+			client->anim_end = FRAME_crstnd19;
+		}
+		else
+		{
+			ent->s.frame = FRAME_stand01;
+			client->anim_end = FRAME_stand40;
+		}
+	}
+}
+
+
+/*
+=================
+ClientEndServerFrame
+
+Called for each player at the end of the server frame
+and right after spawning
+=================
+*/
+void ClientEndServerFrame (edict_t *ent)
+{
+	float	bobtime;
+	int		i;
+
+	current_player = ent;
+	current_client = ent->client;
+
+	//
+	// If the origin or velocity have changed since ClientThink(),
+	// update the pmove values.  This will happen when the client
+	// is pushed by a bmodel or kicked by an explosion.
+	// 
+	// If it wasn't updated here, the view position would lag a frame
+	// behind the body position when pushed -- "sinking into plats"
+	//
+	for (i=0 ; i<3 ; i++)
+	{
+		current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
+		current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
+	}
+
+	//
+	// If the end of unit layout is displayed, don't give
+	// the player any normal movement attributes
+	//
+	if (level.intermissiontime)
+	{
+		// FIXME: add view drifting here?
+		current_client->ps.blend[3] = 0;
+		current_client->ps.fov = 90;
+		G_SetStats (ent);
+		return;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, up);
+
+	// burn from lava, etc
+	P_WorldEffects ();
+
+	//
+	// set model angles from view angles so other things in
+	// the world can tell which direction you are looking
+	//
+	if (ent->client->v_angle[PITCH] > 180)
+		ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
+	else
+		ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
+	ent->s.angles[YAW] = ent->client->v_angle[YAW];
+	ent->s.angles[ROLL] = 0;
+	ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;
+
+	//
+	// calculate speed and cycle to be used for
+	// all cyclic walking effects
+	//
+	xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);
+
+	if (xyspeed < 5)
+	{
+		bobmove = 0;
+		current_client->bobtime = 0;	// start at beginning of cycle again
+	}
+	else if (ent->groundentity)
+	{	// so bobbing only cycles when on ground
+		if (xyspeed > 210)
+			bobmove = 0.25;
+		else if (xyspeed > 100)
+			bobmove = 0.125;
+		else
+			bobmove = 0.0625;
+	}
+	
+	bobtime = (current_client->bobtime += bobmove);
+
+	if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
+		bobtime *= 4;
+
+	bobcycle = (int)bobtime;
+	bobfracsin = fabs(sin(bobtime*M_PI));
+
+	// detect hitting the floor
+	P_FallingDamage (ent);
+
+	// apply all the damage taken this frame
+	P_DamageFeedback (ent);
+
+	// determine the view offsets
+	SV_CalcViewOffset (ent);
+
+	// determine the gun offsets
+	SV_CalcGunOffset (ent);
+
+	// determine the full screen color blend
+	// must be after viewoffset, so eye contents can be
+	// accurately determined
+	// FIXME: with client prediction, the contents
+	// should be determined by the client
+	SV_CalcBlend (ent);
+
+//ZOID
+	if (!ent->client->chase_target)
+//ZOID
+		G_SetStats (ent);
+
+//ZOID
+//update chasecam follower stats
+	for (i = 1; i <= maxclients->value; i++) {
+		edict_t *e = g_edicts + i;
+		if (!e->inuse || e->client->chase_target != ent)
+			continue;
+		memcpy(e->client->ps.stats, 
+			ent->client->ps.stats, 
+			sizeof(ent->client->ps.stats));
+		e->client->ps.stats[STAT_LAYOUTS] = 1;
+		break;
+	}
+//ZOID
+
+
+	G_SetClientEvent (ent);
+
+	G_SetClientEffects (ent);
+
+	G_SetClientSound (ent);
+
+	G_SetClientFrame (ent);
+
+	VectorCopy (ent->velocity, ent->client->oldvelocity);
+	VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);
+
+	// clear weapon kicks
+	VectorClear (ent->client->kick_origin);
+	VectorClear (ent->client->kick_angles);
+
+	// if the scoreboard is up, update it
+	if (ent->client->showscores && !(level.framenum & 31) )
+	{
+//ZOID
+		if (ent->client->menu) {
+			PMenu_Do_Update(ent);
+			ent->client->menudirty = false;
+			ent->client->menutime = level.time;
+		} else
+//ZOID
+			DeathmatchScoreboardMessage (ent, ent->enemy);
+		gi.unicast (ent, false);
+	}
+}
+
--- /dev/null
+++ b/ctf/p_weapon.c
@@ -1,0 +1,1469 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_weapon.c
+
+#include "g_local.h"
+#include "m_player.h"
+
+
+static qboolean	is_quad;
+static byte		is_silenced;
+
+
+void weapon_grenade_fire (edict_t *ent, qboolean held);
+
+
+void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
+{
+	vec3_t	_distance;
+
+	VectorCopy (distance, _distance);
+	if (client->pers.hand == LEFT_HANDED)
+		_distance[1] *= -1;
+	else if (client->pers.hand == CENTER_HANDED)
+		_distance[1] = 0;
+	G_ProjectSource (point, _distance, forward, right, result);
+}
+
+
+/*
+===============
+PlayerNoise
+
+Each player can have two noise objects associated with it:
+a personal noise (jumping, pain, weapon firing), and a weapon
+target noise (bullet wall impacts)
+
+Monsters that don't directly see the player can move
+to a noise in hopes of seeing the player from there.
+===============
+*/
+void PlayerNoise(edict_t *who, vec3_t where, int type)
+{
+	edict_t		*noise;
+
+	if (type == PNOISE_WEAPON)
+	{
+		if (who->client->silencer_shots)
+		{
+			who->client->silencer_shots--;
+			return;
+		}
+	}
+
+	if (deathmatch->value)
+		return;
+
+	if (who->flags & FL_NOTARGET)
+		return;
+
+
+	if (!who->mynoise)
+	{
+		noise = G_Spawn();
+		noise->classname = "player_noise";
+		VectorSet (noise->mins, -8, -8, -8);
+		VectorSet (noise->maxs, 8, 8, 8);
+		noise->owner = who;
+		noise->svflags = SVF_NOCLIENT;
+		who->mynoise = noise;
+
+		noise = G_Spawn();
+		noise->classname = "player_noise";
+		VectorSet (noise->mins, -8, -8, -8);
+		VectorSet (noise->maxs, 8, 8, 8);
+		noise->owner = who;
+		noise->svflags = SVF_NOCLIENT;
+		who->mynoise2 = noise;
+	}
+
+	if (type == PNOISE_SELF || type == PNOISE_WEAPON)
+	{
+		noise = who->mynoise;
+		level.sound_entity = noise;
+		level.sound_entity_framenum = level.framenum;
+	}
+	else // type == PNOISE_IMPACT
+	{
+		noise = who->mynoise2;
+		level.sound2_entity = noise;
+		level.sound2_entity_framenum = level.framenum;
+	}
+
+	VectorCopy (where, noise->s.origin);
+	VectorSubtract (where, noise->maxs, noise->absmin);
+	VectorAdd (where, noise->maxs, noise->absmax);
+	noise->teleport_time = level.time;
+	gi.linkentity (noise);
+}
+
+
+qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
+{
+	int			index;
+	gitem_t		*ammo;
+
+	index = ITEM_INDEX(ent->item);
+
+	if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) 
+		&& other->client->pers.inventory[index])
+	{
+		if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
+			return false;	// leave the weapon for others to pickup
+	}
+
+	other->client->pers.inventory[index]++;
+
+	if (!(ent->spawnflags & DROPPED_ITEM) )
+	{
+		// give them some ammo with it
+		ammo = FindItem (ent->item->ammo);
+		if ( (int)dmflags->value & DF_INFINITE_AMMO )
+			Add_Ammo (other, ammo, 1000);
+		else
+			Add_Ammo (other, ammo, ammo->quantity);
+
+		if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
+		{
+			if (deathmatch->value)
+			{
+				if ((int)(dmflags->value) & DF_WEAPONS_STAY)
+					ent->flags |= FL_RESPAWN;
+				else
+					SetRespawn (ent, 30);
+			}
+			if (coop->value)
+				ent->flags |= FL_RESPAWN;
+		}
+	}
+
+	if (other->client->pers.weapon != ent->item && 
+		(other->client->pers.inventory[index] == 1) &&
+		( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
+		other->client->newweapon = ent->item;
+
+	return true;
+}
+
+
+/*
+===============
+ChangeWeapon
+
+The old weapon has been dropped all the way, so make the new one
+current
+===============
+*/
+void ChangeWeapon (edict_t *ent)
+{
+	int i;
+
+	if (ent->client->grenade_time)
+	{
+		ent->client->grenade_time = level.time;
+		ent->client->weapon_sound = 0;
+		weapon_grenade_fire (ent, false);
+		ent->client->grenade_time = 0;
+	}
+
+	ent->client->pers.lastweapon = ent->client->pers.weapon;
+	ent->client->pers.weapon = ent->client->newweapon;
+	ent->client->newweapon = NULL;
+	ent->client->machinegun_shots = 0;
+
+	// set visible model
+	if (ent->s.modelindex == 255) {
+		if (ent->client->pers.weapon)
+			i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
+		else
+			i = 0;
+		ent->s.skinnum = (ent - g_edicts - 1) | i;
+	}
+
+	if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
+		ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
+	else
+		ent->client->ammo_index = 0;
+
+	if (!ent->client->pers.weapon)
+	{	// dead
+		ent->client->ps.gunindex = 0;
+		return;
+	}
+
+	ent->client->weaponstate = WEAPON_ACTIVATING;
+	ent->client->ps.gunframe = 0;
+	ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
+
+	ent->client->anim_priority = ANIM_PAIN;
+	if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+			ent->s.frame = FRAME_crpain1;
+			ent->client->anim_end = FRAME_crpain4;
+	}
+	else
+	{
+			ent->s.frame = FRAME_pain301;
+			ent->client->anim_end = FRAME_pain304;
+			
+	}
+}
+
+/*
+=================
+NoAmmoWeaponChange
+=================
+*/
+void NoAmmoWeaponChange (edict_t *ent)
+{
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
+	{
+		ent->client->newweapon = FindItem ("railgun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
+	{
+		ent->client->newweapon = FindItem ("hyperblaster");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
+	{
+		ent->client->newweapon = FindItem ("chaingun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
+	{
+		ent->client->newweapon = FindItem ("machinegun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
+	{
+		ent->client->newweapon = FindItem ("super shotgun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
+	{
+		ent->client->newweapon = FindItem ("shotgun");
+		return;
+	}
+	ent->client->newweapon = FindItem ("blaster");
+}
+
+/*
+=================
+Think_Weapon
+
+Called by ClientBeginServerFrame and ClientThink
+=================
+*/
+void Think_Weapon (edict_t *ent)
+{
+	// if just died, put the weapon away
+	if (ent->health < 1)
+	{
+		ent->client->newweapon = NULL;
+		ChangeWeapon (ent);
+	}
+
+	// call active weapon think routine
+	if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
+	{
+		is_quad = (ent->client->quad_framenum > level.framenum);
+		if (ent->client->silencer_shots)
+			is_silenced = MZ_SILENCED;
+		else
+			is_silenced = 0;
+		ent->client->pers.weapon->weaponthink (ent);
+	}
+}
+
+
+/*
+================
+Use_Weapon
+
+Make the weapon ready if there is ammo
+================
+*/
+void Use_Weapon (edict_t *ent, gitem_t *item)
+{
+	int			ammo_index;
+	gitem_t		*ammo_item;
+
+	// see if we're already using it
+	if (item == ent->client->pers.weapon)
+		return;
+
+	if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
+	{
+		ammo_item = FindItem(item->ammo);
+		ammo_index = ITEM_INDEX(ammo_item);
+
+		if (!ent->client->pers.inventory[ammo_index])
+		{
+			gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
+			return;
+		}
+
+		if (ent->client->pers.inventory[ammo_index] < item->quantity)
+		{
+			gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
+			return;
+		}
+	}
+
+	// change to this weapon when down
+	ent->client->newweapon = item;
+}
+
+
+
+/*
+================
+Drop_Weapon
+================
+*/
+void Drop_Weapon (edict_t *ent, gitem_t *item)
+{
+	int		index;
+
+	if ((int)(dmflags->value) & DF_WEAPONS_STAY)
+		return;
+
+	index = ITEM_INDEX(item);
+	// see if we're already using it
+	if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
+		return;
+	}
+
+	Drop_Item (ent, item);
+	ent->client->pers.inventory[index]--;
+}
+
+
+/*
+================
+Weapon_Generic
+
+A generic function to handle the basics of weapon thinking
+================
+*/
+#define FRAME_FIRE_FIRST		(FRAME_ACTIVATE_LAST + 1)
+#define FRAME_IDLE_FIRST		(FRAME_FIRE_LAST + 1)
+#define FRAME_DEACTIVATE_FIRST	(FRAME_IDLE_LAST + 1)
+
+static void Weapon_Generic2 (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
+{
+	int		n;
+
+	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
+	{
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_DROPPING)
+	{
+		if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
+		{
+			ChangeWeapon (ent);
+			return;
+		}
+		else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
+		{
+			ent->client->anim_priority = ANIM_REVERSE;
+			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				ent->s.frame = FRAME_crpain4+1;
+				ent->client->anim_end = FRAME_crpain1;
+			}
+			else
+			{
+				ent->s.frame = FRAME_pain304+1;
+				ent->client->anim_end = FRAME_pain301;
+				
+			}
+		}
+
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_ACTIVATING)
+	{
+		if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST || instantweap->value)
+		{
+			ent->client->weaponstate = WEAPON_READY;
+			ent->client->ps.gunframe = FRAME_IDLE_FIRST;
+			// we go recursive here to instant ready the weapon
+			Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
+				FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
+				fire_frames, fire);
+			return;
+		}
+
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
+	{
+		ent->client->weaponstate = WEAPON_DROPPING;
+		if (instantweap->value) {
+			ChangeWeapon(ent);
+			return;
+		} else
+			ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
+
+		if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
+		{
+			ent->client->anim_priority = ANIM_REVERSE;
+			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				ent->s.frame = FRAME_crpain4+1;
+				ent->client->anim_end = FRAME_crpain1;
+			}
+			else
+			{
+				ent->s.frame = FRAME_pain304+1;
+				ent->client->anim_end = FRAME_pain301;
+				
+			}
+		}
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_READY)
+	{
+		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
+		{
+			ent->client->latched_buttons &= ~BUTTON_ATTACK;
+			if ((!ent->client->ammo_index) || 
+				( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
+			{
+				ent->client->ps.gunframe = FRAME_FIRE_FIRST;
+				ent->client->weaponstate = WEAPON_FIRING;
+
+				// start the animation
+				ent->client->anim_priority = ANIM_ATTACK;
+				if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+				{
+					ent->s.frame = FRAME_crattak1-1;
+					ent->client->anim_end = FRAME_crattak9;
+				}
+				else
+				{
+					ent->s.frame = FRAME_attack1-1;
+					ent->client->anim_end = FRAME_attack8;
+				}
+			}
+			else
+			{
+				if (level.time >= ent->pain_debounce_time)
+				{
+					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+					ent->pain_debounce_time = level.time + 1;
+				}
+				NoAmmoWeaponChange (ent);
+			}
+		}
+		else
+		{
+			if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
+			{
+				ent->client->ps.gunframe = FRAME_IDLE_FIRST;
+				return;
+			}
+
+			if (pause_frames)
+			{
+				for (n = 0; pause_frames[n]; n++)
+				{
+					if (ent->client->ps.gunframe == pause_frames[n])
+					{
+						if (rand()&15)
+							return;
+					}
+				}
+			}
+
+			ent->client->ps.gunframe++;
+			return;
+		}
+	}
+
+	if (ent->client->weaponstate == WEAPON_FIRING)
+	{
+		for (n = 0; fire_frames[n]; n++)
+		{
+			if (ent->client->ps.gunframe == fire_frames[n])
+			{
+//ZOID
+				if (!CTFApplyStrengthSound(ent))
+//ZOID
+				if (ent->client->quad_framenum > level.framenum)
+					gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
+//ZOID
+				CTFApplyHasteSound(ent);
+//ZOID
+
+				fire (ent);
+				break;
+			}
+		}
+
+		if (!fire_frames[n])
+			ent->client->ps.gunframe++;
+
+		if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
+			ent->client->weaponstate = WEAPON_READY;
+	}
+}
+
+//ZOID
+void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
+{
+	int oldstate = ent->client->weaponstate;
+
+	Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
+		FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
+		fire_frames, fire);
+
+	// run the weapon frame again if hasted
+	if (stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
+		ent->client->weaponstate == WEAPON_FIRING)
+		return;
+
+	if ((CTFApplyHaste(ent) ||
+		(Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
+		ent->client->weaponstate != WEAPON_FIRING))
+		&& oldstate == ent->client->weaponstate) {
+		Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
+			FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
+			fire_frames, fire);
+	}
+}
+//ZOID
+
+/*
+======================================================================
+
+GRENADE
+
+======================================================================
+*/
+
+#define GRENADE_TIMER		3.0
+#define GRENADE_MINSPEED	400
+#define GRENADE_MAXSPEED	800
+
+void weapon_grenade_fire (edict_t *ent, qboolean held)
+{
+	vec3_t	offset;
+	vec3_t	forward, right;
+	vec3_t	start;
+	int		damage = 125;
+	float	timer;
+	int		speed;
+	float	radius;
+
+	radius = damage+40;
+	if (is_quad)
+		damage *= 4;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	timer = ent->client->grenade_time - level.time;
+	speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
+	fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+
+	ent->client->grenade_time = level.time + 1.0;
+
+	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
+	{
+		return;
+	}
+
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+		ent->client->anim_priority = ANIM_ATTACK;
+		ent->s.frame = FRAME_crattak1-1;
+		ent->client->anim_end = FRAME_crattak3;
+	}
+	else
+	{
+		ent->client->anim_priority = ANIM_REVERSE;
+		ent->s.frame = FRAME_wave08;
+		ent->client->anim_end = FRAME_wave01;
+	}
+}
+
+void Weapon_Grenade (edict_t *ent)
+{
+	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
+	{
+		ChangeWeapon (ent);
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_ACTIVATING)
+	{
+		ent->client->weaponstate = WEAPON_READY;
+		ent->client->ps.gunframe = 16;
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_READY)
+	{
+		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
+		{
+			ent->client->latched_buttons &= ~BUTTON_ATTACK;
+			if (ent->client->pers.inventory[ent->client->ammo_index])
+			{
+				ent->client->ps.gunframe = 1;
+				ent->client->weaponstate = WEAPON_FIRING;
+				ent->client->grenade_time = 0;
+			}
+			else
+			{
+				if (level.time >= ent->pain_debounce_time)
+				{
+					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+					ent->pain_debounce_time = level.time + 1;
+				}
+				NoAmmoWeaponChange (ent);
+			}
+			return;
+		}
+
+		if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
+		{
+			if (rand()&15)
+				return;
+		}
+
+		if (++ent->client->ps.gunframe > 48)
+			ent->client->ps.gunframe = 16;
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_FIRING)
+	{
+		if (ent->client->ps.gunframe == 5)
+			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
+
+		if (ent->client->ps.gunframe == 11)
+		{
+			if (!ent->client->grenade_time)
+			{
+				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
+				ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
+			}
+
+			// they waited too long, detonate it in their hand
+			if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
+			{
+				ent->client->weapon_sound = 0;
+				weapon_grenade_fire (ent, true);
+				ent->client->grenade_blew_up = true;
+			}
+
+			if (ent->client->buttons & BUTTON_ATTACK)
+				return;
+
+			if (ent->client->grenade_blew_up)
+			{
+				if (level.time >= ent->client->grenade_time)
+				{
+					ent->client->ps.gunframe = 15;
+					ent->client->grenade_blew_up = false;
+				}
+				else
+				{
+					return;
+				}
+			}
+		}
+
+		if (ent->client->ps.gunframe == 12)
+		{
+			ent->client->weapon_sound = 0;
+			weapon_grenade_fire (ent, false);
+		}
+
+		if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
+			return;
+
+		ent->client->ps.gunframe++;
+
+		if (ent->client->ps.gunframe == 16)
+		{
+			ent->client->grenade_time = 0;
+			ent->client->weaponstate = WEAPON_READY;
+		}
+	}
+}
+
+/*
+======================================================================
+
+GRENADE LAUNCHER
+
+======================================================================
+*/
+
+void weapon_grenadelauncher_fire (edict_t *ent)
+{
+	vec3_t	offset;
+	vec3_t	forward, right;
+	vec3_t	start;
+	int		damage = 120;
+	float	radius;
+
+	radius = damage+40;
+	if (is_quad)
+		damage *= 4;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
+
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_GRENADE | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+void Weapon_GrenadeLauncher (edict_t *ent)
+{
+	static int	pause_frames[]	= {34, 51, 59, 0};
+	static int	fire_frames[]	= {6, 0};
+
+	Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
+}
+
+/*
+======================================================================
+
+ROCKET
+
+======================================================================
+*/
+
+void Weapon_RocketLauncher_Fire (edict_t *ent)
+{
+	vec3_t	offset, start;
+	vec3_t	forward, right;
+	int		damage;
+	float	damage_radius;
+	int		radius_damage;
+
+	damage = 100 + (int)(random() * 20.0);
+	radius_damage = 120;
+	damage_radius = 120;
+	if (is_quad)
+	{
+		damage *= 4;
+		radius_damage *= 4;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_ROCKET | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+void Weapon_RocketLauncher (edict_t *ent)
+{
+	static int	pause_frames[]	= {25, 33, 42, 50, 0};
+	static int	fire_frames[]	= {5, 0};
+
+	Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
+}
+
+
+/*
+======================================================================
+
+BLASTER / HYPERBLASTER
+
+======================================================================
+*/
+
+void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	offset;
+
+	if (is_quad)
+		damage *= 4;
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+	VectorSet(offset, 24, 8, ent->viewheight-8);
+	VectorAdd (offset, g_offset, offset);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	if (hyper)
+		gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
+	else
+		gi.WriteByte (MZ_BLASTER | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+}
+
+
+void Weapon_Blaster_Fire (edict_t *ent)
+{
+	int		damage;
+
+	if (deathmatch->value)
+		damage = 15;
+	else
+		damage = 10;
+	Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
+	ent->client->ps.gunframe++;
+}
+
+void Weapon_Blaster (edict_t *ent)
+{
+	static int	pause_frames[]	= {19, 32, 0};
+	static int	fire_frames[]	= {5, 0};
+
+	Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
+}
+
+
+void Weapon_HyperBlaster_Fire (edict_t *ent)
+{
+	float	rotation;
+	vec3_t	offset;
+	int		effect;
+	int		damage;
+
+	ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
+
+	if (!(ent->client->buttons & BUTTON_ATTACK))
+	{
+		ent->client->ps.gunframe++;
+	}
+	else
+	{
+		if (! ent->client->pers.inventory[ent->client->ammo_index] )
+		{
+			if (level.time >= ent->pain_debounce_time)
+			{
+				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+				ent->pain_debounce_time = level.time + 1;
+			}
+			NoAmmoWeaponChange (ent);
+		}
+		else
+		{
+			rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
+			offset[0] = -4 * sin(rotation);
+			offset[1] = 0;
+			offset[2] = 4 * cos(rotation);
+
+			if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
+				effect = EF_HYPERBLASTER;
+			else
+				effect = 0;
+			if (deathmatch->value)
+				damage = 15;
+			else
+				damage = 20;
+			Blaster_Fire (ent, offset, damage, true, effect);
+			if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+				ent->client->pers.inventory[ent->client->ammo_index]--;
+
+			ent->client->anim_priority = ANIM_ATTACK;
+			if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				ent->s.frame = FRAME_crattak1 - 1;
+				ent->client->anim_end = FRAME_crattak9;
+			}
+			else
+			{
+				ent->s.frame = FRAME_attack1 - 1;
+				ent->client->anim_end = FRAME_attack8;
+			}
+		}
+
+		ent->client->ps.gunframe++;
+		if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
+			ent->client->ps.gunframe = 6;
+	}
+
+	if (ent->client->ps.gunframe == 12)
+	{
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
+		ent->client->weapon_sound = 0;
+	}
+
+}
+
+void Weapon_HyperBlaster (edict_t *ent)
+{
+	static int	pause_frames[]	= {0};
+	static int	fire_frames[]	= {6, 7, 8, 9, 10, 11, 0};
+
+	Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
+}
+
+/*
+======================================================================
+
+MACHINEGUN / CHAINGUN
+
+======================================================================
+*/
+
+void Machinegun_Fire (edict_t *ent)
+{
+	int	i;
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		angles;
+	int			damage = 8;
+	int			kick = 2;
+	vec3_t		offset;
+
+	if (!(ent->client->buttons & BUTTON_ATTACK))
+	{
+		ent->client->machinegun_shots = 0;
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if (ent->client->ps.gunframe == 5)
+		ent->client->ps.gunframe = 4;
+	else
+		ent->client->ps.gunframe = 5;
+
+	if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
+	{
+		ent->client->ps.gunframe = 6;
+		if (level.time >= ent->pain_debounce_time)
+		{
+			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+			ent->pain_debounce_time = level.time + 1;
+		}
+		NoAmmoWeaponChange (ent);
+		return;
+	}
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	for (i=1 ; i<3 ; i++)
+	{
+		ent->client->kick_origin[i] = crandom() * 0.35;
+		ent->client->kick_angles[i] = crandom() * 0.7;
+	}
+	ent->client->kick_origin[0] = crandom() * 0.35;
+	ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
+
+	// raise the gun as it is firing
+	if (!deathmatch->value)
+	{
+		ent->client->machinegun_shots++;
+		if (ent->client->machinegun_shots > 9)
+			ent->client->machinegun_shots = 9;
+	}
+
+	// get start / end positions
+	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
+	AngleVectors (angles, forward, right, NULL);
+	VectorSet(offset, 0, 8, ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
+
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_MACHINEGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+
+	ent->client->anim_priority = ANIM_ATTACK;
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+		ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
+		ent->client->anim_end = FRAME_crattak9;
+	}
+	else
+	{
+		ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
+		ent->client->anim_end = FRAME_attack8;
+	}
+}
+
+void Weapon_Machinegun (edict_t *ent)
+{
+	static int	pause_frames[]	= {23, 45, 0};
+	static int	fire_frames[]	= {4, 5, 0};
+
+	Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
+}
+
+void Chaingun_Fire (edict_t *ent)
+{
+	int			i;
+	int			shots;
+	vec3_t		start;
+	vec3_t		forward, right, up;
+	float		r, u;
+	vec3_t		offset;
+	int			damage;
+	int			kick = 2;
+
+	if (deathmatch->value)
+		damage = 6;
+	else
+		damage = 8;
+
+	if (ent->client->ps.gunframe == 5)
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
+
+	if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
+	{
+		ent->client->ps.gunframe = 32;
+		ent->client->weapon_sound = 0;
+		return;
+	}
+	else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
+		&& ent->client->pers.inventory[ent->client->ammo_index])
+	{
+		ent->client->ps.gunframe = 15;
+	}
+	else
+	{
+		ent->client->ps.gunframe++;
+	}
+
+	if (ent->client->ps.gunframe == 22)
+	{
+		ent->client->weapon_sound = 0;
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
+	}
+	else
+	{
+		ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
+	}
+
+	ent->client->anim_priority = ANIM_ATTACK;
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+		ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
+		ent->client->anim_end = FRAME_crattak9;
+	}
+	else
+	{
+		ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
+		ent->client->anim_end = FRAME_attack8;
+	}
+
+	if (ent->client->ps.gunframe <= 9)
+		shots = 1;
+	else if (ent->client->ps.gunframe <= 14)
+	{
+		if (ent->client->buttons & BUTTON_ATTACK)
+			shots = 2;
+		else
+			shots = 1;
+	}
+	else
+		shots = 3;
+
+	if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
+		shots = ent->client->pers.inventory[ent->client->ammo_index];
+
+	if (!shots)
+	{
+		if (level.time >= ent->pain_debounce_time)
+		{
+			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+			ent->pain_debounce_time = level.time + 1;
+		}
+		NoAmmoWeaponChange (ent);
+		return;
+	}
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		ent->client->kick_origin[i] = crandom() * 0.35;
+		ent->client->kick_angles[i] = crandom() * 0.7;
+	}
+
+	for (i=0 ; i<shots ; i++)
+	{
+		// get start / end positions
+		AngleVectors (ent->client->v_angle, forward, right, up);
+		r = 7 + crandom()*4;
+		u = crandom()*4;
+		VectorSet(offset, 0, r, u + ent->viewheight-8);
+		P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+		fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
+	}
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index] -= shots;
+}
+
+
+void Weapon_Chaingun (edict_t *ent)
+{
+	static int	pause_frames[]	= {38, 43, 51, 61, 0};
+	static int	fire_frames[]	= {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
+
+	Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
+}
+
+
+/*
+======================================================================
+
+SHOTGUN / SUPERSHOTGUN
+
+======================================================================
+*/
+
+void weapon_shotgun_fire (edict_t *ent)
+{
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		offset;
+	int			damage = 4;
+	int			kick = 8;
+
+	if (ent->client->ps.gunframe == 9)
+	{
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -2;
+
+	VectorSet(offset, 0, 8,  ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	if (deathmatch->value)
+		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
+	else
+		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_SHOTGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+void Weapon_Shotgun (edict_t *ent)
+{
+	static int	pause_frames[]	= {22, 28, 34, 0};
+	static int	fire_frames[]	= {8, 9, 0};
+
+	Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
+}
+
+
+void weapon_supershotgun_fire (edict_t *ent)
+{
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		offset;
+	vec3_t		v;
+	int			damage = 6;
+	int			kick = 12;
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -2;
+
+	VectorSet(offset, 0, 8,  ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	v[PITCH] = ent->client->v_angle[PITCH];
+	v[YAW]   = ent->client->v_angle[YAW] - 5;
+	v[ROLL]  = ent->client->v_angle[ROLL];
+	AngleVectors (v, forward, NULL, NULL);
+	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
+	v[YAW]   = ent->client->v_angle[YAW] + 5;
+	AngleVectors (v, forward, NULL, NULL);
+	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_SSHOTGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index] -= 2;
+}
+
+void Weapon_SuperShotgun (edict_t *ent)
+{
+	static int	pause_frames[]	= {29, 42, 57, 0};
+	static int	fire_frames[]	= {7, 0};
+
+	Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
+}
+
+
+
+/*
+======================================================================
+
+RAILGUN
+
+======================================================================
+*/
+
+void weapon_railgun_fire (edict_t *ent)
+{
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		offset;
+	int			damage;
+	int			kick;
+
+	if (deathmatch->value)
+	{	// normal damage is too extreme in dm
+		damage = 100;
+		kick = 200;
+	}
+	else
+	{
+		damage = 150;
+		kick = 250;
+	}
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -3, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -3;
+
+	VectorSet(offset, 0, 7,  ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_rail (ent, start, forward, damage, kick);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_RAILGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+
+void Weapon_Railgun (edict_t *ent)
+{
+	static int	pause_frames[]	= {56, 0};
+	static int	fire_frames[]	= {4, 0};
+
+	Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
+}
+
+
+/*
+======================================================================
+
+BFG10K
+
+======================================================================
+*/
+
+void weapon_bfg_fire (edict_t *ent)
+{
+	vec3_t	offset, start;
+	vec3_t	forward, right;
+	int		damage;
+	float	damage_radius = 1000;
+
+	if (deathmatch->value)
+		damage = 200;
+	else
+		damage = 500;
+
+	if (ent->client->ps.gunframe == 9)
+	{
+		// send muzzle flash
+		gi.WriteByte (svc_muzzleflash);
+		gi.WriteShort (ent-g_edicts);
+		gi.WriteByte (MZ_BFG | is_silenced);
+		gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+		ent->client->ps.gunframe++;
+
+		PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON);
+		return;
+	}
+
+	// cells can go down during windup (from power armor hits), so
+	// check again and abort firing if we don't have enough now
+	if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
+	{
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if (is_quad)
+		damage *= 4;
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+
+	// make a big pitch kick with an inverse fall
+	ent->client->v_dmg_pitch = -40;
+	ent->client->v_dmg_roll = crandom()*8;
+	ent->client->v_dmg_time = level.time + DAMAGE_TIME;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_bfg (ent, start, forward, damage, 400, damage_radius);
+
+	ent->client->ps.gunframe++;
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index] -= 50;
+}
+
+void Weapon_BFG (edict_t *ent)
+{
+	static int	pause_frames[]	= {39, 45, 50, 55, 0};
+	static int	fire_frames[]	= {9, 17, 0};
+
+	Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
+}
+
+
+//======================================================================
--- /dev/null
+++ b/ctf/q_shared.c
@@ -1,0 +1,1419 @@
+/*
+Copyright (C) 1997-2001 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 "q_shared.h"
+
+#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
+
+vec3_t vec3_origin = {0,0,0};
+
+//============================================================================
+
+#ifdef _WIN32
+#pragma optimize( "", off )
+#endif
+
+void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
+{
+	float	m[3][3];
+	float	im[3][3];
+	float	zrot[3][3];
+	float	tmpmat[3][3];
+	float	rot[3][3];
+	int	i;
+	vec3_t vr, vup, vf;
+
+	vf[0] = dir[0];
+	vf[1] = dir[1];
+	vf[2] = dir[2];
+
+	PerpendicularVector( vr, dir );
+	CrossProduct( vr, vf, vup );
+
+	m[0][0] = vr[0];
+	m[1][0] = vr[1];
+	m[2][0] = vr[2];
+
+	m[0][1] = vup[0];
+	m[1][1] = vup[1];
+	m[2][1] = vup[2];
+
+	m[0][2] = vf[0];
+	m[1][2] = vf[1];
+	m[2][2] = vf[2];
+
+	memcpy( im, m, sizeof( im ) );
+
+	im[0][1] = m[1][0];
+	im[0][2] = m[2][0];
+	im[1][0] = m[0][1];
+	im[1][2] = m[2][1];
+	im[2][0] = m[0][2];
+	im[2][1] = m[1][2];
+
+	memset( zrot, 0, sizeof( zrot ) );
+	zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
+
+	zrot[0][0] = cos( DEG2RAD( degrees ) );
+	zrot[0][1] = sin( DEG2RAD( degrees ) );
+	zrot[1][0] = -sin( DEG2RAD( degrees ) );
+	zrot[1][1] = cos( DEG2RAD( degrees ) );
+
+	R_ConcatRotations( m, zrot, tmpmat );
+	R_ConcatRotations( tmpmat, im, rot );
+
+	for ( i = 0; i < 3; i++ )
+	{
+		dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
+	}
+}
+
+#ifdef _WIN32
+#pragma optimize( "", on )
+#endif
+
+
+
+void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
+{
+	float		angle;
+	static float		sr, sp, sy, cr, cp, cy;
+	// static to help MS compiler fp bugs
+
+	angle = angles[YAW] * (M_PI*2 / 360);
+	sy = sin(angle);
+	cy = cos(angle);
+	angle = angles[PITCH] * (M_PI*2 / 360);
+	sp = sin(angle);
+	cp = cos(angle);
+	angle = angles[ROLL] * (M_PI*2 / 360);
+	sr = sin(angle);
+	cr = cos(angle);
+
+	if (forward)
+	{
+		forward[0] = cp*cy;
+		forward[1] = cp*sy;
+		forward[2] = -sp;
+	}
+	if (right)
+	{
+		right[0] = (-1*sr*sp*cy+-1*cr*-sy);
+		right[1] = (-1*sr*sp*sy+-1*cr*cy);
+		right[2] = -1*sr*cp;
+	}
+	if (up)
+	{
+		up[0] = (cr*sp*cy+-sr*-sy);
+		up[1] = (cr*sp*sy+-sr*cy);
+		up[2] = cr*cp;
+	}
+}
+
+
+void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
+{
+	float d;
+	vec3_t n;
+	float inv_denom;
+
+	inv_denom = 1.0F / DotProduct( normal, normal );
+
+	d = DotProduct( normal, p ) * inv_denom;
+
+	n[0] = normal[0] * inv_denom;
+	n[1] = normal[1] * inv_denom;
+	n[2] = normal[2] * inv_denom;
+
+	dst[0] = p[0] - d * n[0];
+	dst[1] = p[1] - d * n[1];
+	dst[2] = p[2] - d * n[2];
+}
+
+/*
+** assumes "src" is normalized
+*/
+void PerpendicularVector( vec3_t dst, const vec3_t src )
+{
+	int	pos;
+	int i;
+	float minelem = 1.0F;
+	vec3_t tempvec;
+
+	/*
+	** find the smallest magnitude axially aligned vector
+	*/
+	for ( pos = 0, i = 0; i < 3; i++ )
+	{
+		if ( fabs( src[i] ) < minelem )
+		{
+			pos = i;
+			minelem = fabs( src[i] );
+		}
+	}
+	tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
+	tempvec[pos] = 1.0F;
+
+	/*
+	** project the point onto the plane defined by src
+	*/
+	ProjectPointOnPlane( dst, tempvec, src );
+
+	/*
+	** normalize the result
+	*/
+	VectorNormalize( dst );
+}
+
+
+
+/*
+================
+R_ConcatRotations
+================
+*/
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
+{
+	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
+				in1[0][2] * in2[2][0];
+	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
+				in1[0][2] * in2[2][1];
+	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
+				in1[0][2] * in2[2][2];
+	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
+				in1[1][2] * in2[2][0];
+	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
+				in1[1][2] * in2[2][1];
+	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
+				in1[1][2] * in2[2][2];
+	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
+				in1[2][2] * in2[2][0];
+	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
+				in1[2][2] * in2[2][1];
+	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
+				in1[2][2] * in2[2][2];
+}
+
+
+/*
+================
+R_ConcatTransforms
+================
+*/
+void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
+{
+	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
+				in1[0][2] * in2[2][0];
+	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
+				in1[0][2] * in2[2][1];
+	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
+				in1[0][2] * in2[2][2];
+	out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
+				in1[0][2] * in2[2][3] + in1[0][3];
+	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
+				in1[1][2] * in2[2][0];
+	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
+				in1[1][2] * in2[2][1];
+	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
+				in1[1][2] * in2[2][2];
+	out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
+				in1[1][2] * in2[2][3] + in1[1][3];
+	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
+				in1[2][2] * in2[2][0];
+	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
+				in1[2][2] * in2[2][1];
+	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
+				in1[2][2] * in2[2][2];
+	out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
+				in1[2][2] * in2[2][3] + in1[2][3];
+}
+
+
+//============================================================================
+
+
+float Q_fabs (float f)
+{
+#if 0
+	if (f >= 0)
+		return f;
+	return -f;
+#else
+	int tmp = * ( int * ) &f;
+	tmp &= 0x7FFFFFFF;
+	return * ( float * ) &tmp;
+#endif
+}
+
+#if defined _M_IX86 && !defined C_ONLY
+#pragma warning (disable:4035)
+__declspec( naked ) long Q_ftol( float f )
+{
+	static int tmp;
+	__asm fld dword ptr [esp+4]
+	__asm fistp tmp
+	__asm mov eax, tmp
+	__asm ret
+}
+#pragma warning (default:4035)
+#endif
+
+/*
+===============
+LerpAngle
+
+===============
+*/
+float LerpAngle (float a2, float a1, float frac)
+{
+	if (a1 - a2 > 180)
+		a1 -= 360;
+	if (a1 - a2 < -180)
+		a1 += 360;
+	return a2 + frac * (a1 - a2);
+}
+
+
+float	anglemod(float a)
+{
+#if 0
+	if (a >= 0)
+		a -= 360*(int)(a/360);
+	else
+		a += 360*( 1 + (int)(-a/360) );
+#endif
+	a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
+	return a;
+}
+
+	int		i;
+	vec3_t	corners[2];
+
+
+// this is the slow, general version
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+{
+	int		i;
+	float	dist1, dist2;
+	int		sides;
+	vec3_t	corners[2];
+
+	for (i=0 ; i<3 ; i++)
+	{
+		if (p->normal[i] < 0)
+		{
+			corners[0][i] = emins[i];
+			corners[1][i] = emaxs[i];
+		}
+		else
+		{
+			corners[1][i] = emins[i];
+			corners[0][i] = emaxs[i];
+		}
+	}
+	dist1 = DotProduct (p->normal, corners[0]) - p->dist;
+	dist2 = DotProduct (p->normal, corners[1]) - p->dist;
+	sides = 0;
+	if (dist1 >= 0)
+		sides = 1;
+	if (dist2 < 0)
+		sides |= 2;
+
+	return sides;
+}
+
+/*
+==================
+BoxOnPlaneSide
+
+Returns 1, 2, or 1 + 2
+==================
+*/
+#if !id386
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+{
+	float	dist1, dist2;
+	int		sides;
+
+// fast axial cases
+	if (p->type < 3)
+	{
+		if (p->dist <= emins[p->type])
+			return 1;
+		if (p->dist >= emaxs[p->type])
+			return 2;
+		return 3;
+	}
+	
+// general case
+	switch (p->signbits)
+	{
+	case 0:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+		break;
+	case 1:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+		break;
+	case 2:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+		break;
+	case 3:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+		break;
+	case 4:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+		break;
+	case 5:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+		break;
+	case 6:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+		break;
+	case 7:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+		break;
+	default:
+		dist1 = dist2 = 0;		// shut up compiler
+		assert( 0 );
+		break;
+	}
+
+	sides = 0;
+	if (dist1 >= p->dist)
+		sides = 1;
+	if (dist2 < p->dist)
+		sides |= 2;
+
+	assert( sides != 0 );
+
+	return sides;
+}
+#else
+#pragma warning( disable: 4035 )
+
+__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+{
+	static int bops_initialized;
+	static int Ljmptab[8];
+
+	__asm {
+
+		push ebx
+			
+		cmp bops_initialized, 1
+		je  initialized
+		mov bops_initialized, 1
+		
+		mov Ljmptab[0*4], offset Lcase0
+		mov Ljmptab[1*4], offset Lcase1
+		mov Ljmptab[2*4], offset Lcase2
+		mov Ljmptab[3*4], offset Lcase3
+		mov Ljmptab[4*4], offset Lcase4
+		mov Ljmptab[5*4], offset Lcase5
+		mov Ljmptab[6*4], offset Lcase6
+		mov Ljmptab[7*4], offset Lcase7
+			
+initialized:
+
+		mov edx,ds:dword ptr[4+12+esp]
+		mov ecx,ds:dword ptr[4+4+esp]
+		xor eax,eax
+		mov ebx,ds:dword ptr[4+8+esp]
+		mov al,ds:byte ptr[17+edx]
+		cmp al,8
+		jge Lerror
+		fld ds:dword ptr[0+edx]
+		fld st(0)
+		jmp dword ptr[Ljmptab+eax*4]
+Lcase0:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase1:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase2:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase3:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase4:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase5:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase6:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase7:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+LSetSides:
+		faddp st(2),st(0)
+		fcomp ds:dword ptr[12+edx]
+		xor ecx,ecx
+		fnstsw ax
+		fcomp ds:dword ptr[12+edx]
+		and ah,1
+		xor ah,1
+		add cl,ah
+		fnstsw ax
+		and ah,1
+		add ah,ah
+		add cl,ah
+		pop ebx
+		mov eax,ecx
+		ret
+Lerror:
+		int 3
+	}
+}
+#pragma warning( default: 4035 )
+#endif
+
+void ClearBounds (vec3_t mins, vec3_t maxs)
+{
+	mins[0] = mins[1] = mins[2] = 99999;
+	maxs[0] = maxs[1] = maxs[2] = -99999;
+}
+
+void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
+{
+	int		i;
+	vec_t	val;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		val = v[i];
+		if (val < mins[i])
+			mins[i] = val;
+		if (val > maxs[i])
+			maxs[i] = val;
+	}
+}
+
+
+int VectorCompare (vec3_t v1, vec3_t v2)
+{
+	if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2])
+			return 0;
+			
+	return 1;
+}
+
+
+vec_t VectorNormalize (vec3_t v)
+{
+	float	length, ilength;
+
+	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+	length = sqrt (length);		// FIXME
+
+	if (length)
+	{
+		ilength = 1/length;
+		v[0] *= ilength;
+		v[1] *= ilength;
+		v[2] *= ilength;
+	}
+		
+	return length;
+
+}
+
+vec_t VectorNormalize2 (vec3_t v, vec3_t out)
+{
+	float	length, ilength;
+
+	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+	length = sqrt (length);		// FIXME
+
+	if (length)
+	{
+		ilength = 1/length;
+		out[0] = v[0]*ilength;
+		out[1] = v[1]*ilength;
+		out[2] = v[2]*ilength;
+	}
+		
+	return length;
+
+}
+
+void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
+{
+	vecc[0] = veca[0] + scale*vecb[0];
+	vecc[1] = veca[1] + scale*vecb[1];
+	vecc[2] = veca[2] + scale*vecb[2];
+}
+
+
+vec_t _DotProduct (vec3_t v1, vec3_t v2)
+{
+	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
+{
+	out[0] = veca[0]-vecb[0];
+	out[1] = veca[1]-vecb[1];
+	out[2] = veca[2]-vecb[2];
+}
+
+void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
+{
+	out[0] = veca[0]+vecb[0];
+	out[1] = veca[1]+vecb[1];
+	out[2] = veca[2]+vecb[2];
+}
+
+void _VectorCopy (vec3_t in, vec3_t out)
+{
+	out[0] = in[0];
+	out[1] = in[1];
+	out[2] = in[2];
+}
+
+void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
+{
+	cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
+	cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
+	cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
+}
+
+double sqrt(double x);
+
+vec_t VectorLength(vec3_t v)
+{
+	int		i;
+	float	length;
+	
+	length = 0;
+	for (i=0 ; i< 3 ; i++)
+		length += v[i]*v[i];
+	length = sqrt (length);		// FIXME
+
+	return length;
+}
+
+void VectorInverse (vec3_t v)
+{
+	v[0] = -v[0];
+	v[1] = -v[1];
+	v[2] = -v[2];
+}
+
+void VectorScale (vec3_t in, vec_t scale, vec3_t out)
+{
+	out[0] = in[0]*scale;
+	out[1] = in[1]*scale;
+	out[2] = in[2]*scale;
+}
+
+
+int Q_log2(int val)
+{
+	int answer=0;
+	while (val>>=1)
+		answer++;
+	return answer;
+}
+
+
+
+//====================================================================================
+
+/*
+============
+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 != in && *s2 != '/' ; s2--)
+	;
+	
+	if (s-s2 < 2)
+		out[0] = 0;
+	else
+	{
+		s--;
+		strncpy (out,s2+1, s-s2);
+		out[s-s2] = 0;
+	}
+}
+
+/*
+============
+COM_FilePath
+
+Returns the path up to, but not including the last /
+============
+*/
+void COM_FilePath (char *in, char *out)
+{
+	char *s;
+	
+	s = in + strlen(in) - 1;
+	
+	while (s != in && *s != '/')
+		s--;
+
+	strncpy (out,in, s-in);
+	out[s-in] = 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);
+}
+
+/*
+============================================================================
+
+					BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+qboolean	bigendien;
+
+// can't just use function pointers, or dll linkage can
+// mess up when qcommon is included in multiple places
+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	BigShort(short l){return _BigShort(l);}
+short	LittleShort(short l) {return _LittleShort(l);}
+int		BigLong (int l) {return _BigLong(l);}
+int		LittleLong (int l) {return _LittleLong(l);}
+float	BigFloat (float l) {return _BigFloat(l);}
+float	LittleFloat (float l) {return _LittleFloat(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;
+}
+
+/*
+================
+Swap_Init
+================
+*/
+void Swap_Init (void)
+{
+	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;
+	}
+
+}
+
+
+
+/*
+============
+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;	
+}
+
+
+char	com_token[MAX_TOKEN_CHARS];
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *COM_Parse (char **data_p)
+{
+	int		c;
+	int		len;
+	char	*data;
+
+	data = *data_p;
+	len = 0;
+	com_token[0] = 0;
+	
+	if (!data)
+	{
+		*data_p = NULL;
+		return "";
+	}
+		
+// skip whitespace
+skipwhite:
+	while ( (c = *data) <= ' ')
+	{
+		if (c == 0)
+		{
+			*data_p = NULL;
+			return "";
+		}
+		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;
+				*data_p = data;
+				return com_token;
+			}
+			if (len < MAX_TOKEN_CHARS)
+			{
+				com_token[len] = c;
+				len++;
+			}
+		}
+	}
+
+// parse a regular word
+	do
+	{
+		if (len < MAX_TOKEN_CHARS)
+		{
+			com_token[len] = c;
+			len++;
+		}
+		data++;
+		c = *data;
+	} while (c>32);
+
+	if (len == MAX_TOKEN_CHARS)
+	{
+//		Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
+		len = 0;
+	}
+	com_token[len] = 0;
+
+	*data_p = data;
+	return com_token;
+}
+
+
+/*
+===============
+Com_PageInMemory
+
+===============
+*/
+int	paged_total;
+
+void Com_PageInMemory (byte *buffer, int size)
+{
+	int		i;
+
+	for (i=size-1 ; i>0 ; i-=4096)
+		paged_total += buffer[i];
+}
+
+
+
+/*
+============================================================================
+
+					LIBRARY REPLACEMENT FUNCTIONS
+
+============================================================================
+*/
+
+// FIXME: replace all Q_stricmp with Q_strcasecmp
+int Q_stricmp (char *s1, char *s2)
+{
+#if defined(WIN32)
+	return _stricmp (s1, s2);
+#else
+	return strcasecmp (s1, s2);
+#endif
+}
+
+
+int Q_strncasecmp (char *s1, char *s2, int n)
+{
+	int		c1, c2;
+	
+	do
+	{
+		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
+		}
+	} while (c1);
+	
+	return 0;		// strings are equal
+}
+
+int Q_strcasecmp (char *s1, char *s2)
+{
+	return Q_strncasecmp (s1, s2, 99999);
+}
+
+
+
+void Com_sprintf (char *dest, int size, char *fmt, ...)
+{
+	int		len;
+	va_list		argptr;
+	char	bigbuffer[0x10000];
+
+	va_start (argptr,fmt);
+	len = vsprintf (bigbuffer,fmt,argptr);
+	va_end (argptr);
+	if (len >= size)
+		Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
+	strncpy (dest, bigbuffer, size-1);
+}
+
+/*
+=====================================================================
+
+  INFO STRINGS
+
+=====================================================================
+*/
+
+/*
+===============
+Info_ValueForKey
+
+Searches the string for the given
+key and returns the associated value, or an empty string.
+===============
+*/
+char *Info_ValueForKey (char *s, char *key)
+{
+	char	pkey[512];
+	static	char value[2][512];	// use two buffers so compares
+								// work without stomping on each other
+	static	int	valueindex;
+	char	*o;
+	
+	valueindex ^= 1;
+	if (*s == '\\')
+		s++;
+	while (1)
+	{
+		o = pkey;
+		while (*s != '\\')
+		{
+			if (!*s)
+				return "";
+			*o++ = *s++;
+		}
+		*o = 0;
+		s++;
+
+		o = value[valueindex];
+
+		while (*s != '\\' && *s)
+		{
+			if (!*s)
+				return "";
+			*o++ = *s++;
+		}
+		*o = 0;
+
+		if (!strcmp (key, pkey) )
+			return value[valueindex];
+
+		if (!*s)
+			return "";
+		s++;
+	}
+}
+
+void Info_RemoveKey (char *s, char *key)
+{
+	char	*start;
+	char	pkey[512];
+	char	value[512];
+	char	*o;
+
+	if (strstr (key, "\\"))
+	{
+//		Com_Printf ("Can't use a key with a \\\n");
+		return;
+	}
+
+	while (1)
+	{
+		start = s;
+		if (*s == '\\')
+			s++;
+		o = pkey;
+		while (*s != '\\')
+		{
+			if (!*s)
+				return;
+			*o++ = *s++;
+		}
+		*o = 0;
+		s++;
+
+		o = value;
+		while (*s != '\\' && *s)
+		{
+			if (!*s)
+				return;
+			*o++ = *s++;
+		}
+		*o = 0;
+
+		if (!strcmp (key, pkey) )
+		{
+			strcpy (start, s);	// remove this part
+			return;
+		}
+
+		if (!*s)
+			return;
+	}
+
+}
+
+
+/*
+==================
+Info_Validate
+
+Some characters are illegal in info strings because they
+can mess up the server's parsing
+==================
+*/
+qboolean Info_Validate (char *s)
+{
+	if (strstr (s, "\""))
+		return false;
+	if (strstr (s, ";"))
+		return false;
+	return true;
+}
+
+void Info_SetValueForKey (char *s, char *key, char *value)
+{
+	char	newi[MAX_INFO_STRING], *v;
+	int		c;
+	int		maxsize = MAX_INFO_STRING;
+
+	if (strstr (key, "\\") || strstr (value, "\\") )
+	{
+		Com_Printf ("Can't use keys or values with a \\\n");
+		return;
+	}
+
+	if (strstr (key, ";") )
+	{
+		Com_Printf ("Can't use keys or values with a semicolon\n");
+		return;
+	}
+
+	if (strstr (key, "\"") || strstr (value, "\"") )
+	{
+		Com_Printf ("Can't use keys or values with a \"\n");
+		return;
+	}
+
+	if (strlen(key) > MAX_INFO_KEY-1 || strlen(value) > MAX_INFO_KEY-1)
+	{
+		Com_Printf ("Keys and values must be < 64 characters.\n");
+		return;
+	}
+	Info_RemoveKey (s, key);
+	if (!value || !strlen(value))
+		return;
+
+	Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
+
+	if (strlen(newi) + strlen(s) > maxsize)
+	{
+		Com_Printf ("Info string length exceeded\n");
+		return;
+	}
+
+	// only copy ascii values
+	s += strlen(s);
+	v = newi;
+	while (*v)
+	{
+		c = *v++;
+		c &= 127;		// strip high bits
+		if (c >= 32 && c < 127)
+			*s++ = c;
+	}
+	*s = 0;
+}
+
+//====================================================================
+
+
--- /dev/null
+++ b/ctf/q_shared.h
@@ -1,0 +1,1200 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+	
+// q_shared.h -- included first by ALL program modules
+
+#ifdef _WIN32
+// unknown pragmas are SUPPOSED to be ignored, but....
+#pragma warning(disable : 4244)     // MIPS
+#pragma warning(disable : 4136)     // X86
+#pragma warning(disable : 4051)     // ALPHA
+
+#pragma warning(disable : 4018)     // signed/unsigned mismatch
+#pragma warning(disable : 4305)		// truncation from const double to float
+
+#endif
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#if (defined _M_IX86 || defined __i386__) && !defined C_ONLY && !defined __sun__
+#define id386	1
+#else
+#define id386	0
+#endif
+
+#if defined _M_ALPHA && !defined C_ONLY
+#define idaxp	1
+#else
+#define idaxp	0
+#endif
+
+typedef unsigned char 		byte;
+typedef enum {false, true}	qboolean;
+
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+
+// angle indexes
+#define	PITCH				0		// up / down
+#define	YAW					1		// left / right
+#define	ROLL				2		// fall over
+
+#define	MAX_STRING_CHARS	1024	// max length of a string passed to Cmd_TokenizeString
+#define	MAX_STRING_TOKENS	80		// max tokens resulting from Cmd_TokenizeString
+#define	MAX_TOKEN_CHARS		128		// max length of an individual token
+
+#define	MAX_QPATH			64		// max length of a quake game pathname
+#define	MAX_OSPATH			128		// max length of a filesystem pathname
+
+//
+// per-level limits
+//
+#define	MAX_CLIENTS			256		// absolute limit
+#define	MAX_EDICTS			1024	// must change protocol to increase more
+#define	MAX_LIGHTSTYLES		256
+#define	MAX_MODELS			256		// these are sent over the net as bytes
+#define	MAX_SOUNDS			256		// so they cannot be blindly increased
+#define	MAX_IMAGES			256
+#define	MAX_ITEMS			256
+#define MAX_GENERAL			(MAX_CLIENTS*2)	// general config strings
+
+
+// game print flags
+#define	PRINT_LOW			0		// pickup messages
+#define	PRINT_MEDIUM		1		// death messages
+#define	PRINT_HIGH			2		// critical messages
+#define	PRINT_CHAT			3		// chat messages
+
+
+
+#define	ERR_FATAL			0		// exit the entire game with a popup window
+#define	ERR_DROP			1		// print to console and disconnect from game
+#define	ERR_DISCONNECT		2		// don't kill server
+
+#define	PRINT_ALL			0
+#define PRINT_DEVELOPER		1		// only print when "developer 1"
+#define PRINT_ALERT			2		
+
+
+// destination class for gi.multicast()
+typedef enum
+{
+MULTICAST_ALL,
+MULTICAST_PHS,
+MULTICAST_PVS,
+MULTICAST_ALL_R,
+MULTICAST_PHS_R,
+MULTICAST_PVS_R
+} multicast_t;
+
+
+/*
+==============================================================
+
+MATHLIB
+
+==============================================================
+*/
+
+typedef float vec_t;
+typedef vec_t vec3_t[3];
+typedef vec_t vec5_t[5];
+
+typedef	int	fixed4_t;
+typedef	int	fixed8_t;
+typedef	int	fixed16_t;
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h
+#endif
+
+struct cplane_s;
+
+extern vec3_t vec3_origin;
+
+#define	nanmask (255<<23)
+
+#define	IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
+
+// microsoft's fabs seems to be ungodly slow...
+//float Q_fabs (float f);
+//#define	fabs(f) Q_fabs(f)
+#if !defined C_ONLY && !defined __linux__ && !defined __sgi
+extern long Q_ftol( float f );
+#else
+#define Q_ftol( f ) ( long ) (f)
+#endif
+
+#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])
+#define VectorAdd(a,b,c)		(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
+#define VectorCopy(a,b)			(b[0]=a[0],b[1]=a[1],b[2]=a[2])
+#define VectorClear(a)			(a[0]=a[1]=a[2]=0)
+#define VectorNegate(a,b)		(b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
+#define VectorSet(v, x, y, z)	(v[0]=(x), v[1]=(y), v[2]=(z))
+
+void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
+
+// just in case you do't want to use the macros
+vec_t _DotProduct (vec3_t v1, vec3_t v2);
+void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
+void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
+void _VectorCopy (vec3_t in, vec3_t out);
+
+void ClearBounds (vec3_t mins, vec3_t maxs);
+void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
+int VectorCompare (vec3_t v1, vec3_t v2);
+vec_t VectorLength (vec3_t v);
+void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
+vec_t VectorNormalize (vec3_t v);		// returns vector length
+vec_t VectorNormalize2 (vec3_t v, vec3_t out);
+void VectorInverse (vec3_t v);
+void VectorScale (vec3_t in, vec_t scale, vec3_t out);
+int Q_log2(int val);
+
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
+void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
+
+void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
+float	anglemod(float a);
+float LerpAngle (float a1, float a2, float frac);
+
+#define BOX_ON_PLANE_SIDE(emins, emaxs, p)	\
+	(((p)->type < 3)?						\
+	(										\
+		((p)->dist <= (emins)[(p)->type])?	\
+			1								\
+		:									\
+		(									\
+			((p)->dist >= (emaxs)[(p)->type])?\
+				2							\
+			:								\
+				3							\
+		)									\
+	)										\
+	:										\
+		BoxOnPlaneSide( (emins), (emaxs), (p)))
+
+void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
+void PerpendicularVector( vec3_t dst, const vec3_t src );
+void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
+
+
+//=============================================
+
+char *COM_SkipPath (char *pathname);
+void COM_StripExtension (char *in, char *out);
+void COM_FileBase (char *in, char *out);
+void COM_FilePath (char *in, char *out);
+void COM_DefaultExtension (char *path, char *extension);
+
+char *COM_Parse (char **data_p);
+// data is an in/out parm, returns a parsed out token
+
+void Com_sprintf (char *dest, int size, char *fmt, ...);
+
+void Com_PageInMemory (byte *buffer, int size);
+
+//=============================================
+
+// portable case insensitive compare
+int Q_stricmp (char *s1, char *s2);
+int Q_strcasecmp (char *s1, char *s2);
+int Q_strncasecmp (char *s1, char *s2, int n);
+
+//=============================================
+
+short	BigShort(short l);
+short	LittleShort(short l);
+int		BigLong (int l);
+int		LittleLong (int l);
+float	BigFloat (float l);
+float	LittleFloat (float l);
+
+void	Swap_Init (void);
+char	*va(char *format, ...);
+
+//=============================================
+
+//
+// key / value info strings
+//
+#define	MAX_INFO_KEY		64
+#define	MAX_INFO_VALUE		64
+#define	MAX_INFO_STRING		512
+
+char *Info_ValueForKey (char *s, char *key);
+void Info_RemoveKey (char *s, char *key);
+void Info_SetValueForKey (char *s, char *key, char *value);
+qboolean Info_Validate (char *s);
+
+/*
+==============================================================
+
+SYSTEM SPECIFIC
+
+==============================================================
+*/
+
+extern	int	curtime;		// time returned by last Sys_Milliseconds
+
+int		Sys_Milliseconds (void);
+void	Sys_Mkdir (char *path);
+
+// large block stack allocation routines
+void	*Hunk_Begin (int maxsize);
+void	*Hunk_Alloc (int size);
+void	Hunk_Free (void *buf);
+int		Hunk_End (void);
+
+// directory searching
+#define SFF_ARCH    0x01
+#define SFF_HIDDEN  0x02
+#define SFF_RDONLY  0x04
+#define SFF_SUBDIR  0x08
+#define SFF_SYSTEM  0x10
+
+/*
+** pass in an attribute mask of things you wish to REJECT
+*/
+char	*Sys_FindFirst (char *path, unsigned musthave, unsigned canthave );
+char	*Sys_FindNext ( unsigned musthave, unsigned canthave );
+void	Sys_FindClose (void);
+
+
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...);
+void Com_Printf (char *msg, ...);
+
+
+/*
+==========================================================
+
+CVARS (console variables)
+
+==========================================================
+*/
+
+#ifndef CVAR
+#define	CVAR
+
+#define	CVAR_ARCHIVE	1	// set to cause it to be saved to vars.rc
+#define	CVAR_USERINFO	2	// added to userinfo  when changed
+#define	CVAR_SERVERINFO	4	// added to serverinfo when changed
+#define	CVAR_NOSET		8	// don't allow change from console at all,
+							// but can be set from the command line
+#define	CVAR_LATCH		16	// save changes until server restart
+
+// nothing outside the Cvar_*() functions should modify these fields!
+typedef struct cvar_s
+{
+	char		*name;
+	char		*string;
+	char		*latched_string;	// for CVAR_LATCH vars
+	int			flags;
+	qboolean	modified;	// set each time the cvar is changed
+	float		value;
+	struct cvar_s *next;
+} cvar_t;
+
+#endif		// CVAR
+
+/*
+==============================================================
+
+COLLISION DETECTION
+
+==============================================================
+*/
+
+// lower bits are stronger, and will eat weaker brushes completely
+#define	CONTENTS_SOLID			1		// an eye is never valid in a solid
+#define	CONTENTS_WINDOW			2		// translucent, but not watery
+#define	CONTENTS_AUX			4
+#define	CONTENTS_LAVA			8
+#define	CONTENTS_SLIME			16
+#define	CONTENTS_WATER			32
+#define	CONTENTS_MIST			64
+#define	LAST_VISIBLE_CONTENTS	64
+
+// remaining contents are non-visible, and don't eat brushes
+
+#define	CONTENTS_AREAPORTAL		0x8000
+
+#define	CONTENTS_PLAYERCLIP		0x10000
+#define	CONTENTS_MONSTERCLIP	0x20000
+
+// currents can be added to any other contents, and may be mixed
+#define	CONTENTS_CURRENT_0		0x40000
+#define	CONTENTS_CURRENT_90		0x80000
+#define	CONTENTS_CURRENT_180	0x100000
+#define	CONTENTS_CURRENT_270	0x200000
+#define	CONTENTS_CURRENT_UP		0x400000
+#define	CONTENTS_CURRENT_DOWN	0x800000
+
+#define	CONTENTS_ORIGIN			0x1000000	// removed before bsping an entity
+
+#define	CONTENTS_MONSTER		0x2000000	// should never be on a brush, only in game
+#define	CONTENTS_DEADMONSTER	0x4000000
+#define	CONTENTS_DETAIL			0x8000000	// brushes to be added after vis leafs
+#define	CONTENTS_TRANSLUCENT	0x10000000	// auto set if any surface has trans
+#define	CONTENTS_LADDER			0x20000000
+
+
+
+#define	SURF_LIGHT		0x1		// value will hold the light strength
+
+#define	SURF_SLICK		0x2		// effects game physics
+
+#define	SURF_SKY		0x4		// don't draw, but add to skybox
+#define	SURF_WARP		0x8		// turbulent water warp
+#define	SURF_TRANS33	0x10
+#define	SURF_TRANS66	0x20
+#define	SURF_FLOWING	0x40	// scroll towards angle
+#define	SURF_NODRAW		0x80	// don't bother referencing the texture
+
+
+
+// content masks
+#define	MASK_ALL				(-1)
+#define	MASK_SOLID				(CONTENTS_SOLID|CONTENTS_WINDOW)
+#define	MASK_PLAYERSOLID		(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
+#define	MASK_DEADSOLID			(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW)
+#define	MASK_MONSTERSOLID		(CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
+#define	MASK_WATER				(CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
+#define	MASK_OPAQUE				(CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
+#define	MASK_SHOT				(CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
+#define MASK_CURRENT			(CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN)
+
+
+// gi.BoxEdicts() can return a list of either solid or trigger entities
+// FIXME: eliminate AREA_ distinction?
+#define	AREA_SOLID		1
+#define	AREA_TRIGGERS	2
+
+
+// plane_t structure
+// !!! if this is changed, it must be changed in asm code too !!!
+typedef struct cplane_s
+{
+	vec3_t	normal;
+	float	dist;
+	byte	type;			// for fast side tests
+	byte	signbits;		// signx + (signy<<1) + (signz<<1)
+	byte	pad[2];
+} cplane_t;
+
+// structure offset for asm code
+#define CPLANE_NORMAL_X			0
+#define CPLANE_NORMAL_Y			4
+#define CPLANE_NORMAL_Z			8
+#define CPLANE_DIST				12
+#define CPLANE_TYPE				16
+#define CPLANE_SIGNBITS			17
+#define CPLANE_PAD0				18
+#define CPLANE_PAD1				19
+
+typedef struct cmodel_s
+{
+	vec3_t		mins, maxs;
+	vec3_t		origin;		// for sounds or lights
+	int			headnode;
+} cmodel_t;
+
+typedef struct csurface_s
+{
+	char		name[16];
+	int			flags;
+	int			value;
+} csurface_t;
+
+typedef struct mapsurface_s  // used internally due to name len probs //ZOID
+{
+	csurface_t	c;
+	char		rname[32];
+} mapsurface_t;
+
+// a trace is returned when a box is swept through the world
+typedef struct
+{
+	qboolean	allsolid;	// if true, plane is not valid
+	qboolean	startsolid;	// if true, the initial point was in a solid area
+	float		fraction;	// time completed, 1.0 = didn't hit anything
+	vec3_t		endpos;		// final position
+	cplane_t	plane;		// surface normal at impact
+	csurface_t	*surface;	// surface hit
+	int			contents;	// contents on other side of surface hit
+	struct edict_s	*ent;		// not set by CM_*() functions
+} trace_t;
+
+
+
+// pmove_state_t is the information necessary for client side movement
+// prediction
+typedef enum 
+{
+	// can accelerate and turn
+	PM_NORMAL,
+	PM_SPECTATOR,
+	// no acceleration or turning
+	PM_DEAD,
+	PM_GIB,		// different bounding box
+	PM_FREEZE
+} pmtype_t;
+
+// pmove->pm_flags
+#define	PMF_DUCKED			1
+#define	PMF_JUMP_HELD		2
+#define	PMF_ON_GROUND		4
+#define	PMF_TIME_WATERJUMP	8	// pm_time is waterjump
+#define	PMF_TIME_LAND		16	// pm_time is time before rejump
+#define	PMF_TIME_TELEPORT	32	// pm_time is non-moving time
+#define PMF_NO_PREDICTION	64	// temporarily disables prediction (used for grappling hook)
+
+// this structure needs to be communicated bit-accurate
+// from the server to the client to guarantee that
+// prediction stays in sync, so no floats are used.
+// if any part of the game code modifies this struct, it
+// will result in a prediction error of some degree.
+typedef struct
+{
+	pmtype_t	pm_type;
+
+	short		origin[3];		// 12.3
+	short		velocity[3];	// 12.3
+	byte		pm_flags;		// ducked, jump_held, etc
+	byte		pm_time;		// each unit = 8 ms
+	short		gravity;
+	short		delta_angles[3];	// add to command angles to get view direction
+									// changed by spawns, rotating objects, and teleporters
+} pmove_state_t;
+
+
+//
+// button bits
+//
+#define	BUTTON_ATTACK		1
+#define	BUTTON_USE			2
+#define	BUTTON_ANY			128			// any key whatsoever
+
+
+// usercmd_t is sent to the server each client frame
+typedef struct usercmd_s
+{
+	byte	msec;
+	byte	buttons;
+	short	angles[3];
+	short	forwardmove, sidemove, upmove;
+	byte	impulse;		// remove?
+	byte	lightlevel;		// light level the player is standing on
+} usercmd_t;
+
+
+#define	MAXTOUCH	32
+typedef struct
+{
+	// state (in / out)
+	pmove_state_t	s;
+
+	// command (in)
+	usercmd_t		cmd;
+	qboolean		snapinitial;	// if s has been changed outside pmove
+
+	// results (out)
+	int			numtouch;
+	struct edict_s	*touchents[MAXTOUCH];
+
+	vec3_t		viewangles;			// clamped
+	float		viewheight;
+
+	vec3_t		mins, maxs;			// bounding box size
+
+	struct edict_s	*groundentity;
+	int			watertype;
+	int			waterlevel;
+
+	// callbacks to test the world
+	trace_t		(*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
+	int			(*pointcontents) (vec3_t point);
+} pmove_t;
+
+
+// entity_state_t->effects
+// Effects are things handled on the client side (lights, particles, frame animations)
+// that happen constantly on the given entity.
+// An entity that has effects will be sent to the client
+// even if it has a zero index model.
+#define	EF_ROTATE			0x00000001		// rotate (bonus items)
+#define	EF_GIB				0x00000002		// leave a trail
+#define	EF_BLASTER			0x00000008		// redlight + trail
+#define	EF_ROCKET			0x00000010		// redlight + trail
+#define	EF_GRENADE			0x00000020
+#define	EF_HYPERBLASTER		0x00000040
+#define	EF_BFG				0x00000080
+#define EF_COLOR_SHELL		0x00000100
+#define EF_POWERSCREEN		0x00000200
+#define	EF_ANIM01			0x00000400		// automatically cycle between frames 0 and 1 at 2 hz
+#define	EF_ANIM23			0x00000800		// automatically cycle between frames 2 and 3 at 2 hz
+#define EF_ANIM_ALL			0x00001000		// automatically cycle through all frames at 2hz
+#define EF_ANIM_ALLFAST		0x00002000		// automatically cycle through all frames at 10hz
+#define	EF_FLIES			0x00004000
+#define	EF_QUAD				0x00008000
+#define	EF_PENT				0x00010000
+#define	EF_TELEPORTER		0x00020000		// particle fountain
+#define EF_FLAG1			0x00040000
+#define EF_FLAG2			0x00080000
+// RAFAEL
+#define EF_IONRIPPER		0x00100000
+#define EF_GREENGIB			0x00200000
+#define	EF_BLUEHYPERBLASTER 0x00400000
+#define EF_SPINNINGLIGHTS	0x00800000
+#define EF_PLASMA			0x01000000
+#define EF_TRAP				0x02000000
+
+//ROGUE
+#define EF_TRACKER			0x04000000
+#define	EF_DOUBLE			0x08000000
+#define	EF_SPHERETRANS		0x10000000
+#define EF_TAGTRAIL			0x20000000
+#define EF_HALF_DAMAGE		0x40000000
+#define EF_TRACKERTRAIL		0x80000000
+//ROGUE
+
+// entity_state_t->renderfx flags
+#define	RF_MINLIGHT			1		// allways have some light (viewmodel)
+#define	RF_VIEWERMODEL		2		// don't draw through eyes, only mirrors
+#define	RF_WEAPONMODEL		4		// only draw through eyes
+#define	RF_FULLBRIGHT		8		// allways draw full intensity
+#define	RF_DEPTHHACK		16		// for view weapon Z crunching
+#define	RF_TRANSLUCENT		32
+#define	RF_FRAMELERP		64
+#define RF_BEAM				128
+#define	RF_CUSTOMSKIN		256		// skin is an index in image_precache
+#define	RF_GLOW				512		// pulse lighting for bonus items
+#define RF_SHELL_RED		1024
+#define	RF_SHELL_GREEN		2048
+#define RF_SHELL_BLUE		4096
+
+//ROGUE
+#define RF_IR_VISIBLE		0x00008000		// 32768
+#define	RF_SHELL_DOUBLE		0x00010000		// 65536
+#define	RF_SHELL_HALF_DAM	0x00020000
+#define RF_USE_DISGUISE		0x00040000
+//ROGUE
+
+// player_state_t->refdef flags
+#define	RDF_UNDERWATER		1		// warp the screen as apropriate
+#define RDF_NOWORLDMODEL	2		// used for player configuration screen
+
+//ROGUE
+#define	RDF_IRGOGGLES		4
+#define RDF_UVGOGGLES		8
+//ROGUE
+
+//
+// muzzle flashes / player effects
+//
+#define	MZ_BLASTER			0
+#define MZ_MACHINEGUN		1
+#define	MZ_SHOTGUN			2
+#define	MZ_CHAINGUN1		3
+#define	MZ_CHAINGUN2		4
+#define	MZ_CHAINGUN3		5
+#define	MZ_RAILGUN			6
+#define	MZ_ROCKET			7
+#define	MZ_GRENADE			8
+#define	MZ_LOGIN			9
+#define	MZ_LOGOUT			10
+#define	MZ_RESPAWN			11
+#define	MZ_BFG				12
+#define	MZ_SSHOTGUN			13
+#define	MZ_HYPERBLASTER		14
+#define	MZ_ITEMRESPAWN		15
+// RAFAEL
+#define MZ_IONRIPPER		16
+#define MZ_BLUEHYPERBLASTER 17
+#define MZ_PHALANX			18
+#define MZ_SILENCED			128		// bit flag ORed with one of the above numbers
+
+//ROGUE
+#define MZ_ETF_RIFLE		30
+#define MZ_UNUSED			31
+#define MZ_SHOTGUN2			32
+#define MZ_HEATBEAM			33
+#define MZ_BLASTER2			34
+#define	MZ_TRACKER			35
+#define	MZ_NUKE1			36
+#define	MZ_NUKE2			37
+#define	MZ_NUKE4			38
+#define	MZ_NUKE8			39
+//ROGUE
+
+//
+// monster muzzle flashes
+//
+#define MZ2_TANK_BLASTER_1				1
+#define MZ2_TANK_BLASTER_2				2
+#define MZ2_TANK_BLASTER_3				3
+#define MZ2_TANK_MACHINEGUN_1			4
+#define MZ2_TANK_MACHINEGUN_2			5
+#define MZ2_TANK_MACHINEGUN_3			6
+#define MZ2_TANK_MACHINEGUN_4			7
+#define MZ2_TANK_MACHINEGUN_5			8
+#define MZ2_TANK_MACHINEGUN_6			9
+#define MZ2_TANK_MACHINEGUN_7			10
+#define MZ2_TANK_MACHINEGUN_8			11
+#define MZ2_TANK_MACHINEGUN_9			12
+#define MZ2_TANK_MACHINEGUN_10			13
+#define MZ2_TANK_MACHINEGUN_11			14
+#define MZ2_TANK_MACHINEGUN_12			15
+#define MZ2_TANK_MACHINEGUN_13			16
+#define MZ2_TANK_MACHINEGUN_14			17
+#define MZ2_TANK_MACHINEGUN_15			18
+#define MZ2_TANK_MACHINEGUN_16			19
+#define MZ2_TANK_MACHINEGUN_17			20
+#define MZ2_TANK_MACHINEGUN_18			21
+#define MZ2_TANK_MACHINEGUN_19			22
+#define MZ2_TANK_ROCKET_1				23
+#define MZ2_TANK_ROCKET_2				24
+#define MZ2_TANK_ROCKET_3				25
+
+#define MZ2_INFANTRY_MACHINEGUN_1		26
+#define MZ2_INFANTRY_MACHINEGUN_2		27
+#define MZ2_INFANTRY_MACHINEGUN_3		28
+#define MZ2_INFANTRY_MACHINEGUN_4		29
+#define MZ2_INFANTRY_MACHINEGUN_5		30
+#define MZ2_INFANTRY_MACHINEGUN_6		31
+#define MZ2_INFANTRY_MACHINEGUN_7		32
+#define MZ2_INFANTRY_MACHINEGUN_8		33
+#define MZ2_INFANTRY_MACHINEGUN_9		34
+#define MZ2_INFANTRY_MACHINEGUN_10		35
+#define MZ2_INFANTRY_MACHINEGUN_11		36
+#define MZ2_INFANTRY_MACHINEGUN_12		37
+#define MZ2_INFANTRY_MACHINEGUN_13		38
+
+#define MZ2_SOLDIER_BLASTER_1			39
+#define MZ2_SOLDIER_BLASTER_2			40
+#define MZ2_SOLDIER_SHOTGUN_1			41
+#define MZ2_SOLDIER_SHOTGUN_2			42
+#define MZ2_SOLDIER_MACHINEGUN_1		43
+#define MZ2_SOLDIER_MACHINEGUN_2		44
+
+#define MZ2_GUNNER_MACHINEGUN_1			45
+#define MZ2_GUNNER_MACHINEGUN_2			46
+#define MZ2_GUNNER_MACHINEGUN_3			47
+#define MZ2_GUNNER_MACHINEGUN_4			48
+#define MZ2_GUNNER_MACHINEGUN_5			49
+#define MZ2_GUNNER_MACHINEGUN_6			50
+#define MZ2_GUNNER_MACHINEGUN_7			51
+#define MZ2_GUNNER_MACHINEGUN_8			52
+#define MZ2_GUNNER_GRENADE_1			53
+#define MZ2_GUNNER_GRENADE_2			54
+#define MZ2_GUNNER_GRENADE_3			55
+#define MZ2_GUNNER_GRENADE_4			56
+
+#define MZ2_CHICK_ROCKET_1				57
+
+#define MZ2_FLYER_BLASTER_1				58
+#define MZ2_FLYER_BLASTER_2				59
+
+#define MZ2_MEDIC_BLASTER_1				60
+
+#define MZ2_GLADIATOR_RAILGUN_1			61
+
+#define MZ2_HOVER_BLASTER_1				62
+
+#define MZ2_ACTOR_MACHINEGUN_1			63
+
+#define MZ2_SUPERTANK_MACHINEGUN_1		64
+#define MZ2_SUPERTANK_MACHINEGUN_2		65
+#define MZ2_SUPERTANK_MACHINEGUN_3		66
+#define MZ2_SUPERTANK_MACHINEGUN_4		67
+#define MZ2_SUPERTANK_MACHINEGUN_5		68
+#define MZ2_SUPERTANK_MACHINEGUN_6		69
+#define MZ2_SUPERTANK_ROCKET_1			70
+#define MZ2_SUPERTANK_ROCKET_2			71
+#define MZ2_SUPERTANK_ROCKET_3			72
+
+#define MZ2_BOSS2_MACHINEGUN_L1			73
+#define MZ2_BOSS2_MACHINEGUN_L2			74
+#define MZ2_BOSS2_MACHINEGUN_L3			75
+#define MZ2_BOSS2_MACHINEGUN_L4			76
+#define MZ2_BOSS2_MACHINEGUN_L5			77
+#define MZ2_BOSS2_ROCKET_1				78
+#define MZ2_BOSS2_ROCKET_2				79
+#define MZ2_BOSS2_ROCKET_3				80
+#define MZ2_BOSS2_ROCKET_4				81
+
+#define MZ2_FLOAT_BLASTER_1				82
+
+#define MZ2_SOLDIER_BLASTER_3			83
+#define MZ2_SOLDIER_SHOTGUN_3			84
+#define MZ2_SOLDIER_MACHINEGUN_3		85
+#define MZ2_SOLDIER_BLASTER_4			86
+#define MZ2_SOLDIER_SHOTGUN_4			87
+#define MZ2_SOLDIER_MACHINEGUN_4		88
+#define MZ2_SOLDIER_BLASTER_5			89
+#define MZ2_SOLDIER_SHOTGUN_5			90
+#define MZ2_SOLDIER_MACHINEGUN_5		91
+#define MZ2_SOLDIER_BLASTER_6			92
+#define MZ2_SOLDIER_SHOTGUN_6			93
+#define MZ2_SOLDIER_MACHINEGUN_6		94
+#define MZ2_SOLDIER_BLASTER_7			95
+#define MZ2_SOLDIER_SHOTGUN_7			96
+#define MZ2_SOLDIER_MACHINEGUN_7		97
+#define MZ2_SOLDIER_BLASTER_8			98
+#define MZ2_SOLDIER_SHOTGUN_8			99
+#define MZ2_SOLDIER_MACHINEGUN_8		100
+
+// --- Xian shit below ---
+#define	MZ2_MAKRON_BFG					101
+#define MZ2_MAKRON_BLASTER_1			102
+#define MZ2_MAKRON_BLASTER_2			103
+#define MZ2_MAKRON_BLASTER_3			104
+#define MZ2_MAKRON_BLASTER_4			105
+#define MZ2_MAKRON_BLASTER_5			106
+#define MZ2_MAKRON_BLASTER_6			107
+#define MZ2_MAKRON_BLASTER_7			108
+#define MZ2_MAKRON_BLASTER_8			109
+#define MZ2_MAKRON_BLASTER_9			110
+#define MZ2_MAKRON_BLASTER_10			111
+#define MZ2_MAKRON_BLASTER_11			112
+#define MZ2_MAKRON_BLASTER_12			113
+#define MZ2_MAKRON_BLASTER_13			114
+#define MZ2_MAKRON_BLASTER_14			115
+#define MZ2_MAKRON_BLASTER_15			116
+#define MZ2_MAKRON_BLASTER_16			117
+#define MZ2_MAKRON_BLASTER_17			118
+#define MZ2_MAKRON_RAILGUN_1			119
+#define	MZ2_JORG_MACHINEGUN_L1			120
+#define	MZ2_JORG_MACHINEGUN_L2			121
+#define	MZ2_JORG_MACHINEGUN_L3			122
+#define	MZ2_JORG_MACHINEGUN_L4			123
+#define	MZ2_JORG_MACHINEGUN_L5			124
+#define	MZ2_JORG_MACHINEGUN_L6			125
+#define	MZ2_JORG_MACHINEGUN_R1			126
+#define	MZ2_JORG_MACHINEGUN_R2			127
+#define	MZ2_JORG_MACHINEGUN_R3			128
+#define	MZ2_JORG_MACHINEGUN_R4			129
+#define MZ2_JORG_MACHINEGUN_R5			130
+#define	MZ2_JORG_MACHINEGUN_R6			131
+#define MZ2_JORG_BFG_1					132
+#define MZ2_BOSS2_MACHINEGUN_R1			133
+#define MZ2_BOSS2_MACHINEGUN_R2			134
+#define MZ2_BOSS2_MACHINEGUN_R3			135
+#define MZ2_BOSS2_MACHINEGUN_R4			136
+#define MZ2_BOSS2_MACHINEGUN_R5			137
+
+//ROGUE
+#define	MZ2_CARRIER_MACHINEGUN_L1		138
+#define	MZ2_CARRIER_MACHINEGUN_R1		139
+#define	MZ2_CARRIER_GRENADE				140
+#define MZ2_TURRET_MACHINEGUN			141
+#define MZ2_TURRET_ROCKET				142
+#define MZ2_TURRET_BLASTER				143
+#define MZ2_STALKER_BLASTER				144
+#define MZ2_DAEDALUS_BLASTER			145
+#define MZ2_MEDIC_BLASTER_2				146
+#define	MZ2_CARRIER_RAILGUN				147
+#define	MZ2_WIDOW_DISRUPTOR				148
+#define	MZ2_WIDOW_BLASTER				149
+#define	MZ2_WIDOW_RAIL					150
+#define	MZ2_WIDOW_PLASMABEAM			151		// PMM - not used
+#define	MZ2_CARRIER_MACHINEGUN_L2		152
+#define	MZ2_CARRIER_MACHINEGUN_R2		153
+#define	MZ2_WIDOW_RAIL_LEFT				154
+#define	MZ2_WIDOW_RAIL_RIGHT			155
+#define	MZ2_WIDOW_BLASTER_SWEEP1		156
+#define	MZ2_WIDOW_BLASTER_SWEEP2		157
+#define	MZ2_WIDOW_BLASTER_SWEEP3		158
+#define	MZ2_WIDOW_BLASTER_SWEEP4		159
+#define	MZ2_WIDOW_BLASTER_SWEEP5		160
+#define	MZ2_WIDOW_BLASTER_SWEEP6		161
+#define	MZ2_WIDOW_BLASTER_SWEEP7		162
+#define	MZ2_WIDOW_BLASTER_SWEEP8		163
+#define	MZ2_WIDOW_BLASTER_SWEEP9		164
+#define	MZ2_WIDOW_BLASTER_100			165
+#define	MZ2_WIDOW_BLASTER_90			166
+#define	MZ2_WIDOW_BLASTER_80			167
+#define	MZ2_WIDOW_BLASTER_70			168
+#define	MZ2_WIDOW_BLASTER_60			169
+#define	MZ2_WIDOW_BLASTER_50			170
+#define	MZ2_WIDOW_BLASTER_40			171
+#define	MZ2_WIDOW_BLASTER_30			172
+#define	MZ2_WIDOW_BLASTER_20			173
+#define	MZ2_WIDOW_BLASTER_10			174
+#define	MZ2_WIDOW_BLASTER_0				175
+#define	MZ2_WIDOW_BLASTER_10L			176
+#define	MZ2_WIDOW_BLASTER_20L			177
+#define	MZ2_WIDOW_BLASTER_30L			178
+#define	MZ2_WIDOW_BLASTER_40L			179
+#define	MZ2_WIDOW_BLASTER_50L			180
+#define	MZ2_WIDOW_BLASTER_60L			181
+#define	MZ2_WIDOW_BLASTER_70L			182
+#define	MZ2_WIDOW_RUN_1					183
+#define	MZ2_WIDOW_RUN_2					184
+#define	MZ2_WIDOW_RUN_3					185
+#define	MZ2_WIDOW_RUN_4					186
+#define	MZ2_WIDOW_RUN_5					187
+#define	MZ2_WIDOW_RUN_6					188
+#define	MZ2_WIDOW_RUN_7					189
+#define	MZ2_WIDOW_RUN_8					190
+#define	MZ2_CARRIER_ROCKET_1			191
+#define	MZ2_CARRIER_ROCKET_2			192
+#define	MZ2_CARRIER_ROCKET_3			193
+#define	MZ2_CARRIER_ROCKET_4			194
+#define	MZ2_WIDOW2_BEAMER_1				195
+#define	MZ2_WIDOW2_BEAMER_2				196
+#define	MZ2_WIDOW2_BEAMER_3				197
+#define	MZ2_WIDOW2_BEAMER_4				198
+#define	MZ2_WIDOW2_BEAMER_5				199
+#define	MZ2_WIDOW2_BEAM_SWEEP_1			200
+#define	MZ2_WIDOW2_BEAM_SWEEP_2			201
+#define	MZ2_WIDOW2_BEAM_SWEEP_3			202
+#define	MZ2_WIDOW2_BEAM_SWEEP_4			203
+#define	MZ2_WIDOW2_BEAM_SWEEP_5			204
+#define	MZ2_WIDOW2_BEAM_SWEEP_6			205
+#define	MZ2_WIDOW2_BEAM_SWEEP_7			206
+#define	MZ2_WIDOW2_BEAM_SWEEP_8			207
+#define	MZ2_WIDOW2_BEAM_SWEEP_9			208
+#define	MZ2_WIDOW2_BEAM_SWEEP_10		209
+#define	MZ2_WIDOW2_BEAM_SWEEP_11		210
+
+// ROGUE
+
+extern	vec3_t monster_flash_offset [];
+
+
+// temp entity events
+//
+// Temp entity events are for things that happen
+// at a location seperate from any existing entity.
+// Temporary entity messages are explicitly constructed
+// and broadcast.
+typedef enum
+{
+	TE_GUNSHOT,
+	TE_BLOOD,
+	TE_BLASTER,
+	TE_RAILTRAIL,
+	TE_SHOTGUN,
+	TE_EXPLOSION1,
+	TE_EXPLOSION2,
+	TE_ROCKET_EXPLOSION,
+	TE_GRENADE_EXPLOSION,
+	TE_SPARKS,
+	TE_SPLASH,
+	TE_BUBBLETRAIL,
+	TE_SCREEN_SPARKS,
+	TE_SHIELD_SPARKS,
+	TE_BULLET_SPARKS,
+	TE_LASER_SPARKS,
+	TE_PARASITE_ATTACK,
+	TE_ROCKET_EXPLOSION_WATER,
+	TE_GRENADE_EXPLOSION_WATER,
+	TE_MEDIC_CABLE_ATTACK,
+	TE_BFG_EXPLOSION,
+	TE_BFG_BIGEXPLOSION,
+	TE_BOSSTPORT,			// used as '22' in a map, so DON'T RENUMBER!!!
+	TE_BFG_LASER,
+	TE_GRAPPLE_CABLE,
+	TE_WELDING_SPARKS,
+	TE_GREENBLOOD,
+	TE_BLUEHYPERBLASTER,
+	TE_PLASMA_EXPLOSION,
+	TE_TUNNEL_SPARKS,
+//ROGUE
+	TE_BLASTER2,
+	TE_RAILTRAIL2,
+	TE_FLAME,
+	TE_LIGHTNING,
+	TE_DEBUGTRAIL,
+	TE_PLAIN_EXPLOSION,
+	TE_FLASHLIGHT,
+	TE_FORCEWALL,
+	TE_HEATBEAM,
+	TE_MONSTER_HEATBEAM,
+	TE_STEAM,
+	TE_BUBBLETRAIL2,
+	TE_MOREBLOOD,
+	TE_HEATBEAM_SPARKS,
+	TE_HEATBEAM_STEAM,
+	TE_CHAINFIST_SMOKE,
+	TE_ELECTRIC_SPARKS,
+	TE_TRACKER_EXPLOSION,
+	TE_TELEPORT_EFFECT,
+	TE_DBALL_GOAL,
+	TE_WIDOWBEAMOUT,
+	TE_NUKEBLAST,
+	TE_WIDOWSPLASH,
+	TE_EXPLOSION1_BIG,
+	TE_EXPLOSION1_NP,
+	TE_FLECHETTE
+//ROGUE
+} temp_event_t;
+
+#define SPLASH_UNKNOWN		0
+#define SPLASH_SPARKS		1
+#define SPLASH_BLUE_WATER	2
+#define SPLASH_BROWN_WATER	3
+#define SPLASH_SLIME		4
+#define	SPLASH_LAVA			5
+#define SPLASH_BLOOD		6
+
+
+// sound channels
+// channel 0 never willingly overrides
+// other channels (1-7) allways override a playing sound on that channel
+#define	CHAN_AUTO               0
+#define	CHAN_WEAPON             1
+#define	CHAN_VOICE              2
+#define	CHAN_ITEM               3
+#define	CHAN_BODY               4
+// modifier flags
+#define	CHAN_NO_PHS_ADD			8	// send to all clients, not just ones in PHS (ATTN 0 will also do this)
+#define	CHAN_RELIABLE			16	// send by reliable message, not datagram
+
+
+// sound attenuation values
+#define	ATTN_NONE               0	// full volume the entire level
+#define	ATTN_NORM               1
+#define	ATTN_IDLE               2
+#define	ATTN_STATIC             3	// diminish very rapidly with distance
+
+
+// player_state->stats[] indexes
+#define STAT_HEALTH_ICON		0
+#define	STAT_HEALTH				1
+#define	STAT_AMMO_ICON			2
+#define	STAT_AMMO				3
+#define	STAT_ARMOR_ICON			4
+#define	STAT_ARMOR				5
+#define	STAT_SELECTED_ICON		6
+#define	STAT_PICKUP_ICON		7
+#define	STAT_PICKUP_STRING		8
+#define	STAT_TIMER_ICON			9
+#define	STAT_TIMER				10
+#define	STAT_HELPICON			11
+#define	STAT_SELECTED_ITEM		12
+#define	STAT_LAYOUTS			13
+#define	STAT_FRAGS				14
+#define	STAT_FLASHES			15		// cleared each frame, 1 = health, 2 = armor
+#define STAT_CHASE				16
+#define STAT_SPECTATOR			17
+
+#define	MAX_STATS				32
+
+
+// dmflags->value flags
+#define	DF_NO_HEALTH		0x00000001	// 1
+#define	DF_NO_ITEMS			0x00000002	// 2
+#define	DF_WEAPONS_STAY		0x00000004	// 4
+#define	DF_NO_FALLING		0x00000008	// 8
+#define	DF_INSTANT_ITEMS	0x00000010	// 16
+#define	DF_SAME_LEVEL		0x00000020	// 32
+#define DF_SKINTEAMS		0x00000040	// 64
+#define DF_MODELTEAMS		0x00000080	// 128
+#define DF_NO_FRIENDLY_FIRE	0x00000100	// 256
+#define	DF_SPAWN_FARTHEST	0x00000200	// 512
+#define DF_FORCE_RESPAWN	0x00000400	// 1024
+#define DF_NO_ARMOR			0x00000800	// 2048
+#define DF_ALLOW_EXIT		0x00001000	// 4096
+#define DF_INFINITE_AMMO	0x00002000	// 8192
+#define DF_QUAD_DROP		0x00004000	// 16384
+#define DF_FIXED_FOV		0x00008000	// 32768
+
+// RAFAEL
+#define	DF_QUADFIRE_DROP	0x00010000	// 65536
+
+//ROGUE
+#define DF_NO_MINES			0x00020000
+#define DF_NO_STACK_DOUBLE	0x00040000
+#define DF_NO_NUKES			0x00080000
+#define DF_NO_SPHERES		0x00100000
+//ROGUE
+
+/*
+ROGUE - VERSIONS
+1234	08/13/1998		Activision
+1235	08/14/1998		Id Software
+1236	08/15/1998		Steve Tietze
+1237	08/15/1998		Phil Dobranski
+1238	08/15/1998		John Sheley
+1239	08/17/1998		Barrett Alexander
+1230	08/17/1998		Brandon Fish
+1245	08/17/1998		Don MacAskill
+1246	08/17/1998		David "Zoid" Kirsch
+1247	08/17/1998		Manu Smith
+1248	08/17/1998		Geoff Scully
+1249	08/17/1998		Andy Van Fossen
+1240	08/20/1998		Activision Build 2
+1256	08/20/1998		Ranger Clan
+1257	08/20/1998		Ensemble Studios
+1258	08/21/1998		Robert Duffy
+1259	08/21/1998		Stephen Seachord
+1250	08/21/1998		Stephen Heaslip
+1267	08/21/1998		Samir Sandesara
+1268	08/21/1998		Oliver Wyman
+1269	08/21/1998		Steven Marchegiano
+1260	08/21/1998		Build #2 for Nihilistic
+1278	08/21/1998		Build #2 for Ensemble
+
+9999	08/20/1998		Internal Use
+*/
+#define ROGUE_VERSION_ID		1278
+
+#define ROGUE_VERSION_STRING	"08/21/1998 Beta 2 for Ensemble"
+
+// ROGUE
+/*
+==========================================================
+
+  ELEMENTS COMMUNICATED ACROSS THE NET
+
+==========================================================
+*/
+
+#define	ANGLE2SHORT(x)	((int)((x)*65536/360) & 65535)
+#define	SHORT2ANGLE(x)	((x)*(360.0/65536))
+
+
+//
+// config strings are a general means of communication from
+// the server to all connected clients.
+// Each config string can be at most MAX_QPATH characters.
+//
+#define	CS_NAME				0
+#define	CS_CDTRACK			1
+#define	CS_SKY				2
+#define	CS_SKYAXIS			3		// %f %f %f format
+#define	CS_SKYROTATE		4
+#define	CS_STATUSBAR		5		// display program string
+
+#define CS_AIRACCEL			29		// air acceleration control
+#define	CS_MAXCLIENTS		30
+#define	CS_MAPCHECKSUM		31		// for catching cheater maps
+
+#define	CS_MODELS			32
+#define	CS_SOUNDS			(CS_MODELS+MAX_MODELS)
+#define	CS_IMAGES			(CS_SOUNDS+MAX_SOUNDS)
+#define	CS_LIGHTS			(CS_IMAGES+MAX_IMAGES)
+#define	CS_ITEMS			(CS_LIGHTS+MAX_LIGHTSTYLES)
+#define	CS_PLAYERSKINS		(CS_ITEMS+MAX_ITEMS)
+#define CS_GENERAL			(CS_PLAYERSKINS+MAX_CLIENTS)
+#define	MAX_CONFIGSTRINGS	(CS_GENERAL+MAX_GENERAL)
+
+
+//==============================================
+
+
+// entity_state_t->event values
+// ertity events are for effects that take place reletive
+// to an existing entities origin.  Very network efficient.
+// All muzzle flashes really should be converted to events...
+typedef enum
+{
+	EV_NONE,
+	EV_ITEM_RESPAWN,
+	EV_FOOTSTEP,
+	EV_FALLSHORT,
+	EV_FALL,
+	EV_FALLFAR,
+	EV_PLAYER_TELEPORT,
+	EV_OTHER_TELEPORT
+} entity_event_t;
+
+
+// entity_state_t is the information conveyed from the server
+// in an update message about entities that the client will
+// need to render in some way
+typedef struct entity_state_s
+{
+	int		number;			// edict index
+
+	vec3_t	origin;
+	vec3_t	angles;
+	vec3_t	old_origin;		// for lerping
+	int		modelindex;
+	int		modelindex2, modelindex3, modelindex4;	// weapons, CTF flags, etc
+	int		frame;
+	int		skinnum;
+	unsigned int		effects;		// PGM - we're filling it, so it needs to be unsigned
+	int		renderfx;
+	int		solid;			// for client side prediction, 8*(bits 0-4) is x/y radius
+							// 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
+							// gi.linkentity sets this properly
+	int		sound;			// for looping sounds, to guarantee shutoff
+	int		event;			// impulse events -- muzzle flashes, footsteps, etc
+							// events only go out for a single frame, they
+							// are automatically cleared each frame
+} entity_state_t;
+
+//==============================================
+
+
+// player_state_t is the information needed in addition to pmove_state_t
+// to rendered a view.  There will only be 10 player_state_t sent each second,
+// but the number of pmove_state_t changes will be reletive to client
+// frame rates
+typedef struct
+{
+	pmove_state_t	pmove;		// for prediction
+
+	// these fields do not need to be communicated bit-precise
+
+	vec3_t		viewangles;		// for fixed views
+	vec3_t		viewoffset;		// add to pmovestate->origin
+	vec3_t		kick_angles;	// add to view direction to get render angles
+								// set by weapon kicks, pain effects, etc
+
+	vec3_t		gunangles;
+	vec3_t		gunoffset;
+	int			gunindex;
+	int			gunframe;
+
+	float		blend[4];		// rgba full screen effect
+	
+	float		fov;			// horizontal field of view
+
+	int			rdflags;		// refdef flags
+
+	short		stats[MAX_STATS];		// fast status bar updates
+} player_state_t;
+
+
+// ==================
+// PGM 
+#define VIDREF_GL		1
+#define VIDREF_SOFT		2
+#define VIDREF_OTHER	3
+
+extern int vidref_val;
+// PGM
+// ==================
--- /dev/null
+++ b/game/g_ai.c
@@ -1,0 +1,1117 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_ai.c
+
+#include "g_local.h"
+
+qboolean FindTarget (edict_t *self);
+extern cvar_t	*maxclients;
+
+qboolean ai_checkattack (edict_t *self, float dist);
+
+qboolean	enemy_vis;
+qboolean	enemy_infront;
+int			enemy_range;
+float		enemy_yaw;
+
+//============================================================================
+
+
+/*
+=================
+AI_SetSightClient
+
+Called once each frame to set level.sight_client to the
+player to be checked for in findtarget.
+
+If all clients are either dead or in notarget, sight_client
+will be null.
+
+In coop games, sight_client will cycle between the clients.
+=================
+*/
+void AI_SetSightClient (void)
+{
+	edict_t	*ent;
+	int		start, check;
+
+	if (level.sight_client == NULL)
+		start = 1;
+	else
+		start = level.sight_client - g_edicts;
+
+	check = start;
+	while (1)
+	{
+		check++;
+		if (check > game.maxclients)
+			check = 1;
+		ent = &g_edicts[check];
+		if (ent->inuse
+			&& ent->health > 0
+			&& !(ent->flags & FL_NOTARGET) )
+		{
+			level.sight_client = ent;
+			return;		// got one
+		}
+		if (check == start)
+		{
+			level.sight_client = NULL;
+			return;		// nobody to see
+		}
+	}
+}
+
+//============================================================================
+
+/*
+=============
+ai_move
+
+Move the specified distance at current facing.
+This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward
+==============
+*/
+void ai_move (edict_t *self, float dist)
+{
+	M_walkmove (self, self->s.angles[YAW], dist);
+}
+
+
+/*
+=============
+ai_stand
+
+Used for standing around and looking for players
+Distance is for slight position adjustments needed by the animations
+==============
+*/
+void ai_stand (edict_t *self, float dist)
+{
+	vec3_t	v;
+
+	if (dist)
+		M_walkmove (self, self->s.angles[YAW], dist);
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		if (self->enemy)
+		{
+			VectorSubtract (self->enemy->s.origin, self->s.origin, v);
+			self->ideal_yaw = vectoyaw(v);
+			if (self->s.angles[YAW] != self->ideal_yaw && self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
+			{
+				self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+				self->monsterinfo.run (self);
+			}
+			M_ChangeYaw (self);
+			ai_checkattack (self, 0);
+		}
+		else
+			FindTarget (self);
+		return;
+	}
+
+	if (FindTarget (self))
+		return;
+	
+	if (level.time > self->monsterinfo.pausetime)
+	{
+		self->monsterinfo.walk (self);
+		return;
+	}
+
+	if (!(self->spawnflags & 1) && (self->monsterinfo.idle) && (level.time > self->monsterinfo.idle_time))
+	{
+		if (self->monsterinfo.idle_time)
+		{
+			self->monsterinfo.idle (self);
+			self->monsterinfo.idle_time = level.time + 15 + random() * 15;
+		}
+		else
+		{
+			self->monsterinfo.idle_time = level.time + random() * 15;
+		}
+	}
+}
+
+
+/*
+=============
+ai_walk
+
+The monster is walking it's beat
+=============
+*/
+void ai_walk (edict_t *self, float dist)
+{
+	M_MoveToGoal (self, dist);
+
+	// check for noticing a player
+	if (FindTarget (self))
+		return;
+
+	if ((self->monsterinfo.search) && (level.time > self->monsterinfo.idle_time))
+	{
+		if (self->monsterinfo.idle_time)
+		{
+			self->monsterinfo.search (self);
+			self->monsterinfo.idle_time = level.time + 15 + random() * 15;
+		}
+		else
+		{
+			self->monsterinfo.idle_time = level.time + random() * 15;
+		}
+	}
+}
+
+
+/*
+=============
+ai_charge
+
+Turns towards target and advances
+Use this call with a distnace of 0 to replace ai_face
+==============
+*/
+void ai_charge (edict_t *self, float dist)
+{
+	vec3_t	v;
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, v);
+	self->ideal_yaw = vectoyaw(v);
+	M_ChangeYaw (self);
+
+	if (dist)
+		M_walkmove (self, self->s.angles[YAW], dist);
+}
+
+
+/*
+=============
+ai_turn
+
+don't move, but turn towards ideal_yaw
+Distance is for slight position adjustments needed by the animations
+=============
+*/
+void ai_turn (edict_t *self, float dist)
+{
+	if (dist)
+		M_walkmove (self, self->s.angles[YAW], dist);
+
+	if (FindTarget (self))
+		return;
+	
+	M_ChangeYaw (self);
+}
+
+
+/*
+
+.enemy
+Will be world if not currently angry at anyone.
+
+.movetarget
+The next path spot to walk toward.  If .enemy, ignore .movetarget.
+When an enemy is killed, the monster will try to return to it's path.
+
+.hunt_time
+Set to time + something when the player is in sight, but movement straight for
+him is blocked.  This causes the monster to use wall following code for
+movement direction instead of sighting on the player.
+
+.ideal_yaw
+A yaw angle of the intended direction, which will be turned towards at up
+to 45 deg / state.  If the enemy is in view and hunt_time is not active,
+this will be the exact line towards the enemy.
+
+.pausetime
+A monster will leave it's stand state and head towards it's .movetarget when
+time > .pausetime.
+
+walkmove(angle, speed) primitive is all or nothing
+*/
+
+/*
+=============
+range
+
+returns the range catagorization of an entity reletive to self
+0	melee range, will become hostile even if back is turned
+1	visibility and infront, or visibility and show hostile
+2	infront and show hostile
+3	only triggered by damage
+=============
+*/
+int range (edict_t *self, edict_t *other)
+{
+	vec3_t	v;
+	float	len;
+
+	VectorSubtract (self->s.origin, other->s.origin, v);
+	len = VectorLength (v);
+	if (len < MELEE_DISTANCE)
+		return RANGE_MELEE;
+	if (len < 500)
+		return RANGE_NEAR;
+	if (len < 1000)
+		return RANGE_MID;
+	return RANGE_FAR;
+}
+
+/*
+=============
+visible
+
+returns 1 if the entity is visible to self, even if not infront ()
+=============
+*/
+qboolean visible (edict_t *self, edict_t *other)
+{
+	vec3_t	spot1;
+	vec3_t	spot2;
+	trace_t	trace;
+
+	VectorCopy (self->s.origin, spot1);
+	spot1[2] += self->viewheight;
+	VectorCopy (other->s.origin, spot2);
+	spot2[2] += other->viewheight;
+	trace = gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
+	
+	if (trace.fraction == 1.0)
+		return true;
+	return false;
+}
+
+
+/*
+=============
+infront
+
+returns 1 if the entity is in front (in sight) of self
+=============
+*/
+qboolean infront (edict_t *self, edict_t *other)
+{
+	vec3_t	vec;
+	float	dot;
+	vec3_t	forward;
+	
+	AngleVectors (self->s.angles, forward, NULL, NULL);
+	VectorSubtract (other->s.origin, self->s.origin, vec);
+	VectorNormalize (vec);
+	dot = DotProduct (vec, forward);
+	
+	if (dot > 0.3)
+		return true;
+	return false;
+}
+
+
+//============================================================================
+
+void HuntTarget (edict_t *self)
+{
+	vec3_t	vec;
+
+	self->goalentity = self->enemy;
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.stand (self);
+	else
+		self->monsterinfo.run (self);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	self->ideal_yaw = vectoyaw(vec);
+	// wait a while before first attack
+	if (!(self->monsterinfo.aiflags & AI_STAND_GROUND))
+		AttackFinished (self, 1);
+}
+
+void FoundTarget (edict_t *self)
+{
+	// let other monsters see this monster for a while
+	if (self->enemy->client)
+	{
+		level.sight_entity = self;
+		level.sight_entity_framenum = level.framenum;
+		level.sight_entity->light_level = 128;
+	}
+
+	self->show_hostile = level.time + 1;		// wake up other monsters
+
+	VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
+	self->monsterinfo.trail_time = level.time;
+
+	if (!self->combattarget)
+	{
+		HuntTarget (self);
+		return;
+	}
+
+	self->goalentity = self->movetarget = G_PickTarget(self->combattarget);
+	if (!self->movetarget)
+	{
+		self->goalentity = self->movetarget = self->enemy;
+		HuntTarget (self);
+		gi.dprintf("%s at %s, combattarget %s not found\n", self->classname, vtos(self->s.origin), self->combattarget);
+		return;
+	}
+
+	// clear out our combattarget, these are a one shot deal
+	self->combattarget = NULL;
+	self->monsterinfo.aiflags |= AI_COMBAT_POINT;
+
+	// clear the targetname, that point is ours!
+	self->movetarget->targetname = NULL;
+	self->monsterinfo.pausetime = 0;
+
+	// run for it
+	self->monsterinfo.run (self);
+}
+
+
+/*
+===========
+FindTarget
+
+Self is currently not attacking anything, so try to find a target
+
+Returns TRUE if an enemy was sighted
+
+When a player fires a missile, the point of impact becomes a fakeplayer so
+that monsters that see the impact will respond as if they had seen the
+player.
+
+To avoid spending too much time, only a single client (or fakeclient) is
+checked each frame.  This means multi player games will have slightly
+slower noticing monsters.
+============
+*/
+qboolean FindTarget (edict_t *self)
+{
+	edict_t		*client;
+	qboolean	heardit;
+	int			r;
+
+	if (self->monsterinfo.aiflags & AI_GOOD_GUY)
+	{
+		if (self->goalentity && self->goalentity->inuse && self->goalentity->classname)
+		{
+			if (strcmp(self->goalentity->classname, "target_actor") == 0)
+				return false;
+		}
+
+		//FIXME look for monsters?
+		return false;
+	}
+
+	// if we're going to a combat point, just proceed
+	if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
+		return false;
+
+// if the first spawnflag bit is set, the monster will only wake up on
+// really seeing the player, not another monster getting angry or hearing
+// something
+
+// revised behavior so they will wake up if they "see" a player make a noise
+// but not weapon impact/explosion noises
+
+	heardit = false;
+	if ((level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
+	{
+		client = level.sight_entity;
+		if (client->enemy == self->enemy)
+		{
+			return false;
+		}
+	}
+	else if (level.sound_entity_framenum >= (level.framenum - 1))
+	{
+		client = level.sound_entity;
+		heardit = true;
+	}
+	else if (!(self->enemy) && (level.sound2_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1) )
+	{
+		client = level.sound2_entity;
+		heardit = true;
+	}
+	else
+	{
+		client = level.sight_client;
+		if (!client)
+			return false;	// no clients to get mad at
+	}
+
+	// if the entity went away, forget it
+	if (!client->inuse)
+		return false;
+
+	if (client == self->enemy)
+		return true;	// JDC false;
+
+	if (client->client)
+	{
+		if (client->flags & FL_NOTARGET)
+			return false;
+	}
+	else if (client->svflags & SVF_MONSTER)
+	{
+		if (!client->enemy)
+			return false;
+		if (client->enemy->flags & FL_NOTARGET)
+			return false;
+	}
+	else if (heardit)
+	{
+		if (client->owner->flags & FL_NOTARGET)
+			return false;
+	}
+	else
+		return false;
+
+	if (!heardit)
+	{
+		r = range (self, client);
+
+		if (r == RANGE_FAR)
+			return false;
+
+// this is where we would check invisibility
+
+		// is client in an spot too dark to be seen?
+		if (client->light_level <= 5)
+			return false;
+
+		if (!visible (self, client))
+		{
+			return false;
+		}
+
+		if (r == RANGE_NEAR)
+		{
+			if (client->show_hostile < level.time && !infront (self, client))
+			{
+				return false;
+			}
+		}
+		else if (r == RANGE_MID)
+		{
+			if (!infront (self, client))
+			{
+				return false;
+			}
+		}
+
+		self->enemy = client;
+
+		if (strcmp(self->enemy->classname, "player_noise") != 0)
+		{
+			self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+
+			if (!self->enemy->client)
+			{
+				self->enemy = self->enemy->enemy;
+				if (!self->enemy->client)
+				{
+					self->enemy = NULL;
+					return false;
+				}
+			}
+		}
+	}
+	else	// heardit
+	{
+		vec3_t	temp;
+
+		if (self->spawnflags & 1)
+		{
+			if (!visible (self, client))
+				return false;
+		}
+		else
+		{
+			if (!gi.inPHS(self->s.origin, client->s.origin))
+				return false;
+		}
+
+		VectorSubtract (client->s.origin, self->s.origin, temp);
+
+		if (VectorLength(temp) > 1000)	// too far to hear
+		{
+			return false;
+		}
+
+		// check area portals - if they are different and not connected then we can't hear it
+		if (client->areanum != self->areanum)
+			if (!gi.AreasConnected(self->areanum, client->areanum))
+				return false;
+
+		self->ideal_yaw = vectoyaw(temp);
+		M_ChangeYaw (self);
+
+		// hunt the sound for a bit; hopefully find the real player
+		self->monsterinfo.aiflags |= AI_SOUND_TARGET;
+		self->enemy = client;
+	}
+
+//
+// got one
+//
+	FoundTarget (self);
+
+	if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) && (self->monsterinfo.sight))
+		self->monsterinfo.sight (self, self->enemy);
+
+	return true;
+}
+
+
+//=============================================================================
+
+/*
+============
+FacingIdeal
+
+============
+*/
+qboolean FacingIdeal(edict_t *self)
+{
+	float	delta;
+
+	delta = anglemod(self->s.angles[YAW] - self->ideal_yaw);
+	if (delta > 45 && delta < 315)
+		return false;
+	return true;
+}
+
+
+//=============================================================================
+
+qboolean M_CheckAttack (edict_t *self)
+{
+	vec3_t	spot1, spot2;
+	float	chance;
+	trace_t	tr;
+
+	if (self->enemy->health > 0)
+	{
+	// see if any entities are in the way of the shot
+		VectorCopy (self->s.origin, spot1);
+		spot1[2] += self->viewheight;
+		VectorCopy (self->enemy->s.origin, spot2);
+		spot2[2] += self->enemy->viewheight;
+
+		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WINDOW);
+
+		// do we have a clear shot?
+		if (tr.ent != self->enemy)
+			return false;
+	}
+	
+	// melee attack
+	if (enemy_range == RANGE_MELEE)
+	{
+		// don't always melee in easy mode
+		if (skill->value == 0 && (rand()&3) )
+			return false;
+		if (self->monsterinfo.melee)
+			self->monsterinfo.attack_state = AS_MELEE;
+		else
+			self->monsterinfo.attack_state = AS_MISSILE;
+		return true;
+	}
+	
+// missile attack
+	if (!self->monsterinfo.attack)
+		return false;
+		
+	if (level.time < self->monsterinfo.attack_finished)
+		return false;
+		
+	if (enemy_range == RANGE_FAR)
+		return false;
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MELEE)
+	{
+		chance = 0.2;
+	}
+	else if (enemy_range == RANGE_NEAR)
+	{
+		chance = 0.1;
+	}
+	else if (enemy_range == RANGE_MID)
+	{
+		chance = 0.02;
+	}
+	else
+	{
+		return false;
+	}
+
+	if (skill->value == 0)
+		chance *= 0.5;
+	else if (skill->value >= 2)
+		chance *= 2;
+
+	if (random () < chance)
+	{
+		self->monsterinfo.attack_state = AS_MISSILE;
+		self->monsterinfo.attack_finished = level.time + 2*random();
+		return true;
+	}
+
+	if (self->flags & FL_FLY)
+	{
+		if (random() < 0.3)
+			self->monsterinfo.attack_state = AS_SLIDING;
+		else
+			self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+
+	return false;
+}
+
+
+/*
+=============
+ai_run_melee
+
+Turn and close until within an angle to launch a melee attack
+=============
+*/
+void ai_run_melee(edict_t *self)
+{
+	self->ideal_yaw = enemy_yaw;
+	M_ChangeYaw (self);
+
+	if (FacingIdeal(self))
+	{
+		self->monsterinfo.melee (self);
+		self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+}
+
+
+/*
+=============
+ai_run_missile
+
+Turn in place until within an angle to launch a missile attack
+=============
+*/
+void ai_run_missile(edict_t *self)
+{
+	self->ideal_yaw = enemy_yaw;
+	M_ChangeYaw (self);
+
+	if (FacingIdeal(self))
+	{
+		self->monsterinfo.attack (self);
+		self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+};
+
+
+/*
+=============
+ai_run_slide
+
+Strafe sideways, but stay at aproximately the same range
+=============
+*/
+void ai_run_slide(edict_t *self, float distance)
+{
+	float	ofs;
+	
+	self->ideal_yaw = enemy_yaw;
+	M_ChangeYaw (self);
+
+	if (self->monsterinfo.lefty)
+		ofs = 90;
+	else
+		ofs = -90;
+	
+	if (M_walkmove (self, self->ideal_yaw + ofs, distance))
+		return;
+		
+	self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
+	M_walkmove (self, self->ideal_yaw - ofs, distance);
+}
+
+
+/*
+=============
+ai_checkattack
+
+Decides if we're going to attack or do something else
+used by ai_run and ai_stand
+=============
+*/
+qboolean ai_checkattack (edict_t *self, float dist)
+{
+	vec3_t		temp;
+	qboolean	hesDeadJim;
+
+// this causes monsters to run blindly to the combat point w/o firing
+	if (self->goalentity)
+	{
+		if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
+			return false;
+
+		if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
+		{
+			if ((level.time - self->enemy->teleport_time) > 5.0)
+			{
+				if (self->goalentity == self->enemy)
+					if (self->movetarget)
+						self->goalentity = self->movetarget;
+					else
+						self->goalentity = NULL;
+				self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+				if (self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
+					self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+			}
+			else
+			{
+				self->show_hostile = level.time + 1;
+				return false;
+			}
+		}
+	}
+
+	enemy_vis = false;
+
+// see if the enemy is dead
+	hesDeadJim = false;
+	if ((!self->enemy) || (!self->enemy->inuse))
+	{
+		hesDeadJim = true;
+	}
+	else if (self->monsterinfo.aiflags & AI_MEDIC)
+	{
+		if (self->enemy->health > 0)
+		{
+			hesDeadJim = true;
+			self->monsterinfo.aiflags &= ~AI_MEDIC;
+		}
+	}
+	else
+	{
+		if (self->monsterinfo.aiflags & AI_BRUTAL)
+		{
+			if (self->enemy->health <= -80)
+				hesDeadJim = true;
+		}
+		else
+		{
+			if (self->enemy->health <= 0)
+				hesDeadJim = true;
+		}
+	}
+
+	if (hesDeadJim)
+	{
+		self->enemy = NULL;
+	// FIXME: look all around for other targets
+		if (self->oldenemy && self->oldenemy->health > 0)
+		{
+			self->enemy = self->oldenemy;
+			self->oldenemy = NULL;
+			HuntTarget (self);
+		}
+		else
+		{
+			if (self->movetarget)
+			{
+				self->goalentity = self->movetarget;
+				self->monsterinfo.walk (self);
+			}
+			else
+			{
+				// we need the pausetime otherwise the stand code
+				// will just revert to walking with no target and
+				// the monsters will wonder around aimlessly trying
+				// to hunt the world entity
+				self->monsterinfo.pausetime = level.time + 100000000;
+				self->monsterinfo.stand (self);
+			}
+			return true;
+		}
+	}
+
+	self->show_hostile = level.time + 1;		// wake up other monsters
+
+// check knowledge of enemy
+	enemy_vis = visible(self, self->enemy);
+	if (enemy_vis)
+	{
+		self->monsterinfo.search_time = level.time + 5;
+		VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
+	}
+
+// look for other coop players here
+//	if (coop && self->monsterinfo.search_time < level.time)
+//	{
+//		if (FindTarget (self))
+//			return true;
+//	}
+
+	enemy_infront = infront(self, self->enemy);
+	enemy_range = range(self, self->enemy);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
+	enemy_yaw = vectoyaw(temp);
+
+
+	// JDC self->ideal_yaw = enemy_yaw;
+
+	if (self->monsterinfo.attack_state == AS_MISSILE)
+	{
+		ai_run_missile (self);
+		return true;
+	}
+	if (self->monsterinfo.attack_state == AS_MELEE)
+	{
+		ai_run_melee (self);
+		return true;
+	}
+
+	// if enemy is not currently visible, we will never attack
+	if (!enemy_vis)
+		return false;
+
+	return self->monsterinfo.checkattack (self);
+}
+
+
+/*
+=============
+ai_run
+
+The monster has an enemy it is trying to kill
+=============
+*/
+void ai_run (edict_t *self, float dist)
+{
+	vec3_t		v;
+	edict_t		*tempgoal;
+	edict_t		*save;
+	qboolean	new;
+	edict_t		*marker;
+	float		d1, d2;
+	trace_t		tr;
+	vec3_t		v_forward, v_right;
+	float		left, center, right;
+	vec3_t		left_target, right_target;
+
+	// if we're going to a combat point, just proceed
+	if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
+	{
+		M_MoveToGoal (self, dist);
+		return;
+	}
+
+	if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
+	{
+		VectorSubtract (self->s.origin, self->enemy->s.origin, v);
+		if (VectorLength(v) < 64)
+		{
+			self->monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+			self->monsterinfo.stand (self);
+			return;
+		}
+
+		M_MoveToGoal (self, dist);
+
+		if (!FindTarget (self))
+			return;
+	}
+
+	if (ai_checkattack (self, dist))
+		return;
+
+	if (self->monsterinfo.attack_state == AS_SLIDING)
+	{
+		ai_run_slide (self, dist);
+		return;
+	}
+
+	if (enemy_vis)
+	{
+//		if (self.aiflags & AI_LOST_SIGHT)
+//			dprint("regained sight\n");
+		M_MoveToGoal (self, dist);
+		self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+		VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
+		self->monsterinfo.trail_time = level.time;
+		return;
+	}
+
+	// coop will change to another enemy if visible
+	if (coop->value)
+	{	// FIXME: insane guys get mad with this, which causes crashes!
+		if (FindTarget (self))
+			return;
+	}
+
+	if ((self->monsterinfo.search_time) && (level.time > (self->monsterinfo.search_time + 20)))
+	{
+		M_MoveToGoal (self, dist);
+		self->monsterinfo.search_time = 0;
+//		dprint("search timeout\n");
+		return;
+	}
+
+	save = self->goalentity;
+	tempgoal = G_Spawn();
+	self->goalentity = tempgoal;
+
+	new = false;
+
+	if (!(self->monsterinfo.aiflags & AI_LOST_SIGHT))
+	{
+		// just lost sight of the player, decide where to go first
+//		dprint("lost sight of player, last seen at "); dprint(vtos(self.last_sighting)); dprint("\n");
+		self->monsterinfo.aiflags |= (AI_LOST_SIGHT | AI_PURSUIT_LAST_SEEN);
+		self->monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP);
+		new = true;
+	}
+
+	if (self->monsterinfo.aiflags & AI_PURSUE_NEXT)
+	{
+		self->monsterinfo.aiflags &= ~AI_PURSUE_NEXT;
+//		dprint("reached current goal: "); dprint(vtos(self.origin)); dprint(" "); dprint(vtos(self.last_sighting)); dprint(" "); dprint(ftos(vlen(self.origin - self.last_sighting))); dprint("\n");
+
+		// give ourself more time since we got this far
+		self->monsterinfo.search_time = level.time + 5;
+
+		if (self->monsterinfo.aiflags & AI_PURSUE_TEMP)
+		{
+//			dprint("was temp goal; retrying original\n");
+			self->monsterinfo.aiflags &= ~AI_PURSUE_TEMP;
+			marker = NULL;
+			VectorCopy (self->monsterinfo.saved_goal, self->monsterinfo.last_sighting);
+			new = true;
+		}
+		else if (self->monsterinfo.aiflags & AI_PURSUIT_LAST_SEEN)
+		{
+			self->monsterinfo.aiflags &= ~AI_PURSUIT_LAST_SEEN;
+			marker = PlayerTrail_PickFirst (self);
+		}
+		else
+		{
+			marker = PlayerTrail_PickNext (self);
+		}
+
+		if (marker)
+		{
+			VectorCopy (marker->s.origin, self->monsterinfo.last_sighting);
+			self->monsterinfo.trail_time = marker->timestamp;
+			self->s.angles[YAW] = self->ideal_yaw = marker->s.angles[YAW];
+//			dprint("heading is "); dprint(ftos(self.ideal_yaw)); dprint("\n");
+
+//			debug_drawline(self.origin, self.last_sighting, 52);
+			new = true;
+		}
+	}
+
+	VectorSubtract (self->s.origin, self->monsterinfo.last_sighting, v);
+	d1 = VectorLength(v);
+	if (d1 <= dist)
+	{
+		self->monsterinfo.aiflags |= AI_PURSUE_NEXT;
+		dist = d1;
+	}
+
+	VectorCopy (self->monsterinfo.last_sighting, self->goalentity->s.origin);
+
+	if (new)
+	{
+//		gi.dprintf("checking for course correction\n");
+
+		tr = gi.trace(self->s.origin, self->mins, self->maxs, self->monsterinfo.last_sighting, self, MASK_PLAYERSOLID);
+		if (tr.fraction < 1)
+		{
+			VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+			d1 = VectorLength(v);
+			center = tr.fraction;
+			d2 = d1 * ((center+1)/2);
+			self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
+			AngleVectors(self->s.angles, v_forward, v_right, NULL);
+
+			VectorSet(v, d2, -16, 0);
+			G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
+			tr = gi.trace(self->s.origin, self->mins, self->maxs, left_target, self, MASK_PLAYERSOLID);
+			left = tr.fraction;
+
+			VectorSet(v, d2, 16, 0);
+			G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
+			tr = gi.trace(self->s.origin, self->mins, self->maxs, right_target, self, MASK_PLAYERSOLID);
+			right = tr.fraction;
+
+			center = (d1*center)/d2;
+			if (left >= center && left > right)
+			{
+				if (left < 1)
+				{
+					VectorSet(v, d2 * left * 0.5, -16, 0);
+					G_ProjectSource (self->s.origin, v, v_forward, v_right, left_target);
+//					gi.dprintf("incomplete path, go part way and adjust again\n");
+				}
+				VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal);
+				self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
+				VectorCopy (left_target, self->goalentity->s.origin);
+				VectorCopy (left_target, self->monsterinfo.last_sighting);
+				VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+				self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
+//				gi.dprintf("adjusted left\n");
+//				debug_drawline(self.origin, self.last_sighting, 152);
+			}
+			else if (right >= center && right > left)
+			{
+				if (right < 1)
+				{
+					VectorSet(v, d2 * right * 0.5, 16, 0);
+					G_ProjectSource (self->s.origin, v, v_forward, v_right, right_target);
+//					gi.dprintf("incomplete path, go part way and adjust again\n");
+				}
+				VectorCopy (self->monsterinfo.last_sighting, self->monsterinfo.saved_goal);
+				self->monsterinfo.aiflags |= AI_PURSUE_TEMP;
+				VectorCopy (right_target, self->goalentity->s.origin);
+				VectorCopy (right_target, self->monsterinfo.last_sighting);
+				VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+				self->s.angles[YAW] = self->ideal_yaw = vectoyaw(v);
+//				gi.dprintf("adjusted right\n");
+//				debug_drawline(self.origin, self.last_sighting, 152);
+			}
+		}
+//		else gi.dprintf("course was fine\n");
+	}
+
+	M_MoveToGoal (self, dist);
+
+	G_FreeEdict(tempgoal);
+
+	if (self)
+		self->goalentity = save;
+}
--- /dev/null
+++ b/game/g_chase.c
@@ -1,0 +1,175 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+void UpdateChaseCam(edict_t *ent)
+{
+	vec3_t o, ownerv, goal;
+	edict_t *targ;
+	vec3_t forward, right;
+	trace_t trace;
+	int i;
+	vec3_t oldgoal;
+	vec3_t angles;
+
+	// is our chase target gone?
+	if (!ent->client->chase_target->inuse
+		|| ent->client->chase_target->client->resp.spectator) {
+		edict_t *old = ent->client->chase_target;
+		ChaseNext(ent);
+		if (ent->client->chase_target == old) {
+			ent->client->chase_target = NULL;
+			ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
+			return;
+		}
+	}
+
+	targ = ent->client->chase_target;
+
+	VectorCopy(targ->s.origin, ownerv);
+	VectorCopy(ent->s.origin, oldgoal);
+
+	ownerv[2] += targ->viewheight;
+
+	VectorCopy(targ->client->v_angle, angles);
+	if (angles[PITCH] > 56)
+		angles[PITCH] = 56;
+	AngleVectors (angles, forward, right, NULL);
+	VectorNormalize(forward);
+	VectorMA(ownerv, -30, forward, o);
+
+	if (o[2] < targ->s.origin[2] + 20)
+		o[2] = targ->s.origin[2] + 20;
+
+	// jump animation lifts
+	if (!targ->groundentity)
+		o[2] += 16;
+
+	trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+
+	VectorCopy(trace.endpos, goal);
+
+	VectorMA(goal, 2, forward, goal);
+
+	// pad for floors and ceilings
+	VectorCopy(goal, o);
+	o[2] += 6;
+	trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+	if (trace.fraction < 1) {
+		VectorCopy(trace.endpos, goal);
+		goal[2] -= 6;
+	}
+
+	VectorCopy(goal, o);
+	o[2] -= 6;
+	trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+	if (trace.fraction < 1) {
+		VectorCopy(trace.endpos, goal);
+		goal[2] += 6;
+	}
+
+	if (targ->deadflag)
+		ent->client->ps.pmove.pm_type = PM_DEAD;
+	else
+		ent->client->ps.pmove.pm_type = PM_FREEZE;
+
+	VectorCopy(goal, ent->s.origin);
+	for (i=0 ; i<3 ; i++)
+		ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
+
+	if (targ->deadflag) {
+		ent->client->ps.viewangles[ROLL] = 40;
+		ent->client->ps.viewangles[PITCH] = -15;
+		ent->client->ps.viewangles[YAW] = targ->client->killer_yaw;
+	} else {
+		VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
+		VectorCopy(targ->client->v_angle, ent->client->v_angle);
+	}
+
+	ent->viewheight = 0;
+	ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
+	gi.linkentity(ent);
+}
+
+void ChaseNext(edict_t *ent)
+{
+	int i;
+	edict_t *e;
+
+	if (!ent->client->chase_target)
+		return;
+
+	i = ent->client->chase_target - g_edicts;
+	do {
+		i++;
+		if (i > maxclients->value)
+			i = 1;
+		e = g_edicts + i;
+		if (!e->inuse)
+			continue;
+		if (!e->client->resp.spectator)
+			break;
+	} while (e != ent->client->chase_target);
+
+	ent->client->chase_target = e;
+	ent->client->update_chase = true;
+}
+
+void ChasePrev(edict_t *ent)
+{
+	int i;
+	edict_t *e;
+
+	if (!ent->client->chase_target)
+		return;
+
+	i = ent->client->chase_target - g_edicts;
+	do {
+		i--;
+		if (i < 1)
+			i = maxclients->value;
+		e = g_edicts + i;
+		if (!e->inuse)
+			continue;
+		if (!e->client->resp.spectator)
+			break;
+	} while (e != ent->client->chase_target);
+
+	ent->client->chase_target = e;
+	ent->client->update_chase = true;
+}
+
+void GetChaseTarget(edict_t *ent)
+{
+	int i;
+	edict_t *other;
+
+	for (i = 1; i <= maxclients->value; i++) {
+		other = g_edicts + i;
+		if (other->inuse && !other->client->resp.spectator) {
+			ent->client->chase_target = other;
+			ent->client->update_chase = true;
+			UpdateChaseCam(ent);
+			return;
+		}
+	}
+	gi.centerprintf(ent, "No other players to chase.");
+}
+
--- /dev/null
+++ b/game/g_cmds.c
@@ -1,0 +1,992 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+
+char *ClientTeam (edict_t *ent)
+{
+	char		*p;
+	static char	value[512];
+
+	value[0] = 0;
+
+	if (!ent->client)
+		return value;
+
+	strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
+	p = strchr(value, '/');
+	if (!p)
+		return value;
+
+	if ((int)(dmflags->value) & DF_MODELTEAMS)
+	{
+		*p = 0;
+		return value;
+	}
+
+	// if ((int)(dmflags->value) & DF_SKINTEAMS)
+	return ++p;
+}
+
+qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
+{
+	char	ent1Team [512];
+	char	ent2Team [512];
+
+	if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
+		return false;
+
+	strcpy (ent1Team, ClientTeam (ent1));
+	strcpy (ent2Team, ClientTeam (ent2));
+
+	if (strcmp(ent1Team, ent2Team) == 0)
+		return true;
+	return false;
+}
+
+
+void SelectNextItem (edict_t *ent, int itflags)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+
+	cl = ent->client;
+
+	if (cl->chase_target) {
+		ChaseNext(ent);
+		return;
+	}
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (cl->pers.selected_item + i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (!(it->flags & itflags))
+			continue;
+
+		cl->pers.selected_item = index;
+		return;
+	}
+
+	cl->pers.selected_item = -1;
+}
+
+void SelectPrevItem (edict_t *ent, int itflags)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+
+	cl = ent->client;
+
+	if (cl->chase_target) {
+		ChasePrev(ent);
+		return;
+	}
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (cl->pers.selected_item + MAX_ITEMS - i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (!(it->flags & itflags))
+			continue;
+
+		cl->pers.selected_item = index;
+		return;
+	}
+
+	cl->pers.selected_item = -1;
+}
+
+void ValidateSelectedItem (edict_t *ent)
+{
+	gclient_t	*cl;
+
+	cl = ent->client;
+
+	if (cl->pers.inventory[cl->pers.selected_item])
+		return;		// valid
+
+	SelectNextItem (ent, -1);
+}
+
+
+//=================================================================================
+
+/*
+==================
+Cmd_Give_f
+
+Give items to a client
+==================
+*/
+void Cmd_Give_f (edict_t *ent)
+{
+	char		*name;
+	gitem_t		*it;
+	int			index;
+	int			i;
+	qboolean	give_all;
+	edict_t		*it_ent;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	name = gi.args();
+
+	if (Q_stricmp(name, "all") == 0)
+		give_all = true;
+	else
+		give_all = false;
+
+	if (give_all || Q_stricmp(gi.argv(1), "health") == 0)
+	{
+		if (gi.argc() == 3)
+			ent->health = atoi(gi.argv(2));
+		else
+			ent->health = ent->max_health;
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "weapons") == 0)
+	{
+		for (i=0 ; i<game.num_items ; i++)
+		{
+			it = itemlist + i;
+			if (!it->pickup)
+				continue;
+			if (!(it->flags & IT_WEAPON))
+				continue;
+			ent->client->pers.inventory[i] += 1;
+		}
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "ammo") == 0)
+	{
+		for (i=0 ; i<game.num_items ; i++)
+		{
+			it = itemlist + i;
+			if (!it->pickup)
+				continue;
+			if (!(it->flags & IT_AMMO))
+				continue;
+			Add_Ammo (ent, it, 1000);
+		}
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "armor") == 0)
+	{
+		gitem_armor_t	*info;
+
+		it = FindItem("Jacket Armor");
+		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
+
+		it = FindItem("Combat Armor");
+		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
+
+		it = FindItem("Body Armor");
+		info = (gitem_armor_t *)it->info;
+		ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;
+
+		if (!give_all)
+			return;
+	}
+
+	if (give_all || Q_stricmp(name, "Power Shield") == 0)
+	{
+		it = FindItem("Power Shield");
+		it_ent = G_Spawn();
+		it_ent->classname = it->classname;
+		SpawnItem (it_ent, it);
+		Touch_Item (it_ent, ent, NULL, NULL);
+		if (it_ent->inuse)
+			G_FreeEdict(it_ent);
+
+		if (!give_all)
+			return;
+	}
+
+	if (give_all)
+	{
+		for (i=0 ; i<game.num_items ; i++)
+		{
+			it = itemlist + i;
+			if (!it->pickup)
+				continue;
+			if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO))
+				continue;
+			ent->client->pers.inventory[i] = 1;
+		}
+		return;
+	}
+
+	it = FindItem (name);
+	if (!it)
+	{
+		name = gi.argv(1);
+		it = FindItem (name);
+		if (!it)
+		{
+			gi.cprintf (ent, PRINT_HIGH, "unknown item\n");
+			return;
+		}
+	}
+
+	if (!it->pickup)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "non-pickup item\n");
+		return;
+	}
+
+	index = ITEM_INDEX(it);
+
+	if (it->flags & IT_AMMO)
+	{
+		if (gi.argc() == 3)
+			ent->client->pers.inventory[index] = atoi(gi.argv(2));
+		else
+			ent->client->pers.inventory[index] += it->quantity;
+	}
+	else
+	{
+		it_ent = G_Spawn();
+		it_ent->classname = it->classname;
+		SpawnItem (it_ent, it);
+		Touch_Item (it_ent, ent, NULL, NULL);
+		if (it_ent->inuse)
+			G_FreeEdict(it_ent);
+	}
+}
+
+
+/*
+==================
+Cmd_God_f
+
+Sets client to godmode
+
+argv(0) god
+==================
+*/
+void Cmd_God_f (edict_t *ent)
+{
+	char	*msg;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	ent->flags ^= FL_GODMODE;
+	if (!(ent->flags & FL_GODMODE) )
+		msg = "godmode OFF\n";
+	else
+		msg = "godmode ON\n";
+
+	gi.cprintf (ent, PRINT_HIGH, msg);
+}
+
+
+/*
+==================
+Cmd_Notarget_f
+
+Sets client to notarget
+
+argv(0) notarget
+==================
+*/
+void Cmd_Notarget_f (edict_t *ent)
+{
+	char	*msg;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	ent->flags ^= FL_NOTARGET;
+	if (!(ent->flags & FL_NOTARGET) )
+		msg = "notarget OFF\n";
+	else
+		msg = "notarget ON\n";
+
+	gi.cprintf (ent, PRINT_HIGH, msg);
+}
+
+
+/*
+==================
+Cmd_Noclip_f
+
+argv(0) noclip
+==================
+*/
+void Cmd_Noclip_f (edict_t *ent)
+{
+	char	*msg;
+
+	if (deathmatch->value && !sv_cheats->value)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+		return;
+	}
+
+	if (ent->movetype == MOVETYPE_NOCLIP)
+	{
+		ent->movetype = MOVETYPE_WALK;
+		msg = "noclip OFF\n";
+	}
+	else
+	{
+		ent->movetype = MOVETYPE_NOCLIP;
+		msg = "noclip ON\n";
+	}
+
+	gi.cprintf (ent, PRINT_HIGH, msg);
+}
+
+
+/*
+==================
+Cmd_Use_f
+
+Use an inventory item
+==================
+*/
+void Cmd_Use_f (edict_t *ent)
+{
+	int			index;
+	gitem_t		*it;
+	char		*s;
+
+	s = gi.args();
+	it = FindItem (s);
+	if (!it)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
+		return;
+	}
+	if (!it->use)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
+		return;
+	}
+	index = ITEM_INDEX(it);
+	if (!ent->client->pers.inventory[index])
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
+		return;
+	}
+
+	it->use (ent, it);
+}
+
+
+/*
+==================
+Cmd_Drop_f
+
+Drop an inventory item
+==================
+*/
+void Cmd_Drop_f (edict_t *ent)
+{
+	int			index;
+	gitem_t		*it;
+	char		*s;
+
+	s = gi.args();
+	it = FindItem (s);
+	if (!it)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
+		return;
+	}
+	if (!it->drop)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
+		return;
+	}
+	index = ITEM_INDEX(it);
+	if (!ent->client->pers.inventory[index])
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
+		return;
+	}
+
+	it->drop (ent, it);
+}
+
+
+/*
+=================
+Cmd_Inven_f
+=================
+*/
+void Cmd_Inven_f (edict_t *ent)
+{
+	int			i;
+	gclient_t	*cl;
+
+	cl = ent->client;
+
+	cl->showscores = false;
+	cl->showhelp = false;
+
+	if (cl->showinventory)
+	{
+		cl->showinventory = false;
+		return;
+	}
+
+	cl->showinventory = true;
+
+	gi.WriteByte (svc_inventory);
+	for (i=0 ; i<MAX_ITEMS ; i++)
+	{
+		gi.WriteShort (cl->pers.inventory[i]);
+	}
+	gi.unicast (ent, true);
+}
+
+/*
+=================
+Cmd_InvUse_f
+=================
+*/
+void Cmd_InvUse_f (edict_t *ent)
+{
+	gitem_t		*it;
+
+	ValidateSelectedItem (ent);
+
+	if (ent->client->pers.selected_item == -1)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "No item to use.\n");
+		return;
+	}
+
+	it = &itemlist[ent->client->pers.selected_item];
+	if (!it->use)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
+		return;
+	}
+	it->use (ent, it);
+}
+
+/*
+=================
+Cmd_WeapPrev_f
+=================
+*/
+void Cmd_WeapPrev_f (edict_t *ent)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+	int			selected_weapon;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon)
+		return;
+
+	selected_weapon = ITEM_INDEX(cl->pers.weapon);
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (selected_weapon + i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (! (it->flags & IT_WEAPON) )
+			continue;
+		it->use (ent, it);
+		if (cl->pers.weapon == it)
+			return;	// successful
+	}
+}
+
+/*
+=================
+Cmd_WeapNext_f
+=================
+*/
+void Cmd_WeapNext_f (edict_t *ent)
+{
+	gclient_t	*cl;
+	int			i, index;
+	gitem_t		*it;
+	int			selected_weapon;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon)
+		return;
+
+	selected_weapon = ITEM_INDEX(cl->pers.weapon);
+
+	// scan  for the next valid one
+	for (i=1 ; i<=MAX_ITEMS ; i++)
+	{
+		index = (selected_weapon + MAX_ITEMS - i)%MAX_ITEMS;
+		if (!cl->pers.inventory[index])
+			continue;
+		it = &itemlist[index];
+		if (!it->use)
+			continue;
+		if (! (it->flags & IT_WEAPON) )
+			continue;
+		it->use (ent, it);
+		if (cl->pers.weapon == it)
+			return;	// successful
+	}
+}
+
+/*
+=================
+Cmd_WeapLast_f
+=================
+*/
+void Cmd_WeapLast_f (edict_t *ent)
+{
+	gclient_t	*cl;
+	int			index;
+	gitem_t		*it;
+
+	cl = ent->client;
+
+	if (!cl->pers.weapon || !cl->pers.lastweapon)
+		return;
+
+	index = ITEM_INDEX(cl->pers.lastweapon);
+	if (!cl->pers.inventory[index])
+		return;
+	it = &itemlist[index];
+	if (!it->use)
+		return;
+	if (! (it->flags & IT_WEAPON) )
+		return;
+	it->use (ent, it);
+}
+
+/*
+=================
+Cmd_InvDrop_f
+=================
+*/
+void Cmd_InvDrop_f (edict_t *ent)
+{
+	gitem_t		*it;
+
+	ValidateSelectedItem (ent);
+
+	if (ent->client->pers.selected_item == -1)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "No item to drop.\n");
+		return;
+	}
+
+	it = &itemlist[ent->client->pers.selected_item];
+	if (!it->drop)
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
+		return;
+	}
+	it->drop (ent, it);
+}
+
+/*
+=================
+Cmd_Kill_f
+=================
+*/
+void Cmd_Kill_f (edict_t *ent)
+{
+	if((level.time - ent->client->respawn_time) < 5)
+		return;
+	ent->flags &= ~FL_GODMODE;
+	ent->health = 0;
+	meansOfDeath = MOD_SUICIDE;
+	player_die (ent, ent, ent, 100000, vec3_origin);
+}
+
+/*
+=================
+Cmd_PutAway_f
+=================
+*/
+void Cmd_PutAway_f (edict_t *ent)
+{
+	ent->client->showscores = false;
+	ent->client->showhelp = false;
+	ent->client->showinventory = false;
+}
+
+
+int PlayerSort (void const *a, void const *b)
+{
+	int		anum, bnum;
+
+	anum = *(int *)a;
+	bnum = *(int *)b;
+
+	anum = game.clients[anum].ps.stats[STAT_FRAGS];
+	bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
+
+	if (anum < bnum)
+		return -1;
+	if (anum > bnum)
+		return 1;
+	return 0;
+}
+
+/*
+=================
+Cmd_Players_f
+=================
+*/
+void Cmd_Players_f (edict_t *ent)
+{
+	int		i;
+	int		count;
+	char	small[64];
+	char	large[1280];
+	int		index[256];
+
+	count = 0;
+	for (i = 0 ; i < maxclients->value ; i++)
+		if (game.clients[i].pers.connected)
+		{
+			index[count] = i;
+			count++;
+		}
+
+	// sort by frags
+	qsort (index, count, sizeof(index[0]), PlayerSort);
+
+	// print information
+	large[0] = 0;
+
+	for (i = 0 ; i < count ; i++)
+	{
+		Com_sprintf (small, sizeof(small), "%3i %s\n",
+			game.clients[index[i]].ps.stats[STAT_FRAGS],
+			game.clients[index[i]].pers.netname);
+		if (strlen (small) + strlen(large) > sizeof(large) - 100 )
+		{	// can't print all of them in one packet
+			strcat (large, "...\n");
+			break;
+		}
+		strcat (large, small);
+	}
+
+	gi.cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count);
+}
+
+/*
+=================
+Cmd_Wave_f
+=================
+*/
+void Cmd_Wave_f (edict_t *ent)
+{
+	int		i;
+
+	i = atoi (gi.argv(1));
+
+	// can't wave when ducked
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+		return;
+
+	if (ent->client->anim_priority > ANIM_WAVE)
+		return;
+
+	ent->client->anim_priority = ANIM_WAVE;
+
+	switch (i)
+	{
+	case 0:
+		gi.cprintf (ent, PRINT_HIGH, "flipoff\n");
+		ent->s.frame = FRAME_flip01-1;
+		ent->client->anim_end = FRAME_flip12;
+		break;
+	case 1:
+		gi.cprintf (ent, PRINT_HIGH, "salute\n");
+		ent->s.frame = FRAME_salute01-1;
+		ent->client->anim_end = FRAME_salute11;
+		break;
+	case 2:
+		gi.cprintf (ent, PRINT_HIGH, "taunt\n");
+		ent->s.frame = FRAME_taunt01-1;
+		ent->client->anim_end = FRAME_taunt17;
+		break;
+	case 3:
+		gi.cprintf (ent, PRINT_HIGH, "wave\n");
+		ent->s.frame = FRAME_wave01-1;
+		ent->client->anim_end = FRAME_wave11;
+		break;
+	case 4:
+	default:
+		gi.cprintf (ent, PRINT_HIGH, "point\n");
+		ent->s.frame = FRAME_point01-1;
+		ent->client->anim_end = FRAME_point12;
+		break;
+	}
+}
+
+/*
+==================
+Cmd_Say_f
+==================
+*/
+void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0)
+{
+	int		i, j;
+	edict_t	*other;
+	char	*p;
+	char	text[2048];
+	gclient_t *cl;
+
+	if (gi.argc () < 2 && !arg0)
+		return;
+
+	if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
+		team = false;
+
+	if (team)
+		Com_sprintf (text, sizeof(text), "(%s): ", ent->client->pers.netname);
+	else
+		Com_sprintf (text, sizeof(text), "%s: ", ent->client->pers.netname);
+
+	if (arg0)
+	{
+		strcat (text, gi.argv(0));
+		strcat (text, " ");
+		strcat (text, gi.args());
+	}
+	else
+	{
+		p = gi.args();
+
+		if (*p == '"')
+		{
+			p++;
+			p[strlen(p)-1] = 0;
+		}
+		strcat(text, p);
+	}
+
+	// don't let text be too long for malicious reasons
+	if (strlen(text) > 150)
+		text[150] = 0;
+
+	strcat(text, "\n");
+
+	if (flood_msgs->value) {
+		cl = ent->client;
+
+        if (level.time < cl->flood_locktill) {
+			gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
+				(int)(cl->flood_locktill - level.time));
+            return;
+        }
+        i = cl->flood_whenhead - flood_msgs->value + 1;
+        if (i < 0)
+            i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i;
+		if (cl->flood_when[i] && 
+			level.time - cl->flood_when[i] < flood_persecond->value) {
+			cl->flood_locktill = level.time + flood_waitdelay->value;
+			gi.cprintf(ent, PRINT_CHAT, "Flood protection:  You can't talk for %d seconds.\n",
+				(int)flood_waitdelay->value);
+            return;
+        }
+		cl->flood_whenhead = (cl->flood_whenhead + 1) %
+			(sizeof(cl->flood_when)/sizeof(cl->flood_when[0]));
+		cl->flood_when[cl->flood_whenhead] = level.time;
+	}
+
+	if (dedicated->value)
+		gi.cprintf(NULL, PRINT_CHAT, "%s", text);
+
+	for (j = 1; j <= game.maxclients; j++)
+	{
+		other = &g_edicts[j];
+		if (!other->inuse)
+			continue;
+		if (!other->client)
+			continue;
+		if (team)
+		{
+			if (!OnSameTeam(ent, other))
+				continue;
+		}
+		gi.cprintf(other, PRINT_CHAT, "%s", text);
+	}
+}
+
+void Cmd_PlayerList_f(edict_t *ent)
+{
+	int i;
+	char st[80];
+	char text[1400];
+	edict_t *e2;
+
+	// connect time, ping, score, name
+	*text = 0;
+	for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++) {
+		if (!e2->inuse)
+			continue;
+
+		sprintf(st, "%02d:%02d %4d %3d %s%s\n",
+			(level.framenum - e2->client->resp.enterframe) / 600,
+			((level.framenum - e2->client->resp.enterframe) % 600)/10,
+			e2->client->ping,
+			e2->client->resp.score,
+			e2->client->pers.netname,
+			e2->client->resp.spectator ? " (spectator)" : "");
+		if (strlen(text) + strlen(st) > sizeof(text) - 50) {
+			sprintf(text+strlen(text), "And more...\n");
+			gi.cprintf(ent, PRINT_HIGH, "%s", text);
+			return;
+		}
+		strcat(text, st);
+	}
+	gi.cprintf(ent, PRINT_HIGH, "%s", text);
+}
+
+
+/*
+=================
+ClientCommand
+=================
+*/
+void ClientCommand (edict_t *ent)
+{
+	char	*cmd;
+
+	if (!ent->client)
+		return;		// not fully in game yet
+
+	cmd = gi.argv(0);
+
+	if (Q_stricmp (cmd, "players") == 0)
+	{
+		Cmd_Players_f (ent);
+		return;
+	}
+	if (Q_stricmp (cmd, "say") == 0)
+	{
+		Cmd_Say_f (ent, false, false);
+		return;
+	}
+	if (Q_stricmp (cmd, "say_team") == 0)
+	{
+		Cmd_Say_f (ent, true, false);
+		return;
+	}
+	if (Q_stricmp (cmd, "score") == 0)
+	{
+		Cmd_Score_f (ent);
+		return;
+	}
+	if (Q_stricmp (cmd, "help") == 0)
+	{
+		Cmd_Help_f (ent);
+		return;
+	}
+
+	if (level.intermissiontime)
+		return;
+
+	if (Q_stricmp (cmd, "use") == 0)
+		Cmd_Use_f (ent);
+	else if (Q_stricmp (cmd, "drop") == 0)
+		Cmd_Drop_f (ent);
+	else if (Q_stricmp (cmd, "give") == 0)
+		Cmd_Give_f (ent);
+	else if (Q_stricmp (cmd, "god") == 0)
+		Cmd_God_f (ent);
+	else if (Q_stricmp (cmd, "notarget") == 0)
+		Cmd_Notarget_f (ent);
+	else if (Q_stricmp (cmd, "noclip") == 0)
+		Cmd_Noclip_f (ent);
+	else if (Q_stricmp (cmd, "inven") == 0)
+		Cmd_Inven_f (ent);
+	else if (Q_stricmp (cmd, "invnext") == 0)
+		SelectNextItem (ent, -1);
+	else if (Q_stricmp (cmd, "invprev") == 0)
+		SelectPrevItem (ent, -1);
+	else if (Q_stricmp (cmd, "invnextw") == 0)
+		SelectNextItem (ent, IT_WEAPON);
+	else if (Q_stricmp (cmd, "invprevw") == 0)
+		SelectPrevItem (ent, IT_WEAPON);
+	else if (Q_stricmp (cmd, "invnextp") == 0)
+		SelectNextItem (ent, IT_POWERUP);
+	else if (Q_stricmp (cmd, "invprevp") == 0)
+		SelectPrevItem (ent, IT_POWERUP);
+	else if (Q_stricmp (cmd, "invuse") == 0)
+		Cmd_InvUse_f (ent);
+	else if (Q_stricmp (cmd, "invdrop") == 0)
+		Cmd_InvDrop_f (ent);
+	else if (Q_stricmp (cmd, "weapprev") == 0)
+		Cmd_WeapPrev_f (ent);
+	else if (Q_stricmp (cmd, "weapnext") == 0)
+		Cmd_WeapNext_f (ent);
+	else if (Q_stricmp (cmd, "weaplast") == 0)
+		Cmd_WeapLast_f (ent);
+	else if (Q_stricmp (cmd, "kill") == 0)
+		Cmd_Kill_f (ent);
+	else if (Q_stricmp (cmd, "putaway") == 0)
+		Cmd_PutAway_f (ent);
+	else if (Q_stricmp (cmd, "wave") == 0)
+		Cmd_Wave_f (ent);
+	else if (Q_stricmp(cmd, "playerlist") == 0)
+		Cmd_PlayerList_f(ent);
+	else	// anything that doesn't match a command will be a chat
+		Cmd_Say_f (ent, false, true);
+}
--- /dev/null
+++ b/game/g_combat.c
@@ -1,0 +1,576 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_combat.c
+
+#include "g_local.h"
+
+/*
+============
+CanDamage
+
+Returns true if the inflictor can directly damage the target.  Used for
+explosions and melee attacks.
+============
+*/
+qboolean CanDamage (edict_t *targ, edict_t *inflictor)
+{
+	vec3_t	dest;
+	trace_t	trace;
+
+// bmodels need special checking because their origin is 0,0,0
+	if (targ->movetype == MOVETYPE_PUSH)
+	{
+		VectorAdd (targ->absmin, targ->absmax, dest);
+		VectorScale (dest, 0.5, dest);
+		trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+		if (trace.fraction == 1.0)
+			return true;
+		if (trace.ent == targ)
+			return true;
+		return false;
+	}
+	
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] += 15.0;
+	dest[1] += 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] += 15.0;
+	dest[1] -= 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] -= 15.0;
+	dest[1] += 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+	VectorCopy (targ->s.origin, dest);
+	dest[0] -= 15.0;
+	dest[1] -= 15.0;
+	trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+	if (trace.fraction == 1.0)
+		return true;
+
+
+	return false;
+}
+
+
+/*
+============
+Killed
+============
+*/
+void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	if (targ->health < -999)
+		targ->health = -999;
+
+	targ->enemy = attacker;
+
+	if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
+	{
+//		targ->svflags |= SVF_DEADMONSTER;	// now treat as a different content type
+		if (!(targ->monsterinfo.aiflags & AI_GOOD_GUY))
+		{
+			level.killed_monsters++;
+			if (coop->value && attacker->client)
+				attacker->client->resp.score++;
+			// medics won't heal monsters that they kill themselves
+			if (strcmp(attacker->classname, "monster_medic") == 0)
+				targ->owner = attacker;
+		}
+	}
+
+	if (targ->movetype == MOVETYPE_PUSH || targ->movetype == MOVETYPE_STOP || targ->movetype == MOVETYPE_NONE)
+	{	// doors, triggers, etc
+		targ->die (targ, inflictor, attacker, damage, point);
+		return;
+	}
+
+	if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
+	{
+		targ->touch = NULL;
+		monster_death_use (targ);
+	}
+
+	targ->die (targ, inflictor, attacker, damage, point);
+}
+
+
+/*
+================
+SpawnDamage
+================
+*/
+void SpawnDamage (int type, vec3_t origin, vec3_t normal, int damage)
+{
+	if (damage > 255)
+		damage = 255;
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (type);
+//	gi.WriteByte (damage);
+	gi.WritePosition (origin);
+	gi.WriteDir (normal);
+	gi.multicast (origin, MULTICAST_PVS);
+}
+
+
+/*
+============
+T_Damage
+
+targ		entity that is being damaged
+inflictor	entity that is causing the damage
+attacker	entity that caused the inflictor to damage targ
+	example: targ=monster, inflictor=rocket, attacker=player
+
+dir			direction of the attack
+point		point at which the damage is being inflicted
+normal		normal vector from that point
+damage		amount of damage being inflicted
+knockback	force to be applied against targ as a result of the damage
+
+dflags		these flags are used to control how T_Damage works
+	DAMAGE_RADIUS			damage was indirect (from a nearby explosion)
+	DAMAGE_NO_ARMOR			armor does not protect from this damage
+	DAMAGE_ENERGY			damage is from an energy based weapon
+	DAMAGE_NO_KNOCKBACK		do not affect velocity, just view angles
+	DAMAGE_BULLET			damage is from a bullet (used for ricochets)
+	DAMAGE_NO_PROTECTION	kills godmode, armor, everything
+============
+*/
+static int CheckPowerArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags)
+{
+	gclient_t	*client;
+	int			save;
+	int			power_armor_type;
+	int			index;
+	int			damagePerCell;
+	int			pa_te_type;
+	int			power;
+	int			power_used;
+
+	if (!damage)
+		return 0;
+
+	client = ent->client;
+
+	if (dflags & DAMAGE_NO_ARMOR)
+		return 0;
+
+	if (client)
+	{
+		power_armor_type = PowerArmorType (ent);
+		if (power_armor_type != POWER_ARMOR_NONE)
+		{
+			index = ITEM_INDEX(FindItem("Cells"));
+			power = client->pers.inventory[index];
+		}
+	}
+	else if (ent->svflags & SVF_MONSTER)
+	{
+		power_armor_type = ent->monsterinfo.power_armor_type;
+		power = ent->monsterinfo.power_armor_power;
+	}
+	else
+		return 0;
+
+	if (power_armor_type == POWER_ARMOR_NONE)
+		return 0;
+	if (!power)
+		return 0;
+
+	if (power_armor_type == POWER_ARMOR_SCREEN)
+	{
+		vec3_t		vec;
+		float		dot;
+		vec3_t		forward;
+
+		// only works if damage point is in front
+		AngleVectors (ent->s.angles, forward, NULL, NULL);
+		VectorSubtract (point, ent->s.origin, vec);
+		VectorNormalize (vec);
+		dot = DotProduct (vec, forward);
+		if (dot <= 0.3)
+			return 0;
+
+		damagePerCell = 1;
+		pa_te_type = TE_SCREEN_SPARKS;
+		damage = damage / 3;
+	}
+	else
+	{
+		damagePerCell = 2;
+		pa_te_type = TE_SHIELD_SPARKS;
+		damage = (2 * damage) / 3;
+	}
+
+	save = power * damagePerCell;
+	if (!save)
+		return 0;
+	if (save > damage)
+		save = damage;
+
+	SpawnDamage (pa_te_type, point, normal, save);
+	ent->powerarmor_time = level.time + 0.2;
+
+	power_used = save / damagePerCell;
+
+	if (client)
+		client->pers.inventory[index] -= power_used;
+	else
+		ent->monsterinfo.power_armor_power -= power_used;
+	return save;
+}
+
+static int CheckArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags)
+{
+	gclient_t	*client;
+	int			save;
+	int			index;
+	gitem_t		*armor;
+
+	if (!damage)
+		return 0;
+
+	client = ent->client;
+
+	if (!client)
+		return 0;
+
+	if (dflags & DAMAGE_NO_ARMOR)
+		return 0;
+
+	index = ArmorIndex (ent);
+	if (!index)
+		return 0;
+
+	armor = GetItemByIndex (index);
+
+	if (dflags & DAMAGE_ENERGY)
+		save = ceil(((gitem_armor_t *)armor->info)->energy_protection*damage);
+	else
+		save = ceil(((gitem_armor_t *)armor->info)->normal_protection*damage);
+	if (save >= client->pers.inventory[index])
+		save = client->pers.inventory[index];
+
+	if (!save)
+		return 0;
+
+	client->pers.inventory[index] -= save;
+	SpawnDamage (te_sparks, point, normal, save);
+
+	return save;
+}
+
+void M_ReactToDamage (edict_t *targ, edict_t *attacker)
+{
+	if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
+		return;
+
+	if (attacker == targ || attacker == targ->enemy)
+		return;
+
+	// if we are a good guy monster and our attacker is a player
+	// or another good guy, do not get mad at them
+	if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
+	{
+		if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
+			return;
+	}
+
+	// we now know that we are not both good guys
+
+	// if attacker is a client, get mad at them because he's good and we're not
+	if (attacker->client)
+	{
+		targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+
+		// this can only happen in coop (both new and old enemies are clients)
+		// only switch if can't see the current enemy
+		if (targ->enemy && targ->enemy->client)
+		{
+			if (visible(targ, targ->enemy))
+			{
+				targ->oldenemy = attacker;
+				return;
+			}
+			targ->oldenemy = targ->enemy;
+		}
+		targ->enemy = attacker;
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
+			FoundTarget (targ);
+		return;
+	}
+
+	// it's the same base (walk/swim/fly) type and a different classname and it's not a tank
+	// (they spray too much), get mad at them
+	if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
+		 (strcmp (targ->classname, attacker->classname) != 0) &&
+		 (strcmp(attacker->classname, "monster_tank") != 0) &&
+		 (strcmp(attacker->classname, "monster_supertank") != 0) &&
+		 (strcmp(attacker->classname, "monster_makron") != 0) &&
+		 (strcmp(attacker->classname, "monster_jorg") != 0) )
+	{
+		if (targ->enemy && targ->enemy->client)
+			targ->oldenemy = targ->enemy;
+		targ->enemy = attacker;
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
+			FoundTarget (targ);
+	}
+	// if they *meant* to shoot us, then shoot back
+	else if (attacker->enemy == targ)
+	{
+		if (targ->enemy && targ->enemy->client)
+			targ->oldenemy = targ->enemy;
+		targ->enemy = attacker;
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
+			FoundTarget (targ);
+	}
+	// otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
+	else if (attacker->enemy && attacker->enemy != targ)
+	{
+		if (targ->enemy && targ->enemy->client)
+			targ->oldenemy = targ->enemy;
+		targ->enemy = attacker->enemy;
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED))
+			FoundTarget (targ);
+	}
+}
+
+qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker)
+{
+		//FIXME make the next line real and uncomment this block
+		// if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
+	return false;
+}
+
+void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
+{
+	gclient_t	*client;
+	int			take;
+	int			save;
+	int			asave;
+	int			psave;
+	int			te_sparks;
+
+	if (!targ->takedamage)
+		return;
+
+	// friendly fire avoidance
+	// if enabled you can't hurt teammates (but you can hurt yourself)
+	// knockback still occurs
+	if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
+	{
+		if (OnSameTeam (targ, attacker))
+		{
+			if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
+				damage = 0;
+			else
+				mod |= MOD_FRIENDLY_FIRE;
+		}
+	}
+	meansOfDeath = mod;
+
+	// easy mode takes half damage
+	if (skill->value == 0 && deathmatch->value == 0 && targ->client)
+	{
+		damage *= 0.5;
+		if (!damage)
+			damage = 1;
+	}
+
+	client = targ->client;
+
+	if (dflags & DAMAGE_BULLET)
+		te_sparks = TE_BULLET_SPARKS;
+	else
+		te_sparks = TE_SPARKS;
+
+	VectorNormalize(dir);
+
+// bonus damage for suprising a monster
+	if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
+		damage *= 2;
+
+	if (targ->flags & FL_NO_KNOCKBACK)
+		knockback = 0;
+
+// figure momentum add
+	if (!(dflags & DAMAGE_NO_KNOCKBACK))
+	{
+		if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
+		{
+			vec3_t	kvel;
+			float	mass;
+
+			if (targ->mass < 50)
+				mass = 50;
+			else
+				mass = targ->mass;
+
+			if (targ->client  && attacker == targ)
+				VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
+			else
+				VectorScale (dir, 500.0 * (float)knockback / mass, kvel);
+
+			VectorAdd (targ->velocity, kvel, targ->velocity);
+		}
+	}
+
+	take = damage;
+	save = 0;
+
+	// check for godmode
+	if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
+	{
+		take = 0;
+		save = damage;
+		SpawnDamage (te_sparks, point, normal, save);
+	}
+
+	// check for invincibility
+	if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
+	{
+		if (targ->pain_debounce_time < level.time)
+		{
+			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
+			targ->pain_debounce_time = level.time + 2;
+		}
+		take = 0;
+		save = damage;
+	}
+
+	psave = CheckPowerArmor (targ, point, normal, take, dflags);
+	take -= psave;
+
+	asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
+	take -= asave;
+
+	//treat cheat/powerup savings the same as armor
+	asave += save;
+
+	// team damage avoidance
+	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
+		return;
+
+// do the damage
+	if (take)
+	{
+		if ((targ->svflags & SVF_MONSTER) || (client))
+			SpawnDamage (TE_BLOOD, point, normal, take);
+		else
+			SpawnDamage (te_sparks, point, normal, take);
+
+
+		targ->health = targ->health - take;
+			
+		if (targ->health <= 0)
+		{
+			if ((targ->svflags & SVF_MONSTER) || (client))
+				targ->flags |= FL_NO_KNOCKBACK;
+			Killed (targ, inflictor, attacker, take, point);
+			return;
+		}
+	}
+
+	if (targ->svflags & SVF_MONSTER)
+	{
+		M_ReactToDamage (targ, attacker);
+		if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
+		{
+			targ->pain (targ, attacker, knockback, take);
+			// nightmare mode monsters don't go into pain frames often
+			if (skill->value == 3)
+				targ->pain_debounce_time = level.time + 5;
+		}
+	}
+	else if (client)
+	{
+		if (!(targ->flags & FL_GODMODE) && (take))
+			targ->pain (targ, attacker, knockback, take);
+	}
+	else if (take)
+	{
+		if (targ->pain)
+			targ->pain (targ, attacker, knockback, take);
+	}
+
+	// add to the damage inflicted on a player this frame
+	// the total will be turned into screen blends and view angle kicks
+	// at the end of the frame
+	if (client)
+	{
+		client->damage_parmor += psave;
+		client->damage_armor += asave;
+		client->damage_blood += take;
+		client->damage_knockback += knockback;
+		VectorCopy (point, client->damage_from);
+	}
+}
+
+
+/*
+============
+T_RadiusDamage
+============
+*/
+void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
+{
+	float	points;
+	edict_t	*ent = NULL;
+	vec3_t	v;
+	vec3_t	dir;
+
+	while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL)
+	{
+		if (ent == ignore)
+			continue;
+		if (!ent->takedamage)
+			continue;
+
+		VectorAdd (ent->mins, ent->maxs, v);
+		VectorMA (ent->s.origin, 0.5, v, v);
+		VectorSubtract (inflictor->s.origin, v, v);
+		points = damage - 0.5 * VectorLength (v);
+		if (ent == attacker)
+			points = points * 0.5;
+		if (points > 0)
+		{
+			if (CanDamage (ent, inflictor))
+			{
+				VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
+				T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
+			}
+		}
+	}
+}
--- /dev/null
+++ b/game/g_func.c
@@ -1,0 +1,2048 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+/*
+=========================================================
+
+  PLATS
+
+  movement options:
+
+  linear
+  smooth start, hard stop
+  smooth start, smooth stop
+
+  start
+  end
+  acceleration
+  speed
+  deceleration
+  begin sound
+  end sound
+  target fired when reaching end
+  wait at end
+
+  object characteristics that use move segments
+  ---------------------------------------------
+  movetype_push, or movetype_stop
+  action when touched
+  action when blocked
+  action when used
+	disabled?
+  auto trigger spawning
+
+
+=========================================================
+*/
+
+#define PLAT_LOW_TRIGGER	1
+
+#define	STATE_TOP			0
+#define	STATE_BOTTOM		1
+#define STATE_UP			2
+#define STATE_DOWN			3
+
+#define DOOR_START_OPEN		1
+#define DOOR_REVERSE		2
+#define DOOR_CRUSHER		4
+#define DOOR_NOMONSTER		8
+#define DOOR_TOGGLE			32
+#define DOOR_X_AXIS			64
+#define DOOR_Y_AXIS			128
+
+
+//
+// Support routines for movement (changes in origin using velocity)
+//
+
+void Move_Done (edict_t *ent)
+{
+	VectorClear (ent->velocity);
+	ent->moveinfo.endfunc (ent);
+}
+
+void Move_Final (edict_t *ent)
+{
+	if (ent->moveinfo.remaining_distance == 0)
+	{
+		Move_Done (ent);
+		return;
+	}
+
+	VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance / FRAMETIME, ent->velocity);
+
+	ent->think = Move_Done;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void Move_Begin (edict_t *ent)
+{
+	float	frames;
+
+	if ((ent->moveinfo.speed * FRAMETIME) >= ent->moveinfo.remaining_distance)
+	{
+		Move_Final (ent);
+		return;
+	}
+	VectorScale (ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity);
+	frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME);
+	ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME;
+	ent->nextthink = level.time + (frames * FRAMETIME);
+	ent->think = Move_Final;
+}
+
+void Think_AccelMove (edict_t *ent);
+
+void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*))
+{
+	VectorClear (ent->velocity);
+	VectorSubtract (dest, ent->s.origin, ent->moveinfo.dir);
+	ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir);
+	ent->moveinfo.endfunc = func;
+
+	if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel)
+	{
+		if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
+		{
+			Move_Begin (ent);
+		}
+		else
+		{
+			ent->nextthink = level.time + FRAMETIME;
+			ent->think = Move_Begin;
+		}
+	}
+	else
+	{
+		// accelerative
+		ent->moveinfo.current_speed = 0;
+		ent->think = Think_AccelMove;
+		ent->nextthink = level.time + FRAMETIME;
+	}
+}
+
+
+//
+// Support routines for angular movement (changes in angle using avelocity)
+//
+
+void AngleMove_Done (edict_t *ent)
+{
+	VectorClear (ent->avelocity);
+	ent->moveinfo.endfunc (ent);
+}
+
+void AngleMove_Final (edict_t *ent)
+{
+	vec3_t	move;
+
+	if (ent->moveinfo.state == STATE_UP)
+		VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, move);
+	else
+		VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, move);
+
+	if (VectorCompare (move, vec3_origin))
+	{
+		AngleMove_Done (ent);
+		return;
+	}
+
+	VectorScale (move, 1.0/FRAMETIME, ent->avelocity);
+
+	ent->think = AngleMove_Done;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void AngleMove_Begin (edict_t *ent)
+{
+	vec3_t	destdelta;
+	float	len;
+	float	traveltime;
+	float	frames;
+
+	// set destdelta to the vector needed to move
+	if (ent->moveinfo.state == STATE_UP)
+		VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, destdelta);
+	else
+		VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta);
+	
+	// calculate length of vector
+	len = VectorLength (destdelta);
+	
+	// divide by speed to get time to reach dest
+	traveltime = len / ent->moveinfo.speed;
+
+	if (traveltime < FRAMETIME)
+	{
+		AngleMove_Final (ent);
+		return;
+	}
+
+	frames = floor(traveltime / FRAMETIME);
+
+	// scale the destdelta vector by the time spent traveling to get velocity
+	VectorScale (destdelta, 1.0 / traveltime, ent->avelocity);
+
+	// set nextthink to trigger a think when dest is reached
+	ent->nextthink = level.time + frames * FRAMETIME;
+	ent->think = AngleMove_Final;
+}
+
+void AngleMove_Calc (edict_t *ent, void(*func)(edict_t*))
+{
+	VectorClear (ent->avelocity);
+	ent->moveinfo.endfunc = func;
+	if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
+	{
+		AngleMove_Begin (ent);
+	}
+	else
+	{
+		ent->nextthink = level.time + FRAMETIME;
+		ent->think = AngleMove_Begin;
+	}
+}
+
+
+/*
+==============
+Think_AccelMove
+
+The team has completed a frame of movement, so
+change the speed for the next frame
+==============
+*/
+#define AccelerationDistance(target, rate)	(target * ((target / rate) + 1) / 2)
+
+void plat_CalcAcceleratedMove(moveinfo_t *moveinfo)
+{
+	float	accel_dist;
+	float	decel_dist;
+
+	moveinfo->move_speed = moveinfo->speed;
+
+	if (moveinfo->remaining_distance < moveinfo->accel)
+	{
+		moveinfo->current_speed = moveinfo->remaining_distance;
+		return;
+	}
+
+	accel_dist = AccelerationDistance (moveinfo->speed, moveinfo->accel);
+	decel_dist = AccelerationDistance (moveinfo->speed, moveinfo->decel);
+
+	if ((moveinfo->remaining_distance - accel_dist - decel_dist) < 0)
+	{
+		float	f;
+
+		f = (moveinfo->accel + moveinfo->decel) / (moveinfo->accel * moveinfo->decel);
+		moveinfo->move_speed = (-2 + sqrt(4 - 4 * f * (-2 * moveinfo->remaining_distance))) / (2 * f);
+		decel_dist = AccelerationDistance (moveinfo->move_speed, moveinfo->decel);
+	}
+
+	moveinfo->decel_distance = decel_dist;
+};
+
+void plat_Accelerate (moveinfo_t *moveinfo)
+{
+	// are we decelerating?
+	if (moveinfo->remaining_distance <= moveinfo->decel_distance)
+	{
+		if (moveinfo->remaining_distance < moveinfo->decel_distance)
+		{
+			if (moveinfo->next_speed)
+			{
+				moveinfo->current_speed = moveinfo->next_speed;
+				moveinfo->next_speed = 0;
+				return;
+			}
+			if (moveinfo->current_speed > moveinfo->decel)
+				moveinfo->current_speed -= moveinfo->decel;
+		}
+		return;
+	}
+
+	// are we at full speed and need to start decelerating during this move?
+	if (moveinfo->current_speed == moveinfo->move_speed)
+		if ((moveinfo->remaining_distance - moveinfo->current_speed) < moveinfo->decel_distance)
+		{
+			float	p1_distance;
+			float	p2_distance;
+			float	distance;
+
+			p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance;
+			p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / moveinfo->move_speed));
+			distance = p1_distance + p2_distance;
+			moveinfo->current_speed = moveinfo->move_speed;
+			moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance);
+			return;
+		}
+
+	// are we accelerating?
+	if (moveinfo->current_speed < moveinfo->speed)
+	{
+		float	old_speed;
+		float	p1_distance;
+		float	p1_speed;
+		float	p2_distance;
+		float	distance;
+
+		old_speed = moveinfo->current_speed;
+
+		// figure simple acceleration up to move_speed
+		moveinfo->current_speed += moveinfo->accel;
+		if (moveinfo->current_speed > moveinfo->speed)
+			moveinfo->current_speed = moveinfo->speed;
+
+		// are we accelerating throughout this entire move?
+		if ((moveinfo->remaining_distance - moveinfo->current_speed) >= moveinfo->decel_distance)
+			return;
+
+		// during this move we will accelrate from current_speed to move_speed
+		// and cross over the decel_distance; figure the average speed for the
+		// entire move
+		p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance;
+		p1_speed = (old_speed + moveinfo->move_speed) / 2.0;
+		p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / p1_speed));
+		distance = p1_distance + p2_distance;
+		moveinfo->current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo->move_speed * (p2_distance / distance));
+		moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance);
+		return;
+	}
+
+	// we are at constant velocity (move_speed)
+	return;
+};
+
+void Think_AccelMove (edict_t *ent)
+{
+	ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed;
+
+	if (ent->moveinfo.current_speed == 0)		// starting or blocked
+		plat_CalcAcceleratedMove(&ent->moveinfo);
+
+	plat_Accelerate (&ent->moveinfo);
+
+	// will the entire move complete on next frame?
+	if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed)
+	{
+		Move_Final (ent);
+		return;
+	}
+
+	VectorScale (ent->moveinfo.dir, ent->moveinfo.current_speed*10, ent->velocity);
+	ent->nextthink = level.time + FRAMETIME;
+	ent->think = Think_AccelMove;
+}
+
+
+void plat_go_down (edict_t *ent);
+
+void plat_hit_top (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_end)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		ent->s.sound = 0;
+	}
+	ent->moveinfo.state = STATE_TOP;
+
+	ent->think = plat_go_down;
+	ent->nextthink = level.time + 3;
+}
+
+void plat_hit_bottom (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_end)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		ent->s.sound = 0;
+	}
+	ent->moveinfo.state = STATE_BOTTOM;
+}
+
+void plat_go_down (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_start)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		ent->s.sound = ent->moveinfo.sound_middle;
+	}
+	ent->moveinfo.state = STATE_DOWN;
+	Move_Calc (ent, ent->moveinfo.end_origin, plat_hit_bottom);
+}
+
+void plat_go_up (edict_t *ent)
+{
+	if (!(ent->flags & FL_TEAMSLAVE))
+	{
+		if (ent->moveinfo.sound_start)
+			gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		ent->s.sound = ent->moveinfo.sound_middle;
+	}
+	ent->moveinfo.state = STATE_UP;
+	Move_Calc (ent, ent->moveinfo.start_origin, plat_hit_top);
+}
+
+void plat_blocked (edict_t *self, edict_t *other)
+{
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+
+	if (self->moveinfo.state == STATE_UP)
+		plat_go_down (self);
+	else if (self->moveinfo.state == STATE_DOWN)
+		plat_go_up (self);
+}
+
+
+void Use_Plat (edict_t *ent, edict_t *other, edict_t *activator)
+{ 
+	if (ent->think)
+		return;		// already down
+	plat_go_down (ent);
+}
+
+
+void Touch_Plat_Center (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (!other->client)
+		return;
+		
+	if (other->health <= 0)
+		return;
+
+	ent = ent->enemy;	// now point at the plat, not the trigger
+	if (ent->moveinfo.state == STATE_BOTTOM)
+		plat_go_up (ent);
+	else if (ent->moveinfo.state == STATE_TOP)
+		ent->nextthink = level.time + 1;	// the player is still on the plat, so delay going down
+}
+
+void plat_spawn_inside_trigger (edict_t *ent)
+{
+	edict_t	*trigger;
+	vec3_t	tmin, tmax;
+
+//
+// middle trigger
+//	
+	trigger = G_Spawn();
+	trigger->touch = Touch_Plat_Center;
+	trigger->movetype = MOVETYPE_NONE;
+	trigger->solid = SOLID_TRIGGER;
+	trigger->enemy = ent;
+	
+	tmin[0] = ent->mins[0] + 25;
+	tmin[1] = ent->mins[1] + 25;
+	tmin[2] = ent->mins[2];
+
+	tmax[0] = ent->maxs[0] - 25;
+	tmax[1] = ent->maxs[1] - 25;
+	tmax[2] = ent->maxs[2] + 8;
+
+	tmin[2] = tmax[2] - (ent->pos1[2] - ent->pos2[2] + st.lip);
+
+	if (ent->spawnflags & PLAT_LOW_TRIGGER)
+		tmax[2] = tmin[2] + 8;
+	
+	if (tmax[0] - tmin[0] <= 0)
+	{
+		tmin[0] = (ent->mins[0] + ent->maxs[0]) *0.5;
+		tmax[0] = tmin[0] + 1;
+	}
+	if (tmax[1] - tmin[1] <= 0)
+	{
+		tmin[1] = (ent->mins[1] + ent->maxs[1]) *0.5;
+		tmax[1] = tmin[1] + 1;
+	}
+	
+	VectorCopy (tmin, trigger->mins);
+	VectorCopy (tmax, trigger->maxs);
+
+	gi.linkentity (trigger);
+}
+
+
+/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
+speed	default 150
+
+Plats are always drawn in the extended position, so they will light correctly.
+
+If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
+
+"speed"	overrides default 200.
+"accel" overrides default 500
+"lip"	overrides default 8 pixel lip
+
+If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height.
+
+Set "sounds" to one of the following:
+1) base fast
+2) chain slow
+*/
+void SP_func_plat (edict_t *ent)
+{
+	VectorClear (ent->s.angles);
+	ent->solid = SOLID_BSP;
+	ent->movetype = MOVETYPE_PUSH;
+
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = plat_blocked;
+
+	if (!ent->speed)
+		ent->speed = 20;
+	else
+		ent->speed *= 0.1;
+
+	if (!ent->accel)
+		ent->accel = 5;
+	else
+		ent->accel *= 0.1;
+
+	if (!ent->decel)
+		ent->decel = 5;
+	else
+		ent->decel *= 0.1;
+
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	if (!st.lip)
+		st.lip = 8;
+
+	// pos1 is the top position, pos2 is the bottom
+	VectorCopy (ent->s.origin, ent->pos1);
+	VectorCopy (ent->s.origin, ent->pos2);
+	if (st.height)
+		ent->pos2[2] -= st.height;
+	else
+		ent->pos2[2] -= (ent->maxs[2] - ent->mins[2]) - st.lip;
+
+	ent->use = Use_Plat;
+
+	plat_spawn_inside_trigger (ent);	// the "start moving" trigger	
+
+	if (ent->targetname)
+	{
+		ent->moveinfo.state = STATE_UP;
+	}
+	else
+	{
+		VectorCopy (ent->pos2, ent->s.origin);
+		gi.linkentity (ent);
+		ent->moveinfo.state = STATE_BOTTOM;
+	}
+
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->pos1, ent->moveinfo.start_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
+	VectorCopy (ent->pos2, ent->moveinfo.end_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
+
+	ent->moveinfo.sound_start = gi.soundindex ("plats/pt1_strt.wav");
+	ent->moveinfo.sound_middle = gi.soundindex ("plats/pt1_mid.wav");
+	ent->moveinfo.sound_end = gi.soundindex ("plats/pt1_end.wav");
+}
+
+//====================================================================
+
+/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS TOUCH_PAIN STOP ANIMATED ANIMATED_FAST
+You need to have an origin brush as part of this entity.  The center of that brush will be
+the point around which it is rotated. It will rotate around the Z axis by default.  You can
+check either the X_AXIS or Y_AXIS box to change that.
+
+"speed" determines how fast it moves; default value is 100.
+"dmg"	damage to inflict when blocked (2 default)
+
+REVERSE will cause the it to rotate in the opposite direction.
+STOP mean it will stop moving instead of pushing entities
+*/
+
+void rotating_blocked (edict_t *self, edict_t *other)
+{
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void rotating_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (self->avelocity[0] || self->avelocity[1] || self->avelocity[2])
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void rotating_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (!VectorCompare (self->avelocity, vec3_origin))
+	{
+		self->s.sound = 0;
+		VectorClear (self->avelocity);
+		self->touch = NULL;
+	}
+	else
+	{
+		self->s.sound = self->moveinfo.sound_middle;
+		VectorScale (self->movedir, self->speed, self->avelocity);
+		if (self->spawnflags & 16)
+			self->touch = rotating_touch;
+	}
+}
+
+void SP_func_rotating (edict_t *ent)
+{
+	ent->solid = SOLID_BSP;
+	if (ent->spawnflags & 32)
+		ent->movetype = MOVETYPE_STOP;
+	else
+		ent->movetype = MOVETYPE_PUSH;
+
+	// set the axis of rotation
+	VectorClear(ent->movedir);
+	if (ent->spawnflags & 4)
+		ent->movedir[2] = 1.0;
+	else if (ent->spawnflags & 8)
+		ent->movedir[0] = 1.0;
+	else // Z_AXIS
+		ent->movedir[1] = 1.0;
+
+	// check for reverse rotation
+	if (ent->spawnflags & 2)
+		VectorNegate (ent->movedir, ent->movedir);
+
+	if (!ent->speed)
+		ent->speed = 100;
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+//	ent->moveinfo.sound_middle = "doors/hydro1.wav";
+
+	ent->use = rotating_use;
+	if (ent->dmg)
+		ent->blocked = rotating_blocked;
+
+	if (ent->spawnflags & 1)
+		ent->use (ent, NULL, NULL);
+
+	if (ent->spawnflags & 64)
+		ent->s.effects |= EF_ANIM_ALL;
+	if (ent->spawnflags & 128)
+		ent->s.effects |= EF_ANIM_ALLFAST;
+
+	gi.setmodel (ent, ent->model);
+	gi.linkentity (ent);
+}
+
+/*
+======================================================================
+
+BUTTONS
+
+======================================================================
+*/
+
+/*QUAKED func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle"		determines the opening direction
+"target"	all entities with a matching targetname will be used
+"speed"		override the default 40 speed
+"wait"		override the default 1 second wait (-1 = never return)
+"lip"		override the default 4 pixel lip remaining at end of move
+"health"	if set, the button must be killed instead of touched
+"sounds"
+1) silent
+2) steam metal
+3) wooden clunk
+4) metallic click
+5) in-out
+*/
+
+void button_done (edict_t *self)
+{
+	self->moveinfo.state = STATE_BOTTOM;
+	self->s.effects &= ~EF_ANIM23;
+	self->s.effects |= EF_ANIM01;
+}
+
+void button_return (edict_t *self)
+{
+	self->moveinfo.state = STATE_DOWN;
+
+	Move_Calc (self, self->moveinfo.start_origin, button_done);
+
+	self->s.frame = 0;
+
+	if (self->health)
+		self->takedamage = DAMAGE_YES;
+}
+
+void button_wait (edict_t *self)
+{
+	self->moveinfo.state = STATE_TOP;
+	self->s.effects &= ~EF_ANIM01;
+	self->s.effects |= EF_ANIM23;
+
+	G_UseTargets (self, self->activator);
+	self->s.frame = 1;
+	if (self->moveinfo.wait >= 0)
+	{
+		self->nextthink = level.time + self->moveinfo.wait;
+		self->think = button_return;
+	}
+}
+
+void button_fire (edict_t *self)
+{
+	if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP)
+		return;
+
+	self->moveinfo.state = STATE_UP;
+	if (self->moveinfo.sound_start && !(self->flags & FL_TEAMSLAVE))
+		gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+	Move_Calc (self, self->moveinfo.end_origin, button_wait);
+}
+
+void button_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+	button_fire (self);
+}
+
+void button_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (!other->client)
+		return;
+
+	if (other->health <= 0)
+		return;
+
+	self->activator = other;
+	button_fire (self);
+}
+
+void button_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	self->activator = attacker;
+	self->health = self->max_health;
+	self->takedamage = DAMAGE_NO;
+	button_fire (self);
+}
+
+void SP_func_button (edict_t *ent)
+{
+	vec3_t	abs_movedir;
+	float	dist;
+
+	G_SetMovedir (ent->s.angles, ent->movedir);
+	ent->movetype = MOVETYPE_STOP;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	if (ent->sounds != 1)
+		ent->moveinfo.sound_start = gi.soundindex ("switches/butn2.wav");
+	
+	if (!ent->speed)
+		ent->speed = 40;
+	if (!ent->accel)
+		ent->accel = ent->speed;
+	if (!ent->decel)
+		ent->decel = ent->speed;
+
+	if (!ent->wait)
+		ent->wait = 3;
+	if (!st.lip)
+		st.lip = 4;
+
+	VectorCopy (ent->s.origin, ent->pos1);
+	abs_movedir[0] = fabs(ent->movedir[0]);
+	abs_movedir[1] = fabs(ent->movedir[1]);
+	abs_movedir[2] = fabs(ent->movedir[2]);
+	dist = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip;
+	VectorMA (ent->pos1, dist, ent->movedir, ent->pos2);
+
+	ent->use = button_use;
+	ent->s.effects |= EF_ANIM01;
+
+	if (ent->health)
+	{
+		ent->max_health = ent->health;
+		ent->die = button_killed;
+		ent->takedamage = DAMAGE_YES;
+	}
+	else if (! ent->targetname)
+		ent->touch = button_touch;
+
+	ent->moveinfo.state = STATE_BOTTOM;
+
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->pos1, ent->moveinfo.start_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
+	VectorCopy (ent->pos2, ent->moveinfo.end_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
+
+	gi.linkentity (ent);
+}
+
+/*
+======================================================================
+
+DOORS
+
+  spawn a trigger surrounding the entire team unless it is
+  already targeted by another
+
+======================================================================
+*/
+
+/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER NOMONSTER ANIMATED TOGGLE ANIMATED_FAST
+TOGGLE		wait in both the start and end states for a trigger event.
+START_OPEN	the door to moves to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+NOMONSTER	monsters will not trigger this door
+
+"message"	is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"		determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"	if set, door must be shot open
+"speed"		movement speed (100 default)
+"wait"		wait before returning (3 default, -1 = never return)
+"lip"		lip remaining at end of move (8 default)
+"dmg"		damage to inflict when blocked (2 default)
+"sounds"
+1)	silent
+2)	light
+3)	medium
+4)	heavy
+*/
+
+void door_use_areaportals (edict_t *self, qboolean open)
+{
+	edict_t	*t = NULL;
+
+	if (!self->target)
+		return;
+
+	while ((t = G_Find (t, FOFS(targetname), self->target)))
+	{
+		if (Q_stricmp(t->classname, "func_areaportal") == 0)
+		{
+			gi.SetAreaPortalState (t->style, open);
+		}
+	}
+}
+
+void door_go_down (edict_t *self);
+
+void door_hit_top (edict_t *self)
+{
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_end)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		self->s.sound = 0;
+	}
+	self->moveinfo.state = STATE_TOP;
+	if (self->spawnflags & DOOR_TOGGLE)
+		return;
+	if (self->moveinfo.wait >= 0)
+	{
+		self->think = door_go_down;
+		self->nextthink = level.time + self->moveinfo.wait;
+	}
+}
+
+void door_hit_bottom (edict_t *self)
+{
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_end)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+		self->s.sound = 0;
+	}
+	self->moveinfo.state = STATE_BOTTOM;
+	door_use_areaportals (self, false);
+}
+
+void door_go_down (edict_t *self)
+{
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_start)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		self->s.sound = self->moveinfo.sound_middle;
+	}
+	if (self->max_health)
+	{
+		self->takedamage = DAMAGE_YES;
+		self->health = self->max_health;
+	}
+	
+	self->moveinfo.state = STATE_DOWN;
+	if (strcmp(self->classname, "func_door") == 0)
+		Move_Calc (self, self->moveinfo.start_origin, door_hit_bottom);
+	else if (strcmp(self->classname, "func_door_rotating") == 0)
+		AngleMove_Calc (self, door_hit_bottom);
+}
+
+void door_go_up (edict_t *self, edict_t *activator)
+{
+	if (self->moveinfo.state == STATE_UP)
+		return;		// already going up
+
+	if (self->moveinfo.state == STATE_TOP)
+	{	// reset top wait time
+		if (self->moveinfo.wait >= 0)
+			self->nextthink = level.time + self->moveinfo.wait;
+		return;
+	}
+	
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_start)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		self->s.sound = self->moveinfo.sound_middle;
+	}
+	self->moveinfo.state = STATE_UP;
+	if (strcmp(self->classname, "func_door") == 0)
+		Move_Calc (self, self->moveinfo.end_origin, door_hit_top);
+	else if (strcmp(self->classname, "func_door_rotating") == 0)
+		AngleMove_Calc (self, door_hit_top);
+
+	G_UseTargets (self, activator);
+	door_use_areaportals (self, true);
+}
+
+void door_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t	*ent;
+
+	if (self->flags & FL_TEAMSLAVE)
+		return;
+
+	if (self->spawnflags & DOOR_TOGGLE)
+	{
+		if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP)
+		{
+			// trigger all paired doors
+			for (ent = self ; ent ; ent = ent->teamchain)
+			{
+				ent->message = NULL;
+				ent->touch = NULL;
+				door_go_down (ent);
+			}
+			return;
+		}
+	}
+	
+	// trigger all paired doors
+	for (ent = self ; ent ; ent = ent->teamchain)
+	{
+		ent->message = NULL;
+		ent->touch = NULL;
+		door_go_up (ent, activator);
+	}
+};
+
+void Touch_DoorTrigger (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other->health <= 0)
+		return;
+
+	if (!(other->svflags & SVF_MONSTER) && (!other->client))
+		return;
+
+	if ((self->owner->spawnflags & DOOR_NOMONSTER) && (other->svflags & SVF_MONSTER))
+		return;
+
+	if (level.time < self->touch_debounce_time)
+		return;
+	self->touch_debounce_time = level.time + 1.0;
+
+	door_use (self->owner, other, other);
+}
+
+void Think_CalcMoveSpeed (edict_t *self)
+{
+	edict_t	*ent;
+	float	min;
+	float	time;
+	float	newspeed;
+	float	ratio;
+	float	dist;
+
+	if (self->flags & FL_TEAMSLAVE)
+		return;		// only the team master does this
+
+	// find the smallest distance any member of the team will be moving
+	min = fabs(self->moveinfo.distance);
+	for (ent = self->teamchain; ent; ent = ent->teamchain)
+	{
+		dist = fabs(ent->moveinfo.distance);
+		if (dist < min)
+			min = dist;
+	}
+
+	time = min / self->moveinfo.speed;
+
+	// adjust speeds so they will all complete at the same time
+	for (ent = self; ent; ent = ent->teamchain)
+	{
+		newspeed = fabs(ent->moveinfo.distance) / time;
+		ratio = newspeed / ent->moveinfo.speed;
+		if (ent->moveinfo.accel == ent->moveinfo.speed)
+			ent->moveinfo.accel = newspeed;
+		else
+			ent->moveinfo.accel *= ratio;
+		if (ent->moveinfo.decel == ent->moveinfo.speed)
+			ent->moveinfo.decel = newspeed;
+		else
+			ent->moveinfo.decel *= ratio;
+		ent->moveinfo.speed = newspeed;
+	}
+}
+
+void Think_SpawnDoorTrigger (edict_t *ent)
+{
+	edict_t		*other;
+	vec3_t		mins, maxs;
+
+	if (ent->flags & FL_TEAMSLAVE)
+		return;		// only the team leader spawns a trigger
+
+	VectorCopy (ent->absmin, mins);
+	VectorCopy (ent->absmax, maxs);
+
+	for (other = ent->teamchain ; other ; other=other->teamchain)
+	{
+		AddPointToBounds (other->absmin, mins, maxs);
+		AddPointToBounds (other->absmax, mins, maxs);
+	}
+
+	// expand 
+	mins[0] -= 60;
+	mins[1] -= 60;
+	maxs[0] += 60;
+	maxs[1] += 60;
+
+	other = G_Spawn ();
+	VectorCopy (mins, other->mins);
+	VectorCopy (maxs, other->maxs);
+	other->owner = ent;
+	other->solid = SOLID_TRIGGER;
+	other->movetype = MOVETYPE_NONE;
+	other->touch = Touch_DoorTrigger;
+	gi.linkentity (other);
+
+	if (ent->spawnflags & DOOR_START_OPEN)
+		door_use_areaportals (ent, true);
+
+	Think_CalcMoveSpeed (ent);
+}
+
+void door_blocked  (edict_t *self, edict_t *other)
+{
+	edict_t	*ent;
+
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+
+	if (self->spawnflags & DOOR_CRUSHER)
+		return;
+
+
+// if a door has a negative wait, it would never come back if blocked,
+// so let it just squash the object to death real fast
+	if (self->moveinfo.wait >= 0)
+	{
+		if (self->moveinfo.state == STATE_DOWN)
+		{
+			for (ent = self->teammaster ; ent ; ent = ent->teamchain)
+				door_go_up (ent, ent->activator);
+		}
+		else
+		{
+			for (ent = self->teammaster ; ent ; ent = ent->teamchain)
+				door_go_down (ent);
+		}
+	}
+}
+
+void door_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	edict_t	*ent;
+
+	for (ent = self->teammaster ; ent ; ent = ent->teamchain)
+	{
+		ent->health = ent->max_health;
+		ent->takedamage = DAMAGE_NO;
+	}
+	door_use (self->teammaster, attacker, attacker);
+}
+
+void door_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (!other->client)
+		return;
+
+	if (level.time < self->touch_debounce_time)
+		return;
+	self->touch_debounce_time = level.time + 5.0;
+
+	gi.centerprintf (other, "%s", self->message);
+	gi.sound (other, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+}
+
+void SP_func_door (edict_t *ent)
+{
+	vec3_t	abs_movedir;
+
+	if (ent->sounds != 1)
+	{
+		ent->moveinfo.sound_start = gi.soundindex  ("doors/dr1_strt.wav");
+		ent->moveinfo.sound_middle = gi.soundindex  ("doors/dr1_mid.wav");
+		ent->moveinfo.sound_end = gi.soundindex  ("doors/dr1_end.wav");
+	}
+
+	G_SetMovedir (ent->s.angles, ent->movedir);
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = door_blocked;
+	ent->use = door_use;
+	
+	if (!ent->speed)
+		ent->speed = 100;
+	if (deathmatch->value)
+		ent->speed *= 2;
+
+	if (!ent->accel)
+		ent->accel = ent->speed;
+	if (!ent->decel)
+		ent->decel = ent->speed;
+
+	if (!ent->wait)
+		ent->wait = 3;
+	if (!st.lip)
+		st.lip = 8;
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	// calculate second position
+	VectorCopy (ent->s.origin, ent->pos1);
+	abs_movedir[0] = fabs(ent->movedir[0]);
+	abs_movedir[1] = fabs(ent->movedir[1]);
+	abs_movedir[2] = fabs(ent->movedir[2]);
+	ent->moveinfo.distance = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip;
+	VectorMA (ent->pos1, ent->moveinfo.distance, ent->movedir, ent->pos2);
+
+	// if it starts open, switch the positions
+	if (ent->spawnflags & DOOR_START_OPEN)
+	{
+		VectorCopy (ent->pos2, ent->s.origin);
+		VectorCopy (ent->pos1, ent->pos2);
+		VectorCopy (ent->s.origin, ent->pos1);
+	}
+
+	ent->moveinfo.state = STATE_BOTTOM;
+
+	if (ent->health)
+	{
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_killed;
+		ent->max_health = ent->health;
+	}
+	else if (ent->targetname && ent->message)
+	{
+		gi.soundindex ("misc/talk.wav");
+		ent->touch = door_touch;
+	}
+	
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->pos1, ent->moveinfo.start_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
+	VectorCopy (ent->pos2, ent->moveinfo.end_origin);
+	VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
+
+	if (ent->spawnflags & 16)
+		ent->s.effects |= EF_ANIM_ALL;
+	if (ent->spawnflags & 64)
+		ent->s.effects |= EF_ANIM_ALLFAST;
+
+	// to simplify logic elsewhere, make non-teamed doors into a team of one
+	if (!ent->team)
+		ent->teammaster = ent;
+
+	gi.linkentity (ent);
+
+	ent->nextthink = level.time + FRAMETIME;
+	if (ent->health || ent->targetname)
+		ent->think = Think_CalcMoveSpeed;
+	else
+		ent->think = Think_SpawnDoorTrigger;
+}
+
+
+/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE CRUSHER NOMONSTER ANIMATED TOGGLE X_AXIS Y_AXIS
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+START_OPEN	the door to moves to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+NOMONSTER	monsters will not trigger this door
+
+You need to have an origin brush as part of this entity.  The center of that brush will be
+the point around which it is rotated. It will rotate around the Z axis by default.  You can
+check either the X_AXIS or Y_AXIS box to change that.
+
+"distance" is how many degrees the door will be rotated.
+"speed" determines how fast the door moves; default value is 100.
+
+REVERSE will cause the door to rotate in the opposite direction.
+
+"message"	is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"		determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"	if set, door must be shot open
+"speed"		movement speed (100 default)
+"wait"		wait before returning (3 default, -1 = never return)
+"dmg"		damage to inflict when blocked (2 default)
+"sounds"
+1)	silent
+2)	light
+3)	medium
+4)	heavy
+*/
+
+void SP_func_door_rotating (edict_t *ent)
+{
+	VectorClear (ent->s.angles);
+
+	// set the axis of rotation
+	VectorClear(ent->movedir);
+	if (ent->spawnflags & DOOR_X_AXIS)
+		ent->movedir[2] = 1.0;
+	else if (ent->spawnflags & DOOR_Y_AXIS)
+		ent->movedir[0] = 1.0;
+	else // Z_AXIS
+		ent->movedir[1] = 1.0;
+
+	// check for reverse rotation
+	if (ent->spawnflags & DOOR_REVERSE)
+		VectorNegate (ent->movedir, ent->movedir);
+
+	if (!st.distance)
+	{
+		gi.dprintf("%s at %s with no distance set\n", ent->classname, vtos(ent->s.origin));
+		st.distance = 90;
+	}
+
+	VectorCopy (ent->s.angles, ent->pos1);
+	VectorMA (ent->s.angles, st.distance, ent->movedir, ent->pos2);
+	ent->moveinfo.distance = st.distance;
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = door_blocked;
+	ent->use = door_use;
+
+	if (!ent->speed)
+		ent->speed = 100;
+	if (!ent->accel)
+		ent->accel = ent->speed;
+	if (!ent->decel)
+		ent->decel = ent->speed;
+
+	if (!ent->wait)
+		ent->wait = 3;
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	if (ent->sounds != 1)
+	{
+		ent->moveinfo.sound_start = gi.soundindex  ("doors/dr1_strt.wav");
+		ent->moveinfo.sound_middle = gi.soundindex  ("doors/dr1_mid.wav");
+		ent->moveinfo.sound_end = gi.soundindex  ("doors/dr1_end.wav");
+	}
+
+	// if it starts open, switch the positions
+	if (ent->spawnflags & DOOR_START_OPEN)
+	{
+		VectorCopy (ent->pos2, ent->s.angles);
+		VectorCopy (ent->pos1, ent->pos2);
+		VectorCopy (ent->s.angles, ent->pos1);
+		VectorNegate (ent->movedir, ent->movedir);
+	}
+
+	if (ent->health)
+	{
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_killed;
+		ent->max_health = ent->health;
+	}
+	
+	if (ent->targetname && ent->message)
+	{
+		gi.soundindex ("misc/talk.wav");
+		ent->touch = door_touch;
+	}
+
+	ent->moveinfo.state = STATE_BOTTOM;
+	ent->moveinfo.speed = ent->speed;
+	ent->moveinfo.accel = ent->accel;
+	ent->moveinfo.decel = ent->decel;
+	ent->moveinfo.wait = ent->wait;
+	VectorCopy (ent->s.origin, ent->moveinfo.start_origin);
+	VectorCopy (ent->pos1, ent->moveinfo.start_angles);
+	VectorCopy (ent->s.origin, ent->moveinfo.end_origin);
+	VectorCopy (ent->pos2, ent->moveinfo.end_angles);
+
+	if (ent->spawnflags & 16)
+		ent->s.effects |= EF_ANIM_ALL;
+
+	// to simplify logic elsewhere, make non-teamed doors into a team of one
+	if (!ent->team)
+		ent->teammaster = ent;
+
+	gi.linkentity (ent);
+
+	ent->nextthink = level.time + FRAMETIME;
+	if (ent->health || ent->targetname)
+		ent->think = Think_CalcMoveSpeed;
+	else
+		ent->think = Think_SpawnDoorTrigger;
+}
+
+
+/*QUAKED func_water (0 .5 .8) ? START_OPEN
+func_water is a moveable water brush.  It must be targeted to operate.  Use a non-water texture at your own risk.
+
+START_OPEN causes the water to move to its destination when spawned and operate in reverse.
+
+"angle"		determines the opening direction (up or down only)
+"speed"		movement speed (25 default)
+"wait"		wait before returning (-1 default, -1 = TOGGLE)
+"lip"		lip remaining at end of move (0 default)
+"sounds"	(yes, these need to be changed)
+0)	no sound
+1)	water
+2)	lava
+*/
+
+void SP_func_water (edict_t *self)
+{
+	vec3_t	abs_movedir;
+
+	G_SetMovedir (self->s.angles, self->movedir);
+	self->movetype = MOVETYPE_PUSH;
+	self->solid = SOLID_BSP;
+	gi.setmodel (self, self->model);
+
+	switch (self->sounds)
+	{
+		default:
+			break;
+
+		case 1: // water
+			self->moveinfo.sound_start = gi.soundindex  ("world/mov_watr.wav");
+			self->moveinfo.sound_end = gi.soundindex  ("world/stp_watr.wav");
+			break;
+
+		case 2: // lava
+			self->moveinfo.sound_start = gi.soundindex  ("world/mov_watr.wav");
+			self->moveinfo.sound_end = gi.soundindex  ("world/stp_watr.wav");
+			break;
+	}
+
+	// calculate second position
+	VectorCopy (self->s.origin, self->pos1);
+	abs_movedir[0] = fabs(self->movedir[0]);
+	abs_movedir[1] = fabs(self->movedir[1]);
+	abs_movedir[2] = fabs(self->movedir[2]);
+	self->moveinfo.distance = abs_movedir[0] * self->size[0] + abs_movedir[1] * self->size[1] + abs_movedir[2] * self->size[2] - st.lip;
+	VectorMA (self->pos1, self->moveinfo.distance, self->movedir, self->pos2);
+
+	// if it starts open, switch the positions
+	if (self->spawnflags & DOOR_START_OPEN)
+	{
+		VectorCopy (self->pos2, self->s.origin);
+		VectorCopy (self->pos1, self->pos2);
+		VectorCopy (self->s.origin, self->pos1);
+	}
+
+	VectorCopy (self->pos1, self->moveinfo.start_origin);
+	VectorCopy (self->s.angles, self->moveinfo.start_angles);
+	VectorCopy (self->pos2, self->moveinfo.end_origin);
+	VectorCopy (self->s.angles, self->moveinfo.end_angles);
+
+	self->moveinfo.state = STATE_BOTTOM;
+
+	if (!self->speed)
+		self->speed = 25;
+	self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed = self->speed;
+
+	if (!self->wait)
+		self->wait = -1;
+	self->moveinfo.wait = self->wait;
+
+	self->use = door_use;
+
+	if (self->wait == -1)
+		self->spawnflags |= DOOR_TOGGLE;
+
+	self->classname = "func_door";
+
+	gi.linkentity (self);
+}
+
+
+#define TRAIN_START_ON		1
+#define TRAIN_TOGGLE		2
+#define TRAIN_BLOCK_STOPS	4
+
+/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
+Trains are moving platforms that players can ride.
+The targets origin specifies the min point of the train at each corner.
+The train spawns at the first target it is pointing at.
+If the train is the target of a button or trigger, it will not begin moving until activated.
+speed	default 100
+dmg		default	2
+noise	looping sound to play when the train is in motion
+
+*/
+void train_next (edict_t *self);
+
+void train_blocked (edict_t *self, edict_t *other)
+{
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	if (level.time < self->touch_debounce_time)
+		return;
+
+	if (!self->dmg)
+		return;
+	self->touch_debounce_time = level.time + 0.5;
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void train_wait (edict_t *self)
+{
+	if (self->target_ent->pathtarget)
+	{
+		char	*savetarget;
+		edict_t	*ent;
+
+		ent = self->target_ent;
+		savetarget = ent->target;
+		ent->target = ent->pathtarget;
+		G_UseTargets (ent, self->activator);
+		ent->target = savetarget;
+
+		// make sure we didn't get killed by a killtarget
+		if (!self->inuse)
+			return;
+	}
+
+	if (self->moveinfo.wait)
+	{
+		if (self->moveinfo.wait > 0)
+		{
+			self->nextthink = level.time + self->moveinfo.wait;
+			self->think = train_next;
+		}
+		else if (self->spawnflags & TRAIN_TOGGLE)  // && wait < 0
+		{
+			train_next (self);
+			self->spawnflags &= ~TRAIN_START_ON;
+			VectorClear (self->velocity);
+			self->nextthink = 0;
+		}
+
+		if (!(self->flags & FL_TEAMSLAVE))
+		{
+			if (self->moveinfo.sound_end)
+				gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
+			self->s.sound = 0;
+		}
+	}
+	else
+	{
+		train_next (self);
+	}
+	
+}
+
+void train_next (edict_t *self)
+{
+	edict_t		*ent;
+	vec3_t		dest;
+	qboolean	first;
+
+	first = true;
+again:
+	if (!self->target)
+	{
+//		gi.dprintf ("train_next: no next target\n");
+		return;
+	}
+
+	ent = G_PickTarget (self->target);
+	if (!ent)
+	{
+		gi.dprintf ("train_next: bad target %s\n", self->target);
+		return;
+	}
+
+	self->target = ent->target;
+
+	// check for a teleport path_corner
+	if (ent->spawnflags & 1)
+	{
+		if (!first)
+		{
+			gi.dprintf ("connected teleport path_corners, see %s at %s\n", ent->classname, vtos(ent->s.origin));
+			return;
+		}
+		first = false;
+		VectorSubtract (ent->s.origin, self->mins, self->s.origin);
+		VectorCopy (self->s.origin, self->s.old_origin);
+		self->s.event = EV_OTHER_TELEPORT;
+		gi.linkentity (self);
+		goto again;
+	}
+
+	self->moveinfo.wait = ent->wait;
+	self->target_ent = ent;
+
+	if (!(self->flags & FL_TEAMSLAVE))
+	{
+		if (self->moveinfo.sound_start)
+			gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
+		self->s.sound = self->moveinfo.sound_middle;
+	}
+
+	VectorSubtract (ent->s.origin, self->mins, dest);
+	self->moveinfo.state = STATE_TOP;
+	VectorCopy (self->s.origin, self->moveinfo.start_origin);
+	VectorCopy (dest, self->moveinfo.end_origin);
+	Move_Calc (self, dest, train_wait);
+	self->spawnflags |= TRAIN_START_ON;
+}
+
+void train_resume (edict_t *self)
+{
+	edict_t	*ent;
+	vec3_t	dest;
+
+	ent = self->target_ent;
+
+	VectorSubtract (ent->s.origin, self->mins, dest);
+	self->moveinfo.state = STATE_TOP;
+	VectorCopy (self->s.origin, self->moveinfo.start_origin);
+	VectorCopy (dest, self->moveinfo.end_origin);
+	Move_Calc (self, dest, train_wait);
+	self->spawnflags |= TRAIN_START_ON;
+}
+
+void func_train_find (edict_t *self)
+{
+	edict_t *ent;
+
+	if (!self->target)
+	{
+		gi.dprintf ("train_find: no target\n");
+		return;
+	}
+	ent = G_PickTarget (self->target);
+	if (!ent)
+	{
+		gi.dprintf ("train_find: target %s not found\n", self->target);
+		return;
+	}
+	self->target = ent->target;
+
+	VectorSubtract (ent->s.origin, self->mins, self->s.origin);
+	gi.linkentity (self);
+
+	// if not triggered, start immediately
+	if (!self->targetname)
+		self->spawnflags |= TRAIN_START_ON;
+
+	if (self->spawnflags & TRAIN_START_ON)
+	{
+		self->nextthink = level.time + FRAMETIME;
+		self->think = train_next;
+		self->activator = self;
+	}
+}
+
+void train_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+
+	if (self->spawnflags & TRAIN_START_ON)
+	{
+		if (!(self->spawnflags & TRAIN_TOGGLE))
+			return;
+		self->spawnflags &= ~TRAIN_START_ON;
+		VectorClear (self->velocity);
+		self->nextthink = 0;
+	}
+	else
+	{
+		if (self->target_ent)
+			train_resume(self);
+		else
+			train_next(self);
+	}
+}
+
+void SP_func_train (edict_t *self)
+{
+	self->movetype = MOVETYPE_PUSH;
+
+	VectorClear (self->s.angles);
+	self->blocked = train_blocked;
+	if (self->spawnflags & TRAIN_BLOCK_STOPS)
+		self->dmg = 0;
+	else
+	{
+		if (!self->dmg)
+			self->dmg = 100;
+	}
+	self->solid = SOLID_BSP;
+	gi.setmodel (self, self->model);
+
+	if (st.noise)
+		self->moveinfo.sound_middle = gi.soundindex  (st.noise);
+
+	if (!self->speed)
+		self->speed = 100;
+
+	self->moveinfo.speed = self->speed;
+	self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed;
+
+	self->use = train_use;
+
+	gi.linkentity (self);
+
+	if (self->target)
+	{
+		// start trains on the second frame, to make sure their targets have had
+		// a chance to spawn
+		self->nextthink = level.time + FRAMETIME;
+		self->think = func_train_find;
+	}
+	else
+	{
+		gi.dprintf ("func_train without a target at %s\n", vtos(self->absmin));
+	}
+}
+
+
+/*QUAKED trigger_elevator (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
+*/
+void trigger_elevator_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t *target;
+
+	if (self->movetarget->nextthink)
+	{
+//		gi.dprintf("elevator busy\n");
+		return;
+	}
+
+	if (!other->pathtarget)
+	{
+		gi.dprintf("elevator used with no pathtarget\n");
+		return;
+	}
+
+	target = G_PickTarget (other->pathtarget);
+	if (!target)
+	{
+		gi.dprintf("elevator used with bad pathtarget: %s\n", other->pathtarget);
+		return;
+	}
+
+	self->movetarget->target_ent = target;
+	train_resume (self->movetarget);
+}
+
+void trigger_elevator_init (edict_t *self)
+{
+	if (!self->target)
+	{
+		gi.dprintf("trigger_elevator has no target\n");
+		return;
+	}
+	self->movetarget = G_PickTarget (self->target);
+	if (!self->movetarget)
+	{
+		gi.dprintf("trigger_elevator unable to find target %s\n", self->target);
+		return;
+	}
+	if (strcmp(self->movetarget->classname, "func_train") != 0)
+	{
+		gi.dprintf("trigger_elevator target %s is not a train\n", self->target);
+		return;
+	}
+
+	self->use = trigger_elevator_use;
+	self->svflags = SVF_NOCLIENT;
+
+}
+
+void SP_trigger_elevator (edict_t *self)
+{
+	self->think = trigger_elevator_init;
+	self->nextthink = level.time + FRAMETIME;
+}
+
+
+/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
+"wait"			base time between triggering all targets, default is 1
+"random"		wait variance, default is 0
+
+so, the basic time between firing is a random time between
+(wait - random) and (wait + random)
+
+"delay"			delay before first firing when turned on, default is 0
+
+"pausetime"		additional delay used only the very first time
+				and only if spawned with START_ON
+
+These can used but not touched.
+*/
+void func_timer_think (edict_t *self)
+{
+	G_UseTargets (self, self->activator);
+	self->nextthink = level.time + self->wait + crandom() * self->random;
+}
+
+void func_timer_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+
+	// if on, turn it off
+	if (self->nextthink)
+	{
+		self->nextthink = 0;
+		return;
+	}
+
+	// turn it on
+	if (self->delay)
+		self->nextthink = level.time + self->delay;
+	else
+		func_timer_think (self);
+}
+
+void SP_func_timer (edict_t *self)
+{
+	if (!self->wait)
+		self->wait = 1.0;
+
+	self->use = func_timer_use;
+	self->think = func_timer_think;
+
+	if (self->random >= self->wait)
+	{
+		self->random = self->wait - FRAMETIME;
+		gi.dprintf("func_timer at %s has random >= wait\n", vtos(self->s.origin));
+	}
+
+	if (self->spawnflags & 1)
+	{
+		self->nextthink = level.time + 1.0 + st.pausetime + self->delay + self->wait + crandom() * self->random;
+		self->activator = self;
+	}
+
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+/*QUAKED func_conveyor (0 .5 .8) ? START_ON TOGGLE
+Conveyors are stationary brushes that move what's on them.
+The brush should be have a surface with at least one current content enabled.
+speed	default 100
+*/
+
+void func_conveyor_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->spawnflags & 1)
+	{
+		self->speed = 0;
+		self->spawnflags &= ~1;
+	}
+	else
+	{
+		self->speed = self->count;
+		self->spawnflags |= 1;
+	}
+
+	if (!(self->spawnflags & 2))
+		self->count = 0;
+}
+
+void SP_func_conveyor (edict_t *self)
+{
+	if (!self->speed)
+		self->speed = 100;
+
+	if (!(self->spawnflags & 1))
+	{
+		self->count = self->speed;
+		self->speed = 0;
+	}
+
+	self->use = func_conveyor_use;
+
+	gi.setmodel (self, self->model);
+	self->solid = SOLID_BSP;
+	gi.linkentity (self);
+}
+
+
+/*QUAKED func_door_secret (0 .5 .8) ? always_shoot 1st_left 1st_down
+A secret door.  Slide back and then to the side.
+
+open_once		doors never closes
+1st_left		1st move is left of arrow
+1st_down		1st move is down from arrow
+always_shoot	door is shootebale even if targeted
+
+"angle"		determines the direction
+"dmg"		damage to inflic when blocked (default 2)
+"wait"		how long to hold in the open position (default 5, -1 means hold)
+*/
+
+#define SECRET_ALWAYS_SHOOT	1
+#define SECRET_1ST_LEFT		2
+#define SECRET_1ST_DOWN		4
+
+void door_secret_move1 (edict_t *self);
+void door_secret_move2 (edict_t *self);
+void door_secret_move3 (edict_t *self);
+void door_secret_move4 (edict_t *self);
+void door_secret_move5 (edict_t *self);
+void door_secret_move6 (edict_t *self);
+void door_secret_done (edict_t *self);
+
+void door_secret_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	// make sure we're not already moving
+	if (!VectorCompare(self->s.origin, vec3_origin))
+		return;
+
+	Move_Calc (self, self->pos1, door_secret_move1);
+	door_use_areaportals (self, true);
+}
+
+void door_secret_move1 (edict_t *self)
+{
+	self->nextthink = level.time + 1.0;
+	self->think = door_secret_move2;
+}
+
+void door_secret_move2 (edict_t *self)
+{
+	Move_Calc (self, self->pos2, door_secret_move3);
+}
+
+void door_secret_move3 (edict_t *self)
+{
+	if (self->wait == -1)
+		return;
+	self->nextthink = level.time + self->wait;
+	self->think = door_secret_move4;
+}
+
+void door_secret_move4 (edict_t *self)
+{
+	Move_Calc (self, self->pos1, door_secret_move5);
+}
+
+void door_secret_move5 (edict_t *self)
+{
+	self->nextthink = level.time + 1.0;
+	self->think = door_secret_move6;
+}
+
+void door_secret_move6 (edict_t *self)
+{
+	Move_Calc (self, vec3_origin, door_secret_done);
+}
+
+void door_secret_done (edict_t *self)
+{
+	if (!(self->targetname) || (self->spawnflags & SECRET_ALWAYS_SHOOT))
+	{
+		self->health = 0;
+		self->takedamage = DAMAGE_YES;
+	}
+	door_use_areaportals (self, false);
+}
+
+void door_secret_blocked  (edict_t *self, edict_t *other)
+{
+	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
+	{
+		// give it a chance to go away on it's own terms (like gibs)
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+		// if it's still there, nuke it
+		if (other)
+			BecomeExplosion1 (other);
+		return;
+	}
+
+	if (level.time < self->touch_debounce_time)
+		return;
+	self->touch_debounce_time = level.time + 0.5;
+
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void door_secret_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	self->takedamage = DAMAGE_NO;
+	door_secret_use (self, attacker, attacker);
+}
+
+void SP_func_door_secret (edict_t *ent)
+{
+	vec3_t	forward, right, up;
+	float	side;
+	float	width;
+	float	length;
+
+	ent->moveinfo.sound_start = gi.soundindex  ("doors/dr1_strt.wav");
+	ent->moveinfo.sound_middle = gi.soundindex  ("doors/dr1_mid.wav");
+	ent->moveinfo.sound_end = gi.soundindex  ("doors/dr1_end.wav");
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	gi.setmodel (ent, ent->model);
+
+	ent->blocked = door_secret_blocked;
+	ent->use = door_secret_use;
+
+	if (!(ent->targetname) || (ent->spawnflags & SECRET_ALWAYS_SHOOT))
+	{
+		ent->health = 0;
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_secret_die;
+	}
+
+	if (!ent->dmg)
+		ent->dmg = 2;
+
+	if (!ent->wait)
+		ent->wait = 5;
+
+	ent->moveinfo.accel =
+	ent->moveinfo.decel =
+	ent->moveinfo.speed = 50;
+
+	// calculate positions
+	AngleVectors (ent->s.angles, forward, right, up);
+	VectorClear (ent->s.angles);
+	side = 1.0 - (ent->spawnflags & SECRET_1ST_LEFT);
+	if (ent->spawnflags & SECRET_1ST_DOWN)
+		width = fabs(DotProduct(up, ent->size));
+	else
+		width = fabs(DotProduct(right, ent->size));
+	length = fabs(DotProduct(forward, ent->size));
+	if (ent->spawnflags & SECRET_1ST_DOWN)
+		VectorMA (ent->s.origin, -1 * width, up, ent->pos1);
+	else
+		VectorMA (ent->s.origin, side * width, right, ent->pos1);
+	VectorMA (ent->pos1, length, forward, ent->pos2);
+
+	if (ent->health)
+	{
+		ent->takedamage = DAMAGE_YES;
+		ent->die = door_killed;
+		ent->max_health = ent->health;
+	}
+	else if (ent->targetname && ent->message)
+	{
+		gi.soundindex ("misc/talk.wav");
+		ent->touch = door_touch;
+	}
+	
+	ent->classname = "func_door";
+
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED func_killbox (1 0 0) ?
+Kills everything inside when fired, irrespective of protection.
+*/
+void use_killbox (edict_t *self, edict_t *other, edict_t *activator)
+{
+	KillBox (self);
+}
+
+void SP_func_killbox (edict_t *ent)
+{
+	gi.setmodel (ent, ent->model);
+	ent->use = use_killbox;
+	ent->svflags = SVF_NOCLIENT;
+}
+
--- /dev/null
+++ b/game/g_items.c
@@ -1,0 +1,2216 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+qboolean	Pickup_Weapon (edict_t *ent, edict_t *other);
+void		Use_Weapon (edict_t *ent, gitem_t *inv);
+void		Drop_Weapon (edict_t *ent, gitem_t *inv);
+
+void Weapon_Blaster (edict_t *ent);
+void Weapon_Shotgun (edict_t *ent);
+void Weapon_SuperShotgun (edict_t *ent);
+void Weapon_Machinegun (edict_t *ent);
+void Weapon_Chaingun (edict_t *ent);
+void Weapon_HyperBlaster (edict_t *ent);
+void Weapon_RocketLauncher (edict_t *ent);
+void Weapon_Grenade (edict_t *ent);
+void Weapon_GrenadeLauncher (edict_t *ent);
+void Weapon_Railgun (edict_t *ent);
+void Weapon_BFG (edict_t *ent);
+
+gitem_armor_t jacketarmor_info	= { 25,  50, .30, .00, ARMOR_JACKET};
+gitem_armor_t combatarmor_info	= { 50, 100, .60, .30, ARMOR_COMBAT};
+gitem_armor_t bodyarmor_info	= {100, 200, .80, .60, ARMOR_BODY};
+
+static int	jacket_armor_index;
+static int	combat_armor_index;
+static int	body_armor_index;
+static int	power_screen_index;
+static int	power_shield_index;
+
+#define HEALTH_IGNORE_MAX	1
+#define HEALTH_TIMED		2
+
+void Use_Quad (edict_t *ent, gitem_t *item);
+static int	quad_drop_timeout_hack;
+
+//======================================================================
+
+/*
+===============
+GetItemByIndex
+===============
+*/
+gitem_t	*GetItemByIndex (int index)
+{
+	if (index == 0 || index >= game.num_items)
+		return NULL;
+
+	return &itemlist[index];
+}
+
+
+/*
+===============
+FindItemByClassname
+
+===============
+*/
+gitem_t	*FindItemByClassname (char *classname)
+{
+	int		i;
+	gitem_t	*it;
+
+	it = itemlist;
+	for (i=0 ; i<game.num_items ; i++, it++)
+	{
+		if (!it->classname)
+			continue;
+		if (!Q_stricmp(it->classname, classname))
+			return it;
+	}
+
+	return NULL;
+}
+
+/*
+===============
+FindItem
+
+===============
+*/
+gitem_t	*FindItem (char *pickup_name)
+{
+	int		i;
+	gitem_t	*it;
+
+	it = itemlist;
+	for (i=0 ; i<game.num_items ; i++, it++)
+	{
+		if (!it->pickup_name)
+			continue;
+		if (!Q_stricmp(it->pickup_name, pickup_name))
+			return it;
+	}
+
+	return NULL;
+}
+
+//======================================================================
+
+void DoRespawn (edict_t *ent)
+{
+	if (ent->team)
+	{
+		edict_t	*master;
+		int	count;
+		int choice;
+
+		master = ent->teammaster;
+
+		for (count = 0, ent = master; ent; ent = ent->chain, count++)
+			;
+
+		choice = rand() % count;
+
+		for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
+			;
+	}
+
+	ent->svflags &= ~SVF_NOCLIENT;
+	ent->solid = SOLID_TRIGGER;
+	gi.linkentity (ent);
+
+	// send an effect
+	ent->s.event = EV_ITEM_RESPAWN;
+}
+
+void SetRespawn (edict_t *ent, float delay)
+{
+	ent->flags |= FL_RESPAWN;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->solid = SOLID_NOT;
+	ent->nextthink = level.time + delay;
+	ent->think = DoRespawn;
+	gi.linkentity (ent);
+}
+
+
+//======================================================================
+
+qboolean Pickup_Powerup (edict_t *ent, edict_t *other)
+{
+	int		quantity;
+
+	quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)];
+	if ((skill->value == 1 && quantity >= 2) || (skill->value >= 2 && quantity >= 1))
+		return false;
+
+	if ((coop->value) && (ent->item->flags & IT_STAY_COOP) && (quantity > 0))
+		return false;
+
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+
+	if (deathmatch->value)
+	{
+		if (!(ent->spawnflags & DROPPED_ITEM) )
+			SetRespawn (ent, ent->item->quantity);
+		if (((int)dmflags->value & DF_INSTANT_ITEMS) || ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM)))
+		{
+			if ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM))
+				quad_drop_timeout_hack = (ent->nextthink - level.time) / FRAMETIME;
+			ent->item->use (other, ent->item);
+		}
+	}
+
+	return true;
+}
+
+void Drop_General (edict_t *ent, gitem_t *item)
+{
+	Drop_Item (ent, item);
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+}
+
+
+//======================================================================
+
+qboolean Pickup_Adrenaline (edict_t *ent, edict_t *other)
+{
+	if (!deathmatch->value)
+		other->max_health += 1;
+
+	if (other->health < other->max_health)
+		other->health = other->max_health;
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+qboolean Pickup_AncientHead (edict_t *ent, edict_t *other)
+{
+	other->max_health += 2;
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+qboolean Pickup_Bandolier (edict_t *ent, edict_t *other)
+{
+	gitem_t	*item;
+	int		index;
+
+	if (other->client->pers.max_bullets < 250)
+		other->client->pers.max_bullets = 250;
+	if (other->client->pers.max_shells < 150)
+		other->client->pers.max_shells = 150;
+	if (other->client->pers.max_cells < 250)
+		other->client->pers.max_cells = 250;
+	if (other->client->pers.max_slugs < 75)
+		other->client->pers.max_slugs = 75;
+
+	item = FindItem("Bullets");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_bullets)
+			other->client->pers.inventory[index] = other->client->pers.max_bullets;
+	}
+
+	item = FindItem("Shells");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_shells)
+			other->client->pers.inventory[index] = other->client->pers.max_shells;
+	}
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+qboolean Pickup_Pack (edict_t *ent, edict_t *other)
+{
+	gitem_t	*item;
+	int		index;
+
+	if (other->client->pers.max_bullets < 300)
+		other->client->pers.max_bullets = 300;
+	if (other->client->pers.max_shells < 200)
+		other->client->pers.max_shells = 200;
+	if (other->client->pers.max_rockets < 100)
+		other->client->pers.max_rockets = 100;
+	if (other->client->pers.max_grenades < 100)
+		other->client->pers.max_grenades = 100;
+	if (other->client->pers.max_cells < 300)
+		other->client->pers.max_cells = 300;
+	if (other->client->pers.max_slugs < 100)
+		other->client->pers.max_slugs = 100;
+
+	item = FindItem("Bullets");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_bullets)
+			other->client->pers.inventory[index] = other->client->pers.max_bullets;
+	}
+
+	item = FindItem("Shells");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_shells)
+			other->client->pers.inventory[index] = other->client->pers.max_shells;
+	}
+
+	item = FindItem("Cells");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_cells)
+			other->client->pers.inventory[index] = other->client->pers.max_cells;
+	}
+
+	item = FindItem("Grenades");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_grenades)
+			other->client->pers.inventory[index] = other->client->pers.max_grenades;
+	}
+
+	item = FindItem("Rockets");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_rockets)
+			other->client->pers.inventory[index] = other->client->pers.max_rockets;
+	}
+
+	item = FindItem("Slugs");
+	if (item)
+	{
+		index = ITEM_INDEX(item);
+		other->client->pers.inventory[index] += item->quantity;
+		if (other->client->pers.inventory[index] > other->client->pers.max_slugs)
+			other->client->pers.inventory[index] = other->client->pers.max_slugs;
+	}
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, ent->item->quantity);
+
+	return true;
+}
+
+//======================================================================
+
+void Use_Quad (edict_t *ent, gitem_t *item)
+{
+	int		timeout;
+
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (quad_drop_timeout_hack)
+	{
+		timeout = quad_drop_timeout_hack;
+		quad_drop_timeout_hack = 0;
+	}
+	else
+	{
+		timeout = 300;
+	}
+
+	if (ent->client->quad_framenum > level.framenum)
+		ent->client->quad_framenum += timeout;
+	else
+		ent->client->quad_framenum = level.framenum + timeout;
+
+	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void Use_Breather (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (ent->client->breather_framenum > level.framenum)
+		ent->client->breather_framenum += 300;
+	else
+		ent->client->breather_framenum = level.framenum + 300;
+
+//	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void Use_Envirosuit (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (ent->client->enviro_framenum > level.framenum)
+		ent->client->enviro_framenum += 300;
+	else
+		ent->client->enviro_framenum = level.framenum + 300;
+
+//	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void	Use_Invulnerability (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+
+	if (ent->client->invincible_framenum > level.framenum)
+		ent->client->invincible_framenum += 300;
+	else
+		ent->client->invincible_framenum = level.framenum + 300;
+
+	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+void	Use_Silencer (edict_t *ent, gitem_t *item)
+{
+	ent->client->pers.inventory[ITEM_INDEX(item)]--;
+	ValidateSelectedItem (ent);
+	ent->client->silencer_shots += 30;
+
+//	gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+}
+
+//======================================================================
+
+qboolean Pickup_Key (edict_t *ent, edict_t *other)
+{
+	if (coop->value)
+	{
+		if (strcmp(ent->classname, "key_power_cube") == 0)
+		{
+			if (other->client->pers.power_cubes & ((ent->spawnflags & 0x0000ff00)>> 8))
+				return false;
+			other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+			other->client->pers.power_cubes |= ((ent->spawnflags & 0x0000ff00) >> 8);
+		}
+		else
+		{
+			if (other->client->pers.inventory[ITEM_INDEX(ent->item)])
+				return false;
+			other->client->pers.inventory[ITEM_INDEX(ent->item)] = 1;
+		}
+		return true;
+	}
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+	return true;
+}
+
+//======================================================================
+
+qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count)
+{
+	int			index;
+	int			max;
+
+	if (!ent->client)
+		return false;
+
+	if (item->tag == AMMO_BULLETS)
+		max = ent->client->pers.max_bullets;
+	else if (item->tag == AMMO_SHELLS)
+		max = ent->client->pers.max_shells;
+	else if (item->tag == AMMO_ROCKETS)
+		max = ent->client->pers.max_rockets;
+	else if (item->tag == AMMO_GRENADES)
+		max = ent->client->pers.max_grenades;
+	else if (item->tag == AMMO_CELLS)
+		max = ent->client->pers.max_cells;
+	else if (item->tag == AMMO_SLUGS)
+		max = ent->client->pers.max_slugs;
+	else
+		return false;
+
+	index = ITEM_INDEX(item);
+
+	if (ent->client->pers.inventory[index] == max)
+		return false;
+
+	ent->client->pers.inventory[index] += count;
+
+	if (ent->client->pers.inventory[index] > max)
+		ent->client->pers.inventory[index] = max;
+
+	return true;
+}
+
+qboolean Pickup_Ammo (edict_t *ent, edict_t *other)
+{
+	int			oldcount;
+	int			count;
+	qboolean	weapon;
+
+	weapon = (ent->item->flags & IT_WEAPON);
+	if ( (weapon) && ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		count = 1000;
+	else if (ent->count)
+		count = ent->count;
+	else
+		count = ent->item->quantity;
+
+	oldcount = other->client->pers.inventory[ITEM_INDEX(ent->item)];
+
+	if (!Add_Ammo (other, ent->item, count))
+		return false;
+
+	if (weapon && !oldcount)
+	{
+		if (other->client->pers.weapon != ent->item && ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
+			other->client->newweapon = ent->item;
+	}
+
+	if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) && (deathmatch->value))
+		SetRespawn (ent, 30);
+	return true;
+}
+
+void Drop_Ammo (edict_t *ent, gitem_t *item)
+{
+	edict_t	*dropped;
+	int		index;
+
+	index = ITEM_INDEX(item);
+	dropped = Drop_Item (ent, item);
+	if (ent->client->pers.inventory[index] >= item->quantity)
+		dropped->count = item->quantity;
+	else
+		dropped->count = ent->client->pers.inventory[index];
+
+	if (ent->client->pers.weapon && 
+		ent->client->pers.weapon->tag == AMMO_GRENADES &&
+		item->tag == AMMO_GRENADES &&
+		ent->client->pers.inventory[index] - dropped->count <= 0) {
+		gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
+		G_FreeEdict(dropped);
+		return;
+	}
+
+	ent->client->pers.inventory[index] -= dropped->count;
+	ValidateSelectedItem (ent);
+}
+
+
+//======================================================================
+
+void MegaHealth_think (edict_t *self)
+{
+	if (self->owner->health > self->owner->max_health)
+	{
+		self->nextthink = level.time + 1;
+		self->owner->health -= 1;
+		return;
+	}
+
+	if (!(self->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (self, 20);
+	else
+		G_FreeEdict (self);
+}
+
+qboolean Pickup_Health (edict_t *ent, edict_t *other)
+{
+	if (!(ent->style & HEALTH_IGNORE_MAX))
+		if (other->health >= other->max_health)
+			return false;
+
+	other->health += ent->count;
+
+	if (!(ent->style & HEALTH_IGNORE_MAX))
+	{
+		if (other->health > other->max_health)
+			other->health = other->max_health;
+	}
+
+	if (ent->style & HEALTH_TIMED)
+	{
+		ent->think = MegaHealth_think;
+		ent->nextthink = level.time + 5;
+		ent->owner = other;
+		ent->flags |= FL_RESPAWN;
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+	}
+	else
+	{
+		if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+			SetRespawn (ent, 30);
+	}
+
+	return true;
+}
+
+//======================================================================
+
+int ArmorIndex (edict_t *ent)
+{
+	if (!ent->client)
+		return 0;
+
+	if (ent->client->pers.inventory[jacket_armor_index] > 0)
+		return jacket_armor_index;
+
+	if (ent->client->pers.inventory[combat_armor_index] > 0)
+		return combat_armor_index;
+
+	if (ent->client->pers.inventory[body_armor_index] > 0)
+		return body_armor_index;
+
+	return 0;
+}
+
+qboolean Pickup_Armor (edict_t *ent, edict_t *other)
+{
+	int				old_armor_index;
+	gitem_armor_t	*oldinfo;
+	gitem_armor_t	*newinfo;
+	int				newcount;
+	float			salvage;
+	int				salvagecount;
+
+	// get info on new armor
+	newinfo = (gitem_armor_t *)ent->item->info;
+
+	old_armor_index = ArmorIndex (other);
+
+	// handle armor shards specially
+	if (ent->item->tag == ARMOR_SHARD)
+	{
+		if (!old_armor_index)
+			other->client->pers.inventory[jacket_armor_index] = 2;
+		else
+			other->client->pers.inventory[old_armor_index] += 2;
+	}
+
+	// if player has no armor, just use it
+	else if (!old_armor_index)
+	{
+		other->client->pers.inventory[ITEM_INDEX(ent->item)] = newinfo->base_count;
+	}
+
+	// use the better armor
+	else
+	{
+		// get info on old armor
+		if (old_armor_index == jacket_armor_index)
+			oldinfo = &jacketarmor_info;
+		else if (old_armor_index == combat_armor_index)
+			oldinfo = &combatarmor_info;
+		else // (old_armor_index == body_armor_index)
+			oldinfo = &bodyarmor_info;
+
+		if (newinfo->normal_protection > oldinfo->normal_protection)
+		{
+			// calc new armor values
+			salvage = oldinfo->normal_protection / newinfo->normal_protection;
+			salvagecount = salvage * other->client->pers.inventory[old_armor_index];
+			newcount = newinfo->base_count + salvagecount;
+			if (newcount > newinfo->max_count)
+				newcount = newinfo->max_count;
+
+			// zero count of old armor so it goes away
+			other->client->pers.inventory[old_armor_index] = 0;
+
+			// change armor to new item with computed value
+			other->client->pers.inventory[ITEM_INDEX(ent->item)] = newcount;
+		}
+		else
+		{
+			// calc new armor values
+			salvage = newinfo->normal_protection / oldinfo->normal_protection;
+			salvagecount = salvage * newinfo->base_count;
+			newcount = other->client->pers.inventory[old_armor_index] + salvagecount;
+			if (newcount > oldinfo->max_count)
+				newcount = oldinfo->max_count;
+
+			// if we're already maxed out then we don't need the new armor
+			if (other->client->pers.inventory[old_armor_index] >= newcount)
+				return false;
+
+			// update current armor value
+			other->client->pers.inventory[old_armor_index] = newcount;
+		}
+	}
+
+	if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
+		SetRespawn (ent, 20);
+
+	return true;
+}
+
+//======================================================================
+
+int PowerArmorType (edict_t *ent)
+{
+	if (!ent->client)
+		return POWER_ARMOR_NONE;
+
+	if (!(ent->flags & FL_POWER_ARMOR))
+		return POWER_ARMOR_NONE;
+
+	if (ent->client->pers.inventory[power_shield_index] > 0)
+		return POWER_ARMOR_SHIELD;
+
+	if (ent->client->pers.inventory[power_screen_index] > 0)
+		return POWER_ARMOR_SCREEN;
+
+	return POWER_ARMOR_NONE;
+}
+
+void Use_PowerArmor (edict_t *ent, gitem_t *item)
+{
+	int		index;
+
+	if (ent->flags & FL_POWER_ARMOR)
+	{
+		ent->flags &= ~FL_POWER_ARMOR;
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		index = ITEM_INDEX(FindItem("cells"));
+		if (!ent->client->pers.inventory[index])
+		{
+			gi.cprintf (ent, PRINT_HIGH, "No cells for power armor.\n");
+			return;
+		}
+		ent->flags |= FL_POWER_ARMOR;
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_NORM, 0);
+	}
+}
+
+qboolean Pickup_PowerArmor (edict_t *ent, edict_t *other)
+{
+	int		quantity;
+
+	quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)];
+
+	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
+
+	if (deathmatch->value)
+	{
+		if (!(ent->spawnflags & DROPPED_ITEM) )
+			SetRespawn (ent, ent->item->quantity);
+		// auto-use for DM only if we didn't already have one
+		if (!quantity)
+			ent->item->use (other, ent->item);
+	}
+
+	return true;
+}
+
+void Drop_PowerArmor (edict_t *ent, gitem_t *item)
+{
+	if ((ent->flags & FL_POWER_ARMOR) && (ent->client->pers.inventory[ITEM_INDEX(item)] == 1))
+		Use_PowerArmor (ent, item);
+	Drop_General (ent, item);
+}
+
+//======================================================================
+
+/*
+===============
+Touch_Item
+===============
+*/
+void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	qboolean	taken;
+
+	if (!other->client)
+		return;
+	if (other->health < 1)
+		return;		// dead people can't pickup
+	if (!ent->item->pickup)
+		return;		// not a grabbable item?
+
+	taken = ent->item->pickup(ent, other);
+
+	if (taken)
+	{
+		// flash the screen
+		other->client->bonus_alpha = 0.25;	
+
+		// show icon and name on status bar
+		other->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(ent->item->icon);
+		other->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(ent->item);
+		other->client->pickup_msg_time = level.time + 3.0;
+
+		// change selected item
+		if (ent->item->use)
+			other->client->pers.selected_item = other->client->ps.stats[STAT_SELECTED_ITEM] = ITEM_INDEX(ent->item);
+
+		if (ent->item->pickup == Pickup_Health)
+		{
+			if (ent->count == 2)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/s_health.wav"), 1, ATTN_NORM, 0);
+			else if (ent->count == 10)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/n_health.wav"), 1, ATTN_NORM, 0);
+			else if (ent->count == 25)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/l_health.wav"), 1, ATTN_NORM, 0);
+			else // (ent->count == 100)
+				gi.sound(other, CHAN_ITEM, gi.soundindex("items/m_health.wav"), 1, ATTN_NORM, 0);
+		}
+		else if (ent->item->pickup_sound)
+		{
+			gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0);
+		}
+	}
+
+	if (!(ent->spawnflags & ITEM_TARGETS_USED))
+	{
+		G_UseTargets (ent, other);
+		ent->spawnflags |= ITEM_TARGETS_USED;
+	}
+
+	if (!taken)
+		return;
+
+	if (!((coop->value) &&  (ent->item->flags & IT_STAY_COOP)) || (ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)))
+	{
+		if (ent->flags & FL_RESPAWN)
+			ent->flags &= ~FL_RESPAWN;
+		else
+			G_FreeEdict (ent);
+	}
+}
+
+//======================================================================
+
+static void drop_temp_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other == ent->owner)
+		return;
+
+	Touch_Item (ent, other, plane, surf);
+}
+
+static void drop_make_touchable (edict_t *ent)
+{
+	ent->touch = Touch_Item;
+	if (deathmatch->value)
+	{
+		ent->nextthink = level.time + 29;
+		ent->think = G_FreeEdict;
+	}
+}
+
+edict_t *Drop_Item (edict_t *ent, gitem_t *item)
+{
+	edict_t	*dropped;
+	vec3_t	forward, right;
+	vec3_t	offset;
+
+	dropped = G_Spawn();
+
+	dropped->classname = item->classname;
+	dropped->item = item;
+	dropped->spawnflags = DROPPED_ITEM;
+	dropped->s.effects = item->world_model_flags;
+	dropped->s.renderfx = RF_GLOW;
+	VectorSet (dropped->mins, -15, -15, -15);
+	VectorSet (dropped->maxs, 15, 15, 15);
+	gi.setmodel (dropped, dropped->item->world_model);
+	dropped->solid = SOLID_TRIGGER;
+	dropped->movetype = MOVETYPE_TOSS;  
+	dropped->touch = drop_temp_touch;
+	dropped->owner = ent;
+
+	if (ent->client)
+	{
+		trace_t	trace;
+
+		AngleVectors (ent->client->v_angle, forward, right, NULL);
+		VectorSet(offset, 24, 0, -16);
+		G_ProjectSource (ent->s.origin, offset, forward, right, dropped->s.origin);
+		trace = gi.trace (ent->s.origin, dropped->mins, dropped->maxs,
+			dropped->s.origin, ent, CONTENTS_SOLID);
+		VectorCopy (trace.endpos, dropped->s.origin);
+	}
+	else
+	{
+		AngleVectors (ent->s.angles, forward, right, NULL);
+		VectorCopy (ent->s.origin, dropped->s.origin);
+	}
+
+	VectorScale (forward, 100, dropped->velocity);
+	dropped->velocity[2] = 300;
+
+	dropped->think = drop_make_touchable;
+	dropped->nextthink = level.time + 1;
+
+	gi.linkentity (dropped);
+
+	return dropped;
+}
+
+void Use_Item (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	ent->svflags &= ~SVF_NOCLIENT;
+	ent->use = NULL;
+
+	if (ent->spawnflags & ITEM_NO_TOUCH)
+	{
+		ent->solid = SOLID_BBOX;
+		ent->touch = NULL;
+	}
+	else
+	{
+		ent->solid = SOLID_TRIGGER;
+		ent->touch = Touch_Item;
+	}
+
+	gi.linkentity (ent);
+}
+
+//======================================================================
+
+/*
+================
+droptofloor
+================
+*/
+void droptofloor (edict_t *ent)
+{
+	trace_t		tr;
+	vec3_t		dest;
+	float		*v;
+
+	v = tv(-15,-15,-15);
+	VectorCopy (v, ent->mins);
+	v = tv(15,15,15);
+	VectorCopy (v, ent->maxs);
+
+	if (ent->model)
+		gi.setmodel (ent, ent->model);
+	else
+		gi.setmodel (ent, ent->item->world_model);
+	ent->solid = SOLID_TRIGGER;
+	ent->movetype = MOVETYPE_TOSS;  
+	ent->touch = Touch_Item;
+
+	v = tv(0,0,-128);
+	VectorAdd (ent->s.origin, v, dest);
+
+	tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
+	if (tr.startsolid)
+	{
+		gi.dprintf ("droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	VectorCopy (tr.endpos, ent->s.origin);
+
+	if (ent->team)
+	{
+		ent->flags &= ~FL_TEAMSLAVE;
+		ent->chain = ent->teamchain;
+		ent->teamchain = NULL;
+
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+		if (ent == ent->teammaster)
+		{
+			ent->nextthink = level.time + FRAMETIME;
+			ent->think = DoRespawn;
+		}
+	}
+
+	if (ent->spawnflags & ITEM_NO_TOUCH)
+	{
+		ent->solid = SOLID_BBOX;
+		ent->touch = NULL;
+		ent->s.effects &= ~EF_ROTATE;
+		ent->s.renderfx &= ~RF_GLOW;
+	}
+
+	if (ent->spawnflags & ITEM_TRIGGER_SPAWN)
+	{
+		ent->svflags |= SVF_NOCLIENT;
+		ent->solid = SOLID_NOT;
+		ent->use = Use_Item;
+	}
+
+	gi.linkentity (ent);
+}
+
+
+/*
+===============
+PrecacheItem
+
+Precaches all data needed for a given item.
+This will be called for each item spawned in a level,
+and for each item in each client's inventory.
+===============
+*/
+void PrecacheItem (gitem_t *it)
+{
+	char	*s, *start;
+	char	data[MAX_QPATH];
+	int		len;
+	gitem_t	*ammo;
+
+	if (!it)
+		return;
+
+	if (it->pickup_sound)
+		gi.soundindex (it->pickup_sound);
+	if (it->world_model)
+		gi.modelindex (it->world_model);
+	if (it->view_model)
+		gi.modelindex (it->view_model);
+	if (it->icon)
+		gi.imageindex (it->icon);
+
+	// parse everything for its ammo
+	if (it->ammo && it->ammo[0])
+	{
+		ammo = FindItem (it->ammo);
+		if (ammo != it)
+			PrecacheItem (ammo);
+	}
+
+	// parse the space seperated precache string for other items
+	s = it->precaches;
+	if (!s || !s[0])
+		return;
+
+	while (*s)
+	{
+		start = s;
+		while (*s && *s != ' ')
+			s++;
+
+		len = s-start;
+		if (len >= MAX_QPATH || len < 5)
+			gi.error ("PrecacheItem: %s has bad precache string", it->classname);
+		memcpy (data, start, len);
+		data[len] = 0;
+		if (*s)
+			s++;
+
+		// determine type based on extension
+		if (!strcmp(data+len-3, "md2"))
+			gi.modelindex (data);
+		else if (!strcmp(data+len-3, "sp2"))
+			gi.modelindex (data);
+		else if (!strcmp(data+len-3, "wav"))
+			gi.soundindex (data);
+		if (!strcmp(data+len-3, "pcx"))
+			gi.imageindex (data);
+	}
+}
+
+/*
+============
+SpawnItem
+
+Sets the clipping size and plants the object on the floor.
+
+Items can't be immediately dropped to floor, because they might
+be on an entity that hasn't spawned yet.
+============
+*/
+void SpawnItem (edict_t *ent, gitem_t *item)
+{
+	PrecacheItem (item);
+
+	if (ent->spawnflags)
+	{
+		if (strcmp(ent->classname, "key_power_cube") != 0)
+		{
+			ent->spawnflags = 0;
+			gi.dprintf("%s at %s has invalid spawnflags set\n", ent->classname, vtos(ent->s.origin));
+		}
+	}
+
+	// some items will be prevented in deathmatch
+	if (deathmatch->value)
+	{
+		if ( (int)dmflags->value & DF_NO_ARMOR )
+		{
+			if (item->pickup == Pickup_Armor || item->pickup == Pickup_PowerArmor)
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+		if ( (int)dmflags->value & DF_NO_ITEMS )
+		{
+			if (item->pickup == Pickup_Powerup)
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+		if ( (int)dmflags->value & DF_NO_HEALTH )
+		{
+			if (item->pickup == Pickup_Health || item->pickup == Pickup_Adrenaline || item->pickup == Pickup_AncientHead)
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+		if ( (int)dmflags->value & DF_INFINITE_AMMO )
+		{
+			if ( (item->flags == IT_AMMO) || (strcmp(ent->classname, "weapon_bfg") == 0) )
+			{
+				G_FreeEdict (ent);
+				return;
+			}
+		}
+	}
+
+	if (coop->value && (strcmp(ent->classname, "key_power_cube") == 0))
+	{
+		ent->spawnflags |= (1 << (8 + level.power_cubes));
+		level.power_cubes++;
+	}
+
+	// don't let them drop items that stay in a coop game
+	if ((coop->value) && (item->flags & IT_STAY_COOP))
+	{
+		item->drop = NULL;
+	}
+
+	ent->item = item;
+	ent->nextthink = level.time + 2 * FRAMETIME;    // items start after other solids
+	ent->think = droptofloor;
+	ent->s.effects = item->world_model_flags;
+	ent->s.renderfx = RF_GLOW;
+	if (ent->model)
+		gi.modelindex (ent->model);
+}
+
+//======================================================================
+
+gitem_t	itemlist[] = 
+{
+	{
+		NULL
+	},	// leave index 0 alone
+
+	//
+	// ARMOR
+	//
+
+/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_body", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar1_pkup.wav",
+		"models/items/armor/body/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_bodyarmor",
+/* pickup */	"Body Armor",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		&bodyarmor_info,
+		ARMOR_BODY,
+/* precache */ ""
+	},
+
+/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_combat", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar1_pkup.wav",
+		"models/items/armor/combat/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_combatarmor",
+/* pickup */	"Combat Armor",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		&combatarmor_info,
+		ARMOR_COMBAT,
+/* precache */ ""
+	},
+
+/*QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_jacket", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar1_pkup.wav",
+		"models/items/armor/jacket/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_jacketarmor",
+/* pickup */	"Jacket Armor",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		&jacketarmor_info,
+		ARMOR_JACKET,
+/* precache */ ""
+	},
+
+/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_armor_shard", 
+		Pickup_Armor,
+		NULL,
+		NULL,
+		NULL,
+		"misc/ar2_pkup.wav",
+		"models/items/armor/shard/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_jacketarmor",
+/* pickup */	"Armor Shard",
+/* width */		3,
+		0,
+		NULL,
+		IT_ARMOR,
+		0,
+		NULL,
+		ARMOR_SHARD,
+/* precache */ ""
+	},
+
+
+/*QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_power_screen", 
+		Pickup_PowerArmor,
+		Use_PowerArmor,
+		Drop_PowerArmor,
+		NULL,
+		"misc/ar3_pkup.wav",
+		"models/items/armor/screen/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_powerscreen",
+/* pickup */	"Power Screen",
+/* width */		0,
+		60,
+		NULL,
+		IT_ARMOR,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_power_shield",
+		Pickup_PowerArmor,
+		Use_PowerArmor,
+		Drop_PowerArmor,
+		NULL,
+		"misc/ar3_pkup.wav",
+		"models/items/armor/shield/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_powershield",
+/* pickup */	"Power Shield",
+/* width */		0,
+		60,
+		NULL,
+		IT_ARMOR,
+		0,
+		NULL,
+		0,
+/* precache */ "misc/power2.wav misc/power1.wav"
+	},
+
+
+	//
+	// WEAPONS 
+	//
+
+/* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
+always owned, never in the world
+*/
+	{
+		"weapon_blaster", 
+		NULL,
+		Use_Weapon,
+		NULL,
+		Weapon_Blaster,
+		"misc/w_pkup.wav",
+		NULL, 0,
+		"models/weapons/v_blast/tris.md2",
+/* icon */		"w_blaster",
+/* pickup */	"Blaster",
+		0,
+		0,
+		NULL,
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_BLASTER,
+		NULL,
+		0,
+/* precache */ "weapons/blastf1a.wav misc/lasfly.wav"
+	},
+
+/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_shotgun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Shotgun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_shotg/tris.md2", EF_ROTATE,
+		"models/weapons/v_shotg/tris.md2",
+/* icon */		"w_shotgun",
+/* pickup */	"Shotgun",
+		0,
+		1,
+		"Shells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_SHOTGUN,
+		NULL,
+		0,
+/* precache */ "weapons/shotgf1b.wav weapons/shotgr1b.wav"
+	},
+
+/*QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_supershotgun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_SuperShotgun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_shotg2/tris.md2", EF_ROTATE,
+		"models/weapons/v_shotg2/tris.md2",
+/* icon */		"w_sshotgun",
+/* pickup */	"Super Shotgun",
+		0,
+		2,
+		"Shells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_SUPERSHOTGUN,
+		NULL,
+		0,
+/* precache */ "weapons/sshotf1b.wav"
+	},
+
+/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_machinegun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Machinegun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_machn/tris.md2", EF_ROTATE,
+		"models/weapons/v_machn/tris.md2",
+/* icon */		"w_machinegun",
+/* pickup */	"Machinegun",
+		0,
+		1,
+		"Bullets",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_MACHINEGUN,
+		NULL,
+		0,
+/* precache */ "weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav"
+	},
+
+/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_chaingun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Chaingun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_chain/tris.md2", EF_ROTATE,
+		"models/weapons/v_chain/tris.md2",
+/* icon */		"w_chaingun",
+/* pickup */	"Chaingun",
+		0,
+		1,
+		"Bullets",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_CHAINGUN,
+		NULL,
+		0,
+/* precache */ "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav"
+	},
+
+/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_grenades",
+		Pickup_Ammo,
+		Use_Weapon,
+		Drop_Ammo,
+		Weapon_Grenade,
+		"misc/am_pkup.wav",
+		"models/items/ammo/grenades/medium/tris.md2", 0,
+		"models/weapons/v_handgr/tris.md2",
+/* icon */		"a_grenades",
+/* pickup */	"Grenades",
+/* width */		3,
+		5,
+		"grenades",
+		IT_AMMO|IT_WEAPON,
+		WEAP_GRENADES,
+		NULL,
+		AMMO_GRENADES,
+/* precache */ "weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav "
+	},
+
+/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_grenadelauncher",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_GrenadeLauncher,
+		"misc/w_pkup.wav",
+		"models/weapons/g_launch/tris.md2", EF_ROTATE,
+		"models/weapons/v_launch/tris.md2",
+/* icon */		"w_glauncher",
+/* pickup */	"Grenade Launcher",
+		0,
+		1,
+		"Grenades",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_GRENADELAUNCHER,
+		NULL,
+		0,
+/* precache */ "models/objects/grenade/tris.md2 weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav"
+	},
+
+/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_rocketlauncher",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_RocketLauncher,
+		"misc/w_pkup.wav",
+		"models/weapons/g_rocket/tris.md2", EF_ROTATE,
+		"models/weapons/v_rocket/tris.md2",
+/* icon */		"w_rlauncher",
+/* pickup */	"Rocket Launcher",
+		0,
+		1,
+		"Rockets",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_ROCKETLAUNCHER,
+		NULL,
+		0,
+/* precache */ "models/objects/rocket/tris.md2 weapons/rockfly.wav weapons/rocklf1a.wav weapons/rocklr1b.wav models/objects/debris2/tris.md2"
+	},
+
+/*QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_hyperblaster", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_HyperBlaster,
+		"misc/w_pkup.wav",
+		"models/weapons/g_hyperb/tris.md2", EF_ROTATE,
+		"models/weapons/v_hyperb/tris.md2",
+/* icon */		"w_hyperblaster",
+/* pickup */	"HyperBlaster",
+		0,
+		1,
+		"Cells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_HYPERBLASTER,
+		NULL,
+		0,
+/* precache */ "weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav"
+	},
+
+/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_railgun", 
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_Railgun,
+		"misc/w_pkup.wav",
+		"models/weapons/g_rail/tris.md2", EF_ROTATE,
+		"models/weapons/v_rail/tris.md2",
+/* icon */		"w_railgun",
+/* pickup */	"Railgun",
+		0,
+		1,
+		"Slugs",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_RAILGUN,
+		NULL,
+		0,
+/* precache */ "weapons/rg_hum.wav"
+	},
+
+/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"weapon_bfg",
+		Pickup_Weapon,
+		Use_Weapon,
+		Drop_Weapon,
+		Weapon_BFG,
+		"misc/w_pkup.wav",
+		"models/weapons/g_bfg/tris.md2", EF_ROTATE,
+		"models/weapons/v_bfg/tris.md2",
+/* icon */		"w_bfg",
+/* pickup */	"BFG10K",
+		0,
+		50,
+		"Cells",
+		IT_WEAPON|IT_STAY_COOP,
+		WEAP_BFG,
+		NULL,
+		0,
+/* precache */ "sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav"
+	},
+
+	//
+	// AMMO ITEMS
+	//
+
+/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_shells",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/shells/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_shells",
+/* pickup */	"Shells",
+/* width */		3,
+		10,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_SHELLS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_bullets",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/bullets/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_bullets",
+/* pickup */	"Bullets",
+/* width */		3,
+		50,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_BULLETS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_cells",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/cells/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_cells",
+/* pickup */	"Cells",
+/* width */		3,
+		50,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_CELLS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_rockets",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/rockets/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_rockets",
+/* pickup */	"Rockets",
+/* width */		3,
+		5,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_ROCKETS,
+/* precache */ ""
+	},
+
+/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"ammo_slugs",
+		Pickup_Ammo,
+		NULL,
+		Drop_Ammo,
+		NULL,
+		"misc/am_pkup.wav",
+		"models/items/ammo/slugs/medium/tris.md2", 0,
+		NULL,
+/* icon */		"a_slugs",
+/* pickup */	"Slugs",
+/* width */		3,
+		10,
+		NULL,
+		IT_AMMO,
+		0,
+		NULL,
+		AMMO_SLUGS,
+/* precache */ ""
+	},
+
+
+	//
+	// POWERUP ITEMS
+	//
+/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_quad", 
+		Pickup_Powerup,
+		Use_Quad,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/quaddama/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_quad",
+/* pickup */	"Quad Damage",
+/* width */		2,
+		60,
+		NULL,
+		IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/damage.wav items/damage2.wav items/damage3.wav"
+	},
+
+/*QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_invulnerability",
+		Pickup_Powerup,
+		Use_Invulnerability,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/invulner/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_invulnerability",
+/* pickup */	"Invulnerability",
+/* width */		2,
+		300,
+		NULL,
+		IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/protect.wav items/protect2.wav items/protect4.wav"
+	},
+
+/*QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_silencer",
+		Pickup_Powerup,
+		Use_Silencer,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/silencer/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_silencer",
+/* pickup */	"Silencer",
+/* width */		2,
+		60,
+		NULL,
+		IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_breather",
+		Pickup_Powerup,
+		Use_Breather,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/breather/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_rebreather",
+/* pickup */	"Rebreather",
+/* width */		2,
+		60,
+		NULL,
+		IT_STAY_COOP|IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/airout.wav"
+	},
+
+/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_enviro",
+		Pickup_Powerup,
+		Use_Envirosuit,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/enviro/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_envirosuit",
+/* pickup */	"Environment Suit",
+/* width */		2,
+		60,
+		NULL,
+		IT_STAY_COOP|IT_POWERUP,
+		0,
+		NULL,
+		0,
+/* precache */ "items/airout.wav"
+	},
+
+/*QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16)
+Special item that gives +2 to maximum health
+*/
+	{
+		"item_ancient_head",
+		Pickup_AncientHead,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/c_head/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_fixme",
+/* pickup */	"Ancient Head",
+/* width */		2,
+		60,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16)
+gives +1 to maximum health
+*/
+	{
+		"item_adrenaline",
+		Pickup_Adrenaline,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/adrenal/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_adrenaline",
+/* pickup */	"Adrenaline",
+/* width */		2,
+		60,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_bandolier",
+		Pickup_Bandolier,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/band/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"p_bandolier",
+/* pickup */	"Bandolier",
+/* width */		2,
+		60,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+	{
+		"item_pack",
+		Pickup_Pack,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		"models/items/pack/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_pack",
+/* pickup */	"Ammo Pack",
+/* width */		2,
+		180,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+	//
+	// KEYS
+	//
+/*QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16)
+key for computer centers
+*/
+	{
+		"key_data_cd",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/data_cd/tris.md2", EF_ROTATE,
+		NULL,
+		"k_datacd",
+		"Data CD",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_power_cube (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN NO_TOUCH
+warehouse circuits
+*/
+	{
+		"key_power_cube",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/power/tris.md2", EF_ROTATE,
+		NULL,
+		"k_powercube",
+		"Power Cube",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16)
+key for the entrance of jail3
+*/
+	{
+		"key_pyramid",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/pyramid/tris.md2", EF_ROTATE,
+		NULL,
+		"k_pyramid",
+		"Pyramid Key",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16)
+key for the city computer
+*/
+	{
+		"key_data_spinner",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/spinner/tris.md2", EF_ROTATE,
+		NULL,
+		"k_dataspin",
+		"Data Spinner",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16)
+security pass for the security level
+*/
+	{
+		"key_pass",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/pass/tris.md2", EF_ROTATE,
+		NULL,
+		"k_security",
+		"Security Pass",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16)
+normal door key - blue
+*/
+	{
+		"key_blue_key",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/key/tris.md2", EF_ROTATE,
+		NULL,
+		"k_bluekey",
+		"Blue Key",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16)
+normal door key - red
+*/
+	{
+		"key_red_key",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/red_key/tris.md2", EF_ROTATE,
+		NULL,
+		"k_redkey",
+		"Red Key",
+		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16)
+tank commander's head
+*/
+	{
+		"key_commander_head",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/monsters/commandr/head/tris.md2", EF_GIB,
+		NULL,
+/* icon */		"k_comhead",
+/* pickup */	"Commander's Head",
+/* width */		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+/*QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16)
+tank commander's head
+*/
+	{
+		"key_airstrike_target",
+		Pickup_Key,
+		NULL,
+		Drop_General,
+		NULL,
+		"items/pkup.wav",
+		"models/items/keys/target/tris.md2", EF_ROTATE,
+		NULL,
+/* icon */		"i_airstrike",
+/* pickup */	"Airstrike Marker",
+/* width */		2,
+		0,
+		NULL,
+		IT_STAY_COOP|IT_KEY,
+		0,
+		NULL,
+		0,
+/* precache */ ""
+	},
+
+	{
+		NULL,
+		Pickup_Health,
+		NULL,
+		NULL,
+		NULL,
+		"items/pkup.wav",
+		NULL, 0,
+		NULL,
+/* icon */		"i_health",
+/* pickup */	"Health",
+/* width */		3,
+		0,
+		NULL,
+		0,
+		0,
+		NULL,
+		0,
+/* precache */ "items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"
+	},
+
+	// end of list marker
+	{NULL}
+};
+
+
+/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/healing/medium/tris.md2";
+	self->count = 10;
+	SpawnItem (self, FindItem ("Health"));
+	gi.soundindex ("items/n_health.wav");
+}
+
+/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health_small (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/healing/stimpack/tris.md2";
+	self->count = 2;
+	SpawnItem (self, FindItem ("Health"));
+	self->style = HEALTH_IGNORE_MAX;
+	gi.soundindex ("items/s_health.wav");
+}
+
+/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health_large (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/healing/large/tris.md2";
+	self->count = 25;
+	SpawnItem (self, FindItem ("Health"));
+	gi.soundindex ("items/l_health.wav");
+}
+
+/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16)
+*/
+void SP_item_health_mega (edict_t *self)
+{
+	if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->model = "models/items/mega_h/tris.md2";
+	self->count = 100;
+	SpawnItem (self, FindItem ("Health"));
+	gi.soundindex ("items/m_health.wav");
+	self->style = HEALTH_IGNORE_MAX|HEALTH_TIMED;
+}
+
+
+void InitItems (void)
+{
+	game.num_items = sizeof(itemlist)/sizeof(itemlist[0]) - 1;
+}
+
+
+
+/*
+===============
+SetItemNames
+
+Called by worldspawn
+===============
+*/
+void SetItemNames (void)
+{
+	int		i;
+	gitem_t	*it;
+
+	for (i=0 ; i<game.num_items ; i++)
+	{
+		it = &itemlist[i];
+		gi.configstring (CS_ITEMS+i, it->pickup_name);
+	}
+
+	jacket_armor_index = ITEM_INDEX(FindItem("Jacket Armor"));
+	combat_armor_index = ITEM_INDEX(FindItem("Combat Armor"));
+	body_armor_index   = ITEM_INDEX(FindItem("Body Armor"));
+	power_screen_index = ITEM_INDEX(FindItem("Power Screen"));
+	power_shield_index = ITEM_INDEX(FindItem("Power Shield"));
+}
--- /dev/null
+++ b/game/g_local.h
@@ -1,0 +1,1113 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_local.h -- local definitions for game module
+
+#include "q_shared.h"
+
+// define GAME_INCLUDE so that game.h does not define the
+// short, server-visible gclient_t and edict_t structures,
+// because we define the full size ones in this file
+#define	GAME_INCLUDE
+#include "game.h"
+
+// the "gameversion" client command will print this plus compile date
+#define	GAMEVERSION	"baseq2"
+
+// protocol bytes that can be directly added to messages
+#define	svc_muzzleflash		1
+#define	svc_muzzleflash2	2
+#define	svc_temp_entity		3
+#define	svc_layout			4
+#define	svc_inventory		5
+#define	svc_stufftext		11
+
+//==================================================================
+
+// view pitching times
+#define DAMAGE_TIME		0.5
+#define	FALL_TIME		0.3
+
+
+// edict->spawnflags
+// these are set with checkboxes on each entity in the map editor
+#define	SPAWNFLAG_NOT_EASY			0x00000100
+#define	SPAWNFLAG_NOT_MEDIUM		0x00000200
+#define	SPAWNFLAG_NOT_HARD			0x00000400
+#define	SPAWNFLAG_NOT_DEATHMATCH	0x00000800
+#define	SPAWNFLAG_NOT_COOP			0x00001000
+
+// edict->flags
+#define	FL_FLY					0x00000001
+#define	FL_SWIM					0x00000002	// implied immunity to drowining
+#define FL_IMMUNE_LASER			0x00000004
+#define	FL_INWATER				0x00000008
+#define	FL_GODMODE				0x00000010
+#define	FL_NOTARGET				0x00000020
+#define FL_IMMUNE_SLIME			0x00000040
+#define FL_IMMUNE_LAVA			0x00000080
+#define	FL_PARTIALGROUND		0x00000100	// not all corners are valid
+#define	FL_WATERJUMP			0x00000200	// player jumping out of water
+#define	FL_TEAMSLAVE			0x00000400	// not the first on the team
+#define FL_NO_KNOCKBACK			0x00000800
+#define FL_POWER_ARMOR			0x00001000	// power armor (if any) is active
+#define FL_RESPAWN				0x80000000	// used for item respawning
+
+
+#define	FRAMETIME		0.1
+
+// memory tags to allow dynamic memory to be cleaned up
+#define	TAG_GAME	765		// clear when unloading the dll
+#define	TAG_LEVEL	766		// clear when loading a new level
+
+
+#define MELEE_DISTANCE	80
+
+#define BODY_QUEUE_SIZE		8
+
+typedef enum
+{
+	DAMAGE_NO,
+	DAMAGE_YES,			// will take damage if hit
+	DAMAGE_AIM			// auto targeting recognizes this
+} damage_t;
+
+typedef enum 
+{
+	WEAPON_READY, 
+	WEAPON_ACTIVATING,
+	WEAPON_DROPPING,
+	WEAPON_FIRING
+} weaponstate_t;
+
+typedef enum
+{
+	AMMO_BULLETS,
+	AMMO_SHELLS,
+	AMMO_ROCKETS,
+	AMMO_GRENADES,
+	AMMO_CELLS,
+	AMMO_SLUGS
+} ammo_t;
+
+
+//deadflag
+#define DEAD_NO					0
+#define DEAD_DYING				1
+#define DEAD_DEAD				2
+#define DEAD_RESPAWNABLE		3
+
+//range
+#define RANGE_MELEE				0
+#define RANGE_NEAR				1
+#define RANGE_MID				2
+#define RANGE_FAR				3
+
+//gib types
+#define GIB_ORGANIC				0
+#define GIB_METALLIC			1
+
+//monster ai flags
+#define AI_STAND_GROUND			0x00000001
+#define AI_TEMP_STAND_GROUND	0x00000002
+#define AI_SOUND_TARGET			0x00000004
+#define AI_LOST_SIGHT			0x00000008
+#define AI_PURSUIT_LAST_SEEN	0x00000010
+#define AI_PURSUE_NEXT			0x00000020
+#define AI_PURSUE_TEMP			0x00000040
+#define AI_HOLD_FRAME			0x00000080
+#define AI_GOOD_GUY				0x00000100
+#define AI_BRUTAL				0x00000200
+#define AI_NOSTEP				0x00000400
+#define AI_DUCKED				0x00000800
+#define AI_COMBAT_POINT			0x00001000
+#define AI_MEDIC				0x00002000
+#define AI_RESURRECTING			0x00004000
+
+//monster attack state
+#define AS_STRAIGHT				1
+#define AS_SLIDING				2
+#define	AS_MELEE				3
+#define	AS_MISSILE				4
+
+// armor types
+#define ARMOR_NONE				0
+#define ARMOR_JACKET			1
+#define ARMOR_COMBAT			2
+#define ARMOR_BODY				3
+#define ARMOR_SHARD				4
+
+// power armor types
+#define POWER_ARMOR_NONE		0
+#define POWER_ARMOR_SCREEN		1
+#define POWER_ARMOR_SHIELD		2
+
+// handedness values
+#define RIGHT_HANDED			0
+#define LEFT_HANDED				1
+#define CENTER_HANDED			2
+
+
+// game.serverflags values
+#define SFL_CROSS_TRIGGER_1		0x00000001
+#define SFL_CROSS_TRIGGER_2		0x00000002
+#define SFL_CROSS_TRIGGER_3		0x00000004
+#define SFL_CROSS_TRIGGER_4		0x00000008
+#define SFL_CROSS_TRIGGER_5		0x00000010
+#define SFL_CROSS_TRIGGER_6		0x00000020
+#define SFL_CROSS_TRIGGER_7		0x00000040
+#define SFL_CROSS_TRIGGER_8		0x00000080
+#define SFL_CROSS_TRIGGER_MASK	0x000000ff
+
+
+// noise types for PlayerNoise
+#define PNOISE_SELF				0
+#define PNOISE_WEAPON			1
+#define PNOISE_IMPACT			2
+
+
+// edict->movetype values
+typedef enum
+{
+MOVETYPE_NONE,			// never moves
+MOVETYPE_NOCLIP,		// origin and angles change with no interaction
+MOVETYPE_PUSH,			// no clip to world, push on box contact
+MOVETYPE_STOP,			// no clip to world, stops on box contact
+
+MOVETYPE_WALK,			// gravity
+MOVETYPE_STEP,			// gravity, special edge handling
+MOVETYPE_FLY,
+MOVETYPE_TOSS,			// gravity
+MOVETYPE_FLYMISSILE,	// extra size to monsters
+MOVETYPE_BOUNCE
+} movetype_t;
+
+
+
+typedef struct
+{
+	int		base_count;
+	int		max_count;
+	float	normal_protection;
+	float	energy_protection;
+	int		armor;
+} gitem_armor_t;
+
+
+// gitem_t->flags
+#define	IT_WEAPON		1		// use makes active weapon
+#define	IT_AMMO			2
+#define IT_ARMOR		4
+#define IT_STAY_COOP	8
+#define IT_KEY			16
+#define IT_POWERUP		32
+
+// gitem_t->weapmodel for weapons indicates model index
+#define WEAP_BLASTER			1 
+#define WEAP_SHOTGUN			2 
+#define WEAP_SUPERSHOTGUN		3 
+#define WEAP_MACHINEGUN			4 
+#define WEAP_CHAINGUN			5 
+#define WEAP_GRENADES			6 
+#define WEAP_GRENADELAUNCHER	7 
+#define WEAP_ROCKETLAUNCHER		8 
+#define WEAP_HYPERBLASTER		9 
+#define WEAP_RAILGUN			10
+#define WEAP_BFG				11
+
+typedef struct gitem_s
+{
+	char		*classname;	// spawning name
+	qboolean	(*pickup)(struct edict_s *ent, struct edict_s *other);
+	void		(*use)(struct edict_s *ent, struct gitem_s *item);
+	void		(*drop)(struct edict_s *ent, struct gitem_s *item);
+	void		(*weaponthink)(struct edict_s *ent);
+	char		*pickup_sound;
+	char		*world_model;
+	int			world_model_flags;
+	char		*view_model;
+
+	// client side info
+	char		*icon;
+	char		*pickup_name;	// for printing on pickup
+	int			count_width;		// number of digits to display by icon
+
+	int			quantity;		// for ammo how much, for weapons how much is used per shot
+	char		*ammo;			// for weapons
+	int			flags;			// IT_* flags
+
+	int			weapmodel;		// weapon model index (for weapons)
+
+	void		*info;
+	int			tag;
+
+	char		*precaches;		// string of all models, sounds, and images this item will use
+} gitem_t;
+
+
+
+//
+// this structure is left intact through an entire game
+// it should be initialized at dll load time, and read/written to
+// the server.ssv file for savegames
+//
+typedef struct
+{
+	char		helpmessage1[512];
+	char		helpmessage2[512];
+	int			helpchanged;	// flash F1 icon if non 0, play sound
+								// and increment only if 1, 2, or 3
+
+	gclient_t	*clients;		// [maxclients]
+
+	// can't store spawnpoint in level, because
+	// it would get overwritten by the savegame restore
+	char		spawnpoint[512];	// needed for coop respawns
+
+	// store latched cvars here that we want to get at often
+	int			maxclients;
+	int			maxentities;
+
+	// cross level triggers
+	int			serverflags;
+
+	// items
+	int			num_items;
+
+	qboolean	autosaved;
+} game_locals_t;
+
+
+//
+// this structure is cleared as each map is entered
+// it is read/written to the level.sav file for savegames
+//
+typedef struct
+{
+	int			framenum;
+	float		time;
+
+	char		level_name[MAX_QPATH];	// the descriptive name (Outer Base, etc)
+	char		mapname[MAX_QPATH];		// the server name (base1, etc)
+	char		nextmap[MAX_QPATH];		// go here when fraglimit is hit
+
+	// intermission state
+	float		intermissiontime;		// time the intermission was started
+	char		*changemap;
+	int			exitintermission;
+	vec3_t		intermission_origin;
+	vec3_t		intermission_angle;
+
+	edict_t		*sight_client;	// changed once each frame for coop games
+
+	edict_t		*sight_entity;
+	int			sight_entity_framenum;
+	edict_t		*sound_entity;
+	int			sound_entity_framenum;
+	edict_t		*sound2_entity;
+	int			sound2_entity_framenum;
+
+	int			pic_health;
+
+	int			total_secrets;
+	int			found_secrets;
+
+	int			total_goals;
+	int			found_goals;
+
+	int			total_monsters;
+	int			killed_monsters;
+
+	edict_t		*current_entity;	// entity running from G_RunFrame
+	int			body_que;			// dead bodies
+
+	int			power_cubes;		// ugly necessity for coop
+} level_locals_t;
+
+
+// spawn_temp_t is only used to hold entity field values that
+// can be set from the editor, but aren't actualy present
+// in edict_t during gameplay
+typedef struct
+{
+	// world vars
+	char		*sky;
+	float		skyrotate;
+	vec3_t		skyaxis;
+	char		*nextmap;
+
+	int			lip;
+	int			distance;
+	int			height;
+	char		*noise;
+	float		pausetime;
+	char		*item;
+	char		*gravity;
+
+	float		minyaw;
+	float		maxyaw;
+	float		minpitch;
+	float		maxpitch;
+} spawn_temp_t;
+
+
+typedef struct
+{
+	// fixed data
+	vec3_t		start_origin;
+	vec3_t		start_angles;
+	vec3_t		end_origin;
+	vec3_t		end_angles;
+
+	int			sound_start;
+	int			sound_middle;
+	int			sound_end;
+
+	float		accel;
+	float		speed;
+	float		decel;
+	float		distance;
+
+	float		wait;
+
+	// state data
+	int			state;
+	vec3_t		dir;
+	float		current_speed;
+	float		move_speed;
+	float		next_speed;
+	float		remaining_distance;
+	float		decel_distance;
+	void		(*endfunc)(edict_t *);
+} moveinfo_t;
+
+
+typedef struct
+{
+	void	(*aifunc)(edict_t *self, float dist);
+	float	dist;
+	void	(*thinkfunc)(edict_t *self);
+} mframe_t;
+
+typedef struct
+{
+	int			firstframe;
+	int			lastframe;
+	mframe_t	*frame;
+	void		(*endfunc)(edict_t *self);
+} mmove_t;
+
+typedef struct
+{
+	mmove_t		*currentmove;
+	int			aiflags;
+	int			nextframe;
+	float		scale;
+
+	void		(*stand)(edict_t *self);
+	void		(*idle)(edict_t *self);
+	void		(*search)(edict_t *self);
+	void		(*walk)(edict_t *self);
+	void		(*run)(edict_t *self);
+	void		(*dodge)(edict_t *self, edict_t *other, float eta);
+	void		(*attack)(edict_t *self);
+	void		(*melee)(edict_t *self);
+	void		(*sight)(edict_t *self, edict_t *other);
+	qboolean	(*checkattack)(edict_t *self);
+
+	float		pausetime;
+	float		attack_finished;
+
+	vec3_t		saved_goal;
+	float		search_time;
+	float		trail_time;
+	vec3_t		last_sighting;
+	int			attack_state;
+	int			lefty;
+	float		idle_time;
+	int			linkcount;
+
+	int			power_armor_type;
+	int			power_armor_power;
+} monsterinfo_t;
+
+
+
+extern	game_locals_t	game;
+extern	level_locals_t	level;
+extern	game_import_t	gi;
+extern	game_export_t	globals;
+extern	spawn_temp_t	st;
+
+extern	int	sm_meat_index;
+extern	int	snd_fry;
+
+extern	int	jacket_armor_index;
+extern	int	combat_armor_index;
+extern	int	body_armor_index;
+
+
+// means of death
+#define MOD_UNKNOWN			0
+#define MOD_BLASTER			1
+#define MOD_SHOTGUN			2
+#define MOD_SSHOTGUN		3
+#define MOD_MACHINEGUN		4
+#define MOD_CHAINGUN		5
+#define MOD_GRENADE			6
+#define MOD_G_SPLASH		7
+#define MOD_ROCKET			8
+#define MOD_R_SPLASH		9
+#define MOD_HYPERBLASTER	10
+#define MOD_RAILGUN			11
+#define MOD_BFG_LASER		12
+#define MOD_BFG_BLAST		13
+#define MOD_BFG_EFFECT		14
+#define MOD_HANDGRENADE		15
+#define MOD_HG_SPLASH		16
+#define MOD_WATER			17
+#define MOD_SLIME			18
+#define MOD_LAVA			19
+#define MOD_CRUSH			20
+#define MOD_TELEFRAG		21
+#define MOD_FALLING			22
+#define MOD_SUICIDE			23
+#define MOD_HELD_GRENADE	24
+#define MOD_EXPLOSIVE		25
+#define MOD_BARREL			26
+#define MOD_BOMB			27
+#define MOD_EXIT			28
+#define MOD_SPLASH			29
+#define MOD_TARGET_LASER	30
+#define MOD_TRIGGER_HURT	31
+#define MOD_HIT				32
+#define MOD_TARGET_BLASTER	33
+#define MOD_FRIENDLY_FIRE	0x8000000
+
+extern	int	meansOfDeath;
+
+
+extern	edict_t			*g_edicts;
+
+#define	FOFS(x) (int)&(((edict_t *)0)->x)
+#define	STOFS(x) (int)&(((spawn_temp_t *)0)->x)
+#define	LLOFS(x) (int)&(((level_locals_t *)0)->x)
+#define	CLOFS(x) (int)&(((gclient_t *)0)->x)
+
+#define random()	((rand () & 0x7fff) / ((float)0x7fff))
+#define crandom()	(2.0 * (random() - 0.5))
+
+extern	cvar_t	*maxentities;
+extern	cvar_t	*deathmatch;
+extern	cvar_t	*coop;
+extern	cvar_t	*dmflags;
+extern	cvar_t	*skill;
+extern	cvar_t	*fraglimit;
+extern	cvar_t	*timelimit;
+extern	cvar_t	*password;
+extern	cvar_t	*spectator_password;
+extern	cvar_t	*g_select_empty;
+extern	cvar_t	*dedicated;
+
+extern	cvar_t	*filterban;
+
+extern	cvar_t	*sv_gravity;
+extern	cvar_t	*sv_maxvelocity;
+
+extern	cvar_t	*gun_x, *gun_y, *gun_z;
+extern	cvar_t	*sv_rollspeed;
+extern	cvar_t	*sv_rollangle;
+
+extern	cvar_t	*run_pitch;
+extern	cvar_t	*run_roll;
+extern	cvar_t	*bob_up;
+extern	cvar_t	*bob_pitch;
+extern	cvar_t	*bob_roll;
+
+extern	cvar_t	*sv_cheats;
+extern	cvar_t	*maxclients;
+extern	cvar_t	*maxspectators;
+
+extern	cvar_t	*flood_msgs;
+extern	cvar_t	*flood_persecond;
+extern	cvar_t	*flood_waitdelay;
+
+extern	cvar_t	*sv_maplist;
+
+#define world	(&g_edicts[0])
+
+// item spawnflags
+#define ITEM_TRIGGER_SPAWN		0x00000001
+#define ITEM_NO_TOUCH			0x00000002
+// 6 bits reserved for editor flags
+// 8 bits used as power cube id bits for coop games
+#define DROPPED_ITEM			0x00010000
+#define	DROPPED_PLAYER_ITEM		0x00020000
+#define ITEM_TARGETS_USED		0x00040000
+
+//
+// fields are needed for spawning from the entity string
+// and saving / loading games
+//
+#define FFL_SPAWNTEMP		1
+#define FFL_NOSPAWN			2
+
+typedef enum {
+	F_INT, 
+	F_FLOAT,
+	F_LSTRING,			// string on disk, pointer in memory, TAG_LEVEL
+	F_GSTRING,			// string on disk, pointer in memory, TAG_GAME
+	F_VECTOR,
+	F_ANGLEHACK,
+	F_EDICT,			// index on disk, pointer in memory
+	F_ITEM,				// index on disk, pointer in memory
+	F_CLIENT,			// index on disk, pointer in memory
+	F_FUNCTION,
+	F_MMOVE,
+	F_IGNORE
+} fieldtype_t;
+
+typedef struct
+{
+	char	*name;
+	int		ofs;
+	fieldtype_t	type;
+	int		flags;
+} field_t;
+
+
+extern	field_t fields[];
+extern	gitem_t	itemlist[];
+
+
+//
+// g_cmds.c
+//
+void Cmd_Help_f (edict_t *ent);
+void Cmd_Score_f (edict_t *ent);
+
+//
+// g_items.c
+//
+void PrecacheItem (gitem_t *it);
+void InitItems (void);
+void SetItemNames (void);
+gitem_t	*FindItem (char *pickup_name);
+gitem_t	*FindItemByClassname (char *classname);
+#define	ITEM_INDEX(x) ((x)-itemlist)
+edict_t *Drop_Item (edict_t *ent, gitem_t *item);
+void SetRespawn (edict_t *ent, float delay);
+void ChangeWeapon (edict_t *ent);
+void SpawnItem (edict_t *ent, gitem_t *item);
+void Think_Weapon (edict_t *ent);
+int ArmorIndex (edict_t *ent);
+int PowerArmorType (edict_t *ent);
+gitem_t	*GetItemByIndex (int index);
+qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count);
+void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
+
+//
+// g_utils.c
+//
+qboolean	KillBox (edict_t *ent);
+void	G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
+edict_t *G_Find (edict_t *from, int fieldofs, char *match);
+edict_t *findradius (edict_t *from, vec3_t org, float rad);
+edict_t *G_PickTarget (char *targetname);
+void	G_UseTargets (edict_t *ent, edict_t *activator);
+void	G_SetMovedir (vec3_t angles, vec3_t movedir);
+
+void	G_InitEdict (edict_t *e);
+edict_t	*G_Spawn (void);
+void	G_FreeEdict (edict_t *e);
+
+void	G_TouchTriggers (edict_t *ent);
+void	G_TouchSolids (edict_t *ent);
+
+char	*G_CopyString (char *in);
+
+float	*tv (float x, float y, float z);
+char	*vtos (vec3_t v);
+
+float vectoyaw (vec3_t vec);
+void vectoangles (vec3_t vec, vec3_t angles);
+
+//
+// g_combat.c
+//
+qboolean OnSameTeam (edict_t *ent1, edict_t *ent2);
+qboolean CanDamage (edict_t *targ, edict_t *inflictor);
+void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod);
+void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod);
+
+// damage flags
+#define DAMAGE_RADIUS			0x00000001	// damage was indirect
+#define DAMAGE_NO_ARMOR			0x00000002	// armour does not protect from this damage
+#define DAMAGE_ENERGY			0x00000004	// damage is from an energy based weapon
+#define DAMAGE_NO_KNOCKBACK		0x00000008	// do not affect velocity, just view angles
+#define DAMAGE_BULLET			0x00000010  // damage is from a bullet (used for ricochets)
+#define DAMAGE_NO_PROTECTION	0x00000020  // armor, shields, invulnerability, and godmode have no effect
+
+#define DEFAULT_BULLET_HSPREAD	300
+#define DEFAULT_BULLET_VSPREAD	500
+#define DEFAULT_SHOTGUN_HSPREAD	1000
+#define DEFAULT_SHOTGUN_VSPREAD	500
+#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT	12
+#define DEFAULT_SHOTGUN_COUNT	12
+#define DEFAULT_SSHOTGUN_COUNT	20
+
+//
+// g_monster.c
+//
+void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype);
+void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype);
+void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect);
+void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype);
+void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype);
+void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype);
+void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype);
+void M_droptofloor (edict_t *ent);
+void monster_think (edict_t *self);
+void walkmonster_start (edict_t *self);
+void swimmonster_start (edict_t *self);
+void flymonster_start (edict_t *self);
+void AttackFinished (edict_t *self, float time);
+void monster_death_use (edict_t *self);
+void M_CatagorizePosition (edict_t *ent);
+qboolean M_CheckAttack (edict_t *self);
+void M_FlyCheck (edict_t *self);
+void M_CheckGround (edict_t *ent);
+
+//
+// g_misc.c
+//
+void ThrowHead (edict_t *self, char *gibname, int damage, int type);
+void ThrowClientHead (edict_t *self, int damage);
+void ThrowGib (edict_t *self, char *gibname, int damage, int type);
+void BecomeExplosion1(edict_t *self);
+
+//
+// g_ai.c
+//
+void AI_SetSightClient (void);
+
+void ai_stand (edict_t *self, float dist);
+void ai_move (edict_t *self, float dist);
+void ai_walk (edict_t *self, float dist);
+void ai_turn (edict_t *self, float dist);
+void ai_run (edict_t *self, float dist);
+void ai_charge (edict_t *self, float dist);
+int range (edict_t *self, edict_t *other);
+
+void FoundTarget (edict_t *self);
+qboolean infront (edict_t *self, edict_t *other);
+qboolean visible (edict_t *self, edict_t *other);
+qboolean FacingIdeal(edict_t *self);
+
+//
+// g_weapon.c
+//
+void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
+qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick);
+void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod);
+void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod);
+void fire_blaster (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect, qboolean hyper);
+void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius);
+void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held);
+void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage);
+void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
+void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius);
+
+//
+// g_ptrail.c
+//
+void PlayerTrail_Init (void);
+void PlayerTrail_Add (vec3_t spot);
+void PlayerTrail_New (vec3_t spot);
+edict_t *PlayerTrail_PickFirst (edict_t *self);
+edict_t *PlayerTrail_PickNext (edict_t *self);
+edict_t	*PlayerTrail_LastSpot (void);
+
+//
+// g_client.c
+//
+void respawn (edict_t *ent);
+void BeginIntermission (edict_t *targ);
+void PutClientInServer (edict_t *ent);
+void InitClientPersistant (gclient_t *client);
+void InitClientResp (gclient_t *client);
+void InitBodyQue (void);
+void ClientBeginServerFrame (edict_t *ent);
+
+//
+// g_player.c
+//
+void player_pain (edict_t *self, edict_t *other, float kick, int damage);
+void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+
+//
+// g_svcmds.c
+//
+void	ServerCommand (void);
+qboolean SV_FilterPacket (char *from);
+
+//
+// p_view.c
+//
+void ClientEndServerFrame (edict_t *ent);
+
+//
+// p_hud.c
+//
+void MoveClientToIntermission (edict_t *client);
+void G_SetStats (edict_t *ent);
+void G_SetSpectatorStats (edict_t *ent);
+void G_CheckChaseStats (edict_t *ent);
+void ValidateSelectedItem (edict_t *ent);
+void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer);
+
+//
+// g_pweapon.c
+//
+void PlayerNoise(edict_t *who, vec3_t where, int type);
+
+//
+// m_move.c
+//
+qboolean M_CheckBottom (edict_t *ent);
+qboolean M_walkmove (edict_t *ent, float yaw, float dist);
+void M_MoveToGoal (edict_t *ent, float dist);
+void M_ChangeYaw (edict_t *ent);
+
+//
+// g_phys.c
+//
+void G_RunEntity (edict_t *ent);
+
+//
+// g_main.c
+//
+void SaveClientData (void);
+void FetchClientEntData (edict_t *ent);
+
+//
+// g_chase.c
+//
+void UpdateChaseCam(edict_t *ent);
+void ChaseNext(edict_t *ent);
+void ChasePrev(edict_t *ent);
+void GetChaseTarget(edict_t *ent);
+
+//============================================================================
+
+// client_t->anim_priority
+#define	ANIM_BASIC		0		// stand / run
+#define	ANIM_WAVE		1
+#define	ANIM_JUMP		2
+#define	ANIM_PAIN		3
+#define	ANIM_ATTACK		4
+#define	ANIM_DEATH		5
+#define	ANIM_REVERSE	6
+
+
+// client data that stays across multiple level loads
+typedef struct
+{
+	char		userinfo[MAX_INFO_STRING];
+	char		netname[16];
+	int			hand;
+
+	qboolean	connected;			// a loadgame will leave valid entities that
+									// just don't have a connection yet
+
+	// values saved and restored from edicts when changing levels
+	int			health;
+	int			max_health;
+	int			savedFlags;
+
+	int			selected_item;
+	int			inventory[MAX_ITEMS];
+
+	// ammo capacities
+	int			max_bullets;
+	int			max_shells;
+	int			max_rockets;
+	int			max_grenades;
+	int			max_cells;
+	int			max_slugs;
+
+	gitem_t		*weapon;
+	gitem_t		*lastweapon;
+
+	int			power_cubes;	// used for tracking the cubes in coop games
+	int			score;			// for calculating total unit score in coop games
+
+	int			game_helpchanged;
+	int			helpchanged;
+
+	qboolean	spectator;			// client is a spectator
+} client_persistant_t;
+
+// client data that stays across deathmatch respawns
+typedef struct
+{
+	client_persistant_t	coop_respawn;	// what to set client->pers to on a respawn
+	int			enterframe;			// level.framenum the client entered the game
+	int			score;				// frags, etc
+	vec3_t		cmd_angles;			// angles sent over in the last command
+
+	qboolean	spectator;			// client is a spectator
+} client_respawn_t;
+
+// this structure is cleared on each PutClientInServer(),
+// except for 'client->pers'
+struct gclient_s
+{
+	// known to server
+	player_state_t	ps;				// communicated by server to clients
+	int				ping;
+
+	// private to game
+	client_persistant_t	pers;
+	client_respawn_t	resp;
+	pmove_state_t		old_pmove;	// for detecting out-of-pmove changes
+
+	qboolean	showscores;			// set layout stat
+	qboolean	showinventory;		// set layout stat
+	qboolean	showhelp;
+	qboolean	showhelpicon;
+
+	int			ammo_index;
+
+	int			buttons;
+	int			oldbuttons;
+	int			latched_buttons;
+
+	qboolean	weapon_thunk;
+
+	gitem_t		*newweapon;
+
+	// sum up damage over an entire frame, so
+	// shotgun blasts give a single big kick
+	int			damage_armor;		// damage absorbed by armor
+	int			damage_parmor;		// damage absorbed by power armor
+	int			damage_blood;		// damage taken out of health
+	int			damage_knockback;	// impact damage
+	vec3_t		damage_from;		// origin for vector calculation
+
+	float		killer_yaw;			// when dead, look at killer
+
+	weaponstate_t	weaponstate;
+	vec3_t		kick_angles;	// weapon kicks
+	vec3_t		kick_origin;
+	float		v_dmg_roll, v_dmg_pitch, v_dmg_time;	// damage kicks
+	float		fall_time, fall_value;		// for view drop on fall
+	float		damage_alpha;
+	float		bonus_alpha;
+	vec3_t		damage_blend;
+	vec3_t		v_angle;			// aiming direction
+	float		bobtime;			// so off-ground doesn't change it
+	vec3_t		oldviewangles;
+	vec3_t		oldvelocity;
+
+	float		next_drown_time;
+	int			old_waterlevel;
+	int			breather_sound;
+
+	int			machinegun_shots;	// for weapon raising
+
+	// animation vars
+	int			anim_end;
+	int			anim_priority;
+	qboolean	anim_duck;
+	qboolean	anim_run;
+
+	// powerup timers
+	float		quad_framenum;
+	float		invincible_framenum;
+	float		breather_framenum;
+	float		enviro_framenum;
+
+	qboolean	grenade_blew_up;
+	float		grenade_time;
+	int			silencer_shots;
+	int			weapon_sound;
+
+	float		pickup_msg_time;
+
+	float		flood_locktill;		// locked from talking
+	float		flood_when[10];		// when messages were said
+	int			flood_whenhead;		// head pointer for when said
+
+	float		respawn_time;		// can respawn when time > this
+
+	edict_t		*chase_target;		// player we are chasing
+	qboolean	update_chase;		// need to update chase info?
+};
+
+
+struct edict_s
+{
+	entity_state_t	s;
+	struct gclient_s	*client;	// NULL if not a player
+									// the server expects the first part
+									// of gclient_s to be a player_state_t
+									// but the rest of it is opaque
+
+	qboolean	inuse;
+	int			linkcount;
+
+	// FIXME: move these fields to a server private sv_entity_t
+	link_t		area;				// linked to a division node or leaf
+	
+	int			num_clusters;		// if -1, use headnode instead
+	int			clusternums[MAX_ENT_CLUSTERS];
+	int			headnode;			// unused if num_clusters != -1
+	int			areanum, areanum2;
+
+	//================================
+
+	int			svflags;
+	vec3_t		mins, maxs;
+	vec3_t		absmin, absmax, size;
+	solid_t		solid;
+	int			clipmask;
+	edict_t		*owner;
+
+
+	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
+	// EXPECTS THE FIELDS IN THAT ORDER!
+
+	//================================
+	int			movetype;
+	int			flags;
+
+	char		*model;
+	float		freetime;			// sv.time when the object was freed
+	
+	//
+	// only used locally in game, not by server
+	//
+	char		*message;
+	char		*classname;
+	int			spawnflags;
+
+	float		timestamp;
+
+	float		angle;			// set in qe3, -1 = up, -2 = down
+	char		*target;
+	char		*targetname;
+	char		*killtarget;
+	char		*team;
+	char		*pathtarget;
+	char		*deathtarget;
+	char		*combattarget;
+	edict_t		*target_ent;
+
+	float		speed, accel, decel;
+	vec3_t		movedir;
+	vec3_t		pos1, pos2;
+
+	vec3_t		velocity;
+	vec3_t		avelocity;
+	int			mass;
+	float		air_finished;
+	float		gravity;		// per entity gravity multiplier (1.0 is normal)
+								// use for lowgrav artifact, flares
+
+	edict_t		*goalentity;
+	edict_t		*movetarget;
+	float		yaw_speed;
+	float		ideal_yaw;
+
+	float		nextthink;
+	void		(*prethink) (edict_t *ent);
+	void		(*think)(edict_t *self);
+	void		(*blocked)(edict_t *self, edict_t *other);	//move to moveinfo?
+	void		(*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
+	void		(*use)(edict_t *self, edict_t *other, edict_t *activator);
+	void		(*pain)(edict_t *self, edict_t *other, float kick, int damage);
+	void		(*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+
+	float		touch_debounce_time;		// are all these legit?  do we need more/less of them?
+	float		pain_debounce_time;
+	float		damage_debounce_time;
+	float		fly_sound_debounce_time;	//move to clientinfo
+	float		last_move_time;
+
+	int			health;
+	int			max_health;
+	int			gib_health;
+	int			deadflag;
+	qboolean	show_hostile;
+
+	float		powerarmor_time;
+
+	char		*map;			// target_changelevel
+
+	int			viewheight;		// height above origin where eyesight is determined
+	int			takedamage;
+	int			dmg;
+	int			radius_dmg;
+	float		dmg_radius;
+	int			sounds;			//make this a spawntemp var?
+	int			count;
+
+	edict_t		*chain;
+	edict_t		*enemy;
+	edict_t		*oldenemy;
+	edict_t		*activator;
+	edict_t		*groundentity;
+	int			groundentity_linkcount;
+	edict_t		*teamchain;
+	edict_t		*teammaster;
+
+	edict_t		*mynoise;		// can go in client only
+	edict_t		*mynoise2;
+
+	int			noise_index;
+	int			noise_index2;
+	float		volume;
+	float		attenuation;
+
+	// timing variables
+	float		wait;
+	float		delay;			// before firing targets
+	float		random;
+
+	float		teleport_time;
+
+	int			watertype;
+	int			waterlevel;
+
+	vec3_t		move_origin;
+	vec3_t		move_angles;
+
+	// move this to clientinfo?
+	int			light_level;
+
+	int			style;			// also used as areaportal number
+
+	gitem_t		*item;			// for bonus items
+
+	// common data blocks
+	moveinfo_t		moveinfo;
+	monsterinfo_t	monsterinfo;
+};
+
--- /dev/null
+++ b/game/g_main.c
@@ -1,0 +1,411 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+game_locals_t	game;
+level_locals_t	level;
+game_import_t	gi;
+game_export_t	globals;
+spawn_temp_t	st;
+
+int	sm_meat_index;
+int	snd_fry;
+int meansOfDeath;
+
+edict_t		*g_edicts;
+
+cvar_t	*deathmatch;
+cvar_t	*coop;
+cvar_t	*dmflags;
+cvar_t	*skill;
+cvar_t	*fraglimit;
+cvar_t	*timelimit;
+cvar_t	*password;
+cvar_t	*spectator_password;
+cvar_t	*maxclients;
+cvar_t	*maxspectators;
+cvar_t	*maxentities;
+cvar_t	*g_select_empty;
+cvar_t	*dedicated;
+
+cvar_t	*filterban;
+
+cvar_t	*sv_maxvelocity;
+cvar_t	*sv_gravity;
+
+cvar_t	*sv_rollspeed;
+cvar_t	*sv_rollangle;
+cvar_t	*gun_x;
+cvar_t	*gun_y;
+cvar_t	*gun_z;
+
+cvar_t	*run_pitch;
+cvar_t	*run_roll;
+cvar_t	*bob_up;
+cvar_t	*bob_pitch;
+cvar_t	*bob_roll;
+
+cvar_t	*sv_cheats;
+
+cvar_t	*flood_msgs;
+cvar_t	*flood_persecond;
+cvar_t	*flood_waitdelay;
+
+cvar_t	*sv_maplist;
+
+void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
+void ClientThink (edict_t *ent, usercmd_t *cmd);
+qboolean ClientConnect (edict_t *ent, char *userinfo);
+void ClientUserinfoChanged (edict_t *ent, char *userinfo);
+void ClientDisconnect (edict_t *ent);
+void ClientBegin (edict_t *ent);
+void ClientCommand (edict_t *ent);
+void RunEntity (edict_t *ent);
+void WriteGame (char *filename, qboolean autosave);
+void ReadGame (char *filename);
+void WriteLevel (char *filename);
+void ReadLevel (char *filename);
+void InitGame (void);
+void G_RunFrame (void);
+
+
+//===================================================================
+
+
+void ShutdownGame (void)
+{
+	gi.dprintf ("==== ShutdownGame ====\n");
+
+	gi.FreeTags (TAG_LEVEL);
+	gi.FreeTags (TAG_GAME);
+}
+
+
+/*
+=================
+GetGameAPI
+
+Returns a pointer to the structure with all entry points
+and global variables
+=================
+*/
+game_export_t *GetGameAPI (game_import_t *import)
+{
+	gi = *import;
+
+	globals.apiversion = GAME_API_VERSION;
+	globals.Init = InitGame;
+	globals.Shutdown = ShutdownGame;
+	globals.SpawnEntities = SpawnEntities;
+
+	globals.WriteGame = WriteGame;
+	globals.ReadGame = ReadGame;
+	globals.WriteLevel = WriteLevel;
+	globals.ReadLevel = ReadLevel;
+
+	globals.ClientThink = ClientThink;
+	globals.ClientConnect = ClientConnect;
+	globals.ClientUserinfoChanged = ClientUserinfoChanged;
+	globals.ClientDisconnect = ClientDisconnect;
+	globals.ClientBegin = ClientBegin;
+	globals.ClientCommand = ClientCommand;
+
+	globals.RunFrame = G_RunFrame;
+
+	globals.ServerCommand = ServerCommand;
+
+	globals.edict_size = sizeof(edict_t);
+
+	return &globals;
+}
+
+#ifndef GAME_HARD_LINKED
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, error);
+	vsprintf (text, error, argptr);
+	va_end (argptr);
+
+	gi.error (ERR_FATAL, "%s", text);
+}
+
+void Com_Printf (char *msg, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, msg);
+	vsprintf (text, msg, argptr);
+	va_end (argptr);
+
+	gi.dprintf ("%s", text);
+}
+
+#endif
+
+//======================================================================
+
+
+/*
+=================
+ClientEndServerFrames
+=================
+*/
+void ClientEndServerFrames (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	// calc the player views now that all pushing
+	// and damage has been added
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = g_edicts + 1 + i;
+		if (!ent->inuse || !ent->client)
+			continue;
+		ClientEndServerFrame (ent);
+	}
+
+}
+
+/*
+=================
+CreateTargetChangeLevel
+
+Returns the created target changelevel
+=================
+*/
+edict_t *CreateTargetChangeLevel(char *map)
+{
+	edict_t *ent;
+
+	ent = G_Spawn ();
+	ent->classname = "target_changelevel";
+	Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
+	ent->map = level.nextmap;
+	return ent;
+}
+
+/*
+=================
+EndDMLevel
+
+The timelimit or fraglimit has been exceeded
+=================
+*/
+void EndDMLevel (void)
+{
+	edict_t		*ent;
+	char *s, *t, *f;
+	static const char *seps = " ,\n\r";
+
+	// stay on same level flag
+	if ((int)dmflags->value & DF_SAME_LEVEL)
+	{
+		BeginIntermission (CreateTargetChangeLevel (level.mapname) );
+		return;
+	}
+
+	// see if it's in the map list
+	if (*sv_maplist->string) {
+		s = strdup(sv_maplist->string);
+		f = NULL;
+		t = strtok(s, seps);
+		while (t != NULL) {
+			if (Q_stricmp(t, level.mapname) == 0) {
+				// it's in the list, go to the next one
+				t = strtok(NULL, seps);
+				if (t == NULL) { // end of list, go to first one
+					if (f == NULL) // there isn't a first one, same level
+						BeginIntermission (CreateTargetChangeLevel (level.mapname) );
+					else
+						BeginIntermission (CreateTargetChangeLevel (f) );
+				} else
+					BeginIntermission (CreateTargetChangeLevel (t) );
+				free(s);
+				return;
+			}
+			if (!f)
+				f = t;
+			t = strtok(NULL, seps);
+		}
+		free(s);
+	}
+
+	if (level.nextmap[0]) // go to a specific map
+		BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
+	else {	// search for a changelevel
+		ent = G_Find (NULL, FOFS(classname), "target_changelevel");
+		if (!ent)
+		{	// the map designer didn't include a changelevel,
+			// so create a fake ent that goes back to the same level
+			BeginIntermission (CreateTargetChangeLevel (level.mapname) );
+			return;
+		}
+		BeginIntermission (ent);
+	}
+}
+
+/*
+=================
+CheckDMRules
+=================
+*/
+void CheckDMRules (void)
+{
+	int			i;
+	gclient_t	*cl;
+
+	if (level.intermissiontime)
+		return;
+
+	if (!deathmatch->value)
+		return;
+
+	if (timelimit->value)
+	{
+		if (level.time >= timelimit->value*60)
+		{
+			gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
+			EndDMLevel ();
+			return;
+		}
+	}
+
+	if (fraglimit->value)
+	{
+		for (i=0 ; i<maxclients->value ; i++)
+		{
+			cl = game.clients + i;
+			if (!g_edicts[i+1].inuse)
+				continue;
+
+			if (cl->resp.score >= fraglimit->value)
+			{
+				gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
+				EndDMLevel ();
+				return;
+			}
+		}
+	}
+}
+
+
+/*
+=============
+ExitLevel
+=============
+*/
+void ExitLevel (void)
+{
+	int		i;
+	edict_t	*ent;
+	char	command [256];
+
+	Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
+	gi.AddCommandString (command);
+	level.changemap = NULL;
+	level.exitintermission = 0;
+	level.intermissiontime = 0;
+	ClientEndServerFrames ();
+
+	// clear some things before going to next level
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = g_edicts + 1 + i;
+		if (!ent->inuse)
+			continue;
+		if (ent->health > ent->client->pers.max_health)
+			ent->health = ent->client->pers.max_health;
+	}
+
+}
+
+/*
+================
+G_RunFrame
+
+Advances the world by 0.1 seconds
+================
+*/
+void G_RunFrame (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	level.framenum++;
+	level.time = level.framenum*FRAMETIME;
+
+	// choose a client for monsters to target this frame
+	AI_SetSightClient ();
+
+	// exit intermissions
+
+	if (level.exitintermission)
+	{
+		ExitLevel ();
+		return;
+	}
+
+	//
+	// treat each object in turn
+	// even the world gets a chance to think
+	//
+	ent = &g_edicts[0];
+	for (i=0 ; i<globals.num_edicts ; i++, ent++)
+	{
+		if (!ent->inuse)
+			continue;
+
+		level.current_entity = ent;
+
+		VectorCopy (ent->s.origin, ent->s.old_origin);
+
+		// if the ground entity moved, make sure we are still on it
+		if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
+		{
+			ent->groundentity = NULL;
+			if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
+			{
+				M_CheckGround (ent);
+			}
+		}
+
+		if (i > 0 && i <= maxclients->value)
+		{
+			ClientBeginServerFrame (ent);
+			continue;
+		}
+
+		G_RunEntity (ent);
+	}
+
+	// see if it is time to end a deathmatch
+	CheckDMRules ();
+
+	// build the playerstate_t structures for all players
+	ClientEndServerFrames ();
+}
+
--- /dev/null
+++ b/game/g_misc.c
@@ -1,0 +1,1876 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_misc.c
+
+#include "g_local.h"
+
+
+/*QUAKED func_group (0 0 0) ?
+Used to group brushes together just for editor convenience.
+*/
+
+//=====================================================
+
+void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	ent->count ^= 1;		// toggle state
+//	gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
+	gi.SetAreaPortalState (ent->style, ent->count);
+}
+
+/*QUAKED func_areaportal (0 0 0) ?
+
+This is a non-visible object that divides the world into
+areas that are seperated when this portal is not activated.
+Usually enclosed in the middle of a door.
+*/
+void SP_func_areaportal (edict_t *ent)
+{
+	ent->use = Use_Areaportal;
+	ent->count = 0;		// always start closed;
+}
+
+//=====================================================
+
+
+/*
+=================
+Misc functions
+=================
+*/
+void VelocityForDamage (int damage, vec3_t v)
+{
+	v[0] = 100.0 * crandom();
+	v[1] = 100.0 * crandom();
+	v[2] = 200.0 + 100.0 * random();
+
+	if (damage < 50)
+		VectorScale (v, 0.7, v);
+	else 
+		VectorScale (v, 1.2, v);
+}
+
+void ClipGibVelocity (edict_t *ent)
+{
+	if (ent->velocity[0] < -300)
+		ent->velocity[0] = -300;
+	else if (ent->velocity[0] > 300)
+		ent->velocity[0] = 300;
+	if (ent->velocity[1] < -300)
+		ent->velocity[1] = -300;
+	else if (ent->velocity[1] > 300)
+		ent->velocity[1] = 300;
+	if (ent->velocity[2] < 200)
+		ent->velocity[2] = 200;	// always some upwards
+	else if (ent->velocity[2] > 500)
+		ent->velocity[2] = 500;
+}
+
+
+/*
+=================
+gibs
+=================
+*/
+void gib_think (edict_t *self)
+{
+	self->s.frame++;
+	self->nextthink = level.time + FRAMETIME;
+
+	if (self->s.frame == 10)
+	{
+		self->think = G_FreeEdict;
+		self->nextthink = level.time + 8 + random()*10;
+	}
+}
+
+void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t	normal_angles, right;
+
+	if (!self->groundentity)
+		return;
+
+	self->touch = NULL;
+
+	if (plane)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
+
+		vectoangles (plane->normal, normal_angles);
+		AngleVectors (normal_angles, NULL, right, NULL);
+		vectoangles (right, self->s.angles);
+
+		if (self->s.modelindex == sm_meat_index)
+		{
+			self->s.frame++;
+			self->think = gib_think;
+			self->nextthink = level.time + FRAMETIME;
+		}
+	}
+}
+
+void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	G_FreeEdict (self);
+}
+
+void ThrowGib (edict_t *self, char *gibname, int damage, int type)
+{
+	edict_t *gib;
+	vec3_t	vd;
+	vec3_t	origin;
+	vec3_t	size;
+	float	vscale;
+
+	gib = G_Spawn();
+
+	VectorScale (self->size, 0.5, size);
+	VectorAdd (self->absmin, size, origin);
+	gib->s.origin[0] = origin[0] + crandom() * size[0];
+	gib->s.origin[1] = origin[1] + crandom() * size[1];
+	gib->s.origin[2] = origin[2] + crandom() * size[2];
+
+	gi.setmodel (gib, gibname);
+	gib->solid = SOLID_NOT;
+	gib->s.effects |= EF_GIB;
+	gib->flags |= FL_NO_KNOCKBACK;
+	gib->takedamage = DAMAGE_YES;
+	gib->die = gib_die;
+
+	if (type == GIB_ORGANIC)
+	{
+		gib->movetype = MOVETYPE_TOSS;
+		gib->touch = gib_touch;
+		vscale = 0.5;
+	}
+	else
+	{
+		gib->movetype = MOVETYPE_BOUNCE;
+		vscale = 1.0;
+	}
+
+	VelocityForDamage (damage, vd);
+	VectorMA (self->velocity, vscale, vd, gib->velocity);
+	ClipGibVelocity (gib);
+	gib->avelocity[0] = random()*600;
+	gib->avelocity[1] = random()*600;
+	gib->avelocity[2] = random()*600;
+
+	gib->think = G_FreeEdict;
+	gib->nextthink = level.time + 10 + random()*10;
+
+	gi.linkentity (gib);
+}
+
+void ThrowHead (edict_t *self, char *gibname, int damage, int type)
+{
+	vec3_t	vd;
+	float	vscale;
+
+	self->s.skinnum = 0;
+	self->s.frame = 0;
+	VectorClear (self->mins);
+	VectorClear (self->maxs);
+
+	self->s.modelindex2 = 0;
+	gi.setmodel (self, gibname);
+	self->solid = SOLID_NOT;
+	self->s.effects |= EF_GIB;
+	self->s.effects &= ~EF_FLIES;
+	self->s.sound = 0;
+	self->flags |= FL_NO_KNOCKBACK;
+	self->svflags &= ~SVF_MONSTER;
+	self->takedamage = DAMAGE_YES;
+	self->die = gib_die;
+
+	if (type == GIB_ORGANIC)
+	{
+		self->movetype = MOVETYPE_TOSS;
+		self->touch = gib_touch;
+		vscale = 0.5;
+	}
+	else
+	{
+		self->movetype = MOVETYPE_BOUNCE;
+		vscale = 1.0;
+	}
+
+	VelocityForDamage (damage, vd);
+	VectorMA (self->velocity, vscale, vd, self->velocity);
+	ClipGibVelocity (self);
+
+	self->avelocity[YAW] = crandom()*600;
+
+	self->think = G_FreeEdict;
+	self->nextthink = level.time + 10 + random()*10;
+
+	gi.linkentity (self);
+}
+
+
+void ThrowClientHead (edict_t *self, int damage)
+{
+	vec3_t	vd;
+	char	*gibname;
+
+	if (rand()&1)
+	{
+		gibname = "models/objects/gibs/head2/tris.md2";
+		self->s.skinnum = 1;		// second skin is player
+	}
+	else
+	{
+		gibname = "models/objects/gibs/skull/tris.md2";
+		self->s.skinnum = 0;
+	}
+
+	self->s.origin[2] += 32;
+	self->s.frame = 0;
+	gi.setmodel (self, gibname);
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 16);
+
+	self->takedamage = DAMAGE_NO;
+	self->solid = SOLID_NOT;
+	self->s.effects = EF_GIB;
+	self->s.sound = 0;
+	self->flags |= FL_NO_KNOCKBACK;
+
+	self->movetype = MOVETYPE_BOUNCE;
+	VelocityForDamage (damage, vd);
+	VectorAdd (self->velocity, vd, self->velocity);
+
+	if (self->client)	// bodies in the queue don't have a client anymore
+	{
+		self->client->anim_priority = ANIM_DEATH;
+		self->client->anim_end = self->s.frame;
+	}
+	else
+	{
+		self->think = NULL;
+		self->nextthink = 0;
+	}
+
+	gi.linkentity (self);
+}
+
+
+/*
+=================
+debris
+=================
+*/
+void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	G_FreeEdict (self);
+}
+
+void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
+{
+	edict_t	*chunk;
+	vec3_t	v;
+
+	chunk = G_Spawn();
+	VectorCopy (origin, chunk->s.origin);
+	gi.setmodel (chunk, modelname);
+	v[0] = 100 * crandom();
+	v[1] = 100 * crandom();
+	v[2] = 100 + 100 * crandom();
+	VectorMA (self->velocity, speed, v, chunk->velocity);
+	chunk->movetype = MOVETYPE_BOUNCE;
+	chunk->solid = SOLID_NOT;
+	chunk->avelocity[0] = random()*600;
+	chunk->avelocity[1] = random()*600;
+	chunk->avelocity[2] = random()*600;
+	chunk->think = G_FreeEdict;
+	chunk->nextthink = level.time + 5 + random()*5;
+	chunk->s.frame = 0;
+	chunk->flags = 0;
+	chunk->classname = "debris";
+	chunk->takedamage = DAMAGE_YES;
+	chunk->die = debris_die;
+	gi.linkentity (chunk);
+}
+
+
+void BecomeExplosion1 (edict_t *self)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION1);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	G_FreeEdict (self);
+}
+
+
+void BecomeExplosion2 (edict_t *self)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION2);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	G_FreeEdict (self);
+}
+
+
+/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
+Target: next path corner
+Pathtarget: gets used when an entity that has
+	this path_corner targeted touches it
+*/
+
+void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t		v;
+	edict_t		*next;
+
+	if (other->movetarget != self)
+		return;
+	
+	if (other->enemy)
+		return;
+
+	if (self->pathtarget)
+	{
+		char *savetarget;
+
+		savetarget = self->target;
+		self->target = self->pathtarget;
+		G_UseTargets (self, other);
+		self->target = savetarget;
+	}
+
+	if (self->target)
+		next = G_PickTarget(self->target);
+	else
+		next = NULL;
+
+	if ((next) && (next->spawnflags & 1))
+	{
+		VectorCopy (next->s.origin, v);
+		v[2] += next->mins[2];
+		v[2] -= other->mins[2];
+		VectorCopy (v, other->s.origin);
+		next = G_PickTarget(next->target);
+		other->s.event = EV_OTHER_TELEPORT;
+	}
+
+	other->goalentity = other->movetarget = next;
+
+	if (self->wait)
+	{
+		other->monsterinfo.pausetime = level.time + self->wait;
+		other->monsterinfo.stand (other);
+		return;
+	}
+
+	if (!other->movetarget)
+	{
+		other->monsterinfo.pausetime = level.time + 100000000;
+		other->monsterinfo.stand (other);
+	}
+	else
+	{
+		VectorSubtract (other->goalentity->s.origin, other->s.origin, v);
+		other->ideal_yaw = vectoyaw (v);
+	}
+}
+
+void SP_path_corner (edict_t *self)
+{
+	if (!self->targetname)
+	{
+		gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->solid = SOLID_TRIGGER;
+	self->touch = path_corner_touch;
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+	self->svflags |= SVF_NOCLIENT;
+	gi.linkentity (self);
+}
+
+
+/*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
+Makes this the target of a monster and it will head here
+when first activated before going after the activator.  If
+hold is selected, it will stay here.
+*/
+void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	edict_t	*activator;
+
+	if (other->movetarget != self)
+		return;
+
+	if (self->target)
+	{
+		other->target = self->target;
+		other->goalentity = other->movetarget = G_PickTarget(other->target);
+		if (!other->goalentity)
+		{
+			gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target);
+			other->movetarget = self;
+		}
+		self->target = NULL;
+	}
+	else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY)))
+	{
+		other->monsterinfo.pausetime = level.time + 100000000;
+		other->monsterinfo.aiflags |= AI_STAND_GROUND;
+		other->monsterinfo.stand (other);
+	}
+
+	if (other->movetarget == self)
+	{
+		other->target = NULL;
+		other->movetarget = NULL;
+		other->goalentity = other->enemy;
+		other->monsterinfo.aiflags &= ~AI_COMBAT_POINT;
+	}
+
+	if (self->pathtarget)
+	{
+		char *savetarget;
+
+		savetarget = self->target;
+		self->target = self->pathtarget;
+		if (other->enemy && other->enemy->client)
+			activator = other->enemy;
+		else if (other->oldenemy && other->oldenemy->client)
+			activator = other->oldenemy;
+		else if (other->activator && other->activator->client)
+			activator = other->activator;
+		else
+			activator = other;
+		G_UseTargets (self, activator);
+		self->target = savetarget;
+	}
+}
+
+void SP_point_combat (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+	self->solid = SOLID_TRIGGER;
+	self->touch = point_combat_touch;
+	VectorSet (self->mins, -8, -8, -16);
+	VectorSet (self->maxs, 8, 8, 16);
+	self->svflags = SVF_NOCLIENT;
+	gi.linkentity (self);
+};
+
+
+/*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
+Just for the debugging level.  Don't use
+*/
+void TH_viewthing(edict_t *ent)
+{
+	ent->s.frame = (ent->s.frame + 1) % 7;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void SP_viewthing(edict_t *ent)
+{
+	gi.dprintf ("viewthing spawned\n");
+
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.renderfx = RF_FRAMELERP;
+	VectorSet (ent->mins, -16, -16, -24);
+	VectorSet (ent->maxs, 16, 16, 32);
+	ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
+	gi.linkentity (ent);
+	ent->nextthink = level.time + 0.5;
+	ent->think = TH_viewthing;
+	return;
+}
+
+
+/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for spotlights, etc.
+*/
+void SP_info_null (edict_t *self)
+{
+	G_FreeEdict (self);
+};
+
+
+/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
+Used as a positional target for lightning.
+*/
+void SP_info_notnull (edict_t *self)
+{
+	VectorCopy (self->s.origin, self->absmin);
+	VectorCopy (self->s.origin, self->absmax);
+};
+
+
+/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
+Non-displayed light.
+Default light value is 300.
+Default style is 0.
+If targeted, will toggle between on and off.
+Default _cone value is 10 (used to set size of light for spotlights)
+*/
+
+#define START_OFF	1
+
+static void light_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->spawnflags & START_OFF)
+	{
+		gi.configstring (CS_LIGHTS+self->style, "m");
+		self->spawnflags &= ~START_OFF;
+	}
+	else
+	{
+		gi.configstring (CS_LIGHTS+self->style, "a");
+		self->spawnflags |= START_OFF;
+	}
+}
+
+void SP_light (edict_t *self)
+{
+	// no targeted lights in deathmatch, because they cause global messages
+	if (!self->targetname || deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (self->style >= 32)
+	{
+		self->use = light_use;
+		if (self->spawnflags & START_OFF)
+			gi.configstring (CS_LIGHTS+self->style, "a");
+		else
+			gi.configstring (CS_LIGHTS+self->style, "m");
+	}
+}
+
+
+/*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST
+This is just a solid wall if not inhibited
+
+TRIGGER_SPAWN	the wall will not be present until triggered
+				it will then blink in to existance; it will
+				kill anything that was in it's way
+
+TOGGLE			only valid for TRIGGER_SPAWN walls
+				this allows the wall to be turned on and off
+
+START_ON		only valid for TRIGGER_SPAWN walls
+				the wall will initially be present
+*/
+
+void func_wall_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->solid == SOLID_NOT)
+	{
+		self->solid = SOLID_BSP;
+		self->svflags &= ~SVF_NOCLIENT;
+		KillBox (self);
+	}
+	else
+	{
+		self->solid = SOLID_NOT;
+		self->svflags |= SVF_NOCLIENT;
+	}
+	gi.linkentity (self);
+
+	if (!(self->spawnflags & 2))
+		self->use = NULL;
+}
+
+void SP_func_wall (edict_t *self)
+{
+	self->movetype = MOVETYPE_PUSH;
+	gi.setmodel (self, self->model);
+
+	if (self->spawnflags & 8)
+		self->s.effects |= EF_ANIM_ALL;
+	if (self->spawnflags & 16)
+		self->s.effects |= EF_ANIM_ALLFAST;
+
+	// just a wall
+	if ((self->spawnflags & 7) == 0)
+	{
+		self->solid = SOLID_BSP;
+		gi.linkentity (self);
+		return;
+	}
+
+	// it must be TRIGGER_SPAWN
+	if (!(self->spawnflags & 1))
+	{
+//		gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
+		self->spawnflags |= 1;
+	}
+
+	// yell if the spawnflags are odd
+	if (self->spawnflags & 4)
+	{
+		if (!(self->spawnflags & 2))
+		{
+			gi.dprintf("func_wall START_ON without TOGGLE\n");
+			self->spawnflags |= 2;
+		}
+	}
+
+	self->use = func_wall_use;
+	if (self->spawnflags & 4)
+	{
+		self->solid = SOLID_BSP;
+	}
+	else
+	{
+		self->solid = SOLID_NOT;
+		self->svflags |= SVF_NOCLIENT;
+	}
+	gi.linkentity (self);
+}
+
+
+/*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
+This is solid bmodel that will fall if it's support it removed.
+*/
+
+void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	// only squash thing we fall on top of
+	if (!plane)
+		return;
+	if (plane->normal[2] < 1.0)
+		return;
+	if (other->takedamage == DAMAGE_NO)
+		return;
+	T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
+}
+
+void func_object_release (edict_t *self)
+{
+	self->movetype = MOVETYPE_TOSS;
+	self->touch = func_object_touch;
+}
+
+void func_object_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->solid = SOLID_BSP;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = NULL;
+	KillBox (self);
+	func_object_release (self);
+}
+
+void SP_func_object (edict_t *self)
+{
+	gi.setmodel (self, self->model);
+
+	self->mins[0] += 1;
+	self->mins[1] += 1;
+	self->mins[2] += 1;
+	self->maxs[0] -= 1;
+	self->maxs[1] -= 1;
+	self->maxs[2] -= 1;
+
+	if (!self->dmg)
+		self->dmg = 100;
+
+	if (self->spawnflags == 0)
+	{
+		self->solid = SOLID_BSP;
+		self->movetype = MOVETYPE_PUSH;
+		self->think = func_object_release;
+		self->nextthink = level.time + 2 * FRAMETIME;
+	}
+	else
+	{
+		self->solid = SOLID_NOT;
+		self->movetype = MOVETYPE_PUSH;
+		self->use = func_object_use;
+		self->svflags |= SVF_NOCLIENT;
+	}
+
+	if (self->spawnflags & 2)
+		self->s.effects |= EF_ANIM_ALL;
+	if (self->spawnflags & 4)
+		self->s.effects |= EF_ANIM_ALLFAST;
+
+	self->clipmask = MASK_MONSTERSOLID;
+
+	gi.linkentity (self);
+}
+
+
+/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
+Any brush that you want to explode or break apart.  If you want an
+ex0plosion, set dmg and it will do a radius explosion of that amount
+at the center of the bursh.
+
+If targeted it will not be shootable.
+
+health defaults to 100.
+
+mass defaults to 75.  This determines how much debris is emitted when
+it explodes.  You get one large chunk per 100 of mass (up to 8) and
+one small chunk per 25 of mass (up to 16).  So 800 gives the most.
+*/
+void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	vec3_t	origin;
+	vec3_t	chunkorigin;
+	vec3_t	size;
+	int		count;
+	int		mass;
+
+	// bmodel origins are (0 0 0), we need to adjust that here
+	VectorScale (self->size, 0.5, size);
+	VectorAdd (self->absmin, size, origin);
+	VectorCopy (origin, self->s.origin);
+
+	self->takedamage = DAMAGE_NO;
+
+	if (self->dmg)
+		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
+
+	VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
+	VectorNormalize (self->velocity);
+	VectorScale (self->velocity, 150, self->velocity);
+
+	// start chunks towards the center
+	VectorScale (size, 0.5, size);
+
+	mass = self->mass;
+	if (!mass)
+		mass = 75;
+
+	// big chunks
+	if (mass >= 100)
+	{
+		count = mass / 100;
+		if (count > 8)
+			count = 8;
+		while(count--)
+		{
+			chunkorigin[0] = origin[0] + crandom() * size[0];
+			chunkorigin[1] = origin[1] + crandom() * size[1];
+			chunkorigin[2] = origin[2] + crandom() * size[2];
+			ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
+		}
+	}
+
+	// small chunks
+	count = mass / 25;
+	if (count > 16)
+		count = 16;
+	while(count--)
+	{
+		chunkorigin[0] = origin[0] + crandom() * size[0];
+		chunkorigin[1] = origin[1] + crandom() * size[1];
+		chunkorigin[2] = origin[2] + crandom() * size[2];
+		ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
+	}
+
+	G_UseTargets (self, attacker);
+
+	if (self->dmg)
+		BecomeExplosion1 (self);
+	else
+		G_FreeEdict (self);
+}
+
+void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
+{
+	func_explosive_explode (self, self, other, self->health, vec3_origin);
+}
+
+void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->solid = SOLID_BSP;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = NULL;
+	KillBox (self);
+	gi.linkentity (self);
+}
+
+void SP_func_explosive (edict_t *self)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->movetype = MOVETYPE_PUSH;
+
+	gi.modelindex ("models/objects/debris1/tris.md2");
+	gi.modelindex ("models/objects/debris2/tris.md2");
+
+	gi.setmodel (self, self->model);
+
+	if (self->spawnflags & 1)
+	{
+		self->svflags |= SVF_NOCLIENT;
+		self->solid = SOLID_NOT;
+		self->use = func_explosive_spawn;
+	}
+	else
+	{
+		self->solid = SOLID_BSP;
+		if (self->targetname)
+			self->use = func_explosive_use;
+	}
+
+	if (self->spawnflags & 2)
+		self->s.effects |= EF_ANIM_ALL;
+	if (self->spawnflags & 4)
+		self->s.effects |= EF_ANIM_ALLFAST;
+
+	if (self->use != func_explosive_use)
+	{
+		if (!self->health)
+			self->health = 100;
+		self->die = func_explosive_explode;
+		self->takedamage = DAMAGE_YES;
+	}
+
+	gi.linkentity (self);
+}
+
+
+/*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
+Large exploding box.  You can override its mass (100),
+health (80), and dmg (150).
+*/
+
+void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+
+{
+	float	ratio;
+	vec3_t	v;
+
+	if ((!other->groundentity) || (other->groundentity == self))
+		return;
+
+	ratio = (float)other->mass / (float)self->mass;
+	VectorSubtract (self->s.origin, other->s.origin, v);
+	M_walkmove (self, vectoyaw(v), 20 * ratio * FRAMETIME);
+}
+
+void barrel_explode (edict_t *self)
+{
+	vec3_t	org;
+	float	spd;
+	vec3_t	save;
+
+	T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL);
+
+	VectorCopy (self->s.origin, save);
+	VectorMA (self->absmin, 0.5, self->size, self->s.origin);
+
+	// a few big chunks
+	spd = 1.5 * (float)self->dmg / 200.0;
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
+
+	// bottom corners
+	spd = 1.75 * (float)self->dmg / 200.0;
+	VectorCopy (self->absmin, org);
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+	VectorCopy (self->absmin, org);
+	org[0] += self->size[0];
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+	VectorCopy (self->absmin, org);
+	org[1] += self->size[1];
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+	VectorCopy (self->absmin, org);
+	org[0] += self->size[0];
+	org[1] += self->size[1];
+	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
+
+	// a bunch of little chunks
+	spd = 2 * self->dmg / 200;
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+	org[0] = self->s.origin[0] + crandom() * self->size[0];
+	org[1] = self->s.origin[1] + crandom() * self->size[1];
+	org[2] = self->s.origin[2] + crandom() * self->size[2];
+	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
+
+	VectorCopy (save, self->s.origin);
+	if (self->groundentity)
+		BecomeExplosion2 (self);
+	else
+		BecomeExplosion1 (self);
+}
+
+void barrel_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	self->takedamage = DAMAGE_NO;
+	self->nextthink = level.time + 2 * FRAMETIME;
+	self->think = barrel_explode;
+	self->activator = attacker;
+}
+
+void SP_misc_explobox (edict_t *self)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (self);
+		return;
+	}
+
+	gi.modelindex ("models/objects/debris1/tris.md2");
+	gi.modelindex ("models/objects/debris2/tris.md2");
+	gi.modelindex ("models/objects/debris3/tris.md2");
+
+	self->solid = SOLID_BBOX;
+	self->movetype = MOVETYPE_STEP;
+
+	self->model = "models/objects/barrels/tris.md2";
+	self->s.modelindex = gi.modelindex (self->model);
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 40);
+
+	if (!self->mass)
+		self->mass = 400;
+	if (!self->health)
+		self->health = 10;
+	if (!self->dmg)
+		self->dmg = 150;
+
+	self->die = barrel_delay;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.aiflags = AI_NOSTEP;
+
+	self->touch = barrel_touch;
+
+	self->think = M_droptofloor;
+	self->nextthink = level.time + 2 * FRAMETIME;
+
+	gi.linkentity (self);
+}
+
+
+//
+// miscellaneous specialty items
+//
+
+/*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8)
+*/
+
+void misc_blackhole_use (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	/*
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_BOSSTPORT);
+	gi.WritePosition (ent->s.origin);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+	*/
+	G_FreeEdict (ent);
+}
+
+void misc_blackhole_think (edict_t *self)
+{
+	if (++self->s.frame < 19)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 0;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_blackhole (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	VectorSet (ent->mins, -64, -64, 0);
+	VectorSet (ent->maxs, 64, 64, 8);
+	ent->s.modelindex = gi.modelindex ("models/objects/black/tris.md2");
+	ent->s.renderfx = RF_TRANSLUCENT;
+	ent->use = misc_blackhole_use;
+	ent->think = misc_blackhole_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32)
+*/
+
+void misc_eastertank_think (edict_t *self)
+{
+	if (++self->s.frame < 293)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 254;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_eastertank (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -32, -32, -16);
+	VectorSet (ent->maxs, 32, 32, 32);
+	ent->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
+	ent->s.frame = 254;
+	ent->think = misc_eastertank_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32)
+*/
+
+
+void misc_easterchick_think (edict_t *self)
+{
+	if (++self->s.frame < 247)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 208;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_easterchick (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -32, -32, 0);
+	VectorSet (ent->maxs, 32, 32, 32);
+	ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
+	ent->s.frame = 208;
+	ent->think = misc_easterchick_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32)
+*/
+
+
+void misc_easterchick2_think (edict_t *self)
+{
+	if (++self->s.frame < 287)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 248;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void SP_misc_easterchick2 (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -32, -32, 0);
+	VectorSet (ent->maxs, 32, 32, 32);
+	ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
+	ent->s.frame = 248;
+	ent->think = misc_easterchick2_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48)
+Not really a monster, this is the Tank Commander's decapitated body.
+There should be a item_commander_head that has this as it's target.
+*/
+
+void commander_body_think (edict_t *self)
+{
+	if (++self->s.frame < 24)
+		self->nextthink = level.time + FRAMETIME;
+	else
+		self->nextthink = 0;
+
+	if (self->s.frame == 22)
+		gi.sound (self, CHAN_BODY, gi.soundindex ("tank/thud.wav"), 1, ATTN_NORM, 0);
+}
+
+void commander_body_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->think = commander_body_think;
+	self->nextthink = level.time + FRAMETIME;
+	gi.sound (self, CHAN_BODY, gi.soundindex ("tank/pain.wav"), 1, ATTN_NORM, 0);
+}
+
+void commander_body_drop (edict_t *self)
+{
+	self->movetype = MOVETYPE_TOSS;
+	self->s.origin[2] += 2;
+}
+
+void SP_monster_commander_body (edict_t *self)
+{
+	self->movetype = MOVETYPE_NONE;
+	self->solid = SOLID_BBOX;
+	self->model = "models/monsters/commandr/tris.md2";
+	self->s.modelindex = gi.modelindex (self->model);
+	VectorSet (self->mins, -32, -32, 0);
+	VectorSet (self->maxs, 32, 32, 48);
+	self->use = commander_body_use;
+	self->takedamage = DAMAGE_YES;
+	self->flags = FL_GODMODE;
+	self->s.renderfx |= RF_FRAMELERP;
+	gi.linkentity (self);
+
+	gi.soundindex ("tank/thud.wav");
+	gi.soundindex ("tank/pain.wav");
+
+	self->think = commander_body_drop;
+	self->nextthink = level.time + 5 * FRAMETIME;
+}
+
+
+/*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4)
+The origin is the bottom of the banner.
+The banner is 128 tall.
+*/
+void misc_banner_think (edict_t *ent)
+{
+	ent->s.frame = (ent->s.frame + 1) % 16;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+void SP_misc_banner (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
+	ent->s.frame = rand() % 16;
+	gi.linkentity (ent);
+
+	ent->think = misc_banner_think;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+/*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED
+This is the dead player model. Comes in 6 exciting different poses!
+*/
+void misc_deadsoldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	if (self->health > -80)
+		return;
+
+	gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+	for (n= 0; n < 4; n++)
+		ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+	ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+}
+
+void SP_misc_deadsoldier (edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.modelindex=gi.modelindex ("models/deadbods/dude/tris.md2");
+
+	// Defaults to frame 0
+	if (ent->spawnflags & 2)
+		ent->s.frame = 1;
+	else if (ent->spawnflags & 4)
+		ent->s.frame = 2;
+	else if (ent->spawnflags & 8)
+		ent->s.frame = 3;
+	else if (ent->spawnflags & 16)
+		ent->s.frame = 4;
+	else if (ent->spawnflags & 32)
+		ent->s.frame = 5;
+	else
+		ent->s.frame = 0;
+
+	VectorSet (ent->mins, -16, -16, 0);
+	VectorSet (ent->maxs, 16, 16, 16);
+	ent->deadflag = DEAD_DEAD;
+	ent->takedamage = DAMAGE_YES;
+	ent->svflags |= SVF_MONSTER|SVF_DEADMONSTER;
+	ent->die = misc_deadsoldier_die;
+	ent->monsterinfo.aiflags |= AI_GOOD_GUY;
+
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32)
+This is the Viper for the flyby bombing.
+It is trigger_spawned, so you must have something use it for it to show up.
+There must be a path for it to follow once it is activated.
+
+"speed"		How fast the Viper should fly
+*/
+
+extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
+extern void func_train_find (edict_t *self);
+
+void misc_viper_use  (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = train_use;
+	train_use (self, other, activator);
+}
+
+void SP_misc_viper (edict_t *ent)
+{
+	if (!ent->target)
+	{
+		gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!ent->speed)
+		ent->speed = 300;
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2");
+	VectorSet (ent->mins, -16, -16, 0);
+	VectorSet (ent->maxs, 16, 16, 32);
+
+	ent->think = func_train_find;
+	ent->nextthink = level.time + FRAMETIME;
+	ent->use = misc_viper_use;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
+
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72) 
+This is a large stationary viper as seen in Paul's intro
+*/
+void SP_misc_bigviper (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -176, -120, -24);
+	VectorSet (ent->maxs, 176, 120, 72);
+	ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8)
+"dmg"	how much boom should the bomb make?
+*/
+void misc_viper_bomb_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	G_UseTargets (self, self->activator);
+
+	self->s.origin[2] = self->absmin[2] + 1;
+	T_RadiusDamage (self, self, self->dmg, NULL, self->dmg+40, MOD_BOMB);
+	BecomeExplosion2 (self);
+}
+
+void misc_viper_bomb_prethink (edict_t *self)
+{
+	vec3_t	v;
+	float	diff;
+
+	self->groundentity = NULL;
+
+	diff = self->timestamp - level.time;
+	if (diff < -1.0)
+		diff = -1.0;
+
+	VectorScale (self->moveinfo.dir, 1.0 + diff, v);
+	v[2] = diff;
+
+	diff = self->s.angles[2];
+	vectoangles (v, self->s.angles);
+	self->s.angles[2] = diff + 10;
+}
+
+void misc_viper_bomb_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t	*viper;
+
+	self->solid = SOLID_BBOX;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->s.effects |= EF_ROCKET;
+	self->use = NULL;
+	self->movetype = MOVETYPE_TOSS;
+	self->prethink = misc_viper_bomb_prethink;
+	self->touch = misc_viper_bomb_touch;
+	self->activator = activator;
+
+	viper = G_Find (NULL, FOFS(classname), "misc_viper");
+	VectorScale (viper->moveinfo.dir, viper->moveinfo.speed, self->velocity);
+
+	self->timestamp = level.time;
+	VectorCopy (viper->moveinfo.dir, self->moveinfo.dir);
+}
+
+void SP_misc_viper_bomb (edict_t *self)
+{
+	self->movetype = MOVETYPE_NONE;
+	self->solid = SOLID_NOT;
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+
+	self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2");
+
+	if (!self->dmg)
+		self->dmg = 1000;
+
+	self->use = misc_viper_bomb_use;
+	self->svflags |= SVF_NOCLIENT;
+
+	gi.linkentity (self);
+}
+
+
+/*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32)
+This is a Storgg ship for the flybys.
+It is trigger_spawned, so you must have something use it for it to show up.
+There must be a path for it to follow once it is activated.
+
+"speed"		How fast it should fly
+*/
+
+extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
+extern void func_train_find (edict_t *self);
+
+void misc_strogg_ship_use  (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->svflags &= ~SVF_NOCLIENT;
+	self->use = train_use;
+	train_use (self, other, activator);
+}
+
+void SP_misc_strogg_ship (edict_t *ent)
+{
+	if (!ent->target)
+	{
+		gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!ent->speed)
+		ent->speed = 300;
+
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_NOT;
+	ent->s.modelindex = gi.modelindex ("models/ships/strogg1/tris.md2");
+	VectorSet (ent->mins, -16, -16, 0);
+	VectorSet (ent->maxs, 16, 16, 32);
+
+	ent->think = func_train_find;
+	ent->nextthink = level.time + FRAMETIME;
+	ent->use = misc_strogg_ship_use;
+	ent->svflags |= SVF_NOCLIENT;
+	ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
+
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128)
+*/
+void misc_satellite_dish_think (edict_t *self)
+{
+	self->s.frame++;
+	if (self->s.frame < 38)
+		self->nextthink = level.time + FRAMETIME;
+}
+
+void misc_satellite_dish_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->s.frame = 0;
+	self->think = misc_satellite_dish_think;
+	self->nextthink = level.time + FRAMETIME;
+}
+
+void SP_misc_satellite_dish (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	VectorSet (ent->mins, -64, -64, 0);
+	VectorSet (ent->maxs, 64, 64, 128);
+	ent->s.modelindex = gi.modelindex ("models/objects/satellite/tris.md2");
+	ent->use = misc_satellite_dish_use;
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
+*/
+void SP_light_mine1 (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.modelindex = gi.modelindex ("models/objects/minelite/light1/tris.md2");
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
+*/
+void SP_light_mine2 (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_BBOX;
+	ent->s.modelindex = gi.modelindex ("models/objects/minelite/light2/tris.md2");
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
+Intended for use with the target_spawner
+*/
+void SP_misc_gib_arm (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/gibs/arm/tris.md2");
+	ent->solid = SOLID_NOT;
+	ent->s.effects |= EF_GIB;
+	ent->takedamage = DAMAGE_YES;
+	ent->die = gib_die;
+	ent->movetype = MOVETYPE_TOSS;
+	ent->svflags |= SVF_MONSTER;
+	ent->deadflag = DEAD_DEAD;
+	ent->avelocity[0] = random()*200;
+	ent->avelocity[1] = random()*200;
+	ent->avelocity[2] = random()*200;
+	ent->think = G_FreeEdict;
+	ent->nextthink = level.time + 30;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
+Intended for use with the target_spawner
+*/
+void SP_misc_gib_leg (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/gibs/leg/tris.md2");
+	ent->solid = SOLID_NOT;
+	ent->s.effects |= EF_GIB;
+	ent->takedamage = DAMAGE_YES;
+	ent->die = gib_die;
+	ent->movetype = MOVETYPE_TOSS;
+	ent->svflags |= SVF_MONSTER;
+	ent->deadflag = DEAD_DEAD;
+	ent->avelocity[0] = random()*200;
+	ent->avelocity[1] = random()*200;
+	ent->avelocity[2] = random()*200;
+	ent->think = G_FreeEdict;
+	ent->nextthink = level.time + 30;
+	gi.linkentity (ent);
+}
+
+/*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
+Intended for use with the target_spawner
+*/
+void SP_misc_gib_head (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/gibs/head/tris.md2");
+	ent->solid = SOLID_NOT;
+	ent->s.effects |= EF_GIB;
+	ent->takedamage = DAMAGE_YES;
+	ent->die = gib_die;
+	ent->movetype = MOVETYPE_TOSS;
+	ent->svflags |= SVF_MONSTER;
+	ent->deadflag = DEAD_DEAD;
+	ent->avelocity[0] = random()*200;
+	ent->avelocity[1] = random()*200;
+	ent->avelocity[2] = random()*200;
+	ent->think = G_FreeEdict;
+	ent->nextthink = level.time + 30;
+	gi.linkentity (ent);
+}
+
+//=====================================================
+
+/*QUAKED target_character (0 0 1) ?
+used with target_string (must be on same "team")
+"count" is position in the string (starts at 1)
+*/
+
+void SP_target_character (edict_t *self)
+{
+	self->movetype = MOVETYPE_PUSH;
+	gi.setmodel (self, self->model);
+	self->solid = SOLID_BSP;
+	self->s.frame = 12;
+	gi.linkentity (self);
+	return;
+}
+
+
+/*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
+*/
+
+void target_string_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t *e;
+	int		n, l;
+	char	c;
+
+	l = strlen(self->message);
+	for (e = self->teammaster; e; e = e->teamchain)
+	{
+		if (!e->count)
+			continue;
+		n = e->count - 1;
+		if (n > l)
+		{
+			e->s.frame = 12;
+			continue;
+		}
+
+		c = self->message[n];
+		if (c >= '0' && c <= '9')
+			e->s.frame = c - '0';
+		else if (c == '-')
+			e->s.frame = 10;
+		else if (c == ':')
+			e->s.frame = 11;
+		else
+			e->s.frame = 12;
+	}
+}
+
+void SP_target_string (edict_t *self)
+{
+	if (!self->message)
+		self->message = "";
+	self->use = target_string_use;
+}
+
+
+/*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
+target a target_string with this
+
+The default is to be a time of day clock
+
+TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
+If START_OFF, this entity must be used before it starts
+
+"style"		0 "xx"
+			1 "xx:xx"
+			2 "xx:xx:xx"
+*/
+
+#define	CLOCK_MESSAGE_SIZE	16
+
+// don't let field width of any clock messages change, or it
+// could cause an overwrite after a game load
+
+static void func_clock_reset (edict_t *self)
+{
+	self->activator = NULL;
+	if (self->spawnflags & 1)
+	{
+		self->health = 0;
+		self->wait = self->count;
+	}
+	else if (self->spawnflags & 2)
+	{
+		self->health = self->count;
+		self->wait = 0;
+	}
+}
+
+static void func_clock_format_countdown (edict_t *self)
+{
+	if (self->style == 0)
+	{
+		Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health);
+		return;
+	}
+
+	if (self->style == 1)
+	{
+		Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60);
+		if (self->message[3] == ' ')
+			self->message[3] = '0';
+		return;
+	}
+
+	if (self->style == 2)
+	{
+		Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60);
+		if (self->message[3] == ' ')
+			self->message[3] = '0';
+		if (self->message[6] == ' ')
+			self->message[6] = '0';
+		return;
+	}
+}
+
+void func_clock_think (edict_t *self)
+{
+	if (!self->enemy)
+	{
+		self->enemy = G_Find (NULL, FOFS(targetname), self->target);
+		if (!self->enemy)
+			return;
+	}
+
+	if (self->spawnflags & 1)
+	{
+		func_clock_format_countdown (self);
+		self->health++;
+	}
+	else if (self->spawnflags & 2)
+	{
+		func_clock_format_countdown (self);
+		self->health--;
+	}
+	else
+	{
+		struct tm	*ltime;
+		time_t		gmtime;
+
+		time(&gmtime);
+		ltime = localtime(&gmtime);
+		Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
+		if (self->message[3] == ' ')
+			self->message[3] = '0';
+		if (self->message[6] == ' ')
+			self->message[6] = '0';
+	}
+
+	self->enemy->message = self->message;
+	self->enemy->use (self->enemy, self, self);
+
+	if (((self->spawnflags & 1) && (self->health > self->wait)) ||
+		((self->spawnflags & 2) && (self->health < self->wait)))
+	{
+		if (self->pathtarget)
+		{
+			char *savetarget;
+			char *savemessage;
+
+			savetarget = self->target;
+			savemessage = self->message;
+			self->target = self->pathtarget;
+			self->message = NULL;
+			G_UseTargets (self, self->activator);
+			self->target = savetarget;
+			self->message = savemessage;
+		}
+
+		if (!(self->spawnflags & 8))
+			return;
+
+		func_clock_reset (self);
+
+		if (self->spawnflags & 4)
+			return;
+	}
+
+	self->nextthink = level.time + 1;
+}
+
+void func_clock_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (!(self->spawnflags & 8))
+		self->use = NULL;
+	if (self->activator)
+		return;
+	self->activator = activator;
+	self->think (self);
+}
+
+void SP_func_clock (edict_t *self)
+{
+	if (!self->target)
+	{
+		gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if ((self->spawnflags & 2) && (!self->count))
+	{
+		gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if ((self->spawnflags & 1) && (!self->count))
+		self->count = 60*60;;
+
+	func_clock_reset (self);
+
+	self->message = gi.TagMalloc (CLOCK_MESSAGE_SIZE, TAG_LEVEL);
+
+	self->think = func_clock_think;
+
+	if (self->spawnflags & 4)
+		self->use = func_clock_use;
+	else
+		self->nextthink = level.time + 1;
+}
+
+//=================================================================================
+
+void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	edict_t		*dest;
+	int			i;
+
+	if (!other->client)
+		return;
+	dest = G_Find (NULL, FOFS(targetname), self->target);
+	if (!dest)
+	{
+		gi.dprintf ("Couldn't find destination\n");
+		return;
+	}
+
+	// unlink to make sure it can't possibly interfere with KillBox
+	gi.unlinkentity (other);
+
+	VectorCopy (dest->s.origin, other->s.origin);
+	VectorCopy (dest->s.origin, other->s.old_origin);
+	other->s.origin[2] += 10;
+
+	// clear the velocity and hold them in place briefly
+	VectorClear (other->velocity);
+	other->client->ps.pmove.pm_time = 160>>3;		// hold time
+	other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
+
+	// draw the teleport splash at source and on the player
+	self->owner->s.event = EV_PLAYER_TELEPORT;
+	other->s.event = EV_PLAYER_TELEPORT;
+
+	// set angles
+	for (i=0 ; i<3 ; i++)
+		other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
+
+	VectorClear (other->s.angles);
+	VectorClear (other->client->ps.viewangles);
+	VectorClear (other->client->v_angle);
+
+	// kill anything at the destination
+	KillBox (other);
+
+	gi.linkentity (other);
+}
+
+/*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
+Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
+*/
+void SP_misc_teleporter (edict_t *ent)
+{
+	edict_t		*trig;
+
+	if (!ent->target)
+	{
+		gi.dprintf ("teleporter without a target.\n");
+		G_FreeEdict (ent);
+		return;
+	}
+
+	gi.setmodel (ent, "models/objects/dmspot/tris.md2");
+	ent->s.skinnum = 1;
+	ent->s.effects = EF_TELEPORTER;
+	ent->s.sound = gi.soundindex ("world/amb10.wav");
+	ent->solid = SOLID_BBOX;
+
+	VectorSet (ent->mins, -32, -32, -24);
+	VectorSet (ent->maxs, 32, 32, -16);
+	gi.linkentity (ent);
+
+	trig = G_Spawn ();
+	trig->touch = teleporter_touch;
+	trig->solid = SOLID_TRIGGER;
+	trig->target = ent->target;
+	trig->owner = ent;
+	VectorCopy (ent->s.origin, trig->s.origin);
+	VectorSet (trig->mins, -8, -8, 8);
+	VectorSet (trig->maxs, 8, 8, 24);
+	gi.linkentity (trig);
+	
+}
+
+/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
+Point teleporters at these.
+*/
+void SP_misc_teleporter_dest (edict_t *ent)
+{
+	gi.setmodel (ent, "models/objects/dmspot/tris.md2");
+	ent->s.skinnum = 0;
+	ent->solid = SOLID_BBOX;
+//	ent->s.effects |= EF_FLIES;
+	VectorSet (ent->mins, -32, -32, -24);
+	VectorSet (ent->maxs, 32, 32, -16);
+	gi.linkentity (ent);
+}
+
--- /dev/null
+++ b/game/g_monster.c
@@ -1,0 +1,740 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+//
+// monster weapons
+//
+
+//FIXME mosnters should call these with a totally accurate direction
+// and we can mess it up based on skill.  Spread should be for normal
+// and we can tighten or loosen based on skill.  We could muck with
+// the damages too, but I'm not sure that's such a good idea.
+void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
+{
+	fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
+{
+	fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
+{
+	fire_blaster (self, start, dir, damage, speed, effect, false);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}	
+
+void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
+{
+	fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
+{
+	fire_rocket (self, start, dir, damage, speed, damage+20, damage);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}	
+
+void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
+{
+	fire_rail (self, start, aimdir, damage, kick);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
+{
+	fire_bfg (self, start, aimdir, damage, speed, damage_radius);
+
+	gi.WriteByte (svc_muzzleflash2);
+	gi.WriteShort (self - g_edicts);
+	gi.WriteByte (flashtype);
+	gi.multicast (start, MULTICAST_PVS);
+}
+
+
+
+//
+// Monster utility functions
+//
+
+static void M_FliesOff (edict_t *self)
+{
+	self->s.effects &= ~EF_FLIES;
+	self->s.sound = 0;
+}
+
+static void M_FliesOn (edict_t *self)
+{
+	if (self->waterlevel)
+		return;
+	self->s.effects |= EF_FLIES;
+	self->s.sound = gi.soundindex ("infantry/inflies1.wav");
+	self->think = M_FliesOff;
+	self->nextthink = level.time + 60;
+}
+
+void M_FlyCheck (edict_t *self)
+{
+	if (self->waterlevel)
+		return;
+
+	if (random() > 0.5)
+		return;
+
+	self->think = M_FliesOn;
+	self->nextthink = level.time + 5 + 10 * random();
+}
+
+void AttackFinished (edict_t *self, float time)
+{
+	self->monsterinfo.attack_finished = level.time + time;
+}
+
+
+void M_CheckGround (edict_t *ent)
+{
+	vec3_t		point;
+	trace_t		trace;
+
+	if (ent->flags & (FL_SWIM|FL_FLY))
+		return;
+
+	if (ent->velocity[2] > 100)
+	{
+		ent->groundentity = NULL;
+		return;
+	}
+
+// if the hull point one-quarter unit down is solid the entity is on ground
+	point[0] = ent->s.origin[0];
+	point[1] = ent->s.origin[1];
+	point[2] = ent->s.origin[2] - 0.25;
+
+	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
+
+	// check steepness
+	if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
+	{
+		ent->groundentity = NULL;
+		return;
+	}
+
+//	ent->groundentity = trace.ent;
+//	ent->groundentity_linkcount = trace.ent->linkcount;
+//	if (!trace.startsolid && !trace.allsolid)
+//		VectorCopy (trace.endpos, ent->s.origin);
+	if (!trace.startsolid && !trace.allsolid)
+	{
+		VectorCopy (trace.endpos, ent->s.origin);
+		ent->groundentity = trace.ent;
+		ent->groundentity_linkcount = trace.ent->linkcount;
+		ent->velocity[2] = 0;
+	}
+}
+
+
+void M_CatagorizePosition (edict_t *ent)
+{
+	vec3_t		point;
+	int			cont;
+
+//
+// get waterlevel
+//
+	point[0] = ent->s.origin[0];
+	point[1] = ent->s.origin[1];
+	point[2] = ent->s.origin[2] + ent->mins[2] + 1;	
+	cont = gi.pointcontents (point);
+
+	if (!(cont & MASK_WATER))
+	{
+		ent->waterlevel = 0;
+		ent->watertype = 0;
+		return;
+	}
+
+	ent->watertype = cont;
+	ent->waterlevel = 1;
+	point[2] += 26;
+	cont = gi.pointcontents (point);
+	if (!(cont & MASK_WATER))
+		return;
+
+	ent->waterlevel = 2;
+	point[2] += 22;
+	cont = gi.pointcontents (point);
+	if (cont & MASK_WATER)
+		ent->waterlevel = 3;
+}
+
+
+void M_WorldEffects (edict_t *ent)
+{
+	int		dmg;
+
+	if (ent->health > 0)
+	{
+		if (!(ent->flags & FL_SWIM))
+		{
+			if (ent->waterlevel < 3)
+			{
+				ent->air_finished = level.time + 12;
+			}
+			else if (ent->air_finished < level.time)
+			{	// drown!
+				if (ent->pain_debounce_time < level.time)
+				{
+					dmg = 2 + 2 * floor(level.time - ent->air_finished);
+					if (dmg > 15)
+						dmg = 15;
+					T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
+					ent->pain_debounce_time = level.time + 1;
+				}
+			}
+		}
+		else
+		{
+			if (ent->waterlevel > 0)
+			{
+				ent->air_finished = level.time + 9;
+			}
+			else if (ent->air_finished < level.time)
+			{	// suffocate!
+				if (ent->pain_debounce_time < level.time)
+				{
+					dmg = 2 + 2 * floor(level.time - ent->air_finished);
+					if (dmg > 15)
+						dmg = 15;
+					T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
+					ent->pain_debounce_time = level.time + 1;
+				}
+			}
+		}
+	}
+	
+	if (ent->waterlevel == 0)
+	{
+		if (ent->flags & FL_INWATER)
+		{	
+			gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
+			ent->flags &= ~FL_INWATER;
+		}
+		return;
+	}
+
+	if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
+	{
+		if (ent->damage_debounce_time < level.time)
+		{
+			ent->damage_debounce_time = level.time + 0.2;
+			T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
+		}
+	}
+	if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
+	{
+		if (ent->damage_debounce_time < level.time)
+		{
+			ent->damage_debounce_time = level.time + 1;
+			T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
+		}
+	}
+	
+	if ( !(ent->flags & FL_INWATER) )
+	{	
+		if (!(ent->svflags & SVF_DEADMONSTER))
+		{
+			if (ent->watertype & CONTENTS_LAVA)
+				if (random() <= 0.5)
+					gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
+			else if (ent->watertype & CONTENTS_SLIME)
+				gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+			else if (ent->watertype & CONTENTS_WATER)
+				gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+		}
+
+		ent->flags |= FL_INWATER;
+		ent->damage_debounce_time = 0;
+	}
+}
+
+
+void M_droptofloor (edict_t *ent)
+{
+	vec3_t		end;
+	trace_t		trace;
+
+	ent->s.origin[2] += 1;
+	VectorCopy (ent->s.origin, end);
+	end[2] -= 256;
+	
+	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
+
+	if (trace.fraction == 1 || trace.allsolid)
+		return;
+
+	VectorCopy (trace.endpos, ent->s.origin);
+
+	gi.linkentity (ent);
+	M_CheckGround (ent);
+	M_CatagorizePosition (ent);
+}
+
+
+void M_SetEffects (edict_t *ent)
+{
+	ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
+	ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
+
+	if (ent->monsterinfo.aiflags & AI_RESURRECTING)
+	{
+		ent->s.effects |= EF_COLOR_SHELL;
+		ent->s.renderfx |= RF_SHELL_RED;
+	}
+
+	if (ent->health <= 0)
+		return;
+
+	if (ent->powerarmor_time > level.time)
+	{
+		if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
+		{
+			ent->s.effects |= EF_POWERSCREEN;
+		}
+		else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
+		{
+			ent->s.effects |= EF_COLOR_SHELL;
+			ent->s.renderfx |= RF_SHELL_GREEN;
+		}
+	}
+}
+
+
+void M_MoveFrame (edict_t *self)
+{
+	mmove_t	*move;
+	int		index;
+
+	move = self->monsterinfo.currentmove;
+	self->nextthink = level.time + FRAMETIME;
+
+	if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
+	{
+		self->s.frame = self->monsterinfo.nextframe;
+		self->monsterinfo.nextframe = 0;
+	}
+	else
+	{
+		if (self->s.frame == move->lastframe)
+		{
+			if (move->endfunc)
+			{
+				move->endfunc (self);
+
+				// regrab move, endfunc is very likely to change it
+				move = self->monsterinfo.currentmove;
+
+				// check for death
+				if (self->svflags & SVF_DEADMONSTER)
+					return;
+			}
+		}
+
+		if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
+		{
+			self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+			self->s.frame = move->firstframe;
+		}
+		else
+		{
+			if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
+			{
+				self->s.frame++;
+				if (self->s.frame > move->lastframe)
+					self->s.frame = move->firstframe;
+			}
+		}
+	}
+
+	index = self->s.frame - move->firstframe;
+	if (move->frame[index].aifunc)
+		if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
+			move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
+		else
+			move->frame[index].aifunc (self, 0);
+
+	if (move->frame[index].thinkfunc)
+		move->frame[index].thinkfunc (self);
+}
+
+
+void monster_think (edict_t *self)
+{
+	M_MoveFrame (self);
+	if (self->linkcount != self->monsterinfo.linkcount)
+	{
+		self->monsterinfo.linkcount = self->linkcount;
+		M_CheckGround (self);
+	}
+	M_CatagorizePosition (self);
+	M_WorldEffects (self);
+	M_SetEffects (self);
+}
+
+
+/*
+================
+monster_use
+
+Using a monster makes it angry at the current activator
+================
+*/
+void monster_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->enemy)
+		return;
+	if (self->health <= 0)
+		return;
+	if (activator->flags & FL_NOTARGET)
+		return;
+	if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
+		return;
+	
+// delay reaction so if the monster is teleported, its sound is still heard
+	self->enemy = activator;
+	FoundTarget (self);
+}
+
+
+void monster_start_go (edict_t *self);
+
+
+void monster_triggered_spawn (edict_t *self)
+{
+	self->s.origin[2] += 1;
+	KillBox (self);
+
+	self->solid = SOLID_BBOX;
+	self->movetype = MOVETYPE_STEP;
+	self->svflags &= ~SVF_NOCLIENT;
+	self->air_finished = level.time + 12;
+	gi.linkentity (self);
+
+	monster_start_go (self);
+
+	if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
+	{
+		FoundTarget (self);
+	}
+	else
+	{
+		self->enemy = NULL;
+	}
+}
+
+void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	// we have a one frame delay here so we don't telefrag the guy who activated us
+	self->think = monster_triggered_spawn;
+	self->nextthink = level.time + FRAMETIME;
+	if (activator->client)
+		self->enemy = activator;
+	self->use = monster_use;
+}
+
+void monster_triggered_start (edict_t *self)
+{
+	self->solid = SOLID_NOT;
+	self->movetype = MOVETYPE_NONE;
+	self->svflags |= SVF_NOCLIENT;
+	self->nextthink = 0;
+	self->use = monster_triggered_spawn_use;
+}
+
+
+/*
+================
+monster_death_use
+
+When a monster dies, it fires all of its targets with the current
+enemy as activator.
+================
+*/
+void monster_death_use (edict_t *self)
+{
+	self->flags &= ~(FL_FLY|FL_SWIM);
+	self->monsterinfo.aiflags &= AI_GOOD_GUY;
+
+	if (self->item)
+	{
+		Drop_Item (self, self->item);
+		self->item = NULL;
+	}
+
+	if (self->deathtarget)
+		self->target = self->deathtarget;
+
+	if (!self->target)
+		return;
+
+	G_UseTargets (self, self->enemy);
+}
+
+
+//============================================================================
+
+qboolean monster_start (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return false;
+	}
+
+	if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
+	{
+		self->spawnflags &= ~4;
+		self->spawnflags |= 1;
+//		gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
+	}
+
+	if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
+		level.total_monsters++;
+
+	self->nextthink = level.time + FRAMETIME;
+	self->svflags |= SVF_MONSTER;
+	self->s.renderfx |= RF_FRAMELERP;
+	self->takedamage = DAMAGE_AIM;
+	self->air_finished = level.time + 12;
+	self->use = monster_use;
+	self->max_health = self->health;
+	self->clipmask = MASK_MONSTERSOLID;
+
+	self->s.skinnum = 0;
+	self->deadflag = DEAD_NO;
+	self->svflags &= ~SVF_DEADMONSTER;
+
+	if (!self->monsterinfo.checkattack)
+		self->monsterinfo.checkattack = M_CheckAttack;
+	VectorCopy (self->s.origin, self->s.old_origin);
+
+	if (st.item)
+	{
+		self->item = FindItemByClassname (st.item);
+		if (!self->item)
+			gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
+	}
+
+	// randomize what frame they start on
+	if (self->monsterinfo.currentmove)
+		self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
+
+	return true;
+}
+
+void monster_start_go (edict_t *self)
+{
+	vec3_t	v;
+
+	if (self->health <= 0)
+		return;
+
+	// check for target to combat_point and change to combattarget
+	if (self->target)
+	{
+		qboolean	notcombat;
+		qboolean	fixup;
+		edict_t		*target;
+
+		target = NULL;
+		notcombat = false;
+		fixup = false;
+		while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
+		{
+			if (strcmp(target->classname, "point_combat") == 0)
+			{
+				self->combattarget = self->target;
+				fixup = true;
+			}
+			else
+			{
+				notcombat = true;
+			}
+		}
+		if (notcombat && self->combattarget)
+			gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
+		if (fixup)
+			self->target = NULL;
+	}
+
+	// validate combattarget
+	if (self->combattarget)
+	{
+		edict_t		*target;
+
+		target = NULL;
+		while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
+		{
+			if (strcmp(target->classname, "point_combat") != 0)
+			{
+				gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
+					self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
+					self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
+					(int)target->s.origin[2]);
+			}
+		}
+	}
+
+	if (self->target)
+	{
+		self->goalentity = self->movetarget = G_PickTarget(self->target);
+		if (!self->movetarget)
+		{
+			gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
+			self->target = NULL;
+			self->monsterinfo.pausetime = 100000000;
+			self->monsterinfo.stand (self);
+		}
+		else if (strcmp (self->movetarget->classname, "path_corner") == 0)
+		{
+			VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+			self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
+			self->monsterinfo.walk (self);
+			self->target = NULL;
+		}
+		else
+		{
+			self->goalentity = self->movetarget = NULL;
+			self->monsterinfo.pausetime = 100000000;
+			self->monsterinfo.stand (self);
+		}
+	}
+	else
+	{
+		self->monsterinfo.pausetime = 100000000;
+		self->monsterinfo.stand (self);
+	}
+
+	self->think = monster_think;
+	self->nextthink = level.time + FRAMETIME;
+}
+
+
+void walkmonster_start_go (edict_t *self)
+{
+	if (!(self->spawnflags & 2) && level.time < 1)
+	{
+		M_droptofloor (self);
+
+		if (self->groundentity)
+			if (!M_walkmove (self, 0, 0))
+				gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
+	}
+	
+	if (!self->yaw_speed)
+		self->yaw_speed = 20;
+	self->viewheight = 25;
+
+	monster_start_go (self);
+
+	if (self->spawnflags & 2)
+		monster_triggered_start (self);
+}
+
+void walkmonster_start (edict_t *self)
+{
+	self->think = walkmonster_start_go;
+	monster_start (self);
+}
+
+
+void flymonster_start_go (edict_t *self)
+{
+	if (!M_walkmove (self, 0, 0))
+		gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
+
+	if (!self->yaw_speed)
+		self->yaw_speed = 10;
+	self->viewheight = 25;
+
+	monster_start_go (self);
+
+	if (self->spawnflags & 2)
+		monster_triggered_start (self);
+}
+
+
+void flymonster_start (edict_t *self)
+{
+	self->flags |= FL_FLY;
+	self->think = flymonster_start_go;
+	monster_start (self);
+}
+
+
+void swimmonster_start_go (edict_t *self)
+{
+	if (!self->yaw_speed)
+		self->yaw_speed = 10;
+	self->viewheight = 10;
+
+	monster_start_go (self);
+
+	if (self->spawnflags & 2)
+		monster_triggered_start (self);
+}
+
+void swimmonster_start (edict_t *self)
+{
+	self->flags |= FL_SWIM;
+	self->think = swimmonster_start_go;
+	monster_start (self);
+}
--- /dev/null
+++ b/game/g_phys.c
@@ -1,0 +1,961 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_phys.c
+
+#include "g_local.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.
+
+*/
+
+
+/*
+============
+SV_TestEntityPosition
+
+============
+*/
+edict_t	*SV_TestEntityPosition (edict_t *ent)
+{
+	trace_t	trace;
+	int		mask;
+
+	if (ent->clipmask)
+		mask = ent->clipmask;
+	else
+		mask = MASK_SOLID;
+	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
+	
+	if (trace.startsolid)
+		return g_edicts;
+		
+	return NULL;
+}
+
+
+/*
+================
+SV_CheckVelocity
+================
+*/
+void SV_CheckVelocity (edict_t *ent)
+{
+	int		i;
+
+//
+// bound velocity
+//
+	for (i=0 ; i<3 ; i++)
+	{
+		if (ent->velocity[i] > sv_maxvelocity->value)
+			ent->velocity[i] = sv_maxvelocity->value;
+		else if (ent->velocity[i] < -sv_maxvelocity->value)
+			ent->velocity[i] = -sv_maxvelocity->value;
+	}
+}
+
+/*
+=============
+SV_RunThink
+
+Runs thinking code for this frame if necessary
+=============
+*/
+qboolean SV_RunThink (edict_t *ent)
+{
+	float	thinktime;
+
+	thinktime = ent->nextthink;
+	if (thinktime <= 0)
+		return true;
+	if (thinktime > level.time+0.001)
+		return true;
+	
+	ent->nextthink = 0;
+	if (!ent->think)
+		gi.error ("NULL ent->think");
+	ent->think (ent);
+
+	return false;
+}
+
+/*
+==================
+SV_Impact
+
+Two entities have touched, so run their touch functions
+==================
+*/
+void SV_Impact (edict_t *e1, trace_t *trace)
+{
+	edict_t		*e2;
+//	cplane_t	backplane;
+
+	e2 = trace->ent;
+
+	if (e1->touch && e1->solid != SOLID_NOT)
+		e1->touch (e1, e2, &trace->plane, trace->surface);
+	
+	if (e2->touch && e2->solid != SOLID_NOT)
+		e2->touch (e2, e1, NULL, NULL);
+}
+
+
+/*
+==================
+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
+============
+*/
+#define	MAX_CLIP_PLANES	5
+int SV_FlyMove (edict_t *ent, float time, int mask)
+{
+	edict_t		*hit;
+	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->velocity, original_velocity);
+	VectorCopy (ent->velocity, primal_velocity);
+	numplanes = 0;
+	
+	time_left = time;
+
+	ent->groundentity = NULL;
+	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+	{
+		for (i=0 ; i<3 ; i++)
+			end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
+
+		trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
+
+		if (trace.allsolid)
+		{	// entity is trapped in another solid
+			VectorCopy (vec3_origin, ent->velocity);
+			return 3;
+		}
+
+		if (trace.fraction > 0)
+		{	// actually covered some distance
+			VectorCopy (trace.endpos, ent->s.origin);
+			VectorCopy (ent->velocity, original_velocity);
+			numplanes = 0;
+		}
+
+		if (trace.fraction == 1)
+			 break;		// moved the entire distance
+
+		hit = trace.ent;
+
+		if (trace.plane.normal[2] > 0.7)
+		{
+			blocked |= 1;		// floor
+			if ( hit->solid == SOLID_BSP)
+			{
+				ent->groundentity = hit;
+				ent->groundentity_linkcount = hit->linkcount;
+			}
+		}
+		if (!trace.plane.normal[2])
+		{
+			blocked |= 2;		// step
+		}
+
+//
+// run the impact function
+//
+		SV_Impact (ent, &trace);
+		if (!ent->inuse)
+			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->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) && !VectorCompare (planes[i], planes[j]))
+				{
+					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->velocity);
+		}
+		else
+		{	// go along the crease
+			if (numplanes != 2)
+			{
+//				gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
+				VectorCopy (vec3_origin, ent->velocity);
+				return 7;
+			}
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, ent->velocity);
+			VectorScale (dir, d, ent->velocity);
+		}
+
+//
+// if original velocity is against the original velocity, stop dead
+// to avoid tiny occilations in sloping corners
+//
+		if (DotProduct (ent->velocity, primal_velocity) <= 0)
+		{
+			VectorCopy (vec3_origin, ent->velocity);
+			return blocked;
+		}
+	}
+
+	return blocked;
+}
+
+
+/*
+============
+SV_AddGravity
+
+============
+*/
+void SV_AddGravity (edict_t *ent)
+{
+	ent->velocity[2] -= ent->gravity * sv_gravity->value * 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	start;
+	vec3_t	end;
+	int		mask;
+
+	VectorCopy (ent->s.origin, start);
+	VectorAdd (start, push, end);
+
+retry:
+	if (ent->clipmask)
+		mask = ent->clipmask;
+	else
+		mask = MASK_SOLID;
+
+	trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
+	
+	VectorCopy (trace.endpos, ent->s.origin);
+	gi.linkentity (ent);
+
+	if (trace.fraction != 1.0)
+	{
+		SV_Impact (ent, &trace);
+
+		// if the pushed entity went away and the pusher is still there
+		if (!trace.ent->inuse && ent->inuse)
+		{
+			// move the pusher back and try again
+			VectorCopy (start, ent->s.origin);
+			gi.linkentity (ent);
+			goto retry;
+		}
+	}
+
+	if (ent->inuse)
+		G_TouchTriggers (ent);
+
+	return trace;
+}					
+
+
+typedef struct
+{
+	edict_t	*ent;
+	vec3_t	origin;
+	vec3_t	angles;
+	float	deltayaw;
+} pushed_t;
+pushed_t	pushed[MAX_EDICTS], *pushed_p;
+
+edict_t	*obstacle;
+
+/*
+============
+SV_Push
+
+Objects need to be moved back on a failed push,
+otherwise riders would continue to slide.
+============
+*/
+qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
+{
+	int			i, e;
+	edict_t		*check, *block;
+	vec3_t		mins, maxs;
+	pushed_t	*p;
+	vec3_t		org, org2, move2, forward, right, up;
+
+	// clamp the move to 1/8 units, so the position will
+	// be accurate for client side prediction
+	for (i=0 ; i<3 ; i++)
+	{
+		float	temp;
+		temp = move[i]*8.0;
+		if (temp > 0.0)
+			temp += 0.5;
+		else
+			temp -= 0.5;
+		move[i] = 0.125 * (int)temp;
+	}
+
+	// find the bounding box
+	for (i=0 ; i<3 ; i++)
+	{
+		mins[i] = pusher->absmin[i] + move[i];
+		maxs[i] = pusher->absmax[i] + move[i];
+	}
+
+// we need this for pushing things later
+	VectorSubtract (vec3_origin, amove, org);
+	AngleVectors (org, forward, right, up);
+
+// save the pusher's original position
+	pushed_p->ent = pusher;
+	VectorCopy (pusher->s.origin, pushed_p->origin);
+	VectorCopy (pusher->s.angles, pushed_p->angles);
+	if (pusher->client)
+		pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
+	pushed_p++;
+
+// move the pusher to it's final position
+	VectorAdd (pusher->s.origin, move, pusher->s.origin);
+	VectorAdd (pusher->s.angles, amove, pusher->s.angles);
+	gi.linkentity (pusher);
+
+// see if any solid entities are inside the final position
+	check = g_edicts+1;
+	for (e = 1; e < globals.num_edicts; e++, check++)
+	{
+		if (!check->inuse)
+			continue;
+		if (check->movetype == MOVETYPE_PUSH
+		|| check->movetype == MOVETYPE_STOP
+		|| check->movetype == MOVETYPE_NONE
+		|| check->movetype == MOVETYPE_NOCLIP)
+			continue;
+
+		if (!check->area.prev)
+			continue;		// not linked in anywhere
+
+	// if the entity is standing on the pusher, it will definitely be moved
+		if (check->groundentity != pusher)
+		{
+			// see if the ent needs to be tested
+			if ( check->absmin[0] >= maxs[0]
+			|| check->absmin[1] >= maxs[1]
+			|| check->absmin[2] >= maxs[2]
+			|| check->absmax[0] <= mins[0]
+			|| check->absmax[1] <= mins[1]
+			|| check->absmax[2] <= mins[2] )
+				continue;
+
+			// see if the ent's bbox is inside the pusher's final position
+			if (!SV_TestEntityPosition (check))
+				continue;
+		}
+
+		if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
+		{
+			// move this entity
+			pushed_p->ent = check;
+			VectorCopy (check->s.origin, pushed_p->origin);
+			VectorCopy (check->s.angles, pushed_p->angles);
+			pushed_p++;
+
+			// try moving the contacted entity 
+			VectorAdd (check->s.origin, move, check->s.origin);
+			if (check->client)
+			{	// FIXME: doesn't rotate monsters?
+				check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
+			}
+
+			// figure movement due to the pusher's amove
+			VectorSubtract (check->s.origin, pusher->s.origin, org);
+			org2[0] = DotProduct (org, forward);
+			org2[1] = -DotProduct (org, right);
+			org2[2] = DotProduct (org, up);
+			VectorSubtract (org2, org, move2);
+			VectorAdd (check->s.origin, move2, check->s.origin);
+
+			// may have pushed them off an edge
+			if (check->groundentity != pusher)
+				check->groundentity = NULL;
+
+			block = SV_TestEntityPosition (check);
+			if (!block)
+			{	// pushed ok
+				gi.linkentity (check);
+				// impact?
+				continue;
+			}
+
+			// if it is ok to leave in the old position, do it
+			// this is only relevent for riding entities, not pushed
+			// FIXME: this doesn't acount for rotation
+			VectorSubtract (check->s.origin, move, check->s.origin);
+			block = SV_TestEntityPosition (check);
+			if (!block)
+			{
+				pushed_p--;
+				continue;
+			}
+		}
+		
+		// save off the obstacle so we can call the block function
+		obstacle = check;
+
+		// move back any entities we already moved
+		// go backwards, so if the same entity was pushed
+		// twice, it goes back to the original position
+		for (p=pushed_p-1 ; p>=pushed ; p--)
+		{
+			VectorCopy (p->origin, p->ent->s.origin);
+			VectorCopy (p->angles, p->ent->s.angles);
+			if (p->ent->client)
+			{
+				p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
+			}
+			gi.linkentity (p->ent);
+		}
+		return false;
+	}
+
+//FIXME: is there a better way to handle this?
+	// see if anything we moved has touched a trigger
+	for (p=pushed_p-1 ; p>=pushed ; p--)
+		G_TouchTriggers (p->ent);
+
+	return true;
+}
+
+/*
+================
+SV_Physics_Pusher
+
+Bmodel objects don't interact with each other, but
+push all box objects
+================
+*/
+void SV_Physics_Pusher (edict_t *ent)
+{
+	vec3_t		move, amove;
+	edict_t		*part, *mv;
+
+	// if not a team captain, so movement will be handled elsewhere
+	if ( ent->flags & FL_TEAMSLAVE)
+		return;
+
+	// make sure all team slaves can move before commiting
+	// any moves or calling any think functions
+	// if the move is blocked, all moved objects will be backed out
+//retry:
+	pushed_p = pushed;
+	for (part = ent ; part ; part=part->teamchain)
+	{
+		if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
+			part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
+			)
+		{	// object is moving
+			VectorScale (part->velocity, FRAMETIME, move);
+			VectorScale (part->avelocity, FRAMETIME, amove);
+
+			if (!SV_Push (part, move, amove))
+				break;	// move was blocked
+		}
+	}
+	if (pushed_p > &pushed[MAX_EDICTS])
+		gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
+
+	if (part)
+	{
+		// the move failed, bump all nextthink times and back out moves
+		for (mv = ent ; mv ; mv=mv->teamchain)
+		{
+			if (mv->nextthink > 0)
+				mv->nextthink += FRAMETIME;
+		}
+
+		// if the pusher has a "blocked" function, call it
+		// otherwise, just stay in place until the obstacle is gone
+		if (part->blocked)
+			part->blocked (part, obstacle);
+#if 0
+		// if the pushed entity went away and the pusher is still there
+		if (!obstacle->inuse && part->inuse)
+			goto retry;
+#endif
+	}
+	else
+	{
+		// the move succeeded, so call all think functions
+		for (part = ent ; part ; part=part->teamchain)
+		{
+			SV_RunThink (part);
+		}
+	}
+}
+
+//==================================================================
+
+/*
+=============
+SV_Physics_None
+
+Non moving objects can only think
+=============
+*/
+void SV_Physics_None (edict_t *ent)
+{
+// regular thinking
+	SV_RunThink (ent);
+}
+
+/*
+=============
+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->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
+	VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
+
+	gi.linkentity (ent);
+}
+
+/*
+==============================================================================
+
+TOSS / BOUNCE
+
+==============================================================================
+*/
+
+/*
+=============
+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;
+	edict_t		*slave;
+	qboolean	wasinwater;
+	qboolean	isinwater;
+	vec3_t		old_origin;
+
+// regular thinking
+	SV_RunThink (ent);
+
+	// if not a team captain, so movement will be handled elsewhere
+	if ( ent->flags & FL_TEAMSLAVE)
+		return;
+
+	if (ent->velocity[2] > 0)
+		ent->groundentity = NULL;
+
+// check for the groundentity going away
+	if (ent->groundentity)
+		if (!ent->groundentity->inuse)
+			ent->groundentity = NULL;
+
+// if onground, return without moving
+	if ( ent->groundentity )
+		return;
+
+	VectorCopy (ent->s.origin, old_origin);
+
+	SV_CheckVelocity (ent);
+
+// add gravity
+	if (ent->movetype != MOVETYPE_FLY
+	&& ent->movetype != MOVETYPE_FLYMISSILE)
+		SV_AddGravity (ent);
+
+// move angles
+	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
+
+// move origin
+	VectorScale (ent->velocity, FRAMETIME, move);
+	trace = SV_PushEntity (ent, move);
+	if (!ent->inuse)
+		return;
+
+	if (trace.fraction < 1)
+	{
+		if (ent->movetype == MOVETYPE_BOUNCE)
+			backoff = 1.5;
+		else
+			backoff = 1;
+
+		ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
+
+	// stop if on ground
+		if (trace.plane.normal[2] > 0.7)
+		{		
+			if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
+			{
+				ent->groundentity = trace.ent;
+				ent->groundentity_linkcount = trace.ent->linkcount;
+				VectorCopy (vec3_origin, ent->velocity);
+				VectorCopy (vec3_origin, ent->avelocity);
+			}
+		}
+
+//		if (ent->touch)
+//			ent->touch (ent, trace.ent, &trace.plane, trace.surface);
+	}
+	
+// check for water transition
+	wasinwater = (ent->watertype & MASK_WATER);
+	ent->watertype = gi.pointcontents (ent->s.origin);
+	isinwater = ent->watertype & MASK_WATER;
+
+	if (isinwater)
+		ent->waterlevel = 1;
+	else
+		ent->waterlevel = 0;
+
+	if (!wasinwater && isinwater)
+		gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
+	else if (wasinwater && !isinwater)
+		gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
+
+// move teamslaves
+	for (slave = ent->teamchain; slave; slave = slave->teamchain)
+	{
+		VectorCopy (ent->s.origin, slave->s.origin);
+		gi.linkentity (slave);
+	}
+}
+
+/*
+===============================================================================
+
+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.
+FIXME: is this true?
+=============
+*/
+
+//FIXME: hacked in for E3 demo
+#define	sv_stopspeed		100
+#define sv_friction			6
+#define sv_waterfriction	1
+
+void SV_AddRotationalFriction (edict_t *ent)
+{
+	int		n;
+	float	adjustment;
+
+	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
+	adjustment = FRAMETIME * sv_stopspeed * sv_friction;
+	for (n = 0; n < 3; n++)
+	{
+		if (ent->avelocity[n] > 0)
+		{
+			ent->avelocity[n] -= adjustment;
+			if (ent->avelocity[n] < 0)
+				ent->avelocity[n] = 0;
+		}
+		else
+		{
+			ent->avelocity[n] += adjustment;
+			if (ent->avelocity[n] > 0)
+				ent->avelocity[n] = 0;
+		}
+	}
+}
+
+void SV_Physics_Step (edict_t *ent)
+{
+	qboolean	wasonground;
+	qboolean	hitsound = false;
+	float		*vel;
+	float		speed, newspeed, control;
+	float		friction;
+	edict_t		*groundentity;
+	int			mask;
+
+	// airborn monsters should always check for ground
+	if (!ent->groundentity)
+		M_CheckGround (ent);
+
+	groundentity = ent->groundentity;
+
+	SV_CheckVelocity (ent);
+
+	if (groundentity)
+		wasonground = true;
+	else
+		wasonground = false;
+		
+	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
+		SV_AddRotationalFriction (ent);
+
+	// add gravity except:
+	//   flying monsters
+	//   swimming monsters who are in the water
+	if (! wasonground)
+		if (!(ent->flags & FL_FLY))
+			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
+			{
+				if (ent->velocity[2] < sv_gravity->value*-0.1)
+					hitsound = true;
+				if (ent->waterlevel == 0)
+					SV_AddGravity (ent);
+			}
+
+	// friction for flying monsters that have been given vertical velocity
+	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
+	{
+		speed = fabs(ent->velocity[2]);
+		control = speed < sv_stopspeed ? sv_stopspeed : speed;
+		friction = sv_friction/3;
+		newspeed = speed - (FRAMETIME * control * friction);
+		if (newspeed < 0)
+			newspeed = 0;
+		newspeed /= speed;
+		ent->velocity[2] *= newspeed;
+	}
+
+	// friction for flying monsters that have been given vertical velocity
+	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
+	{
+		speed = fabs(ent->velocity[2]);
+		control = speed < sv_stopspeed ? sv_stopspeed : speed;
+		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
+		if (newspeed < 0)
+			newspeed = 0;
+		newspeed /= speed;
+		ent->velocity[2] *= newspeed;
+	}
+
+	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
+	{
+		// apply friction
+		// let dead monsters who aren't completely onground slide
+		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
+			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
+			{
+				vel = ent->velocity;
+				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
+				if (speed)
+				{
+					friction = sv_friction;
+
+					control = speed < sv_stopspeed ? sv_stopspeed : speed;
+					newspeed = speed - FRAMETIME*control*friction;
+
+					if (newspeed < 0)
+						newspeed = 0;
+					newspeed /= speed;
+
+					vel[0] *= newspeed;
+					vel[1] *= newspeed;
+				}
+			}
+
+		if (ent->svflags & SVF_MONSTER)
+			mask = MASK_MONSTERSOLID;
+		else
+			mask = MASK_SOLID;
+		SV_FlyMove (ent, FRAMETIME, mask);
+
+		gi.linkentity (ent);
+		G_TouchTriggers (ent);
+		if (!ent->inuse)
+			return;
+
+		if (ent->groundentity)
+			if (!wasonground)
+				if (hitsound)
+					gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
+	}
+
+// regular thinking
+	SV_RunThink (ent);
+}
+
+//============================================================================
+/*
+================
+G_RunEntity
+
+================
+*/
+void G_RunEntity (edict_t *ent)
+{
+	if (ent->prethink)
+		ent->prethink (ent);
+
+	switch ( (int)ent->movetype)
+	{
+	case MOVETYPE_PUSH:
+	case MOVETYPE_STOP:
+		SV_Physics_Pusher (ent);
+		break;
+	case MOVETYPE_NONE:
+		SV_Physics_None (ent);
+		break;
+	case MOVETYPE_NOCLIP:
+		SV_Physics_Noclip (ent);
+		break;
+	case MOVETYPE_STEP:
+		SV_Physics_Step (ent);
+		break;
+	case MOVETYPE_TOSS:
+	case MOVETYPE_BOUNCE:
+	case MOVETYPE_FLY:
+	case MOVETYPE_FLYMISSILE:
+		SV_Physics_Toss (ent);
+		break;
+	default:
+		gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);			
+	}
+}
--- /dev/null
+++ b/game/g_save.c
@@ -1,0 +1,769 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+#define Function(f) {#f, f}
+
+mmove_t mmove_reloc;
+
+field_t fields[] = {
+	{"classname", FOFS(classname), F_LSTRING},
+	{"model", FOFS(model), F_LSTRING},
+	{"spawnflags", FOFS(spawnflags), F_INT},
+	{"speed", FOFS(speed), F_FLOAT},
+	{"accel", FOFS(accel), F_FLOAT},
+	{"decel", FOFS(decel), F_FLOAT},
+	{"target", FOFS(target), F_LSTRING},
+	{"targetname", FOFS(targetname), F_LSTRING},
+	{"pathtarget", FOFS(pathtarget), F_LSTRING},
+	{"deathtarget", FOFS(deathtarget), F_LSTRING},
+	{"killtarget", FOFS(killtarget), F_LSTRING},
+	{"combattarget", FOFS(combattarget), F_LSTRING},
+	{"message", FOFS(message), F_LSTRING},
+	{"team", FOFS(team), F_LSTRING},
+	{"wait", FOFS(wait), F_FLOAT},
+	{"delay", FOFS(delay), F_FLOAT},
+	{"random", FOFS(random), F_FLOAT},
+	{"move_origin", FOFS(move_origin), F_VECTOR},
+	{"move_angles", FOFS(move_angles), F_VECTOR},
+	{"style", FOFS(style), F_INT},
+	{"count", FOFS(count), F_INT},
+	{"health", FOFS(health), F_INT},
+	{"sounds", FOFS(sounds), F_INT},
+	{"light", 0, F_IGNORE},
+	{"dmg", FOFS(dmg), F_INT},
+	{"mass", FOFS(mass), F_INT},
+	{"volume", FOFS(volume), F_FLOAT},
+	{"attenuation", FOFS(attenuation), F_FLOAT},
+	{"map", FOFS(map), F_LSTRING},
+	{"origin", FOFS(s.origin), F_VECTOR},
+	{"angles", FOFS(s.angles), F_VECTOR},
+	{"angle", FOFS(s.angles), F_ANGLEHACK},
+
+	{"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN},
+	{"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN},
+	{"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN},
+	{"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN},
+	{"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN},
+	{"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN},
+	{"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN},
+	{"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN},
+	{"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN},
+	{"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN},
+	{"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN},
+	{"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN},
+	{"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN},
+
+	{"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN},
+	{"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN},
+	{"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN},
+	{"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN},
+	{"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN},
+	{"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN},
+	{"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN},
+
+	{"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN},
+	{"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN},
+	{"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN},
+	{"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN},
+	{"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN},
+	{"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN},
+	{"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN},
+	{"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN},
+	{"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN},
+	{"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN},
+	{"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN},
+
+	{"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN},
+
+	// temp spawn vars -- only valid when the spawn function is called
+	{"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
+	{"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
+	{"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
+	{"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
+	{"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
+	{"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
+
+//need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
+	{"item", FOFS(item), F_ITEM},
+
+	{"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
+	{"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
+	{"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
+	{"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
+	{"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
+	{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
+	{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
+	{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
+	{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
+
+	{0, 0, 0, 0}
+
+};
+
+field_t		levelfields[] =
+{
+	{"changemap", LLOFS(changemap), F_LSTRING},
+                   
+	{"sight_client", LLOFS(sight_client), F_EDICT},
+	{"sight_entity", LLOFS(sight_entity), F_EDICT},
+	{"sound_entity", LLOFS(sound_entity), F_EDICT},
+	{"sound2_entity", LLOFS(sound2_entity), F_EDICT},
+
+	{NULL, 0, F_INT}
+};
+
+field_t		clientfields[] =
+{
+	{"pers.weapon", CLOFS(pers.weapon), F_ITEM},
+	{"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
+	{"newweapon", CLOFS(newweapon), F_ITEM},
+
+	{NULL, 0, F_INT}
+};
+
+/*
+============
+InitGame
+
+This will be called when the dll is first loaded, which
+only happens when a new game is started or a save game
+is loaded.
+============
+*/
+void InitGame (void)
+{
+	gi.dprintf ("==== InitGame ====\n");
+
+	gun_x = gi.cvar ("gun_x", "0", 0);
+	gun_y = gi.cvar ("gun_y", "0", 0);
+	gun_z = gi.cvar ("gun_z", "0", 0);
+
+	//FIXME: sv_ prefix is wrong for these
+	sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
+	sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
+	sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
+	sv_gravity = gi.cvar ("sv_gravity", "800", 0);
+
+	// noset vars
+	dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
+
+	// latched vars
+	sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
+	gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
+	gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
+
+	maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
+	maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
+	deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
+	coop = gi.cvar ("coop", "0", CVAR_LATCH);
+	skill = gi.cvar ("skill", "1", CVAR_LATCH);
+	maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
+
+	// change anytime vars
+	dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
+	fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
+	timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
+	password = gi.cvar ("password", "", CVAR_USERINFO);
+	spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO);
+	filterban = gi.cvar ("filterban", "1", 0);
+
+	g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
+
+	run_pitch = gi.cvar ("run_pitch", "0.002", 0);
+	run_roll = gi.cvar ("run_roll", "0.005", 0);
+	bob_up  = gi.cvar ("bob_up", "0.005", 0);
+	bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
+	bob_roll = gi.cvar ("bob_roll", "0.002", 0);
+
+	// flood control
+	flood_msgs = gi.cvar ("flood_msgs", "4", 0);
+	flood_persecond = gi.cvar ("flood_persecond", "4", 0);
+	flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
+
+	// dm map list
+	sv_maplist = gi.cvar ("sv_maplist", "", 0);
+
+	// items
+	InitItems ();
+
+	Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
+
+	Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
+
+	// initialize all entities for this game
+	game.maxentities = maxentities->value;
+	g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
+	globals.edicts = g_edicts;
+	globals.max_edicts = game.maxentities;
+
+	// initialize all clients for this game
+	game.maxclients = maxclients->value;
+	game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
+	globals.num_edicts = game.maxclients+1;
+}
+
+//=========================================================
+
+void WriteField1 (FILE *f, field_t *field, byte *base)
+{
+	void		*p;
+	int			len;
+	int			index;
+
+	if (field->flags & FFL_SPAWNTEMP)
+		return;
+
+	p = (void *)(base + field->ofs);
+	switch (field->type)
+	{
+	case F_INT:
+	case F_FLOAT:
+	case F_ANGLEHACK:
+	case F_VECTOR:
+	case F_IGNORE:
+		break;
+
+	case F_LSTRING:
+	case F_GSTRING:
+		if ( *(char **)p )
+			len = strlen(*(char **)p) + 1;
+		else
+			len = 0;
+		*(int *)p = len;
+		break;
+	case F_EDICT:
+		if ( *(edict_t **)p == NULL)
+			index = -1;
+		else
+			index = *(edict_t **)p - g_edicts;
+		*(int *)p = index;
+		break;
+	case F_CLIENT:
+		if ( *(gclient_t **)p == NULL)
+			index = -1;
+		else
+			index = *(gclient_t **)p - game.clients;
+		*(int *)p = index;
+		break;
+	case F_ITEM:
+		if ( *(edict_t **)p == NULL)
+			index = -1;
+		else
+			index = *(gitem_t **)p - itemlist;
+		*(int *)p = index;
+		break;
+
+	//relative to code segment
+	case F_FUNCTION:
+		if (*(byte **)p == NULL)
+			index = 0;
+		else
+			index = *(byte **)p - ((byte *)InitGame);
+		*(int *)p = index;
+		break;
+
+	//relative to data segment
+	case F_MMOVE:
+		if (*(byte **)p == NULL)
+			index = 0;
+		else
+			index = *(byte **)p - (byte *)&mmove_reloc;
+		*(int *)p = index;
+		break;
+
+	default:
+		gi.error ("WriteEdict: unknown field type");
+	}
+}
+
+
+void WriteField2 (FILE *f, field_t *field, byte *base)
+{
+	int			len;
+	void		*p;
+
+	if (field->flags & FFL_SPAWNTEMP)
+		return;
+
+	p = (void *)(base + field->ofs);
+	switch (field->type)
+	{
+	case F_LSTRING:
+		if ( *(char **)p )
+		{
+			len = strlen(*(char **)p) + 1;
+			fwrite (*(char **)p, len, 1, f);
+		}
+		break;
+	}
+}
+
+void ReadField (FILE *f, field_t *field, byte *base)
+{
+	void		*p;
+	int			len;
+	int			index;
+
+	if (field->flags & FFL_SPAWNTEMP)
+		return;
+
+	p = (void *)(base + field->ofs);
+	switch (field->type)
+	{
+	case F_INT:
+	case F_FLOAT:
+	case F_ANGLEHACK:
+	case F_VECTOR:
+	case F_IGNORE:
+		break;
+
+	case F_LSTRING:
+		len = *(int *)p;
+		if (!len)
+			*(char **)p = NULL;
+		else
+		{
+			*(char **)p = gi.TagMalloc (len, TAG_LEVEL);
+			fread (*(char **)p, len, 1, f);
+		}
+		break;
+	case F_EDICT:
+		index = *(int *)p;
+		if ( index == -1 )
+			*(edict_t **)p = NULL;
+		else
+			*(edict_t **)p = &g_edicts[index];
+		break;
+	case F_CLIENT:
+		index = *(int *)p;
+		if ( index == -1 )
+			*(gclient_t **)p = NULL;
+		else
+			*(gclient_t **)p = &game.clients[index];
+		break;
+	case F_ITEM:
+		index = *(int *)p;
+		if ( index == -1 )
+			*(gitem_t **)p = NULL;
+		else
+			*(gitem_t **)p = &itemlist[index];
+		break;
+
+	//relative to code segment
+	case F_FUNCTION:
+		index = *(int *)p;
+		if ( index == 0 )
+			*(byte **)p = NULL;
+		else
+			*(byte **)p = ((byte *)InitGame) + index;
+		break;
+
+	//relative to data segment
+	case F_MMOVE:
+		index = *(int *)p;
+		if (index == 0)
+			*(byte **)p = NULL;
+		else
+			*(byte **)p = (byte *)&mmove_reloc + index;
+		break;
+
+	default:
+		gi.error ("ReadEdict: unknown field type");
+	}
+}
+
+//=========================================================
+
+/*
+==============
+WriteClient
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void WriteClient (FILE *f, gclient_t *client)
+{
+	field_t		*field;
+	gclient_t	temp;
+	
+	// all of the ints, floats, and vectors stay as they are
+	temp = *client;
+
+	// change the pointers to lengths or indexes
+	for (field=clientfields ; field->name ; field++)
+	{
+		WriteField1 (f, field, (byte *)&temp);
+	}
+
+	// write the block
+	fwrite (&temp, sizeof(temp), 1, f);
+
+	// now write any allocated data following the edict
+	for (field=clientfields ; field->name ; field++)
+	{
+		WriteField2 (f, field, (byte *)client);
+	}
+}
+
+/*
+==============
+ReadClient
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void ReadClient (FILE *f, gclient_t *client)
+{
+	field_t		*field;
+
+	fread (client, sizeof(*client), 1, f);
+
+	for (field=clientfields ; field->name ; field++)
+	{
+		ReadField (f, field, (byte *)client);
+	}
+}
+
+/*
+============
+WriteGame
+
+This will be called whenever the game goes to a new level,
+and when the user explicitly saves the game.
+
+Game information include cross level data, like multi level
+triggers, help computer info, and all client states.
+
+A single player death will automatically restore from the
+last save position.
+============
+*/
+void WriteGame (char *filename, qboolean autosave)
+{
+	FILE	*f;
+	int		i;
+	char	str[16];
+
+	if (!autosave)
+		SaveClientData ();
+
+	f = fopen (filename, "wb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	memset (str, 0, sizeof(str));
+	strcpy (str, __DATE__);
+	fwrite (str, sizeof(str), 1, f);
+
+	game.autosaved = autosave;
+	fwrite (&game, sizeof(game), 1, f);
+	game.autosaved = false;
+
+	for (i=0 ; i<game.maxclients ; i++)
+		WriteClient (f, &game.clients[i]);
+
+	fclose (f);
+}
+
+void ReadGame (char *filename)
+{
+	FILE	*f;
+	int		i;
+	char	str[16];
+
+	gi.FreeTags (TAG_GAME);
+
+	f = fopen (filename, "rb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	fread (str, sizeof(str), 1, f);
+	if (strcmp (str, __DATE__))
+	{
+		fclose (f);
+		gi.error ("Savegame from an older version.\n");
+	}
+
+	g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
+	globals.edicts = g_edicts;
+
+	fread (&game, sizeof(game), 1, f);
+	game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
+	for (i=0 ; i<game.maxclients ; i++)
+		ReadClient (f, &game.clients[i]);
+
+	fclose (f);
+}
+
+//==========================================================
+
+
+/*
+==============
+WriteEdict
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void WriteEdict (FILE *f, edict_t *ent)
+{
+	field_t		*field;
+	edict_t		temp;
+
+	// all of the ints, floats, and vectors stay as they are
+	temp = *ent;
+
+	// change the pointers to lengths or indexes
+	for (field=fields ; field->name ; field++)
+	{
+		WriteField1 (f, field, (byte *)&temp);
+	}
+
+	// write the block
+	fwrite (&temp, sizeof(temp), 1, f);
+
+	// now write any allocated data following the edict
+	for (field=fields ; field->name ; field++)
+	{
+		WriteField2 (f, field, (byte *)ent);
+	}
+
+}
+
+/*
+==============
+WriteLevelLocals
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void WriteLevelLocals (FILE *f)
+{
+	field_t		*field;
+	level_locals_t		temp;
+
+	// all of the ints, floats, and vectors stay as they are
+	temp = level;
+
+	// change the pointers to lengths or indexes
+	for (field=levelfields ; field->name ; field++)
+	{
+		WriteField1 (f, field, (byte *)&temp);
+	}
+
+	// write the block
+	fwrite (&temp, sizeof(temp), 1, f);
+
+	// now write any allocated data following the edict
+	for (field=levelfields ; field->name ; field++)
+	{
+		WriteField2 (f, field, (byte *)&level);
+	}
+}
+
+
+/*
+==============
+ReadEdict
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void ReadEdict (FILE *f, edict_t *ent)
+{
+	field_t		*field;
+
+	fread (ent, sizeof(*ent), 1, f);
+
+	for (field=fields ; field->name ; field++)
+	{
+		ReadField (f, field, (byte *)ent);
+	}
+}
+
+/*
+==============
+ReadLevelLocals
+
+All pointer variables (except function pointers) must be handled specially.
+==============
+*/
+void ReadLevelLocals (FILE *f)
+{
+	field_t		*field;
+
+	fread (&level, sizeof(level), 1, f);
+
+	for (field=levelfields ; field->name ; field++)
+	{
+		ReadField (f, field, (byte *)&level);
+	}
+}
+
+/*
+=================
+WriteLevel
+
+=================
+*/
+void WriteLevel (char *filename)
+{
+	int		i;
+	edict_t	*ent;
+	FILE	*f;
+	void	*base;
+
+	f = fopen (filename, "wb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	// write out edict size for checking
+	i = sizeof(edict_t);
+	fwrite (&i, sizeof(i), 1, f);
+
+	// write out a function pointer for checking
+	base = (void *)InitGame;
+	fwrite (&base, sizeof(base), 1, f);
+
+	// write out level_locals_t
+	WriteLevelLocals (f);
+
+	// write out all the entities
+	for (i=0 ; i<globals.num_edicts ; i++)
+	{
+		ent = &g_edicts[i];
+		if (!ent->inuse)
+			continue;
+		fwrite (&i, sizeof(i), 1, f);
+		WriteEdict (f, ent);
+	}
+	i = -1;
+	fwrite (&i, sizeof(i), 1, f);
+
+	fclose (f);
+}
+
+
+/*
+=================
+ReadLevel
+
+SpawnEntities will allready have been called on the
+level the same way it was when the level was saved.
+
+That is necessary to get the baselines
+set up identically.
+
+The server will have cleared all of the world links before
+calling ReadLevel.
+
+No clients are connected yet.
+=================
+*/
+void ReadLevel (char *filename)
+{
+	int		entnum;
+	FILE	*f;
+	int		i;
+	void	*base;
+	edict_t	*ent;
+
+	f = fopen (filename, "rb");
+	if (!f)
+		gi.error ("Couldn't open %s", filename);
+
+	// free any dynamic memory allocated by loading the level
+	// base state
+	gi.FreeTags (TAG_LEVEL);
+
+	// wipe all the entities
+	memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
+	globals.num_edicts = maxclients->value+1;
+
+	// check edict size
+	fread (&i, sizeof(i), 1, f);
+	if (i != sizeof(edict_t))
+	{
+		fclose (f);
+		gi.error ("ReadLevel: mismatched edict size");
+	}
+
+	// check function pointer base address
+	fread (&base, sizeof(base), 1, f);
+#ifdef _WIN32
+	if (base != (void *)InitGame)
+	{
+		fclose (f);
+		gi.error ("ReadLevel: function pointers have moved");
+	}
+#else
+	gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
+#endif
+
+	// load the level locals
+	ReadLevelLocals (f);
+
+	// load all the entities
+	while (1)
+	{
+		if (fread (&entnum, sizeof(entnum), 1, f) != 1)
+		{
+			fclose (f);
+			gi.error ("ReadLevel: failed to read entnum");
+		}
+		if (entnum == -1)
+			break;
+		if (entnum >= globals.num_edicts)
+			globals.num_edicts = entnum+1;
+
+		ent = &g_edicts[entnum];
+		ReadEdict (f, ent);
+
+		// let the server rebuild world links for this ent
+		memset (&ent->area, 0, sizeof(ent->area));
+		gi.linkentity (ent);
+	}
+
+	fclose (f);
+
+	// mark all clients as unconnected
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = &g_edicts[i+1];
+		ent->client = game.clients + i;
+		ent->client->pers.connected = false;
+	}
+
+	// do any load time things at this point
+	for (i=0 ; i<globals.num_edicts ; i++)
+	{
+		ent = &g_edicts[i];
+
+		if (!ent->inuse)
+			continue;
+
+		// fire any cross-level triggers
+		if (ent->classname)
+			if (strcmp(ent->classname, "target_crosslevel_target") == 0)
+				ent->nextthink = level.time + ent->delay;
+	}
+}
--- /dev/null
+++ b/game/g_spawn.c
@@ -1,0 +1,984 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+typedef struct
+{
+	char	*name;
+	void	(*spawn)(edict_t *ent);
+} spawn_t;
+
+
+void SP_item_health (edict_t *self);
+void SP_item_health_small (edict_t *self);
+void SP_item_health_large (edict_t *self);
+void SP_item_health_mega (edict_t *self);
+
+void SP_info_player_start (edict_t *ent);
+void SP_info_player_deathmatch (edict_t *ent);
+void SP_info_player_coop (edict_t *ent);
+void SP_info_player_intermission (edict_t *ent);
+
+void SP_func_plat (edict_t *ent);
+void SP_func_rotating (edict_t *ent);
+void SP_func_button (edict_t *ent);
+void SP_func_door (edict_t *ent);
+void SP_func_door_secret (edict_t *ent);
+void SP_func_door_rotating (edict_t *ent);
+void SP_func_water (edict_t *ent);
+void SP_func_train (edict_t *ent);
+void SP_func_conveyor (edict_t *self);
+void SP_func_wall (edict_t *self);
+void SP_func_object (edict_t *self);
+void SP_func_explosive (edict_t *self);
+void SP_func_timer (edict_t *self);
+void SP_func_areaportal (edict_t *ent);
+void SP_func_clock (edict_t *ent);
+void SP_func_killbox (edict_t *ent);
+
+void SP_trigger_always (edict_t *ent);
+void SP_trigger_once (edict_t *ent);
+void SP_trigger_multiple (edict_t *ent);
+void SP_trigger_relay (edict_t *ent);
+void SP_trigger_push (edict_t *ent);
+void SP_trigger_hurt (edict_t *ent);
+void SP_trigger_key (edict_t *ent);
+void SP_trigger_counter (edict_t *ent);
+void SP_trigger_elevator (edict_t *ent);
+void SP_trigger_gravity (edict_t *ent);
+void SP_trigger_monsterjump (edict_t *ent);
+
+void SP_target_temp_entity (edict_t *ent);
+void SP_target_speaker (edict_t *ent);
+void SP_target_explosion (edict_t *ent);
+void SP_target_changelevel (edict_t *ent);
+void SP_target_secret (edict_t *ent);
+void SP_target_goal (edict_t *ent);
+void SP_target_splash (edict_t *ent);
+void SP_target_spawner (edict_t *ent);
+void SP_target_blaster (edict_t *ent);
+void SP_target_crosslevel_trigger (edict_t *ent);
+void SP_target_crosslevel_target (edict_t *ent);
+void SP_target_laser (edict_t *self);
+void SP_target_help (edict_t *ent);
+void SP_target_actor (edict_t *ent);
+void SP_target_lightramp (edict_t *self);
+void SP_target_earthquake (edict_t *ent);
+void SP_target_character (edict_t *ent);
+void SP_target_string (edict_t *ent);
+
+void SP_worldspawn (edict_t *ent);
+void SP_viewthing (edict_t *ent);
+
+void SP_light (edict_t *self);
+void SP_light_mine1 (edict_t *ent);
+void SP_light_mine2 (edict_t *ent);
+void SP_info_null (edict_t *self);
+void SP_info_notnull (edict_t *self);
+void SP_path_corner (edict_t *self);
+void SP_point_combat (edict_t *self);
+
+void SP_misc_explobox (edict_t *self);
+void SP_misc_banner (edict_t *self);
+void SP_misc_satellite_dish (edict_t *self);
+void SP_misc_actor (edict_t *self);
+void SP_misc_gib_arm (edict_t *self);
+void SP_misc_gib_leg (edict_t *self);
+void SP_misc_gib_head (edict_t *self);
+void SP_misc_insane (edict_t *self);
+void SP_misc_deadsoldier (edict_t *self);
+void SP_misc_viper (edict_t *self);
+void SP_misc_viper_bomb (edict_t *self);
+void SP_misc_bigviper (edict_t *self);
+void SP_misc_strogg_ship (edict_t *self);
+void SP_misc_teleporter (edict_t *self);
+void SP_misc_teleporter_dest (edict_t *self);
+void SP_misc_blackhole (edict_t *self);
+void SP_misc_eastertank (edict_t *self);
+void SP_misc_easterchick (edict_t *self);
+void SP_misc_easterchick2 (edict_t *self);
+
+void SP_monster_berserk (edict_t *self);
+void SP_monster_gladiator (edict_t *self);
+void SP_monster_gunner (edict_t *self);
+void SP_monster_infantry (edict_t *self);
+void SP_monster_soldier_light (edict_t *self);
+void SP_monster_soldier (edict_t *self);
+void SP_monster_soldier_ss (edict_t *self);
+void SP_monster_tank (edict_t *self);
+void SP_monster_medic (edict_t *self);
+void SP_monster_flipper (edict_t *self);
+void SP_monster_chick (edict_t *self);
+void SP_monster_parasite (edict_t *self);
+void SP_monster_flyer (edict_t *self);
+void SP_monster_brain (edict_t *self);
+void SP_monster_floater (edict_t *self);
+void SP_monster_hover (edict_t *self);
+void SP_monster_mutant (edict_t *self);
+void SP_monster_supertank (edict_t *self);
+void SP_monster_boss2 (edict_t *self);
+void SP_monster_jorg (edict_t *self);
+void SP_monster_boss3_stand (edict_t *self);
+
+void SP_monster_commander_body (edict_t *self);
+
+void SP_turret_breach (edict_t *self);
+void SP_turret_base (edict_t *self);
+void SP_turret_driver (edict_t *self);
+
+
+spawn_t	spawns[] = {
+	{"item_health", SP_item_health},
+	{"item_health_small", SP_item_health_small},
+	{"item_health_large", SP_item_health_large},
+	{"item_health_mega", SP_item_health_mega},
+
+	{"info_player_start", SP_info_player_start},
+	{"info_player_deathmatch", SP_info_player_deathmatch},
+	{"info_player_coop", SP_info_player_coop},
+	{"info_player_intermission", SP_info_player_intermission},
+
+	{"func_plat", SP_func_plat},
+	{"func_button", SP_func_button},
+	{"func_door", SP_func_door},
+	{"func_door_secret", SP_func_door_secret},
+	{"func_door_rotating", SP_func_door_rotating},
+	{"func_rotating", SP_func_rotating},
+	{"func_train", SP_func_train},
+	{"func_water", SP_func_water},
+	{"func_conveyor", SP_func_conveyor},
+	{"func_areaportal", SP_func_areaportal},
+	{"func_clock", SP_func_clock},
+	{"func_wall", SP_func_wall},
+	{"func_object", SP_func_object},
+	{"func_timer", SP_func_timer},
+	{"func_explosive", SP_func_explosive},
+	{"func_killbox", SP_func_killbox},
+
+	{"trigger_always", SP_trigger_always},
+	{"trigger_once", SP_trigger_once},
+	{"trigger_multiple", SP_trigger_multiple},
+	{"trigger_relay", SP_trigger_relay},
+	{"trigger_push", SP_trigger_push},
+	{"trigger_hurt", SP_trigger_hurt},
+	{"trigger_key", SP_trigger_key},
+	{"trigger_counter", SP_trigger_counter},
+	{"trigger_elevator", SP_trigger_elevator},
+	{"trigger_gravity", SP_trigger_gravity},
+	{"trigger_monsterjump", SP_trigger_monsterjump},
+
+	{"target_temp_entity", SP_target_temp_entity},
+	{"target_speaker", SP_target_speaker},
+	{"target_explosion", SP_target_explosion},
+	{"target_changelevel", SP_target_changelevel},
+	{"target_secret", SP_target_secret},
+	{"target_goal", SP_target_goal},
+	{"target_splash", SP_target_splash},
+	{"target_spawner", SP_target_spawner},
+	{"target_blaster", SP_target_blaster},
+	{"target_crosslevel_trigger", SP_target_crosslevel_trigger},
+	{"target_crosslevel_target", SP_target_crosslevel_target},
+	{"target_laser", SP_target_laser},
+	{"target_help", SP_target_help},
+	{"target_actor", SP_target_actor},
+	{"target_lightramp", SP_target_lightramp},
+	{"target_earthquake", SP_target_earthquake},
+	{"target_character", SP_target_character},
+	{"target_string", SP_target_string},
+
+	{"worldspawn", SP_worldspawn},
+	{"viewthing", SP_viewthing},
+
+	{"light", SP_light},
+	{"light_mine1", SP_light_mine1},
+	{"light_mine2", SP_light_mine2},
+	{"info_null", SP_info_null},
+	{"func_group", SP_info_null},
+	{"info_notnull", SP_info_notnull},
+	{"path_corner", SP_path_corner},
+	{"point_combat", SP_point_combat},
+
+	{"misc_explobox", SP_misc_explobox},
+	{"misc_banner", SP_misc_banner},
+	{"misc_satellite_dish", SP_misc_satellite_dish},
+	{"misc_actor", SP_misc_actor},
+	{"misc_gib_arm", SP_misc_gib_arm},
+	{"misc_gib_leg", SP_misc_gib_leg},
+	{"misc_gib_head", SP_misc_gib_head},
+	{"misc_insane", SP_misc_insane},
+	{"misc_deadsoldier", SP_misc_deadsoldier},
+	{"misc_viper", SP_misc_viper},
+	{"misc_viper_bomb", SP_misc_viper_bomb},
+	{"misc_bigviper", SP_misc_bigviper},
+	{"misc_strogg_ship", SP_misc_strogg_ship},
+	{"misc_teleporter", SP_misc_teleporter},
+	{"misc_teleporter_dest", SP_misc_teleporter_dest},
+	{"misc_blackhole", SP_misc_blackhole},
+	{"misc_eastertank", SP_misc_eastertank},
+	{"misc_easterchick", SP_misc_easterchick},
+	{"misc_easterchick2", SP_misc_easterchick2},
+
+	{"monster_berserk", SP_monster_berserk},
+	{"monster_gladiator", SP_monster_gladiator},
+	{"monster_gunner", SP_monster_gunner},
+	{"monster_infantry", SP_monster_infantry},
+	{"monster_soldier_light", SP_monster_soldier_light},
+	{"monster_soldier", SP_monster_soldier},
+	{"monster_soldier_ss", SP_monster_soldier_ss},
+	{"monster_tank", SP_monster_tank},
+	{"monster_tank_commander", SP_monster_tank},
+	{"monster_medic", SP_monster_medic},
+	{"monster_flipper", SP_monster_flipper},
+	{"monster_chick", SP_monster_chick},
+	{"monster_parasite", SP_monster_parasite},
+	{"monster_flyer", SP_monster_flyer},
+	{"monster_brain", SP_monster_brain},
+	{"monster_floater", SP_monster_floater},
+	{"monster_hover", SP_monster_hover},
+	{"monster_mutant", SP_monster_mutant},
+	{"monster_supertank", SP_monster_supertank},
+	{"monster_boss2", SP_monster_boss2},
+	{"monster_boss3_stand", SP_monster_boss3_stand},
+	{"monster_jorg", SP_monster_jorg},
+
+	{"monster_commander_body", SP_monster_commander_body},
+
+	{"turret_breach", SP_turret_breach},
+	{"turret_base", SP_turret_base},
+	{"turret_driver", SP_turret_driver},
+
+	{NULL, NULL}
+};
+
+/*
+===============
+ED_CallSpawn
+
+Finds the spawn function for the entity and calls it
+===============
+*/
+void ED_CallSpawn (edict_t *ent)
+{
+	spawn_t	*s;
+	gitem_t	*item;
+	int		i;
+
+	if (!ent->classname)
+	{
+		gi.dprintf ("ED_CallSpawn: NULL classname\n");
+		return;
+	}
+
+	// check item spawn functions
+	for (i=0,item=itemlist ; i<game.num_items ; i++,item++)
+	{
+		if (!item->classname)
+			continue;
+		if (!strcmp(item->classname, ent->classname))
+		{	// found it
+			SpawnItem (ent, item);
+			return;
+		}
+	}
+
+	// check normal spawn functions
+	for (s=spawns ; s->name ; s++)
+	{
+		if (!strcmp(s->name, ent->classname))
+		{	// found it
+			s->spawn (ent);
+			return;
+		}
+	}
+	gi.dprintf ("%s doesn't have a spawn function\n", ent->classname);
+}
+
+/*
+=============
+ED_NewString
+=============
+*/
+char *ED_NewString (char *string)
+{
+	char	*newb, *new_p;
+	int		i,l;
+	
+	l = strlen(string) + 1;
+
+	newb = gi.TagMalloc (l, TAG_LEVEL);
+
+	new_p = newb;
+
+	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 newb;
+}
+
+
+
+
+/*
+===============
+ED_ParseField
+
+Takes a key/value pair and sets the binary values
+in an edict
+===============
+*/
+void ED_ParseField (char *key, char *value, edict_t *ent)
+{
+	field_t	*f;
+	byte	*b;
+	float	v;
+	vec3_t	vec;
+
+	for (f=fields ; f->name ; f++)
+	{
+		if (!(f->flags & FFL_NOSPAWN) && !Q_stricmp(f->name, key))
+		{	// found it
+			if (f->flags & FFL_SPAWNTEMP)
+				b = (byte *)&st;
+			else
+				b = (byte *)ent;
+
+			switch (f->type)
+			{
+			case F_LSTRING:
+				*(char **)(b+f->ofs) = ED_NewString (value);
+				break;
+			case F_VECTOR:
+				sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
+				((float *)(b+f->ofs))[0] = vec[0];
+				((float *)(b+f->ofs))[1] = vec[1];
+				((float *)(b+f->ofs))[2] = vec[2];
+				break;
+			case F_INT:
+				*(int *)(b+f->ofs) = atoi(value);
+				break;
+			case F_FLOAT:
+				*(float *)(b+f->ofs) = atof(value);
+				break;
+			case F_ANGLEHACK:
+				v = atof(value);
+				((float *)(b+f->ofs))[0] = 0;
+				((float *)(b+f->ofs))[1] = v;
+				((float *)(b+f->ofs))[2] = 0;
+				break;
+			case F_IGNORE:
+				break;
+			}
+			return;
+		}
+	}
+	gi.dprintf ("%s is not a field\n", key);
+}
+
+/*
+====================
+ED_ParseEdict
+
+Parses an edict out of the given string, returning the new position
+ed should be a properly initialized empty edict.
+====================
+*/
+char *ED_ParseEdict (char *data, edict_t *ent)
+{
+	qboolean	init;
+	char		keyname[256];
+	char		*com_token;
+
+	init = false;
+	memset (&st, 0, sizeof(st));
+
+// go through all the dictionary pairs
+	while (1)
+	{	
+	// parse key
+		com_token = COM_Parse (&data);
+		if (com_token[0] == '}')
+			break;
+		if (!data)
+			gi.error ("ED_ParseEntity: EOF without closing brace");
+
+		strncpy (keyname, com_token, sizeof(keyname)-1);
+		
+	// parse value	
+		com_token = COM_Parse (&data);
+		if (!data)
+			gi.error ("ED_ParseEntity: EOF without closing brace");
+
+		if (com_token[0] == '}')
+			gi.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;
+
+		ED_ParseField (keyname, com_token, ent);
+	}
+
+	if (!init)
+		memset (ent, 0, sizeof(*ent));
+
+	return data;
+}
+
+
+/*
+================
+G_FindTeams
+
+Chain together all entities with a matching team field.
+
+All but the first will have the FL_TEAMSLAVE flag set.
+All but the last will have the teamchain field set to the next one
+================
+*/
+void G_FindTeams (void)
+{
+	edict_t	*e, *e2, *chain;
+	int		i, j;
+	int		c, c2;
+
+	c = 0;
+	c2 = 0;
+	for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
+	{
+		if (!e->inuse)
+			continue;
+		if (!e->team)
+			continue;
+		if (e->flags & FL_TEAMSLAVE)
+			continue;
+		chain = e;
+		e->teammaster = e;
+		c++;
+		c2++;
+		for (j=i+1, e2=e+1 ; j < globals.num_edicts ; j++,e2++)
+		{
+			if (!e2->inuse)
+				continue;
+			if (!e2->team)
+				continue;
+			if (e2->flags & FL_TEAMSLAVE)
+				continue;
+			if (!strcmp(e->team, e2->team))
+			{
+				c2++;
+				chain->teamchain = e2;
+				e2->teammaster = e;
+				chain = e2;
+				e2->flags |= FL_TEAMSLAVE;
+			}
+		}
+	}
+
+	gi.dprintf ("%i teams with %i entities\n", c, c2);
+}
+
+/*
+==============
+SpawnEntities
+
+Creates a server's entity / program execution context by
+parsing textual entity definitions out of an ent file.
+==============
+*/
+void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
+{
+	edict_t		*ent;
+	int			inhibit;
+	char		*com_token;
+	int			i;
+	float		skill_level;
+
+	skill_level = floor (skill->value);
+	if (skill_level < 0)
+		skill_level = 0;
+	if (skill_level > 3)
+		skill_level = 3;
+	if (skill->value != skill_level)
+		gi.cvar_forceset("skill", va("%f", skill_level));
+
+	SaveClientData ();
+
+	gi.FreeTags (TAG_LEVEL);
+
+	memset (&level, 0, sizeof(level));
+	memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));
+
+	strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
+	strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);
+
+	// set client fields on player ents
+	for (i=0 ; i<game.maxclients ; i++)
+		g_edicts[i+1].client = game.clients + i;
+
+	ent = NULL;
+	inhibit = 0;
+
+// parse ents
+	while (1)
+	{
+		// parse the opening brace	
+		com_token = COM_Parse (&entities);
+		if (!entities)
+			break;
+		if (com_token[0] != '{')
+			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);
+
+		if (!ent)
+			ent = g_edicts;
+		else
+			ent = G_Spawn ();
+		entities = ED_ParseEdict (entities, ent);
+
+		// yet another map hack
+		if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
+			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;
+
+		// remove things (except the world) from different skill levels or deathmatch
+		if (ent != g_edicts)
+		{
+			if (deathmatch->value)
+			{
+				if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
+				{
+					G_FreeEdict (ent);	
+					inhibit++;
+					continue;
+				}
+			}
+			else
+			{
+				if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */
+					((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
+					((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
+					(((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))
+					)
+					{
+						G_FreeEdict (ent);	
+						inhibit++;
+						continue;
+					}
+			}
+
+			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
+		}
+
+		ED_CallSpawn (ent);
+	}	
+
+	gi.dprintf ("%i entities inhibited\n", inhibit);
+
+#ifdef DEBUG
+	i = 1;
+	ent = EDICT_NUM(i);
+	while (i < globals.num_edicts) {
+		if (ent->inuse != 0 || ent->inuse != 1)
+			Com_DPrintf("Invalid entity %d\n", i);
+		i++, ent++;
+	}
+#endif
+
+	G_FindTeams ();
+
+	PlayerTrail_Init ();
+}
+
+
+//===================================================================
+
+#if 0
+	// cursor positioning
+	xl <value>
+	xr <value>
+	yb <value>
+	yt <value>
+	xv <value>
+	yv <value>
+
+	// drawing
+	statpic <name>
+	pic <stat>
+	num <fieldwidth> <stat>
+	string <stat>
+
+	// control
+	if <stat>
+	ifeq <stat> <value>
+	ifbit <stat> <value>
+	endif
+
+#endif
+
+char *single_statusbar = 
+"yb	-24 "
+
+// health
+"xv	0 "
+"hnum "
+"xv	50 "
+"pic 0 "
+
+// ammo
+"if 2 "
+"	xv	100 "
+"	anum "
+"	xv	150 "
+"	pic 2 "
+"endif "
+
+// armor
+"if 4 "
+"	xv	200 "
+"	rnum "
+"	xv	250 "
+"	pic 4 "
+"endif "
+
+// selected item
+"if 6 "
+"	xv	296 "
+"	pic 6 "
+"endif "
+
+"yb	-50 "
+
+// picked up item
+"if 7 "
+"	xv	0 "
+"	pic 7 "
+"	xv	26 "
+"	yb	-42 "
+"	stat_string 8 "
+"	yb	-50 "
+"endif "
+
+// timer
+"if 9 "
+"	xv	262 "
+"	num	2	10 "
+"	xv	296 "
+"	pic	9 "
+"endif "
+
+//  help / weapon icon 
+"if 11 "
+"	xv	148 "
+"	pic	11 "
+"endif "
+;
+
+char *dm_statusbar =
+"yb	-24 "
+
+// health
+"xv	0 "
+"hnum "
+"xv	50 "
+"pic 0 "
+
+// ammo
+"if 2 "
+"	xv	100 "
+"	anum "
+"	xv	150 "
+"	pic 2 "
+"endif "
+
+// armor
+"if 4 "
+"	xv	200 "
+"	rnum "
+"	xv	250 "
+"	pic 4 "
+"endif "
+
+// selected item
+"if 6 "
+"	xv	296 "
+"	pic 6 "
+"endif "
+
+"yb	-50 "
+
+// picked up item
+"if 7 "
+"	xv	0 "
+"	pic 7 "
+"	xv	26 "
+"	yb	-42 "
+"	stat_string 8 "
+"	yb	-50 "
+"endif "
+
+// timer
+"if 9 "
+"	xv	246 "
+"	num	2	10 "
+"	xv	296 "
+"	pic	9 "
+"endif "
+
+//  help / weapon icon 
+"if 11 "
+"	xv	148 "
+"	pic	11 "
+"endif "
+
+//  frags
+"xr	-50 "
+"yt 2 "
+"num 3 14 "
+
+// spectator
+"if 17 "
+  "xv 0 "
+  "yb -58 "
+  "string2 \"SPECTATOR MODE\" "
+"endif "
+
+// chase camera
+"if 16 "
+  "xv 0 "
+  "yb -68 "
+  "string \"Chasing\" "
+  "xv 64 "
+  "stat_string 16 "
+"endif "
+;
+
+
+/*QUAKED worldspawn (0 0 0) ?
+
+Only used for the world.
+"sky"	environment map name
+"skyaxis"	vector axis for rotating sky
+"skyrotate"	speed of rotation in degrees/second
+"sounds"	music cd track number
+"gravity"	800 is default gravity
+"message"	text to print at user logon
+*/
+void SP_worldspawn (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_PUSH;
+	ent->solid = SOLID_BSP;
+	ent->inuse = true;			// since the world doesn't use G_Spawn()
+	ent->s.modelindex = 1;		// world model is always index 1
+
+	//---------------
+
+	// reserve some spots for dead player bodies for coop / deathmatch
+	InitBodyQue ();
+
+	// set configstrings for items
+	SetItemNames ();
+
+	if (st.nextmap)
+		strcpy (level.nextmap, st.nextmap);
+
+	// make some data visible to the server
+
+	if (ent->message && ent->message[0])
+	{
+		gi.configstring (CS_NAME, ent->message);
+		strncpy (level.level_name, ent->message, sizeof(level.level_name));
+	}
+	else
+		strncpy (level.level_name, level.mapname, sizeof(level.level_name));
+
+	if (st.sky && st.sky[0])
+		gi.configstring (CS_SKY, st.sky);
+	else
+		gi.configstring (CS_SKY, "unit1_");
+
+	gi.configstring (CS_SKYROTATE, va("%f", st.skyrotate) );
+
+	gi.configstring (CS_SKYAXIS, va("%f %f %f",
+		st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]) );
+
+	gi.configstring (CS_CDTRACK, va("%i", ent->sounds) );
+
+	gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) );
+
+	// status bar program
+	if (deathmatch->value)
+		gi.configstring (CS_STATUSBAR, dm_statusbar);
+	else
+		gi.configstring (CS_STATUSBAR, single_statusbar);
+
+	//---------------
+
+
+	// help icon for statusbar
+	gi.imageindex ("i_help");
+	level.pic_health = gi.imageindex ("i_health");
+	gi.imageindex ("help");
+	gi.imageindex ("field_3");
+
+	if (!st.gravity)
+		gi.cvar_set("sv_gravity", "800");
+	else
+		gi.cvar_set("sv_gravity", st.gravity);
+
+	snd_fry = gi.soundindex ("player/fry.wav");	// standing in lava / slime
+
+	PrecacheItem (FindItem ("Blaster"));
+
+	gi.soundindex ("player/lava1.wav");
+	gi.soundindex ("player/lava2.wav");
+
+	gi.soundindex ("misc/pc_up.wav");
+	gi.soundindex ("misc/talk1.wav");
+
+	gi.soundindex ("misc/udeath.wav");
+
+	// gibs
+	gi.soundindex ("items/respawn1.wav");
+
+	// sexed sounds
+	gi.soundindex ("*death1.wav");
+	gi.soundindex ("*death2.wav");
+	gi.soundindex ("*death3.wav");
+	gi.soundindex ("*death4.wav");
+	gi.soundindex ("*fall1.wav");
+	gi.soundindex ("*fall2.wav");	
+	gi.soundindex ("*gurp1.wav");		// drowning damage
+	gi.soundindex ("*gurp2.wav");	
+	gi.soundindex ("*jump1.wav");		// player jump
+	gi.soundindex ("*pain25_1.wav");
+	gi.soundindex ("*pain25_2.wav");
+	gi.soundindex ("*pain50_1.wav");
+	gi.soundindex ("*pain50_2.wav");
+	gi.soundindex ("*pain75_1.wav");
+	gi.soundindex ("*pain75_2.wav");
+	gi.soundindex ("*pain100_1.wav");
+	gi.soundindex ("*pain100_2.wav");
+
+	// sexed models
+	// THIS ORDER MUST MATCH THE DEFINES IN g_local.h
+	// you can add more, max 15
+	gi.modelindex ("#w_blaster.md2");
+	gi.modelindex ("#w_shotgun.md2");
+	gi.modelindex ("#w_sshotgun.md2");
+	gi.modelindex ("#w_machinegun.md2");
+	gi.modelindex ("#w_chaingun.md2");
+	gi.modelindex ("#a_grenades.md2");
+	gi.modelindex ("#w_glauncher.md2");
+	gi.modelindex ("#w_rlauncher.md2");
+	gi.modelindex ("#w_hyperblaster.md2");
+	gi.modelindex ("#w_railgun.md2");
+	gi.modelindex ("#w_bfg.md2");
+
+	//-------------------
+
+	gi.soundindex ("player/gasp1.wav");		// gasping for air
+	gi.soundindex ("player/gasp2.wav");		// head breaking surface, not gasping
+
+	gi.soundindex ("player/watr_in.wav");	// feet hitting water
+	gi.soundindex ("player/watr_out.wav");	// feet leaving water
+
+	gi.soundindex ("player/watr_un.wav");	// head going underwater
+	
+	gi.soundindex ("player/u_breath1.wav");
+	gi.soundindex ("player/u_breath2.wav");
+
+	gi.soundindex ("items/pkup.wav");		// bonus item pickup
+	gi.soundindex ("world/land.wav");		// landing thud
+	gi.soundindex ("misc/h2ohit1.wav");		// landing splash
+
+	gi.soundindex ("items/damage.wav");
+	gi.soundindex ("items/protect.wav");
+	gi.soundindex ("items/protect4.wav");
+	gi.soundindex ("weapons/noammo.wav");
+
+	gi.soundindex ("infantry/inflies1.wav");
+
+	sm_meat_index = gi.modelindex ("models/objects/gibs/sm_meat/tris.md2");
+	gi.modelindex ("models/objects/gibs/arm/tris.md2");
+	gi.modelindex ("models/objects/gibs/bone/tris.md2");
+	gi.modelindex ("models/objects/gibs/bone2/tris.md2");
+	gi.modelindex ("models/objects/gibs/chest/tris.md2");
+	gi.modelindex ("models/objects/gibs/skull/tris.md2");
+	gi.modelindex ("models/objects/gibs/head2/tris.md2");
+
+//
+// Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
+//
+
+	// 0 normal
+	gi.configstring(CS_LIGHTS+0, "m");
+	
+	// 1 FLICKER (first variety)
+	gi.configstring(CS_LIGHTS+1, "mmnmmommommnonmmonqnmmo");
+	
+	// 2 SLOW STRONG PULSE
+	gi.configstring(CS_LIGHTS+2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
+	
+	// 3 CANDLE (first variety)
+	gi.configstring(CS_LIGHTS+3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
+	
+	// 4 FAST STROBE
+	gi.configstring(CS_LIGHTS+4, "mamamamamama");
+	
+	// 5 GENTLE PULSE 1
+	gi.configstring(CS_LIGHTS+5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
+	
+	// 6 FLICKER (second variety)
+	gi.configstring(CS_LIGHTS+6, "nmonqnmomnmomomno");
+	
+	// 7 CANDLE (second variety)
+	gi.configstring(CS_LIGHTS+7, "mmmaaaabcdefgmmmmaaaammmaamm");
+	
+	// 8 CANDLE (third variety)
+	gi.configstring(CS_LIGHTS+8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
+	
+	// 9 SLOW STROBE (fourth variety)
+	gi.configstring(CS_LIGHTS+9, "aaaaaaaazzzzzzzz");
+	
+	// 10 FLUORESCENT FLICKER
+	gi.configstring(CS_LIGHTS+10, "mmamammmmammamamaaamammma");
+
+	// 11 SLOW PULSE NOT FADE TO BLACK
+	gi.configstring(CS_LIGHTS+11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
+	
+	// styles 32-62 are assigned by the light program for switchable lights
+
+	// 63 testing
+	gi.configstring(CS_LIGHTS+63, "a");
+}
+
--- /dev/null
+++ b/game/g_svcmds.c
@@ -1,0 +1,300 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+void	Svcmd_Test_f (void)
+{
+	gi.cprintf (NULL, PRINT_HIGH, "Svcmd_Test_f()\n");
+}
+
+/*
+==============================================================================
+
+PACKET FILTERING
+ 
+
+You can add or remove addresses from the filter list with:
+
+addip <ip>
+removeip <ip>
+
+The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
+
+Removeip will only remove an address specified exactly the same way.  You cannot addip a subnet, then removeip a single host.
+
+listip
+Prints the current list of filters.
+
+writeip
+Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date.  The filter lists are not saved and restored by default, because I beleive it would cause too much confusion.
+
+filterban <0 or 1>
+
+If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game.  This is the default setting.
+
+If 0, then only addresses matching the list will be allowed.  This lets you easily set up a private game, or a game that only allows players from your local network.
+
+
+==============================================================================
+*/
+
+typedef struct
+{
+	unsigned	mask;
+	unsigned	compare;
+} ipfilter_t;
+
+#define	MAX_IPFILTERS	1024
+
+ipfilter_t	ipfilters[MAX_IPFILTERS];
+int			numipfilters;
+
+/*
+=================
+StringToFilter
+=================
+*/
+static qboolean StringToFilter (char *s, ipfilter_t *f)
+{
+	char	num[128];
+	int		i, j;
+	byte	b[4];
+	byte	m[4];
+	
+	for (i=0 ; i<4 ; i++)
+	{
+		b[i] = 0;
+		m[i] = 0;
+	}
+	
+	for (i=0 ; i<4 ; i++)
+	{
+		if (*s < '0' || *s > '9')
+		{
+			gi.cprintf(NULL, PRINT_HIGH, "Bad filter address: %s\n", s);
+			return false;
+		}
+		
+		j = 0;
+		while (*s >= '0' && *s <= '9')
+		{
+			num[j++] = *s++;
+		}
+		num[j] = 0;
+		b[i] = atoi(num);
+		if (b[i] != 0)
+			m[i] = 255;
+
+		if (!*s)
+			break;
+		s++;
+	}
+	
+	f->mask = *(unsigned *)m;
+	f->compare = *(unsigned *)b;
+	
+	return true;
+}
+
+/*
+=================
+SV_FilterPacket
+=================
+*/
+qboolean SV_FilterPacket (char *from)
+{
+	int		i;
+	unsigned	in;
+	byte m[4];
+	char *p;
+
+	i = 0;
+	p = from;
+	while (*p && i < 4) {
+		m[i] = 0;
+		while (*p >= '0' && *p <= '9') {
+			m[i] = m[i]*10 + (*p - '0');
+			p++;
+		}
+		if (!*p || *p == ':')
+			break;
+		i++, p++;
+	}
+	
+	in = *(unsigned *)m;
+
+	for (i=0 ; i<numipfilters ; i++)
+		if ( (in & ipfilters[i].mask) == ipfilters[i].compare)
+			return (int)filterban->value;
+
+	return (int)!filterban->value;
+}
+
+
+/*
+=================
+SV_AddIP_f
+=================
+*/
+void SVCmd_AddIP_f (void)
+{
+	int		i;
+	
+	if (gi.argc() < 3) {
+		gi.cprintf(NULL, PRINT_HIGH, "Usage:  addip <ip-mask>\n");
+		return;
+	}
+
+	for (i=0 ; i<numipfilters ; i++)
+		if (ipfilters[i].compare == 0xffffffff)
+			break;		// free spot
+	if (i == numipfilters)
+	{
+		if (numipfilters == MAX_IPFILTERS)
+		{
+			gi.cprintf (NULL, PRINT_HIGH, "IP filter list is full\n");
+			return;
+		}
+		numipfilters++;
+	}
+	
+	if (!StringToFilter (gi.argv(2), &ipfilters[i]))
+		ipfilters[i].compare = 0xffffffff;
+}
+
+/*
+=================
+SV_RemoveIP_f
+=================
+*/
+void SVCmd_RemoveIP_f (void)
+{
+	ipfilter_t	f;
+	int			i, j;
+
+	if (gi.argc() < 3) {
+		gi.cprintf(NULL, PRINT_HIGH, "Usage:  sv removeip <ip-mask>\n");
+		return;
+	}
+
+	if (!StringToFilter (gi.argv(2), &f))
+		return;
+
+	for (i=0 ; i<numipfilters ; i++)
+		if (ipfilters[i].mask == f.mask
+		&& ipfilters[i].compare == f.compare)
+		{
+			for (j=i+1 ; j<numipfilters ; j++)
+				ipfilters[j-1] = ipfilters[j];
+			numipfilters--;
+			gi.cprintf (NULL, PRINT_HIGH, "Removed.\n");
+			return;
+		}
+	gi.cprintf (NULL, PRINT_HIGH, "Didn't find %s.\n", gi.argv(2));
+}
+
+/*
+=================
+SV_ListIP_f
+=================
+*/
+void SVCmd_ListIP_f (void)
+{
+	int		i;
+	byte	b[4];
+
+	gi.cprintf (NULL, PRINT_HIGH, "Filter list:\n");
+	for (i=0 ; i<numipfilters ; i++)
+	{
+		*(unsigned *)b = ipfilters[i].compare;
+		gi.cprintf (NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
+	}
+}
+
+/*
+=================
+SV_WriteIP_f
+=================
+*/
+void SVCmd_WriteIP_f (void)
+{
+	FILE	*f;
+	char	name[MAX_OSPATH];
+	byte	b[4];
+	int		i;
+	cvar_t	*game;
+
+	game = gi.cvar("game", "", 0);
+
+	if (!*game->string)
+		sprintf (name, "%s/listip.cfg", GAMEVERSION);
+	else
+		sprintf (name, "%s/listip.cfg", game->string);
+
+	gi.cprintf (NULL, PRINT_HIGH, "Writing %s.\n", name);
+
+	f = fopen (name, "wb");
+	if (!f)
+	{
+		gi.cprintf (NULL, PRINT_HIGH, "Couldn't open %s\n", name);
+		return;
+	}
+	
+	fprintf(f, "set filterban %d\n", (int)filterban->value);
+
+	for (i=0 ; i<numipfilters ; i++)
+	{
+		*(unsigned *)b = ipfilters[i].compare;
+		fprintf (f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
+	}
+	
+	fclose (f);
+}
+
+/*
+=================
+ServerCommand
+
+ServerCommand will be called when an "sv" command is issued.
+The game can issue gi.argc() / gi.argv() commands to get the rest
+of the parameters
+=================
+*/
+void	ServerCommand (void)
+{
+	char	*cmd;
+
+	cmd = gi.argv(1);
+	if (Q_stricmp (cmd, "test") == 0)
+		Svcmd_Test_f ();
+	else if (Q_stricmp (cmd, "addip") == 0)
+		SVCmd_AddIP_f ();
+	else if (Q_stricmp (cmd, "removeip") == 0)
+		SVCmd_RemoveIP_f ();
+	else if (Q_stricmp (cmd, "listip") == 0)
+		SVCmd_ListIP_f ();
+	else if (Q_stricmp (cmd, "writeip") == 0)
+		SVCmd_WriteIP_f ();
+	else
+		gi.cprintf (NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);
+}
+
--- /dev/null
+++ b/game/g_target.c
@@ -1,0 +1,809 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
+Fire an origin based temp entity event to the clients.
+"style"		type byte
+*/
+void Use_Target_Tent (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (ent->style);
+	gi.WritePosition (ent->s.origin);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+}
+
+void SP_target_temp_entity (edict_t *ent)
+{
+	ent->use = Use_Target_Tent;
+}
+
+
+//==========================================================
+
+//==========================================================
+
+/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable
+"noise"		wav file to play
+"attenuation"
+-1 = none, send to whole level
+1 = normal fighting sounds
+2 = idle sound level
+3 = ambient sound level
+"volume"	0.0 to 1.0
+
+Normal sounds play each time the target is used.  The reliable flag can be set for crucial voiceovers.
+
+Looped sounds are always atten 3 / vol 1, and the use function toggles it on/off.
+Multiple identical looping sounds will just increase volume without any speed cost.
+*/
+void Use_Target_Speaker (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	int		chan;
+
+	if (ent->spawnflags & 3)
+	{	// looping sound toggles
+		if (ent->s.sound)
+			ent->s.sound = 0;	// turn it off
+		else
+			ent->s.sound = ent->noise_index;	// start it
+	}
+	else
+	{	// normal sound
+		if (ent->spawnflags & 4)
+			chan = CHAN_VOICE|CHAN_RELIABLE;
+		else
+			chan = CHAN_VOICE;
+		// use a positioned_sound, because this entity won't normally be
+		// sent to any clients because it is invisible
+		gi.positioned_sound (ent->s.origin, ent, chan, ent->noise_index, ent->volume, ent->attenuation, 0);
+	}
+}
+
+void SP_target_speaker (edict_t *ent)
+{
+	char	buffer[MAX_QPATH];
+
+	if(!st.noise)
+	{
+		gi.dprintf("target_speaker with no noise set at %s\n", vtos(ent->s.origin));
+		return;
+	}
+	if (!strstr (st.noise, ".wav"))
+		Com_sprintf (buffer, sizeof(buffer), "%s.wav", st.noise);
+	else
+		strncpy (buffer, st.noise, sizeof(buffer));
+	ent->noise_index = gi.soundindex (buffer);
+
+	if (!ent->volume)
+		ent->volume = 1.0;
+
+	if (!ent->attenuation)
+		ent->attenuation = 1.0;
+	else if (ent->attenuation == -1)	// use -1 so 0 defaults to 1
+		ent->attenuation = 0;
+
+	// check for prestarted looping sound
+	if (ent->spawnflags & 1)
+		ent->s.sound = ent->noise_index;
+
+	ent->use = Use_Target_Speaker;
+
+	// must link the entity so we get areas and clusters so
+	// the server can determine who to send updates to
+	gi.linkentity (ent);
+}
+
+
+//==========================================================
+
+void Use_Target_Help (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	if (ent->spawnflags & 1)
+		strncpy (game.helpmessage1, ent->message, sizeof(game.helpmessage2)-1);
+	else
+		strncpy (game.helpmessage2, ent->message, sizeof(game.helpmessage1)-1);
+
+	game.helpchanged++;
+}
+
+/*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1
+When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars.
+*/
+void SP_target_help(edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!ent->message)
+	{
+		gi.dprintf ("%s with no message at %s\n", ent->classname, vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+	ent->use = Use_Target_Help;
+}
+
+//==========================================================
+
+/*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8)
+Counts a secret found.
+These are single use targets.
+*/
+void use_target_secret (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
+
+	level.found_secrets++;
+
+	G_UseTargets (ent, activator);
+	G_FreeEdict (ent);
+}
+
+void SP_target_secret (edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->use = use_target_secret;
+	if (!st.noise)
+		st.noise = "misc/secret.wav";
+	ent->noise_index = gi.soundindex (st.noise);
+	ent->svflags = SVF_NOCLIENT;
+	level.total_secrets++;
+	// map bug hack
+	if (!Q_stricmp(level.mapname, "mine3") && ent->s.origin[0] == 280 && ent->s.origin[1] == -2048 && ent->s.origin[2] == -624)
+		ent->message = "You have found a secret area.";
+}
+
+//==========================================================
+
+/*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8)
+Counts a goal completed.
+These are single use targets.
+*/
+void use_target_goal (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
+
+	level.found_goals++;
+
+	if (level.found_goals == level.total_goals)
+		gi.configstring (CS_CDTRACK, "0");
+
+	G_UseTargets (ent, activator);
+	G_FreeEdict (ent);
+}
+
+void SP_target_goal (edict_t *ent)
+{
+	if (deathmatch->value)
+	{	// auto-remove for deathmatch
+		G_FreeEdict (ent);
+		return;
+	}
+
+	ent->use = use_target_goal;
+	if (!st.noise)
+		st.noise = "misc/secret.wav";
+	ent->noise_index = gi.soundindex (st.noise);
+	ent->svflags = SVF_NOCLIENT;
+	level.total_goals++;
+}
+
+//==========================================================
+
+
+/*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8)
+Spawns an explosion temporary entity when used.
+
+"delay"		wait this long before going off
+"dmg"		how much radius damage should be done, defaults to 0
+*/
+void target_explosion_explode (edict_t *self)
+{
+	float		save;
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION1);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PHS);
+
+	T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
+
+	save = self->delay;
+	self->delay = 0;
+	G_UseTargets (self, self->activator);
+	self->delay = save;
+}
+
+void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+
+	if (!self->delay)
+	{
+		target_explosion_explode (self);
+		return;
+	}
+
+	self->think = target_explosion_explode;
+	self->nextthink = level.time + self->delay;
+}
+
+void SP_target_explosion (edict_t *ent)
+{
+	ent->use = use_target_explosion;
+	ent->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8)
+Changes level to "map" when fired
+*/
+void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (level.intermissiontime)
+		return;		// already activated
+
+	if (!deathmatch->value && !coop->value)
+	{
+		if (g_edicts[1].health <= 0)
+			return;
+	}
+
+	// if noexit, do a ton of damage to other
+	if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world)
+	{
+		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 10 * other->max_health, 1000, 0, MOD_EXIT);
+		return;
+	}
+
+	// if multiplayer, let everyone know who hit the exit
+	if (deathmatch->value)
+	{
+		if (activator && activator->client)
+			gi.bprintf (PRINT_HIGH, "%s exited the level.\n", activator->client->pers.netname);
+	}
+
+	// if going to a new unit, clear cross triggers
+	if (strstr(self->map, "*"))	
+		game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK);
+
+	BeginIntermission (self);
+}
+
+void SP_target_changelevel (edict_t *ent)
+{
+	if (!ent->map)
+	{
+		gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin));
+		G_FreeEdict (ent);
+		return;
+	}
+
+	// ugly hack because *SOMEBODY* screwed up their map
+   if((Q_stricmp(level.mapname, "fact1") == 0) && (Q_stricmp(ent->map, "fact3") == 0))
+	   ent->map = "fact3$secret1";
+
+	ent->use = use_target_changelevel;
+	ent->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8)
+Creates a particle splash effect when used.
+
+Set "sounds" to one of the following:
+  1) sparks
+  2) blue water
+  3) brown water
+  4) slime
+  5) lava
+  6) blood
+
+"count"	how many pixels in the splash
+"dmg"	if set, does a radius damage at this location when it splashes
+		useful for lava/sparks
+*/
+
+void use_target_splash (edict_t *self, edict_t *other, edict_t *activator)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_SPLASH);
+	gi.WriteByte (self->count);
+	gi.WritePosition (self->s.origin);
+	gi.WriteDir (self->movedir);
+	gi.WriteByte (self->sounds);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	if (self->dmg)
+		T_RadiusDamage (self, activator, self->dmg, NULL, self->dmg+40, MOD_SPLASH);
+}
+
+void SP_target_splash (edict_t *self)
+{
+	self->use = use_target_splash;
+	G_SetMovedir (self->s.angles, self->movedir);
+
+	if (!self->count)
+		self->count = 32;
+
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8)
+Set target to the type of entity you want spawned.
+Useful for spawning monsters and gibs in the factory levels.
+
+For monsters:
+	Set direction to the facing you want it to have.
+
+For gibs:
+	Set direction if you want it moving and
+	speed how fast it should be moving otherwise it
+	will just be dropped
+*/
+void ED_CallSpawn (edict_t *ent);
+
+void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator)
+{
+	edict_t	*ent;
+
+	ent = G_Spawn();
+	ent->classname = self->target;
+	VectorCopy (self->s.origin, ent->s.origin);
+	VectorCopy (self->s.angles, ent->s.angles);
+	ED_CallSpawn (ent);
+	gi.unlinkentity (ent);
+	KillBox (ent);
+	gi.linkentity (ent);
+	if (self->speed)
+		VectorCopy (self->movedir, ent->velocity);
+}
+
+void SP_target_spawner (edict_t *self)
+{
+	self->use = use_target_spawner;
+	self->svflags = SVF_NOCLIENT;
+	if (self->speed)
+	{
+		G_SetMovedir (self->s.angles, self->movedir);
+		VectorScale (self->movedir, self->speed, self->movedir);
+	}
+}
+
+//==========================================================
+
+/*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS
+Fires a blaster bolt in the set direction when triggered.
+
+dmg		default is 15
+speed	default is 1000
+*/
+
+void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator)
+{
+	int effect;
+
+	if (self->spawnflags & 2)
+		effect = 0;
+	else if (self->spawnflags & 1)
+		effect = EF_HYPERBLASTER;
+	else
+		effect = EF_BLASTER;
+
+	fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER, MOD_TARGET_BLASTER);
+	gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0);
+}
+
+void SP_target_blaster (edict_t *self)
+{
+	self->use = use_target_blaster;
+	G_SetMovedir (self->s.angles, self->movedir);
+	self->noise_index = gi.soundindex ("weapons/laser2.wav");
+
+	if (!self->dmg)
+		self->dmg = 15;
+	if (!self->speed)
+		self->speed = 1000;
+
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+//==========================================================
+
+/*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
+Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit.  It is OK to check multiple triggers.  Message, delay, target, and killtarget also work.
+*/
+void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	game.serverflags |= self->spawnflags;
+	G_FreeEdict (self);
+}
+
+void SP_target_crosslevel_trigger (edict_t *self)
+{
+	self->svflags = SVF_NOCLIENT;
+	self->use = trigger_crosslevel_trigger_use;
+}
+
+/*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
+Triggered by a trigger_crosslevel elsewhere within a unit.  If multiple triggers are checked, all must be true.  Delay, target and
+killtarget also work.
+
+"delay"		delay before using targets if the trigger has been activated (default 1)
+*/
+void target_crosslevel_target_think (edict_t *self)
+{
+	if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags))
+	{
+		G_UseTargets (self, self);
+		G_FreeEdict (self);
+	}
+}
+
+void SP_target_crosslevel_target (edict_t *self)
+{
+	if (! self->delay)
+		self->delay = 1;
+	self->svflags = SVF_NOCLIENT;
+
+	self->think = target_crosslevel_target_think;
+	self->nextthink = level.time + self->delay;
+}
+
+//==========================================================
+
+/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT
+When triggered, fires a laser.  You can either set a target
+or a direction.
+*/
+
+void target_laser_think (edict_t *self)
+{
+	edict_t	*ignore;
+	vec3_t	start;
+	vec3_t	end;
+	trace_t	tr;
+	vec3_t	point;
+	vec3_t	last_movedir;
+	int		count;
+
+	if (self->spawnflags & 0x80000000)
+		count = 8;
+	else
+		count = 4;
+
+	if (self->enemy)
+	{
+		VectorCopy (self->movedir, last_movedir);
+		VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
+		VectorSubtract (point, self->s.origin, self->movedir);
+		VectorNormalize (self->movedir);
+		if (!VectorCompare(self->movedir, last_movedir))
+			self->spawnflags |= 0x80000000;
+	}
+
+	ignore = self;
+	VectorCopy (self->s.origin, start);
+	VectorMA (start, 2048, self->movedir, end);
+	while(1)
+	{
+		tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
+
+		if (!tr.ent)
+			break;
+
+		// hurt it if we can
+		if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
+			T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER);
+
+		// if we hit something that's not a monster or player or is immune to lasers, we're done
+		if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
+		{
+			if (self->spawnflags & 0x80000000)
+			{
+				self->spawnflags &= ~0x80000000;
+				gi.WriteByte (svc_temp_entity);
+				gi.WriteByte (TE_LASER_SPARKS);
+				gi.WriteByte (count);
+				gi.WritePosition (tr.endpos);
+				gi.WriteDir (tr.plane.normal);
+				gi.WriteByte (self->s.skinnum);
+				gi.multicast (tr.endpos, MULTICAST_PVS);
+			}
+			break;
+		}
+
+		ignore = tr.ent;
+		VectorCopy (tr.endpos, start);
+	}
+
+	VectorCopy (tr.endpos, self->s.old_origin);
+
+	self->nextthink = level.time + FRAMETIME;
+}
+
+void target_laser_on (edict_t *self)
+{
+	if (!self->activator)
+		self->activator = self;
+	self->spawnflags |= 0x80000001;
+	self->svflags &= ~SVF_NOCLIENT;
+	target_laser_think (self);
+}
+
+void target_laser_off (edict_t *self)
+{
+	self->spawnflags &= ~1;
+	self->svflags |= SVF_NOCLIENT;
+	self->nextthink = 0;
+}
+
+void target_laser_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->activator = activator;
+	if (self->spawnflags & 1)
+		target_laser_off (self);
+	else
+		target_laser_on (self);
+}
+
+void target_laser_start (edict_t *self)
+{
+	edict_t *ent;
+
+	self->movetype = MOVETYPE_NONE;
+	self->solid = SOLID_NOT;
+	self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT;
+	self->s.modelindex = 1;			// must be non-zero
+
+	// set the beam diameter
+	if (self->spawnflags & 64)
+		self->s.frame = 16;
+	else
+		self->s.frame = 4;
+
+	// set the color
+	if (self->spawnflags & 2)
+		self->s.skinnum = 0xf2f2f0f0;
+	else if (self->spawnflags & 4)
+		self->s.skinnum = 0xd0d1d2d3;
+	else if (self->spawnflags & 8)
+		self->s.skinnum = 0xf3f3f1f1;
+	else if (self->spawnflags & 16)
+		self->s.skinnum = 0xdcdddedf;
+	else if (self->spawnflags & 32)
+		self->s.skinnum = 0xe0e1e2e3;
+
+	if (!self->enemy)
+	{
+		if (self->target)
+		{
+			ent = G_Find (NULL, FOFS(targetname), self->target);
+			if (!ent)
+				gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
+			self->enemy = ent;
+		}
+		else
+		{
+			G_SetMovedir (self->s.angles, self->movedir);
+		}
+	}
+	self->use = target_laser_use;
+	self->think = target_laser_think;
+
+	if (!self->dmg)
+		self->dmg = 1;
+
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+	gi.linkentity (self);
+
+	if (self->spawnflags & 1)
+		target_laser_on (self);
+	else
+		target_laser_off (self);
+}
+
+void SP_target_laser (edict_t *self)
+{
+	// let everything else get spawned before we start firing
+	self->think = target_laser_start;
+	self->nextthink = level.time + 1;
+}
+
+//==========================================================
+
+/*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE
+speed		How many seconds the ramping will take
+message		two letters; starting lightlevel and ending lightlevel
+*/
+
+void target_lightramp_think (edict_t *self)
+{
+	char	style[2];
+
+	style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2];
+	style[1] = 0;
+	gi.configstring (CS_LIGHTS+self->enemy->style, style);
+
+	if ((level.time - self->timestamp) < self->speed)
+	{
+		self->nextthink = level.time + FRAMETIME;
+	}
+	else if (self->spawnflags & 1)
+	{
+		char	temp;
+
+		temp = self->movedir[0];
+		self->movedir[0] = self->movedir[1];
+		self->movedir[1] = temp;
+		self->movedir[2] *= -1;
+	}
+}
+
+void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (!self->enemy)
+	{
+		edict_t		*e;
+
+		// check all the targets
+		e = NULL;
+		while (1)
+		{
+			e = G_Find (e, FOFS(targetname), self->target);
+			if (!e)
+				break;
+			if (strcmp(e->classname, "light") != 0)
+			{
+				gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin));
+				gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin));
+			}
+			else
+			{
+				self->enemy = e;
+			}
+		}
+
+		if (!self->enemy)
+		{
+			gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin));
+			G_FreeEdict (self);
+			return;
+		}
+	}
+
+	self->timestamp = level.time;
+	target_lightramp_think (self);
+}
+
+void SP_target_lightramp (edict_t *self)
+{
+	if (!self->message || strlen(self->message) != 2 || self->message[0] < 'a' || self->message[0] > 'z' || self->message[1] < 'a' || self->message[1] > 'z' || self->message[0] == self->message[1])
+	{
+		gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (!self->target)
+	{
+		gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->svflags |= SVF_NOCLIENT;
+	self->use = target_lightramp_use;
+	self->think = target_lightramp_think;
+
+	self->movedir[0] = self->message[0] - 'a';
+	self->movedir[1] = self->message[1] - 'a';
+	self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME);
+}
+
+//==========================================================
+
+/*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8)
+When triggered, this initiates a level-wide earthquake.
+All players and monsters are affected.
+"speed"		severity of the quake (default:200)
+"count"		duration of the quake (default:5)
+*/
+
+void target_earthquake_think (edict_t *self)
+{
+	int		i;
+	edict_t	*e;
+
+	if (self->last_move_time < level.time)
+	{
+		gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0);
+		self->last_move_time = level.time + 0.5;
+	}
+
+	for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++)
+	{
+		if (!e->inuse)
+			continue;
+		if (!e->client)
+			continue;
+		if (!e->groundentity)
+			continue;
+
+		e->groundentity = NULL;
+		e->velocity[0] += crandom()* 150;
+		e->velocity[1] += crandom()* 150;
+		e->velocity[2] = self->speed * (100.0 / e->mass);
+	}
+
+	if (level.time < self->timestamp)
+		self->nextthink = level.time + FRAMETIME;
+}
+
+void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->timestamp = level.time + self->count;
+	self->nextthink = level.time + FRAMETIME;
+	self->activator = activator;
+	self->last_move_time = 0;
+}
+
+void SP_target_earthquake (edict_t *self)
+{
+	if (!self->targetname)
+		gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
+
+	if (!self->count)
+		self->count = 5;
+
+	if (!self->speed)
+		self->speed = 200;
+
+	self->svflags |= SVF_NOCLIENT;
+	self->think = target_earthquake_think;
+	self->use = target_earthquake_use;
+
+	self->noise_index = gi.soundindex ("world/quake.wav");
+}
--- /dev/null
+++ b/game/g_trigger.c
@@ -1,0 +1,598 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+void InitTrigger (edict_t *self)
+{
+	if (!VectorCompare (self->s.angles, vec3_origin))
+		G_SetMovedir (self->s.angles, self->movedir);
+
+	self->solid = SOLID_TRIGGER;
+	self->movetype = MOVETYPE_NONE;
+	gi.setmodel (self, self->model);
+	self->svflags = SVF_NOCLIENT;
+}
+
+
+// the wait time has passed, so set back up for another activation
+void multi_wait (edict_t *ent)
+{
+	ent->nextthink = 0;
+}
+
+
+// the trigger was just activated
+// ent->activator should be set to the activator so it can be held through a delay
+// so wait for the delay time before firing
+void multi_trigger (edict_t *ent)
+{
+	if (ent->nextthink)
+		return;		// already been triggered
+
+	G_UseTargets (ent, ent->activator);
+
+	if (ent->wait > 0)	
+	{
+		ent->think = multi_wait;
+		ent->nextthink = level.time + ent->wait;
+	}
+	else
+	{	// we can't just remove (self) here, because this is a touch function
+		// called while looping through area links...
+		ent->touch = NULL;
+		ent->nextthink = level.time + FRAMETIME;
+		ent->think = G_FreeEdict;
+	}
+}
+
+void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	ent->activator = activator;
+	multi_trigger (ent);
+}
+
+void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if(other->client)
+	{
+		if (self->spawnflags & 2)
+			return;
+	}
+	else if (other->svflags & SVF_MONSTER)
+	{
+		if (!(self->spawnflags & 1))
+			return;
+	}
+	else
+		return;
+
+	if (!VectorCompare(self->movedir, vec3_origin))
+	{
+		vec3_t	forward;
+
+		AngleVectors(other->s.angles, forward, NULL, NULL);
+		if (_DotProduct(forward, self->movedir) < 0)
+			return;
+	}
+
+	self->activator = other;
+	multi_trigger (self);
+}
+
+/*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
+Variable sized repeatable trigger.  Must be targeted at one or more entities.
+If "delay" is set, the trigger waits some time after activating before firing.
+"wait" : Seconds between triggerings. (.2 default)
+sounds
+1)	secret
+2)	beep beep
+3)	large switch
+4)
+set "message" to text string
+*/
+void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
+{
+	self->solid = SOLID_TRIGGER;
+	self->use = Use_Multi;
+	gi.linkentity (self);
+}
+
+void SP_trigger_multiple (edict_t *ent)
+{
+	if (ent->sounds == 1)
+		ent->noise_index = gi.soundindex ("misc/secret.wav");
+	else if (ent->sounds == 2)
+		ent->noise_index = gi.soundindex ("misc/talk.wav");
+	else if (ent->sounds == 3)
+		ent->noise_index = gi.soundindex ("misc/trigger1.wav");
+	
+	if (!ent->wait)
+		ent->wait = 0.2;
+	ent->touch = Touch_Multi;
+	ent->movetype = MOVETYPE_NONE;
+	ent->svflags |= SVF_NOCLIENT;
+
+
+	if (ent->spawnflags & 4)
+	{
+		ent->solid = SOLID_NOT;
+		ent->use = trigger_enable;
+	}
+	else
+	{
+		ent->solid = SOLID_TRIGGER;
+		ent->use = Use_Multi;
+	}
+
+	if (!VectorCompare(ent->s.angles, vec3_origin))
+		G_SetMovedir (ent->s.angles, ent->movedir);
+
+	gi.setmodel (ent, ent->model);
+	gi.linkentity (ent);
+}
+
+
+/*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
+Triggers once, then removes itself.
+You must set the key "target" to the name of another object in the level that has a matching "targetname".
+
+If TRIGGERED, this trigger must be triggered before it is live.
+
+sounds
+ 1)	secret
+ 2)	beep beep
+ 3)	large switch
+ 4)
+
+"message"	string to be displayed when triggered
+*/
+
+void SP_trigger_once(edict_t *ent)
+{
+	// make old maps work because I messed up on flag assignments here
+	// triggered was on bit 1 when it should have been on bit 4
+	if (ent->spawnflags & 1)
+	{
+		vec3_t	v;
+
+		VectorMA (ent->mins, 0.5, ent->size, v);
+		ent->spawnflags &= ~1;
+		ent->spawnflags |= 4;
+		gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
+	}
+
+	ent->wait = -1;
+	SP_trigger_multiple (ent);
+}
+
+/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
+This fixed size trigger cannot be touched, it can only be fired by other events.
+*/
+void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	G_UseTargets (self, activator);
+}
+
+void SP_trigger_relay (edict_t *self)
+{
+	self->use = trigger_relay_use;
+}
+
+
+/*
+==============================================================================
+
+trigger_key
+
+==============================================================================
+*/
+
+/*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
+A relay trigger that only fires it's targets if player has the proper key.
+Use "item" to specify the required key, for example "key_data_cd"
+*/
+void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	int			index;
+
+	if (!self->item)
+		return;
+	if (!activator->client)
+		return;
+
+	index = ITEM_INDEX(self->item);
+	if (!activator->client->pers.inventory[index])
+	{
+		if (level.time < self->touch_debounce_time)
+			return;
+		self->touch_debounce_time = level.time + 5.0;
+		gi.centerprintf (activator, "You need the %s", self->item->pickup_name);
+		gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
+		return;
+	}
+
+	gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
+	if (coop->value)
+	{
+		int		player;
+		edict_t	*ent;
+
+		if (strcmp(self->item->classname, "key_power_cube") == 0)
+		{
+			int	cube;
+
+			for (cube = 0; cube < 8; cube++)
+				if (activator->client->pers.power_cubes & (1 << cube))
+					break;
+			for (player = 1; player <= game.maxclients; player++)
+			{
+				ent = &g_edicts[player];
+				if (!ent->inuse)
+					continue;
+				if (!ent->client)
+					continue;
+				if (ent->client->pers.power_cubes & (1 << cube))
+				{
+					ent->client->pers.inventory[index]--;
+					ent->client->pers.power_cubes &= ~(1 << cube);
+				}
+			}
+		}
+		else
+		{
+			for (player = 1; player <= game.maxclients; player++)
+			{
+				ent = &g_edicts[player];
+				if (!ent->inuse)
+					continue;
+				if (!ent->client)
+					continue;
+				ent->client->pers.inventory[index] = 0;
+			}
+		}
+	}
+	else
+	{
+		activator->client->pers.inventory[index]--;
+	}
+
+	G_UseTargets (self, activator);
+
+	self->use = NULL;
+}
+
+void SP_trigger_key (edict_t *self)
+{
+	if (!st.item)
+	{
+		gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
+		return;
+	}
+	self->item = FindItemByClassname (st.item);
+
+	if (!self->item)
+	{
+		gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
+		return;
+	}
+
+	if (!self->target)
+	{
+		gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
+		return;
+	}
+
+	gi.soundindex ("misc/keytry.wav");
+	gi.soundindex ("misc/keyuse.wav");
+
+	self->use = trigger_key_use;
+}
+
+
+/*
+==============================================================================
+
+trigger_counter
+
+==============================================================================
+*/
+
+/*QUAKED trigger_counter (.5 .5 .5) ? nomessage
+Acts as an intermediary for an action that takes multiple inputs.
+
+If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
+
+After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
+*/
+
+void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->count == 0)
+		return;
+	
+	self->count--;
+
+	if (self->count)
+	{
+		if (! (self->spawnflags & 1))
+		{
+			gi.centerprintf(activator, "%i more to go...", self->count);
+			gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+		}
+		return;
+	}
+	
+	if (! (self->spawnflags & 1))
+	{
+		gi.centerprintf(activator, "Sequence completed!");
+		gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+	}
+	self->activator = activator;
+	multi_trigger (self);
+}
+
+void SP_trigger_counter (edict_t *self)
+{
+	self->wait = -1;
+	if (!self->count)
+		self->count = 2;
+
+	self->use = trigger_counter_use;
+}
+
+
+/*
+==============================================================================
+
+trigger_always
+
+==============================================================================
+*/
+
+/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
+This trigger will always fire.  It is activated by the world.
+*/
+void SP_trigger_always (edict_t *ent)
+{
+	// we must have some delay to make sure our use targets are present
+	if (ent->delay < 0.2)
+		ent->delay = 0.2;
+	G_UseTargets(ent, ent);
+}
+
+
+/*
+==============================================================================
+
+trigger_push
+
+==============================================================================
+*/
+
+#define PUSH_ONCE		1
+
+static int windsound;
+
+void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (strcmp(other->classname, "grenade") == 0)
+	{
+		VectorScale (self->movedir, self->speed * 10, other->velocity);
+	}
+	else if (other->health > 0)
+	{
+		VectorScale (self->movedir, self->speed * 10, other->velocity);
+
+		if (other->client)
+		{
+			// don't take falling damage immediately from this
+			VectorCopy (other->velocity, other->client->oldvelocity);
+			if (other->fly_sound_debounce_time < level.time)
+			{
+				other->fly_sound_debounce_time = level.time + 1.5;
+				gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
+			}
+		}
+	}
+	if (self->spawnflags & PUSH_ONCE)
+		G_FreeEdict (self);
+}
+
+
+/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
+Pushes the player
+"speed"		defaults to 1000
+*/
+void SP_trigger_push (edict_t *self)
+{
+	InitTrigger (self);
+	windsound = gi.soundindex ("misc/windfly.wav");
+	self->touch = trigger_push_touch;
+	if (!self->speed)
+		self->speed = 1000;
+	gi.linkentity (self);
+}
+
+
+/*
+==============================================================================
+
+trigger_hurt
+
+==============================================================================
+*/
+
+/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
+Any entity that touches this will be hurt.
+
+It does dmg points of damage each server frame
+
+SILENT			supresses playing the sound
+SLOW			changes the damage rate to once per second
+NO_PROTECTION	*nothing* stops the damage
+
+"dmg"			default 5 (whole numbers only)
+
+*/
+void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	if (self->solid == SOLID_NOT)
+		self->solid = SOLID_TRIGGER;
+	else
+		self->solid = SOLID_NOT;
+	gi.linkentity (self);
+
+	if (!(self->spawnflags & 2))
+		self->use = NULL;
+}
+
+
+void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	int		dflags;
+
+	if (!other->takedamage)
+		return;
+
+	if (self->timestamp > level.time)
+		return;
+
+	if (self->spawnflags & 16)
+		self->timestamp = level.time + 1;
+	else
+		self->timestamp = level.time + FRAMETIME;
+
+	if (!(self->spawnflags & 4))
+	{
+		if ((level.framenum % 10) == 0)
+			gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
+	}
+
+	if (self->spawnflags & 8)
+		dflags = DAMAGE_NO_PROTECTION;
+	else
+		dflags = 0;
+	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
+}
+
+void SP_trigger_hurt (edict_t *self)
+{
+	InitTrigger (self);
+
+	self->noise_index = gi.soundindex ("world/electro.wav");
+	self->touch = hurt_touch;
+
+	if (!self->dmg)
+		self->dmg = 5;
+
+	if (self->spawnflags & 1)
+		self->solid = SOLID_NOT;
+	else
+		self->solid = SOLID_TRIGGER;
+
+	if (self->spawnflags & 2)
+		self->use = hurt_use;
+
+	gi.linkentity (self);
+}
+
+
+/*
+==============================================================================
+
+trigger_gravity
+
+==============================================================================
+*/
+
+/*QUAKED trigger_gravity (.5 .5 .5) ?
+Changes the touching entites gravity to
+the value of "gravity".  1.0 is standard
+gravity for the level.
+*/
+
+void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	other->gravity = self->gravity;
+}
+
+void SP_trigger_gravity (edict_t *self)
+{
+	if (st.gravity == 0)
+	{
+		gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
+		G_FreeEdict  (self);
+		return;
+	}
+
+	InitTrigger (self);
+	self->gravity = atoi(st.gravity);
+	self->touch = trigger_gravity_touch;
+}
+
+
+/*
+==============================================================================
+
+trigger_monsterjump
+
+==============================================================================
+*/
+
+/*QUAKED trigger_monsterjump (.5 .5 .5) ?
+Walking monsters that touch this will jump in the direction of the trigger's angle
+"speed" default to 200, the speed thrown forward
+"height" default to 200, the speed thrown upwards
+*/
+
+void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other->flags & (FL_FLY | FL_SWIM) )
+		return;
+	if (other->svflags & SVF_DEADMONSTER)
+		return;
+	if ( !(other->svflags & SVF_MONSTER))
+		return;
+
+// set XY even if not on ground, so the jump will clear lips
+	other->velocity[0] = self->movedir[0] * self->speed;
+	other->velocity[1] = self->movedir[1] * self->speed;
+	
+	if (!other->groundentity)
+		return;
+	
+	other->groundentity = NULL;
+	other->velocity[2] = self->movedir[2];
+}
+
+void SP_trigger_monsterjump (edict_t *self)
+{
+	if (!self->speed)
+		self->speed = 200;
+	if (!st.height)
+		st.height = 200;
+	if (self->s.angles[YAW] == 0)
+		self->s.angles[YAW] = 360;
+	InitTrigger (self);
+	self->touch = trigger_monsterjump_touch;
+	self->movedir[2] = st.height;
+}
+
--- /dev/null
+++ b/game/g_turret.c
@@ -1,0 +1,432 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_turret.c
+
+#include "g_local.h"
+
+
+void AnglesNormalize(vec3_t vec)
+{
+	while(vec[0] > 360)
+		vec[0] -= 360;
+	while(vec[0] < 0)
+		vec[0] += 360;
+	while(vec[1] > 360)
+		vec[1] -= 360;
+	while(vec[1] < 0)
+		vec[1] += 360;
+}
+
+float SnapToEights(float x)
+{
+	x *= 8.0;
+	if (x > 0.0)
+		x += 0.5;
+	else
+		x -= 0.5;
+	return 0.125 * (int)x;
+}
+
+
+void turret_blocked(edict_t *self, edict_t *other)
+{
+	edict_t	*attacker;
+
+	if (other->takedamage)
+	{
+		if (self->teammaster->owner)
+			attacker = self->teammaster->owner;
+		else
+			attacker = self->teammaster;
+		T_Damage (other, self, attacker, vec3_origin, other->s.origin, vec3_origin, self->teammaster->dmg, 10, 0, MOD_CRUSH);
+	}
+}
+
+/*QUAKED turret_breach (0 0 0) ?
+This portion of the turret can change both pitch and yaw.
+The model  should be made with a flat pitch.
+It (and the associated base) need to be oriented towards 0.
+Use "angle" to set the starting angle.
+
+"speed"		default 50
+"dmg"		default 10
+"angle"		point this forward
+"target"	point this at an info_notnull at the muzzle tip
+"minpitch"	min acceptable pitch angle : default -30
+"maxpitch"	max acceptable pitch angle : default 30
+"minyaw"	min acceptable yaw angle   : default 0
+"maxyaw"	max acceptable yaw angle   : default 360
+*/
+
+void turret_breach_fire (edict_t *self)
+{
+	vec3_t	f, r, u;
+	vec3_t	start;
+	int		damage;
+	int		speed;
+
+	AngleVectors (self->s.angles, f, r, u);
+	VectorMA (self->s.origin, self->move_origin[0], f, start);
+	VectorMA (start, self->move_origin[1], r, start);
+	VectorMA (start, self->move_origin[2], u, start);
+
+	damage = 100 + random() * 50;
+	speed = 550 + 50 * skill->value;
+	fire_rocket (self->teammaster->owner, start, f, damage, speed, 150, damage);
+	gi.positioned_sound (start, self, CHAN_WEAPON, gi.soundindex("weapons/rocklf1a.wav"), 1, ATTN_NORM, 0);
+}
+
+void turret_breach_think (edict_t *self)
+{
+	edict_t	*ent;
+	vec3_t	current_angles;
+	vec3_t	delta;
+
+	VectorCopy (self->s.angles, current_angles);
+	AnglesNormalize(current_angles);
+
+	AnglesNormalize(self->move_angles);
+	if (self->move_angles[PITCH] > 180)
+		self->move_angles[PITCH] -= 360;
+
+	// clamp angles to mins & maxs
+	if (self->move_angles[PITCH] > self->pos1[PITCH])
+		self->move_angles[PITCH] = self->pos1[PITCH];
+	else if (self->move_angles[PITCH] < self->pos2[PITCH])
+		self->move_angles[PITCH] = self->pos2[PITCH];
+
+	if ((self->move_angles[YAW] < self->pos1[YAW]) || (self->move_angles[YAW] > self->pos2[YAW]))
+	{
+		float	dmin, dmax;
+
+		dmin = fabs(self->pos1[YAW] - self->move_angles[YAW]);
+		if (dmin < -180)
+			dmin += 360;
+		else if (dmin > 180)
+			dmin -= 360;
+		dmax = fabs(self->pos2[YAW] - self->move_angles[YAW]);
+		if (dmax < -180)
+			dmax += 360;
+		else if (dmax > 180)
+			dmax -= 360;
+		if (fabs(dmin) < fabs(dmax))
+			self->move_angles[YAW] = self->pos1[YAW];
+		else
+			self->move_angles[YAW] = self->pos2[YAW];
+	}
+
+	VectorSubtract (self->move_angles, current_angles, delta);
+	if (delta[0] < -180)
+		delta[0] += 360;
+	else if (delta[0] > 180)
+		delta[0] -= 360;
+	if (delta[1] < -180)
+		delta[1] += 360;
+	else if (delta[1] > 180)
+		delta[1] -= 360;
+	delta[2] = 0;
+
+	if (delta[0] > self->speed * FRAMETIME)
+		delta[0] = self->speed * FRAMETIME;
+	if (delta[0] < -1 * self->speed * FRAMETIME)
+		delta[0] = -1 * self->speed * FRAMETIME;
+	if (delta[1] > self->speed * FRAMETIME)
+		delta[1] = self->speed * FRAMETIME;
+	if (delta[1] < -1 * self->speed * FRAMETIME)
+		delta[1] = -1 * self->speed * FRAMETIME;
+
+	VectorScale (delta, 1.0/FRAMETIME, self->avelocity);
+
+	self->nextthink = level.time + FRAMETIME;
+
+	for (ent = self->teammaster; ent; ent = ent->teamchain)
+		ent->avelocity[1] = self->avelocity[1];
+
+	// if we have adriver, adjust his velocities
+	if (self->owner)
+	{
+		float	angle;
+		float	target_z;
+		float	diff;
+		vec3_t	target;
+		vec3_t	dir;
+
+		// angular is easy, just copy ours
+		self->owner->avelocity[0] = self->avelocity[0];
+		self->owner->avelocity[1] = self->avelocity[1];
+
+		// x & y
+		angle = self->s.angles[1] + self->owner->move_origin[1];
+		angle *= (M_PI*2 / 360);
+		target[0] = SnapToEights(self->s.origin[0] + cos(angle) * self->owner->move_origin[0]);
+		target[1] = SnapToEights(self->s.origin[1] + sin(angle) * self->owner->move_origin[0]);
+		target[2] = self->owner->s.origin[2];
+
+		VectorSubtract (target, self->owner->s.origin, dir);
+		self->owner->velocity[0] = dir[0] * 1.0 / FRAMETIME;
+		self->owner->velocity[1] = dir[1] * 1.0 / FRAMETIME;
+
+		// z
+		angle = self->s.angles[PITCH] * (M_PI*2 / 360);
+		target_z = SnapToEights(self->s.origin[2] + self->owner->move_origin[0] * tan(angle) + self->owner->move_origin[2]);
+
+		diff = target_z - self->owner->s.origin[2];
+		self->owner->velocity[2] = diff * 1.0 / FRAMETIME;
+
+		if (self->spawnflags & 65536)
+		{
+			turret_breach_fire (self);
+			self->spawnflags &= ~65536;
+		}
+	}
+}
+
+void turret_breach_finish_init (edict_t *self)
+{
+	// get and save info for muzzle location
+	if (!self->target)
+	{
+		gi.dprintf("%s at %s needs a target\n", self->classname, vtos(self->s.origin));
+	}
+	else
+	{
+		self->target_ent = G_PickTarget (self->target);
+		VectorSubtract (self->target_ent->s.origin, self->s.origin, self->move_origin);
+		G_FreeEdict(self->target_ent);
+	}
+
+	self->teammaster->dmg = self->dmg;
+	self->think = turret_breach_think;
+	self->think (self);
+}
+
+void SP_turret_breach (edict_t *self)
+{
+	self->solid = SOLID_BSP;
+	self->movetype = MOVETYPE_PUSH;
+	gi.setmodel (self, self->model);
+
+	if (!self->speed)
+		self->speed = 50;
+	if (!self->dmg)
+		self->dmg = 10;
+
+	if (!st.minpitch)
+		st.minpitch = -30;
+	if (!st.maxpitch)
+		st.maxpitch = 30;
+	if (!st.maxyaw)
+		st.maxyaw = 360;
+
+	self->pos1[PITCH] = -1 * st.minpitch;
+	self->pos1[YAW]   = st.minyaw;
+	self->pos2[PITCH] = -1 * st.maxpitch;
+	self->pos2[YAW]   = st.maxyaw;
+
+	self->ideal_yaw = self->s.angles[YAW];
+	self->move_angles[YAW] = self->ideal_yaw;
+
+	self->blocked = turret_blocked;
+
+	self->think = turret_breach_finish_init;
+	self->nextthink = level.time + FRAMETIME;
+	gi.linkentity (self);
+}
+
+
+/*QUAKED turret_base (0 0 0) ?
+This portion of the turret changes yaw only.
+MUST be teamed with a turret_breach.
+*/
+
+void SP_turret_base (edict_t *self)
+{
+	self->solid = SOLID_BSP;
+	self->movetype = MOVETYPE_PUSH;
+	gi.setmodel (self, self->model);
+	self->blocked = turret_blocked;
+	gi.linkentity (self);
+}
+
+
+/*QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
+Must NOT be on the team with the rest of the turret parts.
+Instead it must target the turret_breach.
+*/
+
+void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
+void infantry_stand (edict_t *self);
+void monster_use (edict_t *self, edict_t *other, edict_t *activator);
+
+void turret_driver_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	edict_t	*ent;
+
+	// level the gun
+	self->target_ent->move_angles[0] = 0;
+
+	// remove the driver from the end of them team chain
+	for (ent = self->target_ent->teammaster; ent->teamchain != self; ent = ent->teamchain)
+		;
+	ent->teamchain = NULL;
+	self->teammaster = NULL;
+	self->flags &= ~FL_TEAMSLAVE;
+
+	self->target_ent->owner = NULL;
+	self->target_ent->teammaster->owner = NULL;
+
+	infantry_die (self, inflictor, attacker, damage);
+}
+
+qboolean FindTarget (edict_t *self);
+
+void turret_driver_think (edict_t *self)
+{
+	vec3_t	target;
+	vec3_t	dir;
+	float	reaction_time;
+
+	self->nextthink = level.time + FRAMETIME;
+
+	if (self->enemy && (!self->enemy->inuse || self->enemy->health <= 0))
+		self->enemy = NULL;
+
+	if (!self->enemy)
+	{
+		if (!FindTarget (self))
+			return;
+		self->monsterinfo.trail_time = level.time;
+		self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+	}
+	else
+	{
+		if (visible (self, self->enemy))
+		{
+			if (self->monsterinfo.aiflags & AI_LOST_SIGHT)
+			{
+				self->monsterinfo.trail_time = level.time;
+				self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+			}
+		}
+		else
+		{
+			self->monsterinfo.aiflags |= AI_LOST_SIGHT;
+			return;
+		}
+	}
+
+	// let the turret know where we want it to aim
+	VectorCopy (self->enemy->s.origin, target);
+	target[2] += self->enemy->viewheight;
+	VectorSubtract (target, self->target_ent->s.origin, dir);
+	vectoangles (dir, self->target_ent->move_angles);
+
+	// decide if we should shoot
+	if (level.time < self->monsterinfo.attack_finished)
+		return;
+
+	reaction_time = (3 - skill->value) * 1.0;
+	if ((level.time - self->monsterinfo.trail_time) < reaction_time)
+		return;
+
+	self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
+	//FIXME how do we really want to pass this along?
+	self->target_ent->spawnflags |= 65536;
+}
+
+void turret_driver_link (edict_t *self)
+{
+	vec3_t	vec;
+	edict_t	*ent;
+
+	self->think = turret_driver_think;
+	self->nextthink = level.time + FRAMETIME;
+
+	self->target_ent = G_PickTarget (self->target);
+	self->target_ent->owner = self;
+	self->target_ent->teammaster->owner = self;
+	VectorCopy (self->target_ent->s.angles, self->s.angles);
+
+	vec[0] = self->target_ent->s.origin[0] - self->s.origin[0];
+	vec[1] = self->target_ent->s.origin[1] - self->s.origin[1];
+	vec[2] = 0;
+	self->move_origin[0] = VectorLength(vec);
+
+	VectorSubtract (self->s.origin, self->target_ent->s.origin, vec);
+	vectoangles (vec, vec);
+	AnglesNormalize(vec);
+	self->move_origin[1] = vec[1];
+
+	self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
+
+	// add the driver to the end of them team chain
+	for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
+		;
+	ent->teamchain = self;
+	self->teammaster = self->target_ent->teammaster;
+	self->flags |= FL_TEAMSLAVE;
+}
+
+void SP_turret_driver (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->movetype = MOVETYPE_PUSH;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	self->health = 100;
+	self->gib_health = 0;
+	self->mass = 200;
+	self->viewheight = 24;
+
+	self->die = turret_driver_die;
+	self->monsterinfo.stand = infantry_stand;
+
+	self->flags |= FL_NO_KNOCKBACK;
+
+	level.total_monsters++;
+
+	self->svflags |= SVF_MONSTER;
+	self->s.renderfx |= RF_FRAMELERP;
+	self->takedamage = DAMAGE_AIM;
+	self->use = monster_use;
+	self->clipmask = MASK_MONSTERSOLID;
+	VectorCopy (self->s.origin, self->s.old_origin);
+	self->monsterinfo.aiflags |= AI_STAND_GROUND|AI_DUCKED;
+
+	if (st.item)
+	{
+		self->item = FindItemByClassname (st.item);
+		if (!self->item)
+			gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
+	}
+
+	self->think = turret_driver_link;
+	self->nextthink = level.time + FRAMETIME;
+
+	gi.linkentity (self);
+}
--- /dev/null
+++ b/game/g_utils.c
@@ -1,0 +1,568 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_utils.c -- misc utility functions for game module
+
+#include "g_local.h"
+
+
+void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
+{
+	result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
+	result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
+	result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
+}
+
+
+/*
+=============
+G_Find
+
+Searches all active entities for the next one that holds
+the matching string at fieldofs (use the FOFS() macro) in the structure.
+
+Searches beginning at the edict after from, or the beginning if NULL
+NULL will be returned if the end of the list is reached.
+
+=============
+*/
+edict_t *G_Find (edict_t *from, int fieldofs, char *match)
+{
+	char	*s;
+
+	if (!from)
+		from = g_edicts;
+	else
+		from++;
+
+	for ( ; from < &g_edicts[globals.num_edicts] ; from++)
+	{
+		if (!from->inuse)
+			continue;
+		s = *(char **) ((byte *)from + fieldofs);
+		if (!s)
+			continue;
+		if (!Q_stricmp (s, match))
+			return from;
+	}
+
+	return NULL;
+}
+
+
+/*
+=================
+findradius
+
+Returns entities that have origins within a spherical area
+
+findradius (origin, radius)
+=================
+*/
+edict_t *findradius (edict_t *from, vec3_t org, float rad)
+{
+	vec3_t	eorg;
+	int		j;
+
+	if (!from)
+		from = g_edicts;
+	else
+		from++;
+	for ( ; from < &g_edicts[globals.num_edicts]; from++)
+	{
+		if (!from->inuse)
+			continue;
+		if (from->solid == SOLID_NOT)
+			continue;
+		for (j=0 ; j<3 ; j++)
+			eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
+		if (VectorLength(eorg) > rad)
+			continue;
+		return from;
+	}
+
+	return NULL;
+}
+
+
+/*
+=============
+G_PickTarget
+
+Searches all active entities for the next one that holds
+the matching string at fieldofs (use the FOFS() macro) in the structure.
+
+Searches beginning at the edict after from, or the beginning if NULL
+NULL will be returned if the end of the list is reached.
+
+=============
+*/
+#define MAXCHOICES	8
+
+edict_t *G_PickTarget (char *targetname)
+{
+	edict_t	*ent = NULL;
+	int		num_choices = 0;
+	edict_t	*choice[MAXCHOICES];
+
+	if (!targetname)
+	{
+		gi.dprintf("G_PickTarget called with NULL targetname\n");
+		return NULL;
+	}
+
+	while(1)
+	{
+		ent = G_Find (ent, FOFS(targetname), targetname);
+		if (!ent)
+			break;
+		choice[num_choices++] = ent;
+		if (num_choices == MAXCHOICES)
+			break;
+	}
+
+	if (!num_choices)
+	{
+		gi.dprintf("G_PickTarget: target %s not found\n", targetname);
+		return NULL;
+	}
+
+	return choice[rand() % num_choices];
+}
+
+
+
+void Think_Delay (edict_t *ent)
+{
+	G_UseTargets (ent, ent->activator);
+	G_FreeEdict (ent);
+}
+
+/*
+==============================
+G_UseTargets
+
+the global "activator" should be set to the entity that initiated the firing.
+
+If self.delay is set, a DelayedUse entity will be created that will actually
+do the SUB_UseTargets after that many seconds have passed.
+
+Centerprints any self.message to the activator.
+
+Search for (string)targetname in all entities that
+match (string)self.target and call their .use function
+
+==============================
+*/
+void G_UseTargets (edict_t *ent, edict_t *activator)
+{
+	edict_t		*t;
+
+//
+// check for a delay
+//
+	if (ent->delay)
+	{
+	// create a temp object to fire at a later time
+		t = G_Spawn();
+		t->classname = "DelayedUse";
+		t->nextthink = level.time + ent->delay;
+		t->think = Think_Delay;
+		t->activator = activator;
+		if (!activator)
+			gi.dprintf ("Think_Delay with no activator\n");
+		t->message = ent->message;
+		t->target = ent->target;
+		t->killtarget = ent->killtarget;
+		return;
+	}
+	
+	
+//
+// print the message
+//
+	if ((ent->message) && !(activator->svflags & SVF_MONSTER))
+	{
+		gi.centerprintf (activator, "%s", ent->message);
+		if (ent->noise_index)
+			gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
+		else
+			gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
+	}
+
+//
+// kill killtargets
+//
+	if (ent->killtarget)
+	{
+		t = NULL;
+		while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
+		{
+			G_FreeEdict (t);
+			if (!ent->inuse)
+			{
+				gi.dprintf("entity was removed while using killtargets\n");
+				return;
+			}
+		}
+	}
+
+//
+// fire targets
+//
+	if (ent->target)
+	{
+		t = NULL;
+		while ((t = G_Find (t, FOFS(targetname), ent->target)))
+		{
+			// doors fire area portals in a specific way
+			if (!Q_stricmp(t->classname, "func_areaportal") &&
+				(!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
+				continue;
+
+			if (t == ent)
+			{
+				gi.dprintf ("WARNING: Entity used itself.\n");
+			}
+			else
+			{
+				if (t->use)
+					t->use (t, ent, activator);
+			}
+			if (!ent->inuse)
+			{
+				gi.dprintf("entity was removed while using targets\n");
+				return;
+			}
+		}
+	}
+}
+
+
+/*
+=============
+TempVector
+
+This is just a convenience function
+for making temporary vectors for function calls
+=============
+*/
+float	*tv (float x, float y, float z)
+{
+	static	int		index;
+	static	vec3_t	vecs[8];
+	float	*v;
+
+	// use an array so that multiple tempvectors won't collide
+	// for a while
+	v = vecs[index];
+	index = (index + 1)&7;
+
+	v[0] = x;
+	v[1] = y;
+	v[2] = z;
+
+	return v;
+}
+
+
+/*
+=============
+VectorToString
+
+This is just a convenience function
+for printing vectors
+=============
+*/
+char	*vtos (vec3_t v)
+{
+	static	int		index;
+	static	char	str[8][32];
+	char	*s;
+
+	// use an array so that multiple vtos won't collide
+	s = str[index];
+	index = (index + 1)&7;
+
+	Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
+
+	return s;
+}
+
+
+vec3_t VEC_UP		= {0, -1, 0};
+vec3_t MOVEDIR_UP	= {0, 0, 1};
+vec3_t VEC_DOWN		= {0, -2, 0};
+vec3_t MOVEDIR_DOWN	= {0, 0, -1};
+
+void G_SetMovedir (vec3_t angles, vec3_t movedir)
+{
+	if (VectorCompare (angles, VEC_UP))
+	{
+		VectorCopy (MOVEDIR_UP, movedir);
+	}
+	else if (VectorCompare (angles, VEC_DOWN))
+	{
+		VectorCopy (MOVEDIR_DOWN, movedir);
+	}
+	else
+	{
+		AngleVectors (angles, movedir, NULL, NULL);
+	}
+
+	VectorClear (angles);
+}
+
+
+float vectoyaw (vec3_t vec)
+{
+	float	yaw;
+	
+	if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0) 
+	{
+		yaw = 0;
+		if (vec[YAW] > 0)
+			yaw = 90;
+		else if (vec[YAW] < 0)
+			yaw = -90;
+	} 
+	else
+	{
+		yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
+		if (yaw < 0)
+			yaw += 360;
+	}
+
+	return yaw;
+}
+
+
+void vectoangles (vec3_t value1, vec3_t angles)
+{
+	float	forward;
+	float	yaw, pitch;
+	
+	if (value1[1] == 0 && value1[0] == 0)
+	{
+		yaw = 0;
+		if (value1[2] > 0)
+			pitch = 90;
+		else
+			pitch = 270;
+	}
+	else
+	{
+		if (value1[0])
+			yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
+		else if (value1[1] > 0)
+			yaw = 90;
+		else
+			yaw = -90;
+		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;
+	}
+
+	angles[PITCH] = -pitch;
+	angles[YAW] = yaw;
+	angles[ROLL] = 0;
+}
+
+char *G_CopyString (char *in)
+{
+	char	*out;
+	
+	out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
+	strcpy (out, in);
+	return out;
+}
+
+
+void G_InitEdict (edict_t *e)
+{
+	e->inuse = true;
+	e->classname = "noclass";
+	e->gravity = 1.0;
+	e->s.number = e - g_edicts;
+}
+
+/*
+=================
+G_Spawn
+
+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 *G_Spawn (void)
+{
+	int			i;
+	edict_t		*e;
+
+	e = &g_edicts[(int)maxclients->value+1];
+	for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
+	{
+		// the first couple seconds of server time can involve a lot of
+		// freeing and allocating, so relax the replacement policy
+		if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
+		{
+			G_InitEdict (e);
+			return e;
+		}
+	}
+	
+	if (i == game.maxentities)
+		gi.error ("ED_Alloc: no free edicts");
+		
+	globals.num_edicts++;
+	G_InitEdict (e);
+	return e;
+}
+
+/*
+=================
+G_FreeEdict
+
+Marks the edict as free
+=================
+*/
+void G_FreeEdict (edict_t *ed)
+{
+	gi.unlinkentity (ed);		// unlink from world
+
+	if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
+	{
+//		gi.dprintf("tried to free special edict\n");
+		return;
+	}
+
+	memset (ed, 0, sizeof(*ed));
+	ed->classname = "freed";
+	ed->freetime = level.time;
+	ed->inuse = false;
+}
+
+
+/*
+============
+G_TouchTriggers
+
+============
+*/
+void	G_TouchTriggers (edict_t *ent)
+{
+	int			i, num;
+	edict_t		*touch[MAX_EDICTS], *hit;
+
+	// dead things don't activate triggers!
+	if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
+		return;
+
+	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
+		, MAX_EDICTS, AREA_TRIGGERS);
+
+	// be careful, it is possible to have an entity in this
+	// list removed before we get to it (killtriggered)
+	for (i=0 ; i<num ; i++)
+	{
+		hit = touch[i];
+		if (!hit->inuse)
+			continue;
+		if (!hit->touch)
+			continue;
+		hit->touch (hit, ent, NULL, NULL);
+	}
+}
+
+/*
+============
+G_TouchSolids
+
+Call after linking a new trigger in during gameplay
+to force all entities it covers to immediately touch it
+============
+*/
+void	G_TouchSolids (edict_t *ent)
+{
+	int			i, num;
+	edict_t		*touch[MAX_EDICTS], *hit;
+
+	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
+		, MAX_EDICTS, AREA_SOLID);
+
+	// be careful, it is possible to have an entity in this
+	// list removed before we get to it (killtriggered)
+	for (i=0 ; i<num ; i++)
+	{
+		hit = touch[i];
+		if (!hit->inuse)
+			continue;
+		if (ent->touch)
+			ent->touch (hit, ent, NULL, NULL);
+		if (!ent->inuse)
+			break;
+	}
+}
+
+
+
+
+/*
+==============================================================================
+
+Kill box
+
+==============================================================================
+*/
+
+/*
+=================
+KillBox
+
+Kills all entities that would touch the proposed new positioning
+of ent.  Ent should be unlinked before calling this!
+=================
+*/
+qboolean KillBox (edict_t *ent)
+{
+	trace_t		tr;
+
+	while (1)
+	{
+		tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
+		if (!tr.ent)
+			break;
+
+		// nail it
+		T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
+
+		// if we didn't kill it, fail
+		if (tr.ent->solid)
+			return false;
+	}
+
+	return true;		// all clear
+}
--- /dev/null
+++ b/game/g_weapon.c
@@ -1,0 +1,916 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+/*
+=================
+check_dodge
+
+This is a support routine used when a client is firing
+a non-instant attack weapon.  It checks to see if a
+monster's dodge function should be called.
+=================
+*/
+static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed)
+{
+	vec3_t	end;
+	vec3_t	v;
+	trace_t	tr;
+	float	eta;
+
+	// easy mode only ducks one quarter the time
+	if (skill->value == 0)
+	{
+		if (random() > 0.25)
+			return;
+	}
+	VectorMA (start, 8192, dir, end);
+	tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
+	if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self))
+	{
+		VectorSubtract (tr.endpos, start, v);
+		eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
+		tr.ent->monsterinfo.dodge (tr.ent, self, eta);
+	}
+}
+
+
+/*
+=================
+fire_hit
+
+Used for all impact (hit/punch/slash) attacks
+=================
+*/
+qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick)
+{
+	trace_t		tr;
+	vec3_t		forward, right, up;
+	vec3_t		v;
+	vec3_t		point;
+	float		range;
+	vec3_t		dir;
+
+	//see if enemy is in range
+	VectorSubtract (self->enemy->s.origin, self->s.origin, dir);
+	range = VectorLength(dir);
+	if (range > aim[0])
+		return false;
+
+	if (aim[1] > self->mins[0] && aim[1] < self->maxs[0])
+	{
+		// the hit is straight on so back the range up to the edge of their bbox
+		range -= self->enemy->maxs[0];
+	}
+	else
+	{
+		// this is a side hit so adjust the "right" value out to the edge of their bbox
+		if (aim[1] < 0)
+			aim[1] = self->enemy->mins[0];
+		else
+			aim[1] = self->enemy->maxs[0];
+	}
+
+	VectorMA (self->s.origin, range, dir, point);
+
+	tr = gi.trace (self->s.origin, NULL, NULL, point, self, MASK_SHOT);
+	if (tr.fraction < 1)
+	{
+		if (!tr.ent->takedamage)
+			return false;
+		// if it will hit any client/monster then hit the one we wanted to hit
+		if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
+			tr.ent = self->enemy;
+	}
+
+	AngleVectors(self->s.angles, forward, right, up);
+	VectorMA (self->s.origin, range, forward, point);
+	VectorMA (point, aim[1], right, point);
+	VectorMA (point, aim[2], up, point);
+	VectorSubtract (point, self->enemy->s.origin, dir);
+
+	// do the damage
+	T_Damage (tr.ent, self, self, dir, point, vec3_origin, damage, kick/2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
+
+	if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
+		return false;
+
+	// do our special form of knockback here
+	VectorMA (self->enemy->absmin, 0.5, self->enemy->size, v);
+	VectorSubtract (v, point, v);
+	VectorNormalize (v);
+	VectorMA (self->enemy->velocity, kick, v, self->enemy->velocity);
+	if (self->enemy->velocity[2] > 0)
+		self->enemy->groundentity = NULL;
+	return true;
+}
+
+
+/*
+=================
+fire_lead
+
+This is an internal support routine used for bullet/pellet based weapons.
+=================
+*/
+static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
+{
+	trace_t		tr;
+	vec3_t		dir;
+	vec3_t		forward, right, up;
+	vec3_t		end;
+	float		r;
+	float		u;
+	vec3_t		water_start;
+	qboolean	water = false;
+	int			content_mask = MASK_SHOT | MASK_WATER;
+
+	tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
+	if (!(tr.fraction < 1.0))
+	{
+		vectoangles (aimdir, dir);
+		AngleVectors (dir, forward, right, up);
+
+		r = crandom()*hspread;
+		u = crandom()*vspread;
+		VectorMA (start, 8192, forward, end);
+		VectorMA (end, r, right, end);
+		VectorMA (end, u, up, end);
+
+		if (gi.pointcontents (start) & MASK_WATER)
+		{
+			water = true;
+			VectorCopy (start, water_start);
+			content_mask &= ~MASK_WATER;
+		}
+
+		tr = gi.trace (start, NULL, NULL, end, self, content_mask);
+
+		// see if we hit water
+		if (tr.contents & MASK_WATER)
+		{
+			int		color;
+
+			water = true;
+			VectorCopy (tr.endpos, water_start);
+
+			if (!VectorCompare (start, tr.endpos))
+			{
+				if (tr.contents & CONTENTS_WATER)
+				{
+					if (strcmp(tr.surface->name, "*brwater") == 0)
+						color = SPLASH_BROWN_WATER;
+					else
+						color = SPLASH_BLUE_WATER;
+				}
+				else if (tr.contents & CONTENTS_SLIME)
+					color = SPLASH_SLIME;
+				else if (tr.contents & CONTENTS_LAVA)
+					color = SPLASH_LAVA;
+				else
+					color = SPLASH_UNKNOWN;
+
+				if (color != SPLASH_UNKNOWN)
+				{
+					gi.WriteByte (svc_temp_entity);
+					gi.WriteByte (TE_SPLASH);
+					gi.WriteByte (8);
+					gi.WritePosition (tr.endpos);
+					gi.WriteDir (tr.plane.normal);
+					gi.WriteByte (color);
+					gi.multicast (tr.endpos, MULTICAST_PVS);
+				}
+
+				// change bullet's course when it enters water
+				VectorSubtract (end, start, dir);
+				vectoangles (dir, dir);
+				AngleVectors (dir, forward, right, up);
+				r = crandom()*hspread*2;
+				u = crandom()*vspread*2;
+				VectorMA (water_start, 8192, forward, end);
+				VectorMA (end, r, right, end);
+				VectorMA (end, u, up, end);
+			}
+
+			// re-trace ignoring water this time
+			tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT);
+		}
+	}
+
+	// send gun puff / flash
+	if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
+	{
+		if (tr.fraction < 1.0)
+		{
+			if (tr.ent->takedamage)
+			{
+				T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
+			}
+			else
+			{
+				if (strncmp (tr.surface->name, "sky", 3) != 0)
+				{
+					gi.WriteByte (svc_temp_entity);
+					gi.WriteByte (te_impact);
+					gi.WritePosition (tr.endpos);
+					gi.WriteDir (tr.plane.normal);
+					gi.multicast (tr.endpos, MULTICAST_PVS);
+
+					if (self->client)
+						PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
+				}
+			}
+		}
+	}
+
+	// if went through water, determine where the end and make a bubble trail
+	if (water)
+	{
+		vec3_t	pos;
+
+		VectorSubtract (tr.endpos, water_start, dir);
+		VectorNormalize (dir);
+		VectorMA (tr.endpos, -2, dir, pos);
+		if (gi.pointcontents (pos) & MASK_WATER)
+			VectorCopy (pos, tr.endpos);
+		else
+			tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER);
+
+		VectorAdd (water_start, tr.endpos, pos);
+		VectorScale (pos, 0.5, pos);
+
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_BUBBLETRAIL);
+		gi.WritePosition (water_start);
+		gi.WritePosition (tr.endpos);
+		gi.multicast (pos, MULTICAST_PVS);
+	}
+}
+
+
+/*
+=================
+fire_bullet
+
+Fires a single round.  Used for machinegun and chaingun.  Would be fine for
+pistols, rifles, etc....
+=================
+*/
+void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod)
+{
+	fire_lead (self, start, aimdir, damage, kick, TE_GUNSHOT, hspread, vspread, mod);
+}
+
+
+/*
+=================
+fire_shotgun
+
+Shoots shotgun pellets.  Used by shotgun and super shotgun.
+=================
+*/
+void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod)
+{
+	int		i;
+
+	for (i = 0; i < count; i++)
+		fire_lead (self, start, aimdir, damage, kick, TE_SHOTGUN, hspread, vspread, mod);
+}
+
+
+/*
+=================
+fire_blaster
+
+Fires a single blaster bolt.  Used by the blaster and hyper blaster.
+=================
+*/
+void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	int		mod;
+
+	if (other == self->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (self->owner->client)
+		PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
+
+	if (other->takedamage)
+	{
+		if (self->spawnflags & 1)
+			mod = MOD_HYPERBLASTER;
+		else
+			mod = MOD_BLASTER;
+		T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod);
+	}
+	else
+	{
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_BLASTER);
+		gi.WritePosition (self->s.origin);
+		if (!plane)
+			gi.WriteDir (vec3_origin);
+		else
+			gi.WriteDir (plane->normal);
+		gi.multicast (self->s.origin, MULTICAST_PVS);
+	}
+
+	G_FreeEdict (self);
+}
+
+void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, qboolean hyper)
+{
+	edict_t	*bolt;
+	trace_t	tr;
+
+	VectorNormalize (dir);
+
+	bolt = G_Spawn();
+	bolt->svflags = SVF_DEADMONSTER;
+	// yes, I know it looks weird that projectiles are deadmonsters
+	// what this means is that when prediction is used against the object
+	// (blaster/hyperblaster shots), the player won't be solid clipped against
+	// the object.  Right now trying to run into a firing hyperblaster
+	// is very jerky since you are predicted 'against' the shots.
+	VectorCopy (start, bolt->s.origin);
+	VectorCopy (start, bolt->s.old_origin);
+	vectoangles (dir, bolt->s.angles);
+	VectorScale (dir, speed, bolt->velocity);
+	bolt->movetype = MOVETYPE_FLYMISSILE;
+	bolt->clipmask = MASK_SHOT;
+	bolt->solid = SOLID_BBOX;
+	bolt->s.effects |= effect;
+	VectorClear (bolt->mins);
+	VectorClear (bolt->maxs);
+	bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2");
+	bolt->s.sound = gi.soundindex ("misc/lasfly.wav");
+	bolt->owner = self;
+	bolt->touch = blaster_touch;
+	bolt->nextthink = level.time + 2;
+	bolt->think = G_FreeEdict;
+	bolt->dmg = damage;
+	bolt->classname = "bolt";
+	if (hyper)
+		bolt->spawnflags = 1;
+	gi.linkentity (bolt);
+
+	if (self->client)
+		check_dodge (self, bolt->s.origin, dir, speed);
+
+	tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
+	if (tr.fraction < 1.0)
+	{
+		VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
+		bolt->touch (bolt, tr.ent, NULL, NULL);
+	}
+}	
+
+
+/*
+=================
+fire_grenade
+=================
+*/
+static void Grenade_Explode (edict_t *ent)
+{
+	vec3_t		origin;
+	int			mod;
+
+	if (ent->owner->client)
+		PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
+
+	//FIXME: if we are onground then raise our Z just a bit since we are a point?
+	if (ent->enemy)
+	{
+		float	points;
+		vec3_t	v;
+		vec3_t	dir;
+
+		VectorAdd (ent->enemy->mins, ent->enemy->maxs, v);
+		VectorMA (ent->enemy->s.origin, 0.5, v, v);
+		VectorSubtract (ent->s.origin, v, v);
+		points = ent->dmg - 0.5 * VectorLength (v);
+		VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir);
+		if (ent->spawnflags & 1)
+			mod = MOD_HANDGRENADE;
+		else
+			mod = MOD_GRENADE;
+		T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
+	}
+
+	if (ent->spawnflags & 2)
+		mod = MOD_HELD_GRENADE;
+	else if (ent->spawnflags & 1)
+		mod = MOD_HG_SPLASH;
+	else
+		mod = MOD_G_SPLASH;
+	T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
+
+	VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
+	gi.WriteByte (svc_temp_entity);
+	if (ent->waterlevel)
+	{
+		if (ent->groundentity)
+			gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
+		else
+			gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
+	}
+	else
+	{
+		if (ent->groundentity)
+			gi.WriteByte (TE_GRENADE_EXPLOSION);
+		else
+			gi.WriteByte (TE_ROCKET_EXPLOSION);
+	}
+	gi.WritePosition (origin);
+	gi.multicast (ent->s.origin, MULTICAST_PHS);
+
+	G_FreeEdict (ent);
+}
+
+static void Grenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other == ent->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (!other->takedamage)
+	{
+		if (ent->spawnflags & 1)
+		{
+			if (random() > 0.5)
+				gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
+			else
+				gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
+		}
+		else
+		{
+			gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
+		}
+		return;
+	}
+
+	ent->enemy = other;
+	Grenade_Explode (ent);
+}
+
+void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
+{
+	edict_t	*grenade;
+	vec3_t	dir;
+	vec3_t	forward, right, up;
+
+	vectoangles (aimdir, dir);
+	AngleVectors (dir, forward, right, up);
+
+	grenade = G_Spawn();
+	VectorCopy (start, grenade->s.origin);
+	VectorScale (aimdir, speed, grenade->velocity);
+	VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
+	VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
+	VectorSet (grenade->avelocity, 300, 300, 300);
+	grenade->movetype = MOVETYPE_BOUNCE;
+	grenade->clipmask = MASK_SHOT;
+	grenade->solid = SOLID_BBOX;
+	grenade->s.effects |= EF_GRENADE;
+	VectorClear (grenade->mins);
+	VectorClear (grenade->maxs);
+	grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2");
+	grenade->owner = self;
+	grenade->touch = Grenade_Touch;
+	grenade->nextthink = level.time + timer;
+	grenade->think = Grenade_Explode;
+	grenade->dmg = damage;
+	grenade->dmg_radius = damage_radius;
+	grenade->classname = "grenade";
+
+	gi.linkentity (grenade);
+}
+
+void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
+{
+	edict_t	*grenade;
+	vec3_t	dir;
+	vec3_t	forward, right, up;
+
+	vectoangles (aimdir, dir);
+	AngleVectors (dir, forward, right, up);
+
+	grenade = G_Spawn();
+	VectorCopy (start, grenade->s.origin);
+	VectorScale (aimdir, speed, grenade->velocity);
+	VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
+	VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
+	VectorSet (grenade->avelocity, 300, 300, 300);
+	grenade->movetype = MOVETYPE_BOUNCE;
+	grenade->clipmask = MASK_SHOT;
+	grenade->solid = SOLID_BBOX;
+	grenade->s.effects |= EF_GRENADE;
+	VectorClear (grenade->mins);
+	VectorClear (grenade->maxs);
+	grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2");
+	grenade->owner = self;
+	grenade->touch = Grenade_Touch;
+	grenade->nextthink = level.time + timer;
+	grenade->think = Grenade_Explode;
+	grenade->dmg = damage;
+	grenade->dmg_radius = damage_radius;
+	grenade->classname = "hgrenade";
+	if (held)
+		grenade->spawnflags = 3;
+	else
+		grenade->spawnflags = 1;
+	grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav");
+
+	if (timer <= 0.0)
+		Grenade_Explode (grenade);
+	else
+	{
+		gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
+		gi.linkentity (grenade);
+	}
+}
+
+
+/*
+=================
+fire_rocket
+=================
+*/
+void rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t		origin;
+	int			n;
+
+	if (other == ent->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (ent);
+		return;
+	}
+
+	if (ent->owner->client)
+		PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
+
+	// calculate position for the explosion entity
+	VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
+
+	if (other->takedamage)
+	{
+		T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET);
+	}
+	else
+	{
+		// don't throw any debris in net games
+		if (!deathmatch->value && !coop->value)
+		{
+			if ((surf) && !(surf->flags & (SURF_WARP|SURF_TRANS33|SURF_TRANS66|SURF_FLOWING)))
+			{
+				n = rand() % 5;
+				while(n--)
+					ThrowDebris (ent, "models/objects/debris2/tris.md2", 2, ent->s.origin);
+			}
+		}
+	}
+
+	T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH);
+
+	gi.WriteByte (svc_temp_entity);
+	if (ent->waterlevel)
+		gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
+	else
+		gi.WriteByte (TE_ROCKET_EXPLOSION);
+	gi.WritePosition (origin);
+	gi.multicast (ent->s.origin, MULTICAST_PHS);
+
+	G_FreeEdict (ent);
+}
+
+void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
+{
+	edict_t	*rocket;
+
+	rocket = G_Spawn();
+	VectorCopy (start, rocket->s.origin);
+	VectorCopy (dir, rocket->movedir);
+	vectoangles (dir, rocket->s.angles);
+	VectorScale (dir, speed, rocket->velocity);
+	rocket->movetype = MOVETYPE_FLYMISSILE;
+	rocket->clipmask = MASK_SHOT;
+	rocket->solid = SOLID_BBOX;
+	rocket->s.effects |= EF_ROCKET;
+	VectorClear (rocket->mins);
+	VectorClear (rocket->maxs);
+	rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");
+	rocket->owner = self;
+	rocket->touch = rocket_touch;
+	rocket->nextthink = level.time + 8000/speed;
+	rocket->think = G_FreeEdict;
+	rocket->dmg = damage;
+	rocket->radius_dmg = radius_damage;
+	rocket->dmg_radius = damage_radius;
+	rocket->s.sound = gi.soundindex ("weapons/rockfly.wav");
+	rocket->classname = "rocket";
+
+	if (self->client)
+		check_dodge (self, rocket->s.origin, dir, speed);
+
+	gi.linkentity (rocket);
+}
+
+
+/*
+=================
+fire_rail
+=================
+*/
+void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
+{
+	vec3_t		from;
+	vec3_t		end;
+	trace_t		tr;
+	edict_t		*ignore;
+	int			mask;
+	qboolean	water;
+
+	VectorMA (start, 8192, aimdir, end);
+	VectorCopy (start, from);
+	ignore = self;
+	water = false;
+	mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA;
+	while (ignore)
+	{
+		tr = gi.trace (from, NULL, NULL, end, ignore, mask);
+
+		if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA))
+		{
+			mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA);
+			water = true;
+		}
+		else
+		{
+			if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
+				ignore = tr.ent;
+			else
+				ignore = NULL;
+
+			if ((tr.ent != self) && (tr.ent->takedamage))
+				T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_RAILGUN);
+		}
+
+		VectorCopy (tr.endpos, from);
+	}
+
+	// send gun puff / flash
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_RAILTRAIL);
+	gi.WritePosition (start);
+	gi.WritePosition (tr.endpos);
+	gi.multicast (self->s.origin, MULTICAST_PHS);
+//	gi.multicast (start, MULTICAST_PHS);
+	if (water)
+	{
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_RAILTRAIL);
+		gi.WritePosition (start);
+		gi.WritePosition (tr.endpos);
+		gi.multicast (tr.endpos, MULTICAST_PHS);
+	}
+
+	if (self->client)
+		PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
+}
+
+
+/*
+=================
+fire_bfg
+=================
+*/
+void bfg_explode (edict_t *self)
+{
+	edict_t	*ent;
+	float	points;
+	vec3_t	v;
+	float	dist;
+
+	if (self->s.frame == 0)
+	{
+		// the BFG effect
+		ent = NULL;
+		while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL)
+		{
+			if (!ent->takedamage)
+				continue;
+			if (ent == self->owner)
+				continue;
+			if (!CanDamage (ent, self))
+				continue;
+			if (!CanDamage (ent, self->owner))
+				continue;
+
+			VectorAdd (ent->mins, ent->maxs, v);
+			VectorMA (ent->s.origin, 0.5, v, v);
+			VectorSubtract (self->s.origin, v, v);
+			dist = VectorLength(v);
+			points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius));
+			if (ent == self->owner)
+				points = points * 0.5;
+
+			gi.WriteByte (svc_temp_entity);
+			gi.WriteByte (TE_BFG_EXPLOSION);
+			gi.WritePosition (ent->s.origin);
+			gi.multicast (ent->s.origin, MULTICAST_PHS);
+			T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
+		}
+	}
+
+	self->nextthink = level.time + FRAMETIME;
+	self->s.frame++;
+	if (self->s.frame == 5)
+		self->think = G_FreeEdict;
+}
+
+void bfg_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (other == self->owner)
+		return;
+
+	if (surf && (surf->flags & SURF_SKY))
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (self->owner->client)
+		PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
+
+	// core explosion - prevents firing it into the wall/floor
+	if (other->takedamage)
+		T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST);
+	T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
+
+	gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
+	self->solid = SOLID_NOT;
+	self->touch = NULL;
+	VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
+	VectorClear (self->velocity);
+	self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2");
+	self->s.frame = 0;
+	self->s.sound = 0;
+	self->s.effects &= ~EF_ANIM_ALLFAST;
+	self->think = bfg_explode;
+	self->nextthink = level.time + FRAMETIME;
+	self->enemy = other;
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_BFG_BIGEXPLOSION);
+	gi.WritePosition (self->s.origin);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+}
+
+
+void bfg_think (edict_t *self)
+{
+	edict_t	*ent;
+	edict_t	*ignore;
+	vec3_t	point;
+	vec3_t	dir;
+	vec3_t	start;
+	vec3_t	end;
+	int		dmg;
+	trace_t	tr;
+
+	if (deathmatch->value)
+		dmg = 5;
+	else
+		dmg = 10;
+
+	ent = NULL;
+	while ((ent = findradius(ent, self->s.origin, 256)) != NULL)
+	{
+		if (ent == self)
+			continue;
+
+		if (ent == self->owner)
+			continue;
+
+		if (!ent->takedamage)
+			continue;
+
+		if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
+			continue;
+
+		VectorMA (ent->absmin, 0.5, ent->size, point);
+
+		VectorSubtract (point, self->s.origin, dir);
+		VectorNormalize (dir);
+
+		ignore = self;
+		VectorCopy (self->s.origin, start);
+		VectorMA (start, 2048, dir, end);
+		while(1)
+		{
+			tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
+
+			if (!tr.ent)
+				break;
+
+			// hurt it if we can
+			if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner))
+				T_Damage (tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
+
+			// if we hit something that's not a monster or player we're done
+			if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
+			{
+				gi.WriteByte (svc_temp_entity);
+				gi.WriteByte (TE_LASER_SPARKS);
+				gi.WriteByte (4);
+				gi.WritePosition (tr.endpos);
+				gi.WriteDir (tr.plane.normal);
+				gi.WriteByte (self->s.skinnum);
+				gi.multicast (tr.endpos, MULTICAST_PVS);
+				break;
+			}
+
+			ignore = tr.ent;
+			VectorCopy (tr.endpos, start);
+		}
+
+		gi.WriteByte (svc_temp_entity);
+		gi.WriteByte (TE_BFG_LASER);
+		gi.WritePosition (self->s.origin);
+		gi.WritePosition (tr.endpos);
+		gi.multicast (self->s.origin, MULTICAST_PHS);
+	}
+
+	self->nextthink = level.time + FRAMETIME;
+}
+
+
+void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius)
+{
+	edict_t	*bfg;
+
+	bfg = G_Spawn();
+	VectorCopy (start, bfg->s.origin);
+	VectorCopy (dir, bfg->movedir);
+	vectoangles (dir, bfg->s.angles);
+	VectorScale (dir, speed, bfg->velocity);
+	bfg->movetype = MOVETYPE_FLYMISSILE;
+	bfg->clipmask = MASK_SHOT;
+	bfg->solid = SOLID_BBOX;
+	bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST;
+	VectorClear (bfg->mins);
+	VectorClear (bfg->maxs);
+	bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2");
+	bfg->owner = self;
+	bfg->touch = bfg_touch;
+	bfg->nextthink = level.time + 8000/speed;
+	bfg->think = G_FreeEdict;
+	bfg->radius_dmg = damage;
+	bfg->dmg_radius = damage_radius;
+	bfg->classname = "bfg blast";
+	bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav");
+
+	bfg->think = bfg_think;
+	bfg->nextthink = level.time + FRAMETIME;
+	bfg->teammaster = bfg;
+	bfg->teamchain = NULL;
+
+	if (self->client)
+		check_dodge (self, bfg->s.origin, dir, speed);
+
+	gi.linkentity (bfg);
+}
--- /dev/null
+++ b/game/game.001
@@ -1,0 +1,1619 @@
+# Microsoft Developer Studio Project File - Name="game" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=game - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "game.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "game.mak" CFG="game - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "game - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "game - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "game - Win32 Debug Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "game - Win32 Release Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:I386 /out:"..\release\gamex86.dll"
+# SUBTRACT LINK32 /incremental:yes /debug
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "BUILDING_REF_GL" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"..\debug\gamex86.dll"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug Alpha"
+# PROP BASE Intermediate_Dir "Debug Alpha"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /c
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x20000000" /subsystem:windows /dll /debug /machine:ALPHA
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x20000000" /subsystem:windows /dll /debug /machine:ALPHA /out:"..\DebugAxp/gameaxp.dll"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "game___W"
+# PROP BASE Intermediate_Dir "game___W"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /c
+# SUBTRACT CPP /Z<none> /Fr
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:ALPHA /out:"..\Release/gamex86.dll"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:ALPHA /out:"..\ReleaseAXP/gameaxp.dll"
+# SUBTRACT LINK32 /debug
+
+!ENDIF 
+
+# Begin Target
+
+# Name "game - Win32 Release"
+# Name "game - Win32 Debug"
+# Name "game - Win32 Debug Alpha"
+# Name "game - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\g_ai.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_chase.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_cmds.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_combat.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_func.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_items.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_main.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_misc.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_monster.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_phys.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_save.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_spawn.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_svcmds.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_target.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_trigger.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_turret.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_TUR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_TUR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_utils.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_weapon.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_actor.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_ACT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_actor.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_ACT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_actor.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_berserk.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BER=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_berserk.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BER=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_berserk.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss2.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss2.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss2.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss3.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOSS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOSS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss31.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOSS3=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss31.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOSS3=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss31.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss32.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOSS32=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOSS32=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_brain.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_brain.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_brain.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_chick.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_CHI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_chick.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_CHI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_chick.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flash.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLA=\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLA=\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flipper.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flipper.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flipper.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_float.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLO=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_float.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLO=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_float.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flyer.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flyer.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flyer.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gladiator.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_GLA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gladiator.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_GLA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gladiator.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gunner.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_GUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gunner.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_GUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gunner.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_hover.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_HOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_hover.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_HOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_hover.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_infantry.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_INF=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_infantry.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_INF=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_infantry.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_insane.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_INS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_insane.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_INS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_insane.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_medic.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_MED=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_medic.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_MED=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_medic.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_move.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_mutant.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_MUT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_mutant.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_MUT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_mutant.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_parasite.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_PAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_parasite.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_PAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_parasite.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_soldier.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_SOL=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_soldier.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_SOL=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_soldier.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_supertank.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_SUP=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_supertank.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_SUP=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_supertank.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_tank.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_TAN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_tank.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_TAN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_tank.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_client.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_hud.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_trail.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_view.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_weapon.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\g_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_actor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_berserk.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss31.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss32.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_brain.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_chick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flipper.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_float.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flyer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gladiator.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gunner.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_hover.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_infantry.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_insane.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_medic.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_mutant.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_parasite.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_player.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_soldier.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_supertank.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_tank.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\game.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/game/game.def
@@ -1,0 +1,2 @@
+EXPORTS
+	GetGameAPI
--- /dev/null
+++ b/game/game.dsp
@@ -1,0 +1,1618 @@
+# Microsoft Developer Studio Project File - Name="game" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=game - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "game.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "game.mak" CFG="game - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "game - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "game - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "game - Win32 Debug Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "game - Win32 Release Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:I386 /out:"..\release\gamex86.dll"
+# SUBTRACT LINK32 /incremental:yes /debug
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "BUILDING_REF_GL" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /out:"..\debug\gamex86.dll"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug Alpha"
+# PROP BASE Intermediate_Dir "Debug Alpha"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x20000000" /subsystem:windows /dll /debug /machine:ALPHA
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x20000000" /subsystem:windows /dll /debug /machine:ALPHA /out:"..\DebugAxp/gameaxp.dll"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "game___W"
+# PROP BASE Intermediate_Dir "game___W"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /c
+# SUBTRACT CPP /Z<none> /Fr
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:ALPHA /out:"..\Release/gamex86.dll"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:ALPHA /out:"..\ReleaseAXP/gameaxp.dll"
+# SUBTRACT LINK32 /debug
+
+!ENDIF 
+
+# Begin Target
+
+# Name "game - Win32 Release"
+# Name "game - Win32 Debug"
+# Name "game - Win32 Debug Alpha"
+# Name "game - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\g_ai.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_AI_=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_chase.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_CHA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_cmds.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_CMD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_combat.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_COM=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_func.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_FUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_items.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_ITE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_main.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_MAI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_misc.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_MIS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_monster.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_MON=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_phys.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_PHY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_save.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_SAV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_spawn.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_SPA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_svcmds.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_SVC=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_target.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_TAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_trigger.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_TRI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_turret.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_TUR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_TUR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_utils.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_UTI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\g_weapon.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_G_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_actor.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_ACT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_actor.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_ACT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_actor.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_berserk.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BER=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_berserk.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BER=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_berserk.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss2.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss2.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss2.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss3.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOSS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOSS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss31.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOSS3=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss31.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOSS3=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss31.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss32.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BOSS32=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BOSS32=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_boss32.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_brain.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_BRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_brain.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_BRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_brain.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_chick.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_CHI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_chick.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_CHI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_chick.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flash.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLA=\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLA=\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flipper.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flipper.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flipper.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_float.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLO=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_float.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLO=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_float.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flyer.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_FLY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flyer.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_FLY=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_flyer.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gladiator.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_GLA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gladiator.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_GLA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gladiator.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gunner.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_GUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gunner.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_GUN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_gunner.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_hover.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_HOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_hover.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_HOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_hover.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_infantry.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_INF=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_infantry.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_INF=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_infantry.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_insane.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_INS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_insane.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_INS=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_insane.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_medic.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_MED=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_medic.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_MED=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_medic.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_move.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_MOV=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_mutant.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_MUT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_mutant.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_MUT=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_mutant.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_parasite.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_PAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_parasite.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_PAR=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_parasite.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_soldier.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_SOL=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_soldier.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_SOL=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_soldier.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_supertank.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_SUP=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_supertank.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_SUP=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_supertank.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_tank.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_M_TAN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_tank.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_M_TAN=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_tank.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_client.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_CLI=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_hud.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_HUD=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_trail.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_TRA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_view.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_VIE=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\p_weapon.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_P_WEA=\
+	".\g_local.h"\
+	".\game.h"\
+	".\m_player.h"\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.c
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\g_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_actor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_berserk.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss31.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_boss32.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_brain.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_chick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flipper.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_float.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_flyer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gladiator.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_gunner.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_hover.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_infantry.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_insane.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_medic.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_mutant.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_parasite.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_player.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_soldier.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_supertank.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\m_tank.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\q_shared.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\game.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/game/game.h
@@ -1,0 +1,254 @@
+/*
+Copyright (C) 1997-2001 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) 1997-2001 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.
+
+*/
+
+// game.h -- game dll information visible to server
+
+#define	GAME_API_VERSION	3
+
+// edict->svflags
+
+#define	SVF_NOCLIENT			0x00000001	// don't send entity to clients, even if it has effects
+#define	SVF_DEADMONSTER			0x00000002	// treat as CONTENTS_DEADMONSTER for collision
+#define	SVF_MONSTER				0x00000004	// treat as CONTENTS_MONSTER for collision
+
+// edict->solid values
+
+typedef enum
+{
+SOLID_NOT,			// no interaction with other objects
+SOLID_TRIGGER,		// only touch when inside, after moving
+SOLID_BBOX,			// touch on edge
+SOLID_BSP			// bsp clip, touch on edge
+} solid_t;
+
+//===============================================================
+
+// link_t is only used for entity area links now
+typedef struct link_s
+{
+	struct link_s	*prev, *next;
+} link_t;
+
+#define	MAX_ENT_CLUSTERS	16
+
+
+typedef struct edict_s edict_t;
+typedef struct gclient_s gclient_t;
+
+
+#ifndef GAME_INCLUDE
+
+struct gclient_s
+{
+	player_state_t	ps;		// communicated by server to clients
+	int				ping;
+	// the game dll can add anything it wants after
+	// this point in the structure
+};
+
+
+struct edict_s
+{
+	entity_state_t	s;
+	struct gclient_s	*client;
+	qboolean	inuse;
+	int			linkcount;
+
+	// FIXME: move these fields to a server private sv_entity_t
+	link_t		area;				// linked to a division node or leaf
+	
+	int			num_clusters;		// if -1, use headnode instead
+	int			clusternums[MAX_ENT_CLUSTERS];
+	int			headnode;			// unused if num_clusters != -1
+	int			areanum, areanum2;
+
+	//================================
+
+	int			svflags;			// SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc
+	vec3_t		mins, maxs;
+	vec3_t		absmin, absmax, size;
+	solid_t		solid;
+	int			clipmask;
+	edict_t		*owner;
+
+	// the game dll can add anything it wants after
+	// this point in the structure
+};
+
+#endif		// GAME_INCLUDE
+
+//===============================================================
+
+//
+// functions provided by the main engine
+//
+typedef struct
+{
+	// special messages
+	void	(*bprintf) (int printlevel, char *fmt, ...);
+	void	(*dprintf) (char *fmt, ...);
+	void	(*cprintf) (edict_t *ent, int printlevel, char *fmt, ...);
+	void	(*centerprintf) (edict_t *ent, char *fmt, ...);
+	void	(*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
+	void	(*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
+
+	// config strings hold all the index strings, the lightstyles,
+	// and misc data like the sky definition and cdtrack.
+	// All of the current configstrings are sent to clients when
+	// they connect, and changes are sent to all connected clients.
+	void	(*configstring) (int num, char *string);
+
+	void	(*error) (char *fmt, ...);
+
+	// the *index functions create configstrings and some internal server state
+	int		(*modelindex) (char *name);
+	int		(*soundindex) (char *name);
+	int		(*imageindex) (char *name);
+
+	void	(*setmodel) (edict_t *ent, char *name);
+
+	// collision detection
+	trace_t	(*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
+	int		(*pointcontents) (vec3_t point);
+	qboolean	(*inPVS) (vec3_t p1, vec3_t p2);
+	qboolean	(*inPHS) (vec3_t p1, vec3_t p2);
+	void		(*SetAreaPortalState) (int portalnum, qboolean open);
+	qboolean	(*AreasConnected) (int area1, int area2);
+
+	// an entity will never be sent to a client or used for collision
+	// if it is not passed to linkentity.  If the size, position, or
+	// solidity changes, it must be relinked.
+	void	(*linkentity) (edict_t *ent);
+	void	(*unlinkentity) (edict_t *ent);		// call before removing an interactive edict
+	int		(*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list,	int maxcount, int areatype);
+	void	(*Pmove) (pmove_t *pmove);		// player movement code common with client prediction
+
+	// network messaging
+	void	(*multicast) (vec3_t origin, multicast_t to);
+	void	(*unicast) (edict_t *ent, qboolean reliable);
+	void	(*WriteChar) (int c);
+	void	(*WriteByte) (int c);
+	void	(*WriteShort) (int c);
+	void	(*WriteLong) (int c);
+	void	(*WriteFloat) (float f);
+	void	(*WriteString) (char *s);
+	void	(*WritePosition) (vec3_t pos);	// some fractional bits
+	void	(*WriteDir) (vec3_t pos);		// single byte encoded, very coarse
+	void	(*WriteAngle) (float f);
+
+	// managed memory allocation
+	void	*(*TagMalloc) (int size, int tag);
+	void	(*TagFree) (void *block);
+	void	(*FreeTags) (int tag);
+
+	// console variable interaction
+	cvar_t	*(*cvar) (char *var_name, char *value, int flags);
+	cvar_t	*(*cvar_set) (char *var_name, char *value);
+	cvar_t	*(*cvar_forceset) (char *var_name, char *value);
+
+	// ClientCommand and ServerCommand parameter access
+	int		(*argc) (void);
+	char	*(*argv) (int n);
+	char	*(*args) (void);	// concatenation of all argv >= 1
+
+	// add commands to the server console as if they were typed in
+	// for map changing, etc
+	void	(*AddCommandString) (char *text);
+
+	void	(*DebugGraph) (float value, int color);
+} game_import_t;
+
+//
+// functions exported by the game subsystem
+//
+typedef struct
+{
+	int			apiversion;
+
+	// the init function will only be called when a game starts,
+	// not each time a level is loaded.  Persistant data for clients
+	// and the server can be allocated in init
+	void		(*Init) (void);
+	void		(*Shutdown) (void);
+
+	// each new level entered will cause a call to SpawnEntities
+	void		(*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
+
+	// Read/Write Game is for storing persistant cross level information
+	// about the world state and the clients.
+	// WriteGame is called every time a level is exited.
+	// ReadGame is called on a loadgame.
+	void		(*WriteGame) (char *filename, qboolean autosave);
+	void		(*ReadGame) (char *filename);
+
+	// ReadLevel is called after the default map information has been
+	// loaded with SpawnEntities
+	void		(*WriteLevel) (char *filename);
+	void		(*ReadLevel) (char *filename);
+
+	qboolean	(*ClientConnect) (edict_t *ent, char *userinfo);
+	void		(*ClientBegin) (edict_t *ent);
+	void		(*ClientUserinfoChanged) (edict_t *ent, char *userinfo);
+	void		(*ClientDisconnect) (edict_t *ent);
+	void		(*ClientCommand) (edict_t *ent);
+	void		(*ClientThink) (edict_t *ent, usercmd_t *cmd);
+
+	void		(*RunFrame) (void);
+
+	// ServerCommand will be called when an "sv <command>" command is issued on the
+	// server console.
+	// The game can issue gi.argc() / gi.argv() commands to get the rest
+	// of the parameters
+	void		(*ServerCommand) (void);
+
+	//
+	// global variables shared between game and server
+	//
+
+	// The edict array is allocated in the game dll so it
+	// can vary in size from one game to another.
+	// 
+	// The size will be fixed when ge->Init() is called
+	struct edict_s	*edicts;
+	int			edict_size;
+	int			num_edicts;		// current number, <= max_edicts
+	int			max_edicts;
+} game_export_t;
+
+game_export_t *GetGameApi (game_import_t *import);
--- /dev/null
+++ b/game/game.plg
@@ -1,0 +1,75 @@
+--------------------Configuration: game - Win32 Release Alpha--------------------
+Begining build with project "G:\quake2\code\game\game.dsp", at root.
+Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library)
+
+Project's tools are:
+			"OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
+			"C/C++ Compiler for Alpha" with flags "/nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/game.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /FD /c "
+			"Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" "
+			"Browser Database Maker" with flags "/nologo /o"..\ReleaseAXP/game.bsc" "
+			"COFF Linker for Alpha" with flags "kernel32.lib user32.lib gdi32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/gameaxp.pdb" /debug /machine:ALPHA /def:".\game.def" /out:"..\ReleaseAXP/gameaxp.dll" /implib:"..\ReleaseAXP/gameaxp.lib" "
+			"Custom Build" with flags ""
+			"<Component 0xa>" with flags ""
+
+Creating temp file "C:\TEMP\RSPA6.tmp" with contents </nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/game.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/"  /c 
+"G:\quake2\code\game\p_weapon.c"
+>
+Creating command line "cl.exe @C:\TEMP\RSPA6.tmp" 
+Creating temp file "C:\TEMP\RSPA7.tmp" with contents <kernel32.lib user32.lib gdi32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/gameaxp.pdb" /debug /machine:ALPHA /def:".\game.def" /out:"..\ReleaseAXP/gameaxp.dll" /implib:"..\ReleaseAXP/gameaxp.lib" 
+.\ReleaseAXP\g_ai.obj
+.\ReleaseAXP\g_chase.obj
+.\ReleaseAXP\g_cmds.obj
+.\ReleaseAXP\g_combat.obj
+.\ReleaseAXP\g_func.obj
+.\ReleaseAXP\g_items.obj
+.\ReleaseAXP\g_main.obj
+.\ReleaseAXP\g_misc.obj
+.\ReleaseAXP\g_monster.obj
+.\ReleaseAXP\g_phys.obj
+.\ReleaseAXP\g_save.obj
+.\ReleaseAXP\g_spawn.obj
+.\ReleaseAXP\g_svcmds.obj
+.\ReleaseAXP\g_target.obj
+.\ReleaseAXP\g_trigger.obj
+.\ReleaseAXP\g_turret.obj
+.\ReleaseAXP\g_utils.obj
+.\ReleaseAXP\g_weapon.obj
+.\ReleaseAXP\m_actor.obj
+.\ReleaseAXP\m_berserk.obj
+.\ReleaseAXP\m_boss2.obj
+.\ReleaseAXP\m_boss3.obj
+.\ReleaseAXP\m_boss31.obj
+.\ReleaseAXP\m_boss32.obj
+.\ReleaseAXP\m_brain.obj
+.\ReleaseAXP\m_chick.obj
+.\ReleaseAXP\m_flash.obj
+.\ReleaseAXP\m_flipper.obj
+.\ReleaseAXP\m_float.obj
+.\ReleaseAXP\m_flyer.obj
+.\ReleaseAXP\m_gladiator.obj
+.\ReleaseAXP\m_gunner.obj
+.\ReleaseAXP\m_hover.obj
+.\ReleaseAXP\m_infantry.obj
+.\ReleaseAXP\m_insane.obj
+.\ReleaseAXP\m_medic.obj
+.\ReleaseAXP\m_move.obj
+.\ReleaseAXP\m_mutant.obj
+.\ReleaseAXP\m_parasite.obj
+.\ReleaseAXP\m_soldier.obj
+.\ReleaseAXP\m_supertank.obj
+.\ReleaseAXP\m_tank.obj
+.\ReleaseAXP\p_client.obj
+.\ReleaseAXP\p_hud.obj
+.\ReleaseAXP\p_trail.obj
+.\ReleaseAXP\p_view.obj
+.\ReleaseAXP\p_weapon.obj
+.\ReleaseAXP\q_shared.obj>
+Creating command line "link.exe @C:\TEMP\RSPA7.tmp" 
+Compiling...
+p_weapon.c
+Linking...
+   Creating library ..\ReleaseAXP/gameaxp.lib and object ..\ReleaseAXP/gameaxp.exp
+
+
+
+gameaxp.dll - 0 error(s), 0 warning(s)
--- /dev/null
+++ b/game/m_actor.c
@@ -1,0 +1,609 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_actor.c
+
+#include "g_local.h"
+#include "m_actor.h"
+
+#define	MAX_ACTOR_NAMES		8
+char *actor_names[MAX_ACTOR_NAMES] =
+{
+	"Hellrot",
+	"Tokay",
+	"Killme",
+	"Disruptor",
+	"Adrianator",
+	"Rambear",
+	"Titus",
+	"Bitterman"
+};
+
+
+mframe_t actor_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t actor_move_stand = {FRAME_stand101, FRAME_stand140, actor_frames_stand, NULL};
+
+void actor_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &actor_move_stand;
+
+	// randomize on startup
+	if (level.time < 1.0)
+		self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
+}
+
+
+mframe_t actor_frames_walk [] =
+{
+	ai_walk, 0,  NULL,
+	ai_walk, 6,  NULL,
+	ai_walk, 10, NULL,
+	ai_walk, 3,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 7,  NULL,
+	ai_walk, 10, NULL,
+	ai_walk, 1,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL
+};
+mmove_t actor_move_walk = {FRAME_walk01, FRAME_walk08, actor_frames_walk, NULL};
+
+void actor_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &actor_move_walk;
+}
+
+
+mframe_t actor_frames_run [] =
+{
+	ai_run, 4,  NULL,
+	ai_run, 15, NULL,
+	ai_run, 15, NULL,
+	ai_run, 8,  NULL,
+	ai_run, 20, NULL,
+	ai_run, 15, NULL,
+	ai_run, 8,  NULL,
+	ai_run, 17, NULL,
+	ai_run, 12, NULL,
+	ai_run, -2, NULL,
+	ai_run, -2, NULL,
+	ai_run, -1, NULL
+};
+mmove_t actor_move_run = {FRAME_run02, FRAME_run07, actor_frames_run, NULL};
+
+void actor_run (edict_t *self)
+{
+	if ((level.time < self->pain_debounce_time) && (!self->enemy))
+	{
+		if (self->movetarget)
+			actor_walk(self);
+		else
+			actor_stand(self);
+		return;
+	}
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		actor_stand(self);
+		return;
+	}
+
+	self->monsterinfo.currentmove = &actor_move_run;
+}
+
+
+mframe_t actor_frames_pain1 [] =
+{
+	ai_move, -5, NULL,
+	ai_move, 4,  NULL,
+	ai_move, 1,  NULL
+};
+mmove_t actor_move_pain1 = {FRAME_pain101, FRAME_pain103, actor_frames_pain1, actor_run};
+
+mframe_t actor_frames_pain2 [] =
+{
+	ai_move, -4, NULL,
+	ai_move, 4,  NULL,
+	ai_move, 0,  NULL
+};
+mmove_t actor_move_pain2 = {FRAME_pain201, FRAME_pain203, actor_frames_pain2, actor_run};
+
+mframe_t actor_frames_pain3 [] =
+{
+	ai_move, -1, NULL,
+	ai_move, 1,  NULL,
+	ai_move, 0,  NULL
+};
+mmove_t actor_move_pain3 = {FRAME_pain301, FRAME_pain303, actor_frames_pain3, actor_run};
+
+mframe_t actor_frames_flipoff [] =
+{
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL
+};
+mmove_t actor_move_flipoff = {FRAME_flip01, FRAME_flip14, actor_frames_flipoff, actor_run};
+
+mframe_t actor_frames_taunt [] =
+{
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL,
+	ai_turn, 0,  NULL
+};
+mmove_t actor_move_taunt = {FRAME_taunt01, FRAME_taunt17, actor_frames_taunt, actor_run};
+
+char *messages[] =
+{
+	"Watch it",
+	"#$@*&",
+	"Idiot",
+	"Check your targets"
+};
+
+void actor_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	int		n;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+//	gi.sound (self, CHAN_VOICE, actor.sound_pain, 1, ATTN_NORM, 0);
+
+	if ((other->client) && (random() < 0.4))
+	{
+		vec3_t	v;
+		char	*name;
+
+		VectorSubtract (other->s.origin, self->s.origin, v);
+		self->ideal_yaw = vectoyaw (v);
+		if (random() < 0.5)
+			self->monsterinfo.currentmove = &actor_move_flipoff;
+		else
+			self->monsterinfo.currentmove = &actor_move_taunt;
+		name = actor_names[(self - g_edicts)%MAX_ACTOR_NAMES];
+		gi.cprintf (other, PRINT_CHAT, "%s: %s!\n", name, messages[rand()%3]);
+		return;
+	}
+
+	n = rand() % 3;
+	if (n == 0)
+		self->monsterinfo.currentmove = &actor_move_pain1;
+	else if (n == 1)
+		self->monsterinfo.currentmove = &actor_move_pain2;
+	else
+		self->monsterinfo.currentmove = &actor_move_pain3;
+}
+
+
+void actorMachineGun (edict_t *self)
+{
+	vec3_t	start, target;
+	vec3_t	forward, right;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_ACTOR_MACHINEGUN_1], forward, right, start);
+	if (self->enemy)
+	{
+		if (self->enemy->health > 0)
+		{
+			VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
+			target[2] += self->enemy->viewheight;
+		}
+		else
+		{
+			VectorCopy (self->enemy->absmin, target);
+			target[2] += (self->enemy->size[2] / 2);
+		}
+		VectorSubtract (target, start, forward);
+		VectorNormalize (forward);
+	}
+	else
+	{
+		AngleVectors (self->s.angles, forward, NULL, NULL);
+	}
+	monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_ACTOR_MACHINEGUN_1);
+}
+
+
+void actor_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t actor_frames_death1 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -13, NULL,
+	ai_move, 14,  NULL,
+	ai_move, 3,   NULL,
+	ai_move, -2,  NULL,
+	ai_move, 1,   NULL
+};
+mmove_t actor_move_death1 = {FRAME_death101, FRAME_death107, actor_frames_death1, actor_dead};
+
+mframe_t actor_frames_death2 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 7,   NULL,
+	ai_move, -6,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, 1,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -1,  NULL,
+	ai_move, -2,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, -9,  NULL,
+	ai_move, -13, NULL,
+	ai_move, -13, NULL,
+	ai_move, 0,   NULL
+};
+mmove_t actor_move_death2 = {FRAME_death201, FRAME_death213, actor_frames_death2, actor_dead};
+
+void actor_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= -80)
+	{
+//		gi.sound (self, CHAN_VOICE, actor.sound_gib, 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+//	gi.sound (self, CHAN_VOICE, actor.sound_die, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	n = rand() % 2;
+	if (n == 0)
+		self->monsterinfo.currentmove = &actor_move_death1;
+	else
+		self->monsterinfo.currentmove = &actor_move_death2;
+}
+
+
+void actor_fire (edict_t *self)
+{
+	actorMachineGun (self);
+
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+mframe_t actor_frames_attack [] =
+{
+	ai_charge, -2,  actor_fire,
+	ai_charge, -2,  NULL,
+	ai_charge, 3,   NULL,
+	ai_charge, 2,   NULL
+};
+mmove_t actor_move_attack = {FRAME_attak01, FRAME_attak04, actor_frames_attack, actor_run};
+
+void actor_attack(edict_t *self)
+{
+	int		n;
+
+	self->monsterinfo.currentmove = &actor_move_attack;
+	n = (rand() & 15) + 3 + 7;
+	self->monsterinfo.pausetime = level.time + n * FRAMETIME;
+}
+
+
+void actor_use (edict_t *self, edict_t *other, edict_t *activator)
+{
+	vec3_t		v;
+
+	self->goalentity = self->movetarget = G_PickTarget(self->target);
+	if ((!self->movetarget) || (strcmp(self->movetarget->classname, "target_actor") != 0))
+	{
+		gi.dprintf ("%s has bad target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
+		self->target = NULL;
+		self->monsterinfo.pausetime = 100000000;
+		self->monsterinfo.stand (self);
+		return;
+	}
+
+	VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
+	self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
+	self->monsterinfo.walk (self);
+	self->target = NULL;
+}
+
+
+/*QUAKED misc_actor (1 .5 0) (-16 -16 -24) (16 16 32)
+*/
+
+void SP_misc_actor (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (!self->targetname)
+	{
+		gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	if (!self->target)
+	{
+		gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex("players/male/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	if (!self->health)
+		self->health = 100;
+	self->mass = 200;
+
+	self->pain = actor_pain;
+	self->die = actor_die;
+
+	self->monsterinfo.stand = actor_stand;
+	self->monsterinfo.walk = actor_walk;
+	self->monsterinfo.run = actor_run;
+	self->monsterinfo.attack = actor_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = NULL;
+
+	self->monsterinfo.aiflags |= AI_GOOD_GUY;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &actor_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+
+	// actors always start in a dormant state, they *must* be used to get going
+	self->use = actor_use;
+}
+
+
+/*QUAKED target_actor (.5 .3 0) (-8 -8 -8) (8 8 8) JUMP SHOOT ATTACK x HOLD BRUTAL
+JUMP			jump in set direction upon reaching this target
+SHOOT			take a single shot at the pathtarget
+ATTACK			attack pathtarget until it or actor is dead 
+
+"target"		next target_actor
+"pathtarget"	target of any action to be taken at this point
+"wait"			amount of time actor should pause at this point
+"message"		actor will "say" this to the player
+
+for JUMP only:
+"speed"			speed thrown forward (default 200)
+"height"		speed thrown upwards (default 200)
+*/
+
+void target_actor_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	vec3_t	v;
+
+	if (other->movetarget != self)
+		return;
+	
+	if (other->enemy)
+		return;
+
+	other->goalentity = other->movetarget = NULL;
+
+	if (self->message)
+	{
+		int		n;
+		edict_t	*ent;
+
+		for (n = 1; n <= game.maxclients; n++)
+		{
+			ent = &g_edicts[n];
+			if (!ent->inuse)
+				continue;
+			gi.cprintf (ent, PRINT_CHAT, "%s: %s\n", actor_names[(other - g_edicts)%MAX_ACTOR_NAMES], self->message);
+		}
+	}
+
+	if (self->spawnflags & 1)		//jump
+	{
+		other->velocity[0] = self->movedir[0] * self->speed;
+		other->velocity[1] = self->movedir[1] * self->speed;
+		
+		if (other->groundentity)
+		{
+			other->groundentity = NULL;
+			other->velocity[2] = self->movedir[2];
+			gi.sound(other, CHAN_VOICE, gi.soundindex("player/male/jump1.wav"), 1, ATTN_NORM, 0);
+		}
+	}
+
+	if (self->spawnflags & 2)	//shoot
+	{
+	}
+	else if (self->spawnflags & 4)	//attack
+	{
+		other->enemy = G_PickTarget(self->pathtarget);
+		if (other->enemy)
+		{
+			other->goalentity = other->enemy;
+			if (self->spawnflags & 32)
+				other->monsterinfo.aiflags |= AI_BRUTAL;
+			if (self->spawnflags & 16)
+			{
+				other->monsterinfo.aiflags |= AI_STAND_GROUND;
+				actor_stand (other);
+			}
+			else
+			{
+				actor_run (other);
+			}
+		}
+	}
+
+	if (!(self->spawnflags & 6) && (self->pathtarget))
+	{
+		char *savetarget;
+
+		savetarget = self->target;
+		self->target = self->pathtarget;
+		G_UseTargets (self, other);
+		self->target = savetarget;
+	}
+
+	other->movetarget = G_PickTarget(self->target);
+
+	if (!other->goalentity)
+		other->goalentity = other->movetarget;
+
+	if (!other->movetarget && !other->enemy)
+	{
+		other->monsterinfo.pausetime = level.time + 100000000;
+		other->monsterinfo.stand (other);
+	}
+	else if (other->movetarget == other->goalentity)
+	{
+		VectorSubtract (other->movetarget->s.origin, other->s.origin, v);
+		other->ideal_yaw = vectoyaw (v);
+	}
+}
+
+void SP_target_actor (edict_t *self)
+{
+	if (!self->targetname)
+		gi.dprintf ("%s with no targetname at %s\n", self->classname, vtos(self->s.origin));
+
+	self->solid = SOLID_TRIGGER;
+	self->touch = target_actor_touch;
+	VectorSet (self->mins, -8, -8, -8);
+	VectorSet (self->maxs, 8, 8, 8);
+	self->svflags = SVF_NOCLIENT;
+
+	if (self->spawnflags & 1)
+	{
+		if (!self->speed)
+			self->speed = 200;
+		if (!st.height)
+			st.height = 200;
+		if (self->s.angles[YAW] == 0)
+			self->s.angles[YAW] = 360;
+		G_SetMovedir (self->s.angles, self->movedir);
+		self->movedir[2] = st.height;
+	}
+
+	gi.linkentity (self);
+}
--- /dev/null
+++ b/game/m_actor.h
@@ -1,0 +1,506 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/player_y
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_attak01         	0
+#define FRAME_attak02         	1
+#define FRAME_attak03         	2
+#define FRAME_attak04         	3
+#define FRAME_death101        	4
+#define FRAME_death102        	5
+#define FRAME_death103        	6
+#define FRAME_death104        	7
+#define FRAME_death105        	8
+#define FRAME_death106        	9
+#define FRAME_death107        	10
+#define FRAME_death201        	11
+#define FRAME_death202        	12
+#define FRAME_death203        	13
+#define FRAME_death204        	14
+#define FRAME_death205        	15
+#define FRAME_death206        	16
+#define FRAME_death207        	17
+#define FRAME_death208        	18
+#define FRAME_death209        	19
+#define FRAME_death210        	20
+#define FRAME_death211        	21
+#define FRAME_death212        	22
+#define FRAME_death213        	23
+#define FRAME_death301        	24
+#define FRAME_death302        	25
+#define FRAME_death303        	26
+#define FRAME_death304        	27
+#define FRAME_death305        	28
+#define FRAME_death306        	29
+#define FRAME_death307        	30
+#define FRAME_death308        	31
+#define FRAME_death309        	32
+#define FRAME_death310        	33
+#define FRAME_death311        	34
+#define FRAME_death312        	35
+#define FRAME_death313        	36
+#define FRAME_death314        	37
+#define FRAME_death315        	38
+#define FRAME_flip01          	39
+#define FRAME_flip02          	40
+#define FRAME_flip03          	41
+#define FRAME_flip04          	42
+#define FRAME_flip05          	43
+#define FRAME_flip06          	44
+#define FRAME_flip07          	45
+#define FRAME_flip08          	46
+#define FRAME_flip09          	47
+#define FRAME_flip10          	48
+#define FRAME_flip11          	49
+#define FRAME_flip12          	50
+#define FRAME_flip13          	51
+#define FRAME_flip14          	52
+#define FRAME_grenad01        	53
+#define FRAME_grenad02        	54
+#define FRAME_grenad03        	55
+#define FRAME_grenad04        	56
+#define FRAME_grenad05        	57
+#define FRAME_grenad06        	58
+#define FRAME_grenad07        	59
+#define FRAME_grenad08        	60
+#define FRAME_grenad09        	61
+#define FRAME_grenad10        	62
+#define FRAME_grenad11        	63
+#define FRAME_grenad12        	64
+#define FRAME_grenad13        	65
+#define FRAME_grenad14        	66
+#define FRAME_grenad15        	67
+#define FRAME_jump01          	68
+#define FRAME_jump02          	69
+#define FRAME_jump03          	70
+#define FRAME_jump04          	71
+#define FRAME_jump05          	72
+#define FRAME_jump06          	73
+#define FRAME_pain101         	74
+#define FRAME_pain102         	75
+#define FRAME_pain103         	76
+#define FRAME_pain201         	77
+#define FRAME_pain202         	78
+#define FRAME_pain203         	79
+#define FRAME_pain301         	80
+#define FRAME_pain302         	81
+#define FRAME_pain303         	82
+#define FRAME_push01          	83
+#define FRAME_push02          	84
+#define FRAME_push03          	85
+#define FRAME_push04          	86
+#define FRAME_push05          	87
+#define FRAME_push06          	88
+#define FRAME_push07          	89
+#define FRAME_push08          	90
+#define FRAME_push09          	91
+#define FRAME_run01           	92
+#define FRAME_run02           	93
+#define FRAME_run03           	94
+#define FRAME_run04           	95
+#define FRAME_run05           	96
+#define FRAME_run06           	97
+#define FRAME_run07           	98
+#define FRAME_run08           	99
+#define FRAME_run09           	100
+#define FRAME_run10           	101
+#define FRAME_run11           	102
+#define FRAME_run12           	103
+#define FRAME_runs01          	104
+#define FRAME_runs02          	105
+#define FRAME_runs03          	106
+#define FRAME_runs04          	107
+#define FRAME_runs05          	108
+#define FRAME_runs06          	109
+#define FRAME_runs07          	110
+#define FRAME_runs08          	111
+#define FRAME_runs09          	112
+#define FRAME_runs10          	113
+#define FRAME_runs11          	114
+#define FRAME_runs12          	115
+#define FRAME_salute01        	116
+#define FRAME_salute02        	117
+#define FRAME_salute03        	118
+#define FRAME_salute04        	119
+#define FRAME_salute05        	120
+#define FRAME_salute06        	121
+#define FRAME_salute07        	122
+#define FRAME_salute08        	123
+#define FRAME_salute09        	124
+#define FRAME_salute10        	125
+#define FRAME_salute11        	126
+#define FRAME_salute12        	127
+#define FRAME_stand101        	128
+#define FRAME_stand102        	129
+#define FRAME_stand103        	130
+#define FRAME_stand104        	131
+#define FRAME_stand105        	132
+#define FRAME_stand106        	133
+#define FRAME_stand107        	134
+#define FRAME_stand108        	135
+#define FRAME_stand109        	136
+#define FRAME_stand110        	137
+#define FRAME_stand111        	138
+#define FRAME_stand112        	139
+#define FRAME_stand113        	140
+#define FRAME_stand114        	141
+#define FRAME_stand115        	142
+#define FRAME_stand116        	143
+#define FRAME_stand117        	144
+#define FRAME_stand118        	145
+#define FRAME_stand119        	146
+#define FRAME_stand120        	147
+#define FRAME_stand121        	148
+#define FRAME_stand122        	149
+#define FRAME_stand123        	150
+#define FRAME_stand124        	151
+#define FRAME_stand125        	152
+#define FRAME_stand126        	153
+#define FRAME_stand127        	154
+#define FRAME_stand128        	155
+#define FRAME_stand129        	156
+#define FRAME_stand130        	157
+#define FRAME_stand131        	158
+#define FRAME_stand132        	159
+#define FRAME_stand133        	160
+#define FRAME_stand134        	161
+#define FRAME_stand135        	162
+#define FRAME_stand136        	163
+#define FRAME_stand137        	164
+#define FRAME_stand138        	165
+#define FRAME_stand139        	166
+#define FRAME_stand140        	167
+#define FRAME_stand201        	168
+#define FRAME_stand202        	169
+#define FRAME_stand203        	170
+#define FRAME_stand204        	171
+#define FRAME_stand205        	172
+#define FRAME_stand206        	173
+#define FRAME_stand207        	174
+#define FRAME_stand208        	175
+#define FRAME_stand209        	176
+#define FRAME_stand210        	177
+#define FRAME_stand211        	178
+#define FRAME_stand212        	179
+#define FRAME_stand213        	180
+#define FRAME_stand214        	181
+#define FRAME_stand215        	182
+#define FRAME_stand216        	183
+#define FRAME_stand217        	184
+#define FRAME_stand218        	185
+#define FRAME_stand219        	186
+#define FRAME_stand220        	187
+#define FRAME_stand221        	188
+#define FRAME_stand222        	189
+#define FRAME_stand223        	190
+#define FRAME_swim01          	191
+#define FRAME_swim02          	192
+#define FRAME_swim03          	193
+#define FRAME_swim04          	194
+#define FRAME_swim05          	195
+#define FRAME_swim06          	196
+#define FRAME_swim07          	197
+#define FRAME_swim08          	198
+#define FRAME_swim09          	199
+#define FRAME_swim10          	200
+#define FRAME_swim11          	201
+#define FRAME_swim12          	202
+#define FRAME_sw_atk01        	203
+#define FRAME_sw_atk02        	204
+#define FRAME_sw_atk03        	205
+#define FRAME_sw_atk04        	206
+#define FRAME_sw_atk05        	207
+#define FRAME_sw_atk06        	208
+#define FRAME_sw_pan01        	209
+#define FRAME_sw_pan02        	210
+#define FRAME_sw_pan03        	211
+#define FRAME_sw_pan04        	212
+#define FRAME_sw_pan05        	213
+#define FRAME_sw_std01        	214
+#define FRAME_sw_std02        	215
+#define FRAME_sw_std03        	216
+#define FRAME_sw_std04        	217
+#define FRAME_sw_std05        	218
+#define FRAME_sw_std06        	219
+#define FRAME_sw_std07        	220
+#define FRAME_sw_std08        	221
+#define FRAME_sw_std09        	222
+#define FRAME_sw_std10        	223
+#define FRAME_sw_std11        	224
+#define FRAME_sw_std12        	225
+#define FRAME_sw_std13        	226
+#define FRAME_sw_std14        	227
+#define FRAME_sw_std15        	228
+#define FRAME_sw_std16        	229
+#define FRAME_sw_std17        	230
+#define FRAME_sw_std18        	231
+#define FRAME_sw_std19        	232
+#define FRAME_sw_std20        	233
+#define FRAME_taunt01         	234
+#define FRAME_taunt02         	235
+#define FRAME_taunt03         	236
+#define FRAME_taunt04         	237
+#define FRAME_taunt05         	238
+#define FRAME_taunt06         	239
+#define FRAME_taunt07         	240
+#define FRAME_taunt08         	241
+#define FRAME_taunt09         	242
+#define FRAME_taunt10         	243
+#define FRAME_taunt11         	244
+#define FRAME_taunt12         	245
+#define FRAME_taunt13         	246
+#define FRAME_taunt14         	247
+#define FRAME_taunt15         	248
+#define FRAME_taunt16         	249
+#define FRAME_taunt17         	250
+#define FRAME_walk01          	251
+#define FRAME_walk02          	252
+#define FRAME_walk03          	253
+#define FRAME_walk04          	254
+#define FRAME_walk05          	255
+#define FRAME_walk06          	256
+#define FRAME_walk07          	257
+#define FRAME_walk08          	258
+#define FRAME_walk09          	259
+#define FRAME_walk10          	260
+#define FRAME_walk11          	261
+#define FRAME_wave01          	262
+#define FRAME_wave02          	263
+#define FRAME_wave03          	264
+#define FRAME_wave04          	265
+#define FRAME_wave05          	266
+#define FRAME_wave06          	267
+#define FRAME_wave07          	268
+#define FRAME_wave08          	269
+#define FRAME_wave09          	270
+#define FRAME_wave10          	271
+#define FRAME_wave11          	272
+#define FRAME_wave12          	273
+#define FRAME_wave13          	274
+#define FRAME_wave14          	275
+#define FRAME_wave15          	276
+#define FRAME_wave16          	277
+#define FRAME_wave17          	278
+#define FRAME_wave18          	279
+#define FRAME_wave19          	280
+#define FRAME_wave20          	281
+#define FRAME_wave21          	282
+#define FRAME_bl_atk01        	283
+#define FRAME_bl_atk02        	284
+#define FRAME_bl_atk03        	285
+#define FRAME_bl_atk04        	286
+#define FRAME_bl_atk05        	287
+#define FRAME_bl_atk06        	288
+#define FRAME_bl_flp01        	289
+#define FRAME_bl_flp02        	290
+#define FRAME_bl_flp13        	291
+#define FRAME_bl_flp14        	292
+#define FRAME_bl_flp15        	293
+#define FRAME_bl_jmp01        	294
+#define FRAME_bl_jmp02        	295
+#define FRAME_bl_jmp03        	296
+#define FRAME_bl_jmp04        	297
+#define FRAME_bl_jmp05        	298
+#define FRAME_bl_jmp06        	299
+#define FRAME_bl_pn101        	300
+#define FRAME_bl_pn102        	301
+#define FRAME_bl_pn103        	302
+#define FRAME_bl_pn201        	303
+#define FRAME_bl_pn202        	304
+#define FRAME_bl_pn203        	305
+#define FRAME_bl_pn301        	306
+#define FRAME_bl_pn302        	307
+#define FRAME_bl_pn303        	308
+#define FRAME_bl_psh08        	309
+#define FRAME_bl_psh09        	310
+#define FRAME_bl_run01        	311
+#define FRAME_bl_run02        	312
+#define FRAME_bl_run03        	313
+#define FRAME_bl_run04        	314
+#define FRAME_bl_run05        	315
+#define FRAME_bl_run06        	316
+#define FRAME_bl_run07        	317
+#define FRAME_bl_run08        	318
+#define FRAME_bl_run09        	319
+#define FRAME_bl_run10        	320
+#define FRAME_bl_run11        	321
+#define FRAME_bl_run12        	322
+#define FRAME_bl_rns03        	323
+#define FRAME_bl_rns04        	324
+#define FRAME_bl_rns05        	325
+#define FRAME_bl_rns06        	326
+#define FRAME_bl_rns07        	327
+#define FRAME_bl_rns08        	328
+#define FRAME_bl_rns09        	329
+#define FRAME_bl_sal10        	330
+#define FRAME_bl_sal11        	331
+#define FRAME_bl_sal12        	332
+#define FRAME_bl_std01        	333
+#define FRAME_bl_std02        	334
+#define FRAME_bl_std03        	335
+#define FRAME_bl_std04        	336
+#define FRAME_bl_std05        	337
+#define FRAME_bl_std06        	338
+#define FRAME_bl_std07        	339
+#define FRAME_bl_std08        	340
+#define FRAME_bl_std09        	341
+#define FRAME_bl_std10        	342
+#define FRAME_bl_std11        	343
+#define FRAME_bl_std12        	344
+#define FRAME_bl_std13        	345
+#define FRAME_bl_std14        	346
+#define FRAME_bl_std15        	347
+#define FRAME_bl_std16        	348
+#define FRAME_bl_std17        	349
+#define FRAME_bl_std18        	350
+#define FRAME_bl_std19        	351
+#define FRAME_bl_std20        	352
+#define FRAME_bl_std21        	353
+#define FRAME_bl_std22        	354
+#define FRAME_bl_std23        	355
+#define FRAME_bl_std24        	356
+#define FRAME_bl_std25        	357
+#define FRAME_bl_std26        	358
+#define FRAME_bl_std27        	359
+#define FRAME_bl_std28        	360
+#define FRAME_bl_std29        	361
+#define FRAME_bl_std30        	362
+#define FRAME_bl_std31        	363
+#define FRAME_bl_std32        	364
+#define FRAME_bl_std33        	365
+#define FRAME_bl_std34        	366
+#define FRAME_bl_std35        	367
+#define FRAME_bl_std36        	368
+#define FRAME_bl_std37        	369
+#define FRAME_bl_std38        	370
+#define FRAME_bl_std39        	371
+#define FRAME_bl_std40        	372
+#define FRAME_bl_swm01        	373
+#define FRAME_bl_swm02        	374
+#define FRAME_bl_swm03        	375
+#define FRAME_bl_swm04        	376
+#define FRAME_bl_swm05        	377
+#define FRAME_bl_swm06        	378
+#define FRAME_bl_swm07        	379
+#define FRAME_bl_swm08        	380
+#define FRAME_bl_swm09        	381
+#define FRAME_bl_swm10        	382
+#define FRAME_bl_swm11        	383
+#define FRAME_bl_swm12        	384
+#define FRAME_bl_swk01        	385
+#define FRAME_bl_swk02        	386
+#define FRAME_bl_swk03        	387
+#define FRAME_bl_swk04        	388
+#define FRAME_bl_swk05        	389
+#define FRAME_bl_swk06        	390
+#define FRAME_bl_swp01        	391
+#define FRAME_bl_swp02        	392
+#define FRAME_bl_swp03        	393
+#define FRAME_bl_swp04        	394
+#define FRAME_bl_swp05        	395
+#define FRAME_bl_sws01        	396
+#define FRAME_bl_sws02        	397
+#define FRAME_bl_sws03        	398
+#define FRAME_bl_sws04        	399
+#define FRAME_bl_sws05        	400
+#define FRAME_bl_sws06        	401
+#define FRAME_bl_sws07        	402
+#define FRAME_bl_sws08        	403
+#define FRAME_bl_sws09        	404
+#define FRAME_bl_sws10        	405
+#define FRAME_bl_sws11        	406
+#define FRAME_bl_sws12        	407
+#define FRAME_bl_sws13        	408
+#define FRAME_bl_sws14        	409
+#define FRAME_bl_tau14        	410
+#define FRAME_bl_tau15        	411
+#define FRAME_bl_tau16        	412
+#define FRAME_bl_tau17        	413
+#define FRAME_bl_wlk01        	414
+#define FRAME_bl_wlk02        	415
+#define FRAME_bl_wlk03        	416
+#define FRAME_bl_wlk04        	417
+#define FRAME_bl_wlk05        	418
+#define FRAME_bl_wlk06        	419
+#define FRAME_bl_wlk07        	420
+#define FRAME_bl_wlk08        	421
+#define FRAME_bl_wlk09        	422
+#define FRAME_bl_wlk10        	423
+#define FRAME_bl_wlk11        	424
+#define FRAME_bl_wav19        	425
+#define FRAME_bl_wav20        	426
+#define FRAME_bl_wav21        	427
+#define FRAME_cr_atk01        	428
+#define FRAME_cr_atk02        	429
+#define FRAME_cr_atk03        	430
+#define FRAME_cr_atk04        	431
+#define FRAME_cr_atk05        	432
+#define FRAME_cr_atk06        	433
+#define FRAME_cr_atk07        	434
+#define FRAME_cr_atk08        	435
+#define FRAME_cr_pan01        	436
+#define FRAME_cr_pan02        	437
+#define FRAME_cr_pan03        	438
+#define FRAME_cr_pan04        	439
+#define FRAME_cr_std01        	440
+#define FRAME_cr_std02        	441
+#define FRAME_cr_std03        	442
+#define FRAME_cr_std04        	443
+#define FRAME_cr_std05        	444
+#define FRAME_cr_std06        	445
+#define FRAME_cr_std07        	446
+#define FRAME_cr_std08        	447
+#define FRAME_cr_wlk01        	448
+#define FRAME_cr_wlk02        	449
+#define FRAME_cr_wlk03        	450
+#define FRAME_cr_wlk04        	451
+#define FRAME_cr_wlk05        	452
+#define FRAME_cr_wlk06        	453
+#define FRAME_cr_wlk07        	454
+#define FRAME_crbl_a01        	455
+#define FRAME_crbl_a02        	456
+#define FRAME_crbl_a03        	457
+#define FRAME_crbl_a04        	458
+#define FRAME_crbl_a05        	459
+#define FRAME_crbl_a06        	460
+#define FRAME_crbl_a07        	461
+#define FRAME_crbl_p01        	462
+#define FRAME_crbl_p02        	463
+#define FRAME_crbl_p03        	464
+#define FRAME_crbl_p04        	465
+#define FRAME_crbl_s01        	466
+#define FRAME_crbl_s02        	467
+#define FRAME_crbl_s03        	468
+#define FRAME_crbl_s04        	469
+#define FRAME_crbl_s05        	470
+#define FRAME_crbl_s06        	471
+#define FRAME_crbl_s07        	472
+#define FRAME_crbl_s08        	473
+#define FRAME_crbl_w01        	474
+#define FRAME_crbl_w02        	475
+#define FRAME_crbl_w03        	476
+#define FRAME_crbl_w04        	477
+#define FRAME_crbl_w05        	478
+#define FRAME_crbl_w06        	479
+#define FRAME_crbl_w07        	480
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_berserk.c
@@ -1,0 +1,457 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+BERSERK
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_berserk.h"
+
+
+static int sound_pain;
+static int sound_die;
+static int sound_idle;
+static int sound_punch;
+static int sound_sight;
+static int sound_search;
+
+void berserk_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void berserk_search (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+}
+
+
+void berserk_fidget (edict_t *self);
+mframe_t berserk_frames_stand [] =
+{
+	ai_stand, 0, berserk_fidget,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t berserk_move_stand = {FRAME_stand1, FRAME_stand5, berserk_frames_stand, NULL};
+
+void berserk_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &berserk_move_stand;
+}
+
+mframe_t berserk_frames_stand_fidget [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t berserk_move_stand_fidget = {FRAME_standb1, FRAME_standb20, berserk_frames_stand_fidget, berserk_stand};
+
+void berserk_fidget (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		return;
+	if (random() > 0.15)
+		return;
+
+	self->monsterinfo.currentmove = &berserk_move_stand_fidget;
+	gi.sound (self, CHAN_WEAPON, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+
+mframe_t berserk_frames_walk [] =
+{
+	ai_walk, 9.1, NULL,
+	ai_walk, 6.3, NULL,
+	ai_walk, 4.9, NULL,
+	ai_walk, 6.7, NULL,
+	ai_walk, 6.0, NULL,
+	ai_walk, 8.2, NULL,
+	ai_walk, 7.2, NULL,
+	ai_walk, 6.1, NULL,
+	ai_walk, 4.9, NULL,
+	ai_walk, 4.7, NULL,
+	ai_walk, 4.7, NULL,
+	ai_walk, 4.8, NULL
+};
+mmove_t berserk_move_walk = {FRAME_walkc1, FRAME_walkc11, berserk_frames_walk, NULL};
+
+void berserk_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &berserk_move_walk;
+}
+
+/*
+
+  *****************************
+  SKIPPED THIS FOR NOW!
+  *****************************
+
+   Running -> Arm raised in air
+
+void()	berserk_runb1	=[	$r_att1 ,	berserk_runb2	] {ai_run(21);};
+void()	berserk_runb2	=[	$r_att2 ,	berserk_runb3	] {ai_run(11);};
+void()	berserk_runb3	=[	$r_att3 ,	berserk_runb4	] {ai_run(21);};
+void()	berserk_runb4	=[	$r_att4 ,	berserk_runb5	] {ai_run(25);};
+void()	berserk_runb5	=[	$r_att5 ,	berserk_runb6	] {ai_run(18);};
+void()	berserk_runb6	=[	$r_att6 ,	berserk_runb7	] {ai_run(19);};
+// running with arm in air : start loop
+void()	berserk_runb7	=[	$r_att7 ,	berserk_runb8	] {ai_run(21);};
+void()	berserk_runb8	=[	$r_att8 ,	berserk_runb9	] {ai_run(11);};
+void()	berserk_runb9	=[	$r_att9 ,	berserk_runb10	] {ai_run(21);};
+void()	berserk_runb10	=[	$r_att10 ,	berserk_runb11	] {ai_run(25);};
+void()	berserk_runb11	=[	$r_att11 ,	berserk_runb12	] {ai_run(18);};
+void()	berserk_runb12	=[	$r_att12 ,	berserk_runb7	] {ai_run(19);};
+// running with arm in air : end loop
+*/
+
+
+mframe_t berserk_frames_run1 [] =
+{
+	ai_run, 21, NULL,
+	ai_run, 11, NULL,
+	ai_run, 21, NULL,
+	ai_run, 25, NULL,
+	ai_run, 18, NULL,
+	ai_run, 19, NULL
+};
+mmove_t berserk_move_run1 = {FRAME_run1, FRAME_run6, berserk_frames_run1, NULL};
+
+void berserk_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &berserk_move_stand;
+	else
+		self->monsterinfo.currentmove = &berserk_move_run1;
+}
+
+
+void berserk_attack_spike (edict_t *self)
+{
+	static	vec3_t	aim = {MELEE_DISTANCE, 0, -24};
+	fire_hit (self, aim, (15 + (rand() % 6)), 400);		//	Faster attack -- upwards and backwards
+}
+
+
+void berserk_swing (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
+}
+
+mframe_t berserk_frames_attack_spike [] =
+{
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, berserk_swing,
+		ai_charge, 0, berserk_attack_spike,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL
+};
+mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_frames_attack_spike, berserk_run};
+
+
+void berserk_attack_club (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
+	fire_hit (self, aim, (5 + (rand() % 6)), 400);		// Slower attack
+}
+
+mframe_t berserk_frames_attack_club [] =
+{	
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, berserk_swing,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, berserk_attack_club,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t berserk_move_attack_club = {FRAME_att_c9, FRAME_att_c20, berserk_frames_attack_club, berserk_run};
+
+
+void berserk_strike (edict_t *self)
+{
+	//FIXME play impact sound
+}
+
+
+mframe_t berserk_frames_attack_strike [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, berserk_swing,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, berserk_strike,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 9.7, NULL,
+	ai_move, 13.6, NULL
+};
+	
+mmove_t berserk_move_attack_strike = {FRAME_att_c21, FRAME_att_c34, berserk_frames_attack_strike, berserk_run};
+
+
+void berserk_melee (edict_t *self)
+{
+	if ((rand() % 2) == 0)
+		self->monsterinfo.currentmove = &berserk_move_attack_spike;
+	else
+		self->monsterinfo.currentmove = &berserk_move_attack_club;
+}
+
+
+/*
+void() 	berserk_atke1	=[	$r_attb1,	berserk_atke2	] {ai_run(9);};
+void() 	berserk_atke2	=[	$r_attb2,	berserk_atke3	] {ai_run(6);};
+void() 	berserk_atke3	=[	$r_attb3,	berserk_atke4	] {ai_run(18.4);};
+void() 	berserk_atke4	=[	$r_attb4,	berserk_atke5	] {ai_run(25);};
+void() 	berserk_atke5	=[	$r_attb5,	berserk_atke6	] {ai_run(14);};
+void() 	berserk_atke6	=[	$r_attb6,	berserk_atke7	] {ai_run(20);};
+void() 	berserk_atke7	=[	$r_attb7,	berserk_atke8	] {ai_run(8.5);};
+void() 	berserk_atke8	=[	$r_attb8,	berserk_atke9	] {ai_run(3);};
+void() 	berserk_atke9	=[	$r_attb9,	berserk_atke10	] {ai_run(17.5);};
+void() 	berserk_atke10	=[	$r_attb10,	berserk_atke11	] {ai_run(17);};
+void() 	berserk_atke11	=[	$r_attb11,	berserk_atke12	] {ai_run(9);};
+void() 	berserk_atke12	=[	$r_attb12,	berserk_atke13	] {ai_run(25);};
+void() 	berserk_atke13	=[	$r_attb13,	berserk_atke14	] {ai_run(3.7);};
+void() 	berserk_atke14	=[	$r_attb14,	berserk_atke15	] {ai_run(2.6);};
+void() 	berserk_atke15	=[	$r_attb15,	berserk_atke16	] {ai_run(19);};
+void() 	berserk_atke16	=[	$r_attb16,	berserk_atke17	] {ai_run(25);};
+void() 	berserk_atke17	=[	$r_attb17,	berserk_atke18	] {ai_run(19.6);};
+void() 	berserk_atke18	=[	$r_attb18,	berserk_run1	] {ai_run(7.8);};
+*/
+
+
+mframe_t berserk_frames_pain1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t berserk_move_pain1 = {FRAME_painc1, FRAME_painc4, berserk_frames_pain1, berserk_run};
+
+
+mframe_t berserk_frames_pain2 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t berserk_move_pain2 = {FRAME_painb1, FRAME_painb20, berserk_frames_pain2, berserk_run};
+
+void berserk_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+	gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if ((damage < 20) || (random() < 0.5))
+		self->monsterinfo.currentmove = &berserk_move_pain1;
+	else
+		self->monsterinfo.currentmove = &berserk_move_pain2;
+}
+
+
+void berserk_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+
+mframe_t berserk_frames_death1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+	
+};
+mmove_t berserk_move_death1 = {FRAME_death1, FRAME_death13, berserk_frames_death1, berserk_dead};
+
+
+mframe_t berserk_frames_death2 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t berserk_move_death2 = {FRAME_deathc1, FRAME_deathc8, berserk_frames_death2, berserk_dead};
+
+
+void berserk_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	if (damage >= 50)
+		self->monsterinfo.currentmove = &berserk_move_death1;
+	else
+		self->monsterinfo.currentmove = &berserk_move_death2;
+}
+
+
+/*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_berserk (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	// pre-caches
+	sound_pain  = gi.soundindex ("berserk/berpain2.wav");
+	sound_die   = gi.soundindex ("berserk/berdeth2.wav");
+	sound_idle  = gi.soundindex ("berserk/beridle1.wav");
+	sound_punch = gi.soundindex ("berserk/attack.wav");
+	sound_search = gi.soundindex ("berserk/bersrch1.wav");
+	sound_sight = gi.soundindex ("berserk/sight.wav");
+
+	self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+
+	self->health = 240;
+	self->gib_health = -60;
+	self->mass = 250;
+
+	self->pain = berserk_pain;
+	self->die = berserk_die;
+
+	self->monsterinfo.stand = berserk_stand;
+	self->monsterinfo.walk = berserk_walk;
+	self->monsterinfo.run = berserk_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = NULL;
+	self->monsterinfo.melee = berserk_melee;
+	self->monsterinfo.sight = berserk_sight;
+	self->monsterinfo.search = berserk_search;
+
+	self->monsterinfo.currentmove = &berserk_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	gi.linkentity (self);
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_berserk.h
@@ -1,0 +1,269 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/berserk
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand1          	0
+#define FRAME_stand2          	1
+#define FRAME_stand3          	2
+#define FRAME_stand4          	3
+#define FRAME_stand5          	4
+#define FRAME_standb1         	5
+#define FRAME_standb2         	6
+#define FRAME_standb3         	7
+#define FRAME_standb4         	8
+#define FRAME_standb5         	9
+#define FRAME_standb6         	10
+#define FRAME_standb7         	11
+#define FRAME_standb8         	12
+#define FRAME_standb9         	13
+#define FRAME_standb10        	14
+#define FRAME_standb11        	15
+#define FRAME_standb12        	16
+#define FRAME_standb13        	17
+#define FRAME_standb14        	18
+#define FRAME_standb15        	19
+#define FRAME_standb16        	20
+#define FRAME_standb17        	21
+#define FRAME_standb18        	22
+#define FRAME_standb19        	23
+#define FRAME_standb20        	24
+#define FRAME_walkc1          	25
+#define FRAME_walkc2          	26
+#define FRAME_walkc3          	27
+#define FRAME_walkc4          	28
+#define FRAME_walkc5          	29
+#define FRAME_walkc6          	30
+#define FRAME_walkc7          	31
+#define FRAME_walkc8          	32
+#define FRAME_walkc9          	33
+#define FRAME_walkc10         	34
+#define FRAME_walkc11         	35
+#define FRAME_run1            	36
+#define FRAME_run2            	37
+#define FRAME_run3            	38
+#define FRAME_run4            	39
+#define FRAME_run5            	40
+#define FRAME_run6            	41
+#define FRAME_att_a1          	42
+#define FRAME_att_a2          	43
+#define FRAME_att_a3          	44
+#define FRAME_att_a4          	45
+#define FRAME_att_a5          	46
+#define FRAME_att_a6          	47
+#define FRAME_att_a7          	48
+#define FRAME_att_a8          	49
+#define FRAME_att_a9          	50
+#define FRAME_att_a10         	51
+#define FRAME_att_a11         	52
+#define FRAME_att_a12         	53
+#define FRAME_att_a13         	54
+#define FRAME_att_b1          	55
+#define FRAME_att_b2          	56
+#define FRAME_att_b3          	57
+#define FRAME_att_b4          	58
+#define FRAME_att_b5          	59
+#define FRAME_att_b6          	60
+#define FRAME_att_b7          	61
+#define FRAME_att_b8          	62
+#define FRAME_att_b9          	63
+#define FRAME_att_b10         	64
+#define FRAME_att_b11         	65
+#define FRAME_att_b12         	66
+#define FRAME_att_b13         	67
+#define FRAME_att_b14         	68
+#define FRAME_att_b15         	69
+#define FRAME_att_b16         	70
+#define FRAME_att_b17         	71
+#define FRAME_att_b18         	72
+#define FRAME_att_b19         	73
+#define FRAME_att_b20         	74
+#define FRAME_att_b21         	75
+#define FRAME_att_c1          	76
+#define FRAME_att_c2          	77
+#define FRAME_att_c3          	78
+#define FRAME_att_c4          	79
+#define FRAME_att_c5          	80
+#define FRAME_att_c6          	81
+#define FRAME_att_c7          	82
+#define FRAME_att_c8          	83
+#define FRAME_att_c9          	84
+#define FRAME_att_c10         	85
+#define FRAME_att_c11         	86
+#define FRAME_att_c12         	87
+#define FRAME_att_c13         	88
+#define FRAME_att_c14         	89
+#define FRAME_att_c15         	90
+#define FRAME_att_c16         	91
+#define FRAME_att_c17         	92
+#define FRAME_att_c18         	93
+#define FRAME_att_c19         	94
+#define FRAME_att_c20         	95
+#define FRAME_att_c21         	96
+#define FRAME_att_c22         	97
+#define FRAME_att_c23         	98
+#define FRAME_att_c24         	99
+#define FRAME_att_c25         	100
+#define FRAME_att_c26         	101
+#define FRAME_att_c27         	102
+#define FRAME_att_c28         	103
+#define FRAME_att_c29         	104
+#define FRAME_att_c30         	105
+#define FRAME_att_c31         	106
+#define FRAME_att_c32         	107
+#define FRAME_att_c33         	108
+#define FRAME_att_c34         	109
+#define FRAME_r_att1          	110
+#define FRAME_r_att2          	111
+#define FRAME_r_att3          	112
+#define FRAME_r_att4          	113
+#define FRAME_r_att5          	114
+#define FRAME_r_att6          	115
+#define FRAME_r_att7          	116
+#define FRAME_r_att8          	117
+#define FRAME_r_att9          	118
+#define FRAME_r_att10         	119
+#define FRAME_r_att11         	120
+#define FRAME_r_att12         	121
+#define FRAME_r_att13         	122
+#define FRAME_r_att14         	123
+#define FRAME_r_att15         	124
+#define FRAME_r_att16         	125
+#define FRAME_r_att17         	126
+#define FRAME_r_att18         	127
+#define FRAME_r_attb1         	128
+#define FRAME_r_attb2         	129
+#define FRAME_r_attb3         	130
+#define FRAME_r_attb4         	131
+#define FRAME_r_attb5         	132
+#define FRAME_r_attb6         	133
+#define FRAME_r_attb7         	134
+#define FRAME_r_attb8         	135
+#define FRAME_r_attb9         	136
+#define FRAME_r_attb10        	137
+#define FRAME_r_attb11        	138
+#define FRAME_r_attb12        	139
+#define FRAME_r_attb13        	140
+#define FRAME_r_attb14        	141
+#define FRAME_r_attb15        	142
+#define FRAME_r_attb16        	143
+#define FRAME_r_attb17        	144
+#define FRAME_r_attb18        	145
+#define FRAME_slam1           	146
+#define FRAME_slam2           	147
+#define FRAME_slam3           	148
+#define FRAME_slam4           	149
+#define FRAME_slam5           	150
+#define FRAME_slam6           	151
+#define FRAME_slam7           	152
+#define FRAME_slam8           	153
+#define FRAME_slam9           	154
+#define FRAME_slam10          	155
+#define FRAME_slam11          	156
+#define FRAME_slam12          	157
+#define FRAME_slam13          	158
+#define FRAME_slam14          	159
+#define FRAME_slam15          	160
+#define FRAME_slam16          	161
+#define FRAME_slam17          	162
+#define FRAME_slam18          	163
+#define FRAME_slam19          	164
+#define FRAME_slam20          	165
+#define FRAME_slam21          	166
+#define FRAME_slam22          	167
+#define FRAME_slam23          	168
+#define FRAME_duck1           	169
+#define FRAME_duck2           	170
+#define FRAME_duck3           	171
+#define FRAME_duck4           	172
+#define FRAME_duck5           	173
+#define FRAME_duck6           	174
+#define FRAME_duck7           	175
+#define FRAME_duck8           	176
+#define FRAME_duck9           	177
+#define FRAME_duck10          	178
+#define FRAME_fall1           	179
+#define FRAME_fall2           	180
+#define FRAME_fall3           	181
+#define FRAME_fall4           	182
+#define FRAME_fall5           	183
+#define FRAME_fall6           	184
+#define FRAME_fall7           	185
+#define FRAME_fall8           	186
+#define FRAME_fall9           	187
+#define FRAME_fall10          	188
+#define FRAME_fall11          	189
+#define FRAME_fall12          	190
+#define FRAME_fall13          	191
+#define FRAME_fall14          	192
+#define FRAME_fall15          	193
+#define FRAME_fall16          	194
+#define FRAME_fall17          	195
+#define FRAME_fall18          	196
+#define FRAME_fall19          	197
+#define FRAME_fall20          	198
+#define FRAME_painc1          	199
+#define FRAME_painc2          	200
+#define FRAME_painc3          	201
+#define FRAME_painc4          	202
+#define FRAME_painb1          	203
+#define FRAME_painb2          	204
+#define FRAME_painb3          	205
+#define FRAME_painb4          	206
+#define FRAME_painb5          	207
+#define FRAME_painb6          	208
+#define FRAME_painb7          	209
+#define FRAME_painb8          	210
+#define FRAME_painb9          	211
+#define FRAME_painb10         	212
+#define FRAME_painb11         	213
+#define FRAME_painb12         	214
+#define FRAME_painb13         	215
+#define FRAME_painb14         	216
+#define FRAME_painb15         	217
+#define FRAME_painb16         	218
+#define FRAME_painb17         	219
+#define FRAME_painb18         	220
+#define FRAME_painb19         	221
+#define FRAME_painb20         	222
+#define FRAME_death1          	223
+#define FRAME_death2          	224
+#define FRAME_death3          	225
+#define FRAME_death4          	226
+#define FRAME_death5          	227
+#define FRAME_death6          	228
+#define FRAME_death7          	229
+#define FRAME_death8          	230
+#define FRAME_death9          	231
+#define FRAME_death10         	232
+#define FRAME_death11         	233
+#define FRAME_death12         	234
+#define FRAME_death13         	235
+#define FRAME_deathc1         	236
+#define FRAME_deathc2         	237
+#define FRAME_deathc3         	238
+#define FRAME_deathc4         	239
+#define FRAME_deathc5         	240
+#define FRAME_deathc6         	241
+#define FRAME_deathc7         	242
+#define FRAME_deathc8         	243
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_boss2.c
@@ -1,0 +1,679 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+boss2
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_boss2.h"
+
+void BossExplode (edict_t *self);
+
+qboolean infront (edict_t *self, edict_t *other);
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_pain3;
+static int	sound_death;
+static int	sound_search1;
+
+void boss2_search (edict_t *self)
+{
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
+}
+
+void boss2_run (edict_t *self);
+void boss2_stand (edict_t *self);
+void boss2_dead (edict_t *self);
+void boss2_attack (edict_t *self);
+void boss2_attack_mg (edict_t *self);
+void boss2_reattack_mg (edict_t *self);
+void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+
+void Boss2Rocket (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+
+//1
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start);
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1);
+
+//2
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start);
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
+
+//3
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start);
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3);
+
+//4
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
+}	
+
+void boss2_firebullet_right (edict_t *self)
+{
+	vec3_t	forward, right, target;
+	vec3_t	start;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1], forward, right, start);
+
+	VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
+	target[2] += self->enemy->viewheight;
+	VectorSubtract (target, start, forward);
+	VectorNormalize (forward);
+
+	monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_R1);
+}	
+
+void boss2_firebullet_left (edict_t *self)
+{
+	vec3_t	forward, right, target;
+	vec3_t	start;
+	
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1], forward, right, start);
+
+	VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
+
+	target[2] += self->enemy->viewheight;
+	VectorSubtract (target, start, forward);
+	VectorNormalize (forward);
+
+	monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_L1);
+}	
+
+void Boss2MachineGun (edict_t *self)
+{
+/*	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+	int		flash_number;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+
+	flash_number = MZ2_BOSS2_MACHINEGUN_1 + (self->s.frame - FRAME_attack10);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	monster_fire_bullet (self, start, dir, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+*/
+	boss2_firebullet_left(self);
+	boss2_firebullet_right(self);
+}	
+
+
+mframe_t boss2_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	boss2_move_stand = {FRAME_stand30, FRAME_stand50, boss2_frames_stand, NULL};
+
+mframe_t boss2_frames_fidget [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t boss2_move_fidget = {FRAME_stand1, FRAME_stand30, boss2_frames_fidget, NULL};
+
+mframe_t boss2_frames_walk [] =
+{
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	8,	NULL
+};
+mmove_t boss2_move_walk = {FRAME_walk1, FRAME_walk20, boss2_frames_walk, NULL};
+
+
+mframe_t boss2_frames_run [] =
+{
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL,
+	ai_run,	8,	NULL
+};
+mmove_t boss2_move_run = {FRAME_walk1, FRAME_walk20, boss2_frames_run, NULL};
+
+mframe_t boss2_frames_attack_pre_mg [] =
+{
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	boss2_attack_mg
+};
+mmove_t boss2_move_attack_pre_mg = {FRAME_attack1, FRAME_attack9, boss2_frames_attack_pre_mg, NULL};
+
+
+// Loop this
+mframe_t boss2_frames_attack_mg [] =
+{
+	ai_charge,	1,	Boss2MachineGun,
+	ai_charge,	1,	Boss2MachineGun,
+	ai_charge,	1,	Boss2MachineGun,
+	ai_charge,	1,	Boss2MachineGun,
+	ai_charge,	1,	Boss2MachineGun,
+	ai_charge,	1,	boss2_reattack_mg
+};
+mmove_t boss2_move_attack_mg = {FRAME_attack10, FRAME_attack15, boss2_frames_attack_mg, NULL};
+
+mframe_t boss2_frames_attack_post_mg [] =
+{
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL
+};
+mmove_t boss2_move_attack_post_mg = {FRAME_attack16, FRAME_attack19, boss2_frames_attack_post_mg, boss2_run};
+
+mframe_t boss2_frames_attack_rocket [] =
+{
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_move,	-20,	Boss2Rocket,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL
+};
+mmove_t boss2_move_attack_rocket = {FRAME_attack20, FRAME_attack40, boss2_frames_attack_rocket, boss2_run};
+
+mframe_t boss2_frames_pain_heavy [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t boss2_move_pain_heavy = {FRAME_pain2, FRAME_pain19, boss2_frames_pain_heavy, boss2_run};
+
+mframe_t boss2_frames_pain_light [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t boss2_move_pain_light = {FRAME_pain20, FRAME_pain23, boss2_frames_pain_light, boss2_run};
+
+mframe_t boss2_frames_death [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	BossExplode
+};
+mmove_t boss2_move_death = {FRAME_death2, FRAME_death50, boss2_frames_death, boss2_dead};
+
+void boss2_stand (edict_t *self)
+{
+		self->monsterinfo.currentmove = &boss2_move_stand;
+}
+
+void boss2_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &boss2_move_stand;
+	else
+		self->monsterinfo.currentmove = &boss2_move_run;
+}
+
+void boss2_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &boss2_move_walk;
+}
+
+void boss2_attack (edict_t *self)
+{
+	vec3_t	vec;
+	float	range;
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	range = VectorLength (vec);
+	
+	if (range <= 125)
+	{
+		self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
+	}
+	else 
+	{
+		if (random() <= 0.6)
+			self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
+		else
+			self->monsterinfo.currentmove = &boss2_move_attack_rocket;
+	}
+}
+
+void boss2_attack_mg (edict_t *self)
+{
+	self->monsterinfo.currentmove = &boss2_move_attack_mg;
+}
+
+void boss2_reattack_mg (edict_t *self)
+{
+	if ( infront(self, self->enemy) )
+		if (random() <= 0.7)
+			self->monsterinfo.currentmove = &boss2_move_attack_mg;
+		else
+			self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
+	else
+		self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
+}
+
+
+void boss2_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+// American wanted these at no attenuation
+	if (damage < 10)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
+		self->monsterinfo.currentmove = &boss2_move_pain_light;
+	}
+	else if (damage < 30)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
+		self->monsterinfo.currentmove = &boss2_move_pain_light;
+	}
+	else 
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
+		self->monsterinfo.currentmove = &boss2_move_pain_heavy;
+	}
+}
+
+void boss2_dead (edict_t *self)
+{
+	VectorSet (self->mins, -56, -56, 0);
+	VectorSet (self->maxs, 56, 56, 80);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_NO;
+	self->count = 0;
+	self->monsterinfo.currentmove = &boss2_move_death;
+#if 0
+	int		n;
+
+	self->s.sound = 0;
+	// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.currentmove = &boss2_move_death;
+#endif
+}
+
+qboolean Boss2_CheckAttack (edict_t *self)
+{
+	vec3_t	spot1, spot2;
+	vec3_t	temp;
+	float	chance;
+	trace_t	tr;
+	qboolean	enemy_infront;
+	int			enemy_range;
+	float		enemy_yaw;
+
+	if (self->enemy->health > 0)
+	{
+	// see if any entities are in the way of the shot
+		VectorCopy (self->s.origin, spot1);
+		spot1[2] += self->viewheight;
+		VectorCopy (self->enemy->s.origin, spot2);
+		spot2[2] += self->enemy->viewheight;
+
+		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
+
+		// do we have a clear shot?
+		if (tr.ent != self->enemy)
+			return false;
+	}
+	
+	enemy_infront = infront(self, self->enemy);
+	enemy_range = range(self, self->enemy);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
+	enemy_yaw = vectoyaw(temp);
+
+	self->ideal_yaw = enemy_yaw;
+
+
+	// melee attack
+	if (enemy_range == RANGE_MELEE)
+	{
+		if (self->monsterinfo.melee)
+			self->monsterinfo.attack_state = AS_MELEE;
+		else
+			self->monsterinfo.attack_state = AS_MISSILE;
+		return true;
+	}
+	
+// missile attack
+	if (!self->monsterinfo.attack)
+		return false;
+		
+	if (level.time < self->monsterinfo.attack_finished)
+		return false;
+		
+	if (enemy_range == RANGE_FAR)
+		return false;
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MELEE)
+	{
+		chance = 0.8;
+	}
+	else if (enemy_range == RANGE_NEAR)
+	{
+		chance = 0.8;
+	}
+	else if (enemy_range == RANGE_MID)
+	{
+		chance = 0.8;
+	}
+	else
+	{
+		return false;
+	}
+
+	if (random () < chance)
+	{
+		self->monsterinfo.attack_state = AS_MISSILE;
+		self->monsterinfo.attack_finished = level.time + 2*random();
+		return true;
+	}
+
+	if (self->flags & FL_FLY)
+	{
+		if (random() < 0.3)
+			self->monsterinfo.attack_state = AS_SLIDING;
+		else
+			self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+
+	return false;
+}
+
+
+
+/*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_boss2 (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav");
+	sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav");
+	sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav");
+	sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav");
+	sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav");
+
+	self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/boss2/tris.md2");
+	VectorSet (self->mins, -56, -56, 0);
+	VectorSet (self->maxs, 56, 56, 80);
+
+	self->health = 2000;
+	self->gib_health = -200;
+	self->mass = 1000;
+
+	self->flags |= FL_IMMUNE_LASER;
+
+	self->pain = boss2_pain;
+	self->die = boss2_die;
+
+	self->monsterinfo.stand = boss2_stand;
+	self->monsterinfo.walk = boss2_walk;
+	self->monsterinfo.run = boss2_run;
+	self->monsterinfo.attack = boss2_attack;
+	self->monsterinfo.search = boss2_search;
+	self->monsterinfo.checkattack = Boss2_CheckAttack;
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &boss2_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	flymonster_start (self);
+}
--- /dev/null
+++ b/game/m_boss2.h
@@ -1,0 +1,206 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/boss2
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand30         	0
+#define FRAME_stand31         	1
+#define FRAME_stand32         	2
+#define FRAME_stand33         	3
+#define FRAME_stand34         	4
+#define FRAME_stand35         	5
+#define FRAME_stand36         	6
+#define FRAME_stand37         	7
+#define FRAME_stand38         	8
+#define FRAME_stand39         	9
+#define FRAME_stand40         	10
+#define FRAME_stand41         	11
+#define FRAME_stand42         	12
+#define FRAME_stand43         	13
+#define FRAME_stand44         	14
+#define FRAME_stand45         	15
+#define FRAME_stand46         	16
+#define FRAME_stand47         	17
+#define FRAME_stand48         	18
+#define FRAME_stand49         	19
+#define FRAME_stand50         	20
+#define FRAME_stand1          	21
+#define FRAME_stand2          	22
+#define FRAME_stand3          	23
+#define FRAME_stand4          	24
+#define FRAME_stand5          	25
+#define FRAME_stand6          	26
+#define FRAME_stand7          	27
+#define FRAME_stand8          	28
+#define FRAME_stand9          	29
+#define FRAME_stand10         	30
+#define FRAME_stand11         	31
+#define FRAME_stand12         	32
+#define FRAME_stand13         	33
+#define FRAME_stand14         	34
+#define FRAME_stand15         	35
+#define FRAME_stand16         	36
+#define FRAME_stand17         	37
+#define FRAME_stand18         	38
+#define FRAME_stand19         	39
+#define FRAME_stand20         	40
+#define FRAME_stand21         	41
+#define FRAME_stand22         	42
+#define FRAME_stand23         	43
+#define FRAME_stand24         	44
+#define FRAME_stand25         	45
+#define FRAME_stand26         	46
+#define FRAME_stand27         	47
+#define FRAME_stand28         	48
+#define FRAME_stand29         	49
+#define FRAME_walk1           	50
+#define FRAME_walk2           	51
+#define FRAME_walk3           	52
+#define FRAME_walk4           	53
+#define FRAME_walk5           	54
+#define FRAME_walk6           	55
+#define FRAME_walk7           	56
+#define FRAME_walk8           	57
+#define FRAME_walk9           	58
+#define FRAME_walk10          	59
+#define FRAME_walk11          	60
+#define FRAME_walk12          	61
+#define FRAME_walk13          	62
+#define FRAME_walk14          	63
+#define FRAME_walk15          	64
+#define FRAME_walk16          	65
+#define FRAME_walk17          	66
+#define FRAME_walk18          	67
+#define FRAME_walk19          	68
+#define FRAME_walk20          	69
+#define FRAME_attack1         	70
+#define FRAME_attack2         	71
+#define FRAME_attack3         	72
+#define FRAME_attack4         	73
+#define FRAME_attack5         	74
+#define FRAME_attack6         	75
+#define FRAME_attack7         	76
+#define FRAME_attack8         	77
+#define FRAME_attack9         	78
+#define FRAME_attack10        	79
+#define FRAME_attack11        	80
+#define FRAME_attack12        	81
+#define FRAME_attack13        	82
+#define FRAME_attack14        	83
+#define FRAME_attack15        	84
+#define FRAME_attack16        	85
+#define FRAME_attack17        	86
+#define FRAME_attack18        	87
+#define FRAME_attack19        	88
+#define FRAME_attack20        	89
+#define FRAME_attack21        	90
+#define FRAME_attack22        	91
+#define FRAME_attack23        	92
+#define FRAME_attack24        	93
+#define FRAME_attack25        	94
+#define FRAME_attack26        	95
+#define FRAME_attack27        	96
+#define FRAME_attack28        	97
+#define FRAME_attack29        	98
+#define FRAME_attack30        	99
+#define FRAME_attack31        	100
+#define FRAME_attack32        	101
+#define FRAME_attack33        	102
+#define FRAME_attack34        	103
+#define FRAME_attack35        	104
+#define FRAME_attack36        	105
+#define FRAME_attack37        	106
+#define FRAME_attack38        	107
+#define FRAME_attack39        	108
+#define FRAME_attack40        	109
+#define FRAME_pain2           	110
+#define FRAME_pain3           	111
+#define FRAME_pain4           	112
+#define FRAME_pain5           	113
+#define FRAME_pain6           	114
+#define FRAME_pain7           	115
+#define FRAME_pain8           	116
+#define FRAME_pain9           	117
+#define FRAME_pain10          	118
+#define FRAME_pain11          	119
+#define FRAME_pain12          	120
+#define FRAME_pain13          	121
+#define FRAME_pain14          	122
+#define FRAME_pain15          	123
+#define FRAME_pain16          	124
+#define FRAME_pain17          	125
+#define FRAME_pain18          	126
+#define FRAME_pain19          	127
+#define FRAME_pain20          	128
+#define FRAME_pain21          	129
+#define FRAME_pain22          	130
+#define FRAME_pain23          	131
+#define FRAME_death2          	132
+#define FRAME_death3          	133
+#define FRAME_death4          	134
+#define FRAME_death5          	135
+#define FRAME_death6          	136
+#define FRAME_death7          	137
+#define FRAME_death8          	138
+#define FRAME_death9          	139
+#define FRAME_death10         	140
+#define FRAME_death11         	141
+#define FRAME_death12         	142
+#define FRAME_death13         	143
+#define FRAME_death14         	144
+#define FRAME_death15         	145
+#define FRAME_death16         	146
+#define FRAME_death17         	147
+#define FRAME_death18         	148
+#define FRAME_death19         	149
+#define FRAME_death20         	150
+#define FRAME_death21         	151
+#define FRAME_death22         	152
+#define FRAME_death23         	153
+#define FRAME_death24         	154
+#define FRAME_death25         	155
+#define FRAME_death26         	156
+#define FRAME_death27         	157
+#define FRAME_death28         	158
+#define FRAME_death29         	159
+#define FRAME_death30         	160
+#define FRAME_death31         	161
+#define FRAME_death32         	162
+#define FRAME_death33         	163
+#define FRAME_death34         	164
+#define FRAME_death35         	165
+#define FRAME_death36         	166
+#define FRAME_death37         	167
+#define FRAME_death38         	168
+#define FRAME_death39         	169
+#define FRAME_death40         	170
+#define FRAME_death41         	171
+#define FRAME_death42         	172
+#define FRAME_death43         	173
+#define FRAME_death44         	174
+#define FRAME_death45         	175
+#define FRAME_death46         	176
+#define FRAME_death47         	177
+#define FRAME_death48         	178
+#define FRAME_death49         	179
+#define FRAME_death50         	180
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_boss3.c
@@ -1,0 +1,76 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+boss3
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_boss32.h"
+
+void Use_Boss3 (edict_t *ent, edict_t *other, edict_t *activator)
+{
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_BOSSTPORT);
+	gi.WritePosition (ent->s.origin);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+	G_FreeEdict (ent);
+}
+
+void Think_Boss3Stand (edict_t *ent)
+{
+	if (ent->s.frame == FRAME_stand260)
+		ent->s.frame = FRAME_stand201;
+	else
+		ent->s.frame++;
+	ent->nextthink = level.time + FRAMETIME;
+}
+
+/*QUAKED monster_boss3_stand (1 .5 0) (-32 -32 0) (32 32 90)
+
+Just stands and cycles in one place until targeted, then teleports away.
+*/
+void SP_monster_boss3_stand (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->model = "models/monsters/boss3/rider/tris.md2";
+	self->s.modelindex = gi.modelindex (self->model);
+	self->s.frame = FRAME_stand201;
+
+	gi.soundindex ("misc/bigtele.wav");
+
+	VectorSet (self->mins, -32, -32, 0);
+	VectorSet (self->maxs, 32, 32, 90);
+
+	self->use = Use_Boss3;
+	self->think = Think_Boss3Stand;
+	self->nextthink = level.time + FRAMETIME;
+	gi.linkentity (self);
+}
--- /dev/null
+++ b/game/m_boss31.c
@@ -1,0 +1,749 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+jorg
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_boss31.h"
+
+extern SP_monster_makron (edict_t *self);
+qboolean visible (edict_t *self, edict_t *other);
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_pain3;
+static int	sound_idle;
+static int	sound_death;
+static int	sound_search1;
+static int	sound_search2;
+static int	sound_search3;
+static int	sound_attack1;
+static int	sound_attack2;
+static int	sound_firegun;
+static int	sound_step_left;
+static int	sound_step_right;
+static int	sound_death_hit;
+
+void BossExplode (edict_t *self);
+void MakronToss (edict_t *self);
+
+
+void jorg_search (edict_t *self)
+{
+	float r;
+
+	r = random();
+
+	if (r <= 0.3)
+		gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
+	else if (r <= 0.6)
+		gi.sound (self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_search3, 1, ATTN_NORM, 0);
+}
+
+
+void jorg_dead (edict_t *self);
+void jorgBFG (edict_t *self);
+void jorgMachineGun (edict_t *self);
+void jorg_firebullet (edict_t *self);
+void jorg_reattack1(edict_t *self);
+void jorg_attack1(edict_t *self);
+void jorg_idle(edict_t *self);
+void jorg_step_left(edict_t *self);
+void jorg_step_right(edict_t *self);
+void jorg_death_hit(edict_t *self);
+
+//
+// stand
+//
+
+mframe_t jorg_frames_stand []=
+{
+	ai_stand, 0, jorg_idle,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 10
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 20
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 30
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 19, NULL,
+	ai_stand, 11, jorg_step_left,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 6, NULL,
+	ai_stand, 9, jorg_step_right,
+	ai_stand, 0, NULL,		// 40
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, -2, NULL,
+	ai_stand, -17, jorg_step_left,
+	ai_stand, 0, NULL,
+	ai_stand, -12, NULL,		// 50
+	ai_stand, -14, jorg_step_right	// 51
+};
+mmove_t	jorg_move_stand = {FRAME_stand01, FRAME_stand51, jorg_frames_stand, NULL};
+
+void jorg_idle (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_NORM,0);
+}
+
+void jorg_death_hit (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_death_hit, 1, ATTN_NORM,0);
+}
+
+
+void jorg_step_left (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_step_left, 1, ATTN_NORM,0);
+}
+
+void jorg_step_right (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_step_right, 1, ATTN_NORM,0);
+}
+
+
+void jorg_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &jorg_move_stand;
+}
+
+mframe_t jorg_frames_run [] =
+{
+	ai_run, 17,	jorg_step_left,
+	ai_run, 0,	NULL,
+	ai_run, 0,	NULL,
+	ai_run, 0,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 8,	NULL,
+	ai_run, 10,	NULL,
+	ai_run, 33,	jorg_step_right,
+	ai_run, 0,	NULL,
+	ai_run, 0,	NULL,
+	ai_run, 0,	NULL,
+	ai_run, 9,	NULL,
+	ai_run, 9,	NULL,
+	ai_run, 9,	NULL
+};
+mmove_t	jorg_move_run = {FRAME_walk06, FRAME_walk19, jorg_frames_run, NULL};
+
+//
+// walk
+//
+
+mframe_t jorg_frames_start_walk [] =
+{
+	ai_walk,	5,	NULL,
+	ai_walk,	6,	NULL,
+	ai_walk,	7,	NULL,
+	ai_walk,	9,	NULL,
+	ai_walk,	15,	NULL
+};
+mmove_t jorg_move_start_walk = {FRAME_walk01, FRAME_walk05, jorg_frames_start_walk, NULL};
+
+mframe_t jorg_frames_walk [] =
+{
+	ai_walk, 17,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 12,	NULL,
+	ai_walk, 8,	NULL,
+	ai_walk, 10,	NULL,
+	ai_walk, 33,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 9,	NULL,
+	ai_walk, 9,	NULL,
+	ai_walk, 9,	NULL
+};
+mmove_t	jorg_move_walk = {FRAME_walk06, FRAME_walk19, jorg_frames_walk, NULL};
+
+mframe_t jorg_frames_end_walk [] =
+{
+	ai_walk,	11,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	8,	NULL,
+	ai_walk,	-8,	NULL
+};
+mmove_t jorg_move_end_walk = {FRAME_walk20, FRAME_walk25, jorg_frames_end_walk, NULL};
+
+void jorg_walk (edict_t *self)
+{
+		self->monsterinfo.currentmove = &jorg_move_walk;
+}
+
+void jorg_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &jorg_move_stand;
+	else
+		self->monsterinfo.currentmove = &jorg_move_run;
+}
+
+mframe_t jorg_frames_pain3 [] =
+{
+	ai_move,	-28,	NULL,
+	ai_move,	-6,	NULL,
+	ai_move,	-3,	jorg_step_left,
+	ai_move,	-9,	NULL,
+	ai_move,	0,	jorg_step_right,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-7,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	-11,	NULL,
+	ai_move,	-4,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	10,	NULL,
+	ai_move,	11,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	10,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	10,	NULL,
+	ai_move,	7,	jorg_step_left,
+	ai_move,	17,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	jorg_step_right
+};
+mmove_t jorg_move_pain3 = {FRAME_pain301, FRAME_pain325, jorg_frames_pain3, jorg_run};
+
+mframe_t jorg_frames_pain2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t jorg_move_pain2 = {FRAME_pain201, FRAME_pain203, jorg_frames_pain2, jorg_run};
+
+mframe_t jorg_frames_pain1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t jorg_move_pain1 = {FRAME_pain101, FRAME_pain103, jorg_frames_pain1, jorg_run};
+
+mframe_t jorg_frames_death1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,		// 10
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,		// 20
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,		// 30
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,		// 40
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	MakronToss,
+	ai_move,	0,	BossExplode		// 50
+};
+mmove_t jorg_move_death = {FRAME_death01, FRAME_death50, jorg_frames_death1, jorg_dead};
+
+mframe_t jorg_frames_attack2 []=
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	jorgBFG,		
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t jorg_move_attack2 = {FRAME_attak201, FRAME_attak213, jorg_frames_attack2, jorg_run};
+
+mframe_t jorg_frames_start_attack1 [] =
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL
+};
+mmove_t jorg_move_start_attack1 = {FRAME_attak101, FRAME_attak108, jorg_frames_start_attack1, jorg_attack1};
+
+mframe_t jorg_frames_attack1[]=
+{
+	ai_charge,	0,	jorg_firebullet,
+	ai_charge,	0,	jorg_firebullet,
+	ai_charge,	0,	jorg_firebullet,
+	ai_charge,	0,	jorg_firebullet,
+	ai_charge,	0,	jorg_firebullet,
+	ai_charge,	0,	jorg_firebullet
+};
+mmove_t jorg_move_attack1 = {FRAME_attak109, FRAME_attak114, jorg_frames_attack1, jorg_reattack1};
+
+mframe_t jorg_frames_end_attack1[]=
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t jorg_move_end_attack1 = {FRAME_attak115, FRAME_attak118, jorg_frames_end_attack1, jorg_run};
+
+void jorg_reattack1(edict_t *self)
+{
+	if (visible(self, self->enemy))
+		if (random() < 0.9)
+			self->monsterinfo.currentmove = &jorg_move_attack1;
+		else
+		{
+			self->s.sound = 0;
+			self->monsterinfo.currentmove = &jorg_move_end_attack1;	
+		}
+	else
+	{
+		self->s.sound = 0;
+		self->monsterinfo.currentmove = &jorg_move_end_attack1;	
+	}
+}
+
+void jorg_attack1(edict_t *self)
+{
+	self->monsterinfo.currentmove = &jorg_move_attack1;
+}
+
+void jorg_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+
+	if (self->health < (self->max_health / 2))
+			self->s.skinnum = 1;
+	
+	self->s.sound = 0;
+
+	if (level.time < self->pain_debounce_time)
+			return;
+
+	// Lessen the chance of him going into his pain frames if he takes little damage
+	if (damage <= 40)
+		if (random()<=0.6)
+			return;
+
+	/* 
+	If he's entering his attack1 or using attack1, lessen the chance of him
+	going into pain
+	*/
+	
+	if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak108) )
+		if (random() <= 0.005)
+			return;
+
+	if ( (self->s.frame >= FRAME_attak109) && (self->s.frame <= FRAME_attak114) )
+		if (random() <= 0.00005)
+			return;
+
+
+	if ( (self->s.frame >= FRAME_attak201) && (self->s.frame <= FRAME_attak208) )
+		if (random() <= 0.005)
+			return;
+
+
+	self->pain_debounce_time = level.time + 3;
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (damage <= 50)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM,0);
+		self->monsterinfo.currentmove = &jorg_move_pain1;
+	}
+	else if (damage <= 100)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM,0);
+		self->monsterinfo.currentmove = &jorg_move_pain2;
+	}
+	else
+	{
+		if (random() <= 0.3)
+		{
+			gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM,0);
+			self->monsterinfo.currentmove = &jorg_move_pain3;
+		}
+	}
+};
+
+void jorgBFG (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_JORG_BFG_1], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	gi.sound (self, CHAN_VOICE, sound_attack2, 1, ATTN_NORM, 0);
+	/*void monster_fire_bfg (edict_t *self, 
+							 vec3_t start, 
+							 vec3_t aimdir, 
+							 int damage, 
+							 int speed, 
+							 int kick, 
+							 float damage_radius, 
+							 int flashtype)*/
+	monster_fire_bfg (self, start, dir, 50, 300, 100, 200, MZ2_JORG_BFG_1);
+}	
+
+void jorg_firebullet_right (edict_t *self)
+{
+	vec3_t	forward, right, target;
+	vec3_t	start;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_JORG_MACHINEGUN_R1], forward, right, start);
+
+	VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
+	target[2] += self->enemy->viewheight;
+	VectorSubtract (target, start, forward);
+	VectorNormalize (forward);
+
+	monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_JORG_MACHINEGUN_R1);
+}	
+
+void jorg_firebullet_left (edict_t *self)
+{
+	vec3_t	forward, right, target;
+	vec3_t	start;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_JORG_MACHINEGUN_L1], forward, right, start);
+
+	VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
+	target[2] += self->enemy->viewheight;
+	VectorSubtract (target, start, forward);
+	VectorNormalize (forward);
+
+	monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_JORG_MACHINEGUN_L1);
+}	
+
+void jorg_firebullet (edict_t *self)
+{
+	jorg_firebullet_left(self);
+	jorg_firebullet_right(self);
+};
+
+void jorg_attack(edict_t *self)
+{
+	vec3_t	vec;
+	float	range;
+	
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	range = VectorLength (vec);
+
+	if (random() <= 0.75)
+	{
+		gi.sound (self, CHAN_VOICE, sound_attack1, 1, ATTN_NORM,0);
+		self->s.sound = gi.soundindex ("boss3/w_loop.wav");
+		self->monsterinfo.currentmove = &jorg_move_start_attack1;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_attack2, 1, ATTN_NORM,0);
+		self->monsterinfo.currentmove = &jorg_move_attack2;
+	}
+}
+
+void jorg_dead (edict_t *self)
+{
+#if 0
+	edict_t	*tempent;
+	/*
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	*/
+	
+	// Jorg is on modelindex2. Do not clear him.
+	VectorSet (self->mins, -60, -60, 0);
+	VectorSet (self->maxs, 60, 60, 72);
+	self->movetype = MOVETYPE_TOSS;
+	self->nextthink = 0;
+	gi.linkentity (self);
+
+	tempent = G_Spawn();
+	VectorCopy (self->s.origin, tempent->s.origin);
+	VectorCopy (self->s.angles, tempent->s.angles);
+	tempent->killtarget = self->killtarget;
+	tempent->target = self->target;
+	tempent->activator = self->enemy;
+	self->killtarget = 0;
+	self->target = 0;
+	SP_monster_makron (tempent);
+#endif
+}
+
+
+void jorg_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_NO;
+	self->s.sound = 0;
+	self->count = 0;
+	self->monsterinfo.currentmove = &jorg_move_death;
+}
+
+qboolean Jorg_CheckAttack (edict_t *self)
+{
+	vec3_t	spot1, spot2;
+	vec3_t	temp;
+	float	chance;
+	trace_t	tr;
+	qboolean	enemy_infront;
+	int			enemy_range;
+	float		enemy_yaw;
+
+	if (self->enemy->health > 0)
+	{
+	// see if any entities are in the way of the shot
+		VectorCopy (self->s.origin, spot1);
+		spot1[2] += self->viewheight;
+		VectorCopy (self->enemy->s.origin, spot2);
+		spot2[2] += self->enemy->viewheight;
+
+		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
+
+		// do we have a clear shot?
+		if (tr.ent != self->enemy)
+			return false;
+	}
+	
+	enemy_infront = infront(self, self->enemy);
+	enemy_range = range(self, self->enemy);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
+	enemy_yaw = vectoyaw(temp);
+
+	self->ideal_yaw = enemy_yaw;
+
+
+	// melee attack
+	if (enemy_range == RANGE_MELEE)
+	{
+		if (self->monsterinfo.melee)
+			self->monsterinfo.attack_state = AS_MELEE;
+		else
+			self->monsterinfo.attack_state = AS_MISSILE;
+		return true;
+	}
+	
+// missile attack
+	if (!self->monsterinfo.attack)
+		return false;
+		
+	if (level.time < self->monsterinfo.attack_finished)
+		return false;
+		
+	if (enemy_range == RANGE_FAR)
+		return false;
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MELEE)
+	{
+		chance = 0.8;
+	}
+	else if (enemy_range == RANGE_NEAR)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MID)
+	{
+		chance = 0.2;
+	}
+	else
+	{
+		return false;
+	}
+
+	if (random () < chance)
+	{
+		self->monsterinfo.attack_state = AS_MISSILE;
+		self->monsterinfo.attack_finished = level.time + 2*random();
+		return true;
+	}
+
+	if (self->flags & FL_FLY)
+	{
+		if (random() < 0.3)
+			self->monsterinfo.attack_state = AS_SLIDING;
+		else
+			self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+
+	return false;
+}
+
+
+void MakronPrecache (void);
+
+/*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_jorg (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1 = gi.soundindex ("boss3/bs3pain1.wav");
+	sound_pain2 = gi.soundindex ("boss3/bs3pain2.wav");
+	sound_pain3 = gi.soundindex ("boss3/bs3pain3.wav");
+	sound_death = gi.soundindex ("boss3/bs3deth1.wav");
+	sound_attack1 = gi.soundindex ("boss3/bs3atck1.wav");
+	sound_attack2 = gi.soundindex ("boss3/bs3atck2.wav");
+	sound_search1 = gi.soundindex ("boss3/bs3srch1.wav");
+	sound_search2 = gi.soundindex ("boss3/bs3srch2.wav");
+	sound_search3 = gi.soundindex ("boss3/bs3srch3.wav");
+	sound_idle = gi.soundindex ("boss3/bs3idle1.wav");
+	sound_step_left = gi.soundindex ("boss3/step1.wav");
+	sound_step_right = gi.soundindex ("boss3/step2.wav");
+	sound_firegun = gi.soundindex ("boss3/xfire.wav");
+	sound_death_hit = gi.soundindex ("boss3/d_hit.wav");
+
+	MakronPrecache ();
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
+	self->s.modelindex2 = gi.modelindex ("models/monsters/boss3/jorg/tris.md2");
+	VectorSet (self->mins, -80, -80, 0);
+	VectorSet (self->maxs, 80, 80, 140);
+
+	self->health = 3000;
+	self->gib_health = -2000;
+	self->mass = 1000;
+
+	self->pain = jorg_pain;
+	self->die = jorg_die;
+	self->monsterinfo.stand = jorg_stand;
+	self->monsterinfo.walk = jorg_walk;
+	self->monsterinfo.run = jorg_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = jorg_attack;
+	self->monsterinfo.search = jorg_search;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = NULL;
+	self->monsterinfo.checkattack = Jorg_CheckAttack;
+	gi.linkentity (self);
+	
+	self->monsterinfo.currentmove = &jorg_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start(self);
+}
--- /dev/null
+++ b/game/m_boss31.h
@@ -1,0 +1,213 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/boss3/jorg
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_attak101        	0
+#define FRAME_attak102        	1
+#define FRAME_attak103        	2
+#define FRAME_attak104        	3
+#define FRAME_attak105        	4
+#define FRAME_attak106        	5
+#define FRAME_attak107        	6
+#define FRAME_attak108        	7
+#define FRAME_attak109        	8
+#define FRAME_attak110        	9
+#define FRAME_attak111        	10
+#define FRAME_attak112        	11
+#define FRAME_attak113        	12
+#define FRAME_attak114        	13
+#define FRAME_attak115        	14
+#define FRAME_attak116        	15
+#define FRAME_attak117        	16
+#define FRAME_attak118        	17
+#define FRAME_attak201        	18
+#define FRAME_attak202        	19
+#define FRAME_attak203        	20
+#define FRAME_attak204        	21
+#define FRAME_attak205        	22
+#define FRAME_attak206        	23
+#define FRAME_attak207        	24
+#define FRAME_attak208        	25
+#define FRAME_attak209        	26
+#define FRAME_attak210        	27
+#define FRAME_attak211        	28
+#define FRAME_attak212        	29
+#define FRAME_attak213        	30
+#define FRAME_death01         	31
+#define FRAME_death02         	32
+#define FRAME_death03         	33
+#define FRAME_death04         	34
+#define FRAME_death05         	35
+#define FRAME_death06         	36
+#define FRAME_death07         	37
+#define FRAME_death08         	38
+#define FRAME_death09         	39
+#define FRAME_death10         	40
+#define FRAME_death11         	41
+#define FRAME_death12         	42
+#define FRAME_death13         	43
+#define FRAME_death14         	44
+#define FRAME_death15         	45
+#define FRAME_death16         	46
+#define FRAME_death17         	47
+#define FRAME_death18         	48
+#define FRAME_death19         	49
+#define FRAME_death20         	50
+#define FRAME_death21         	51
+#define FRAME_death22         	52
+#define FRAME_death23         	53
+#define FRAME_death24         	54
+#define FRAME_death25         	55
+#define FRAME_death26         	56
+#define FRAME_death27         	57
+#define FRAME_death28         	58
+#define FRAME_death29         	59
+#define FRAME_death30         	60
+#define FRAME_death31         	61
+#define FRAME_death32         	62
+#define FRAME_death33         	63
+#define FRAME_death34         	64
+#define FRAME_death35         	65
+#define FRAME_death36         	66
+#define FRAME_death37         	67
+#define FRAME_death38         	68
+#define FRAME_death39         	69
+#define FRAME_death40         	70
+#define FRAME_death41         	71
+#define FRAME_death42         	72
+#define FRAME_death43         	73
+#define FRAME_death44         	74
+#define FRAME_death45         	75
+#define FRAME_death46         	76
+#define FRAME_death47         	77
+#define FRAME_death48         	78
+#define FRAME_death49         	79
+#define FRAME_death50         	80
+#define FRAME_pain101         	81
+#define FRAME_pain102         	82
+#define FRAME_pain103         	83
+#define FRAME_pain201         	84
+#define FRAME_pain202         	85
+#define FRAME_pain203         	86
+#define FRAME_pain301         	87
+#define FRAME_pain302         	88
+#define FRAME_pain303         	89
+#define FRAME_pain304         	90
+#define FRAME_pain305         	91
+#define FRAME_pain306         	92
+#define FRAME_pain307         	93
+#define FRAME_pain308         	94
+#define FRAME_pain309         	95
+#define FRAME_pain310         	96
+#define FRAME_pain311         	97
+#define FRAME_pain312         	98
+#define FRAME_pain313         	99
+#define FRAME_pain314         	100
+#define FRAME_pain315         	101
+#define FRAME_pain316         	102
+#define FRAME_pain317         	103
+#define FRAME_pain318         	104
+#define FRAME_pain319         	105
+#define FRAME_pain320         	106
+#define FRAME_pain321         	107
+#define FRAME_pain322         	108
+#define FRAME_pain323         	109
+#define FRAME_pain324         	110
+#define FRAME_pain325         	111
+#define FRAME_stand01         	112
+#define FRAME_stand02         	113
+#define FRAME_stand03         	114
+#define FRAME_stand04         	115
+#define FRAME_stand05         	116
+#define FRAME_stand06         	117
+#define FRAME_stand07         	118
+#define FRAME_stand08         	119
+#define FRAME_stand09         	120
+#define FRAME_stand10         	121
+#define FRAME_stand11         	122
+#define FRAME_stand12         	123
+#define FRAME_stand13         	124
+#define FRAME_stand14         	125
+#define FRAME_stand15         	126
+#define FRAME_stand16         	127
+#define FRAME_stand17         	128
+#define FRAME_stand18         	129
+#define FRAME_stand19         	130
+#define FRAME_stand20         	131
+#define FRAME_stand21         	132
+#define FRAME_stand22         	133
+#define FRAME_stand23         	134
+#define FRAME_stand24         	135
+#define FRAME_stand25         	136
+#define FRAME_stand26         	137
+#define FRAME_stand27         	138
+#define FRAME_stand28         	139
+#define FRAME_stand29         	140
+#define FRAME_stand30         	141
+#define FRAME_stand31         	142
+#define FRAME_stand32         	143
+#define FRAME_stand33         	144
+#define FRAME_stand34         	145
+#define FRAME_stand35         	146
+#define FRAME_stand36         	147
+#define FRAME_stand37         	148
+#define FRAME_stand38         	149
+#define FRAME_stand39         	150
+#define FRAME_stand40         	151
+#define FRAME_stand41         	152
+#define FRAME_stand42         	153
+#define FRAME_stand43         	154
+#define FRAME_stand44         	155
+#define FRAME_stand45         	156
+#define FRAME_stand46         	157
+#define FRAME_stand47         	158
+#define FRAME_stand48         	159
+#define FRAME_stand49         	160
+#define FRAME_stand50         	161
+#define FRAME_stand51         	162
+#define FRAME_walk01          	163
+#define FRAME_walk02          	164
+#define FRAME_walk03          	165
+#define FRAME_walk04          	166
+#define FRAME_walk05          	167
+#define FRAME_walk06          	168
+#define FRAME_walk07          	169
+#define FRAME_walk08          	170
+#define FRAME_walk09          	171
+#define FRAME_walk10          	172
+#define FRAME_walk11          	173
+#define FRAME_walk12          	174
+#define FRAME_walk13          	175
+#define FRAME_walk14          	176
+#define FRAME_walk15          	177
+#define FRAME_walk16          	178
+#define FRAME_walk17          	179
+#define FRAME_walk18          	180
+#define FRAME_walk19          	181
+#define FRAME_walk20          	182
+#define FRAME_walk21          	183
+#define FRAME_walk22          	184
+#define FRAME_walk23          	185
+#define FRAME_walk24          	186
+#define FRAME_walk25          	187
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_boss32.c
@@ -1,0 +1,913 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+Makron -- Final Boss
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_boss32.h"
+
+qboolean visible (edict_t *self, edict_t *other);
+
+void MakronRailgun (edict_t *self);
+void MakronSaveloc (edict_t *self);
+void MakronHyperblaster (edict_t *self);
+void makron_step_left (edict_t *self);
+void makron_step_right (edict_t *self);
+void makronBFG (edict_t *self);
+void makron_dead (edict_t *self);
+
+static int	sound_pain4;
+static int	sound_pain5;
+static int	sound_pain6;
+static int	sound_death;
+static int	sound_step_left;
+static int	sound_step_right;
+static int	sound_attack_bfg;
+static int	sound_brainsplorch;
+static int	sound_prerailgun;
+static int	sound_popup;
+static int	sound_taunt1;
+static int	sound_taunt2;
+static int	sound_taunt3;
+static int	sound_hit;
+
+void makron_taunt (edict_t *self)
+{
+	float r;
+
+	r=random();
+	if (r <= 0.3)
+		gi.sound (self, CHAN_AUTO, sound_taunt1, 1, ATTN_NONE, 0);
+	else if (r <= 0.6)
+		gi.sound (self, CHAN_AUTO, sound_taunt2, 1, ATTN_NONE, 0);
+	else
+		gi.sound (self, CHAN_AUTO, sound_taunt3, 1, ATTN_NONE, 0);
+}
+
+//
+// stand
+//
+
+mframe_t makron_frames_stand []=
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 10
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 20
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 30
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 40
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 50
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL		// 60
+};
+mmove_t	makron_move_stand = {FRAME_stand201, FRAME_stand260, makron_frames_stand, NULL};
+	
+void makron_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &makron_move_stand;
+}
+
+mframe_t makron_frames_run [] =
+{
+	ai_run, 3,	makron_step_left,
+	ai_run, 12,	NULL,
+	ai_run, 8,	NULL,
+	ai_run, 8,	NULL,
+	ai_run, 8,	makron_step_right,
+	ai_run, 6,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 9,	NULL,
+	ai_run, 6,	NULL,
+	ai_run, 12,	NULL
+};
+mmove_t	makron_move_run = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
+
+void makron_hit (edict_t *self)
+{
+	gi.sound (self, CHAN_AUTO, sound_hit, 1, ATTN_NONE,0);
+}
+
+void makron_popup (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_popup, 1, ATTN_NONE,0);
+}
+
+void makron_step_left (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_step_left, 1, ATTN_NORM,0);
+}
+
+void makron_step_right (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_step_right, 1, ATTN_NORM,0);
+}
+
+void makron_brainsplorch (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_brainsplorch, 1, ATTN_NORM,0);
+}
+
+void makron_prerailgun (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM,0);
+}
+
+
+mframe_t makron_frames_walk [] =
+{
+	ai_walk, 3,	makron_step_left,
+	ai_walk, 12,	NULL,
+	ai_walk, 8,	NULL,
+	ai_walk, 8,	NULL,
+	ai_walk, 8,	makron_step_right,
+	ai_walk, 6,	NULL,
+	ai_walk, 12,	NULL,
+	ai_walk, 9,	NULL,
+	ai_walk, 6,	NULL,
+	ai_walk, 12,	NULL
+};
+mmove_t	makron_move_walk = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
+
+void makron_walk (edict_t *self)
+{
+		self->monsterinfo.currentmove = &makron_move_walk;
+}
+
+void makron_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &makron_move_stand;
+	else
+		self->monsterinfo.currentmove = &makron_move_run;
+}
+
+mframe_t makron_frames_pain6 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,		// 10
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	makron_popup,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,		// 20
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	makron_taunt,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_pain6 = {FRAME_pain601, FRAME_pain627, makron_frames_pain6, makron_run};
+
+mframe_t makron_frames_pain5 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_pain5 = {FRAME_pain501, FRAME_pain504, makron_frames_pain5, makron_run};
+
+mframe_t makron_frames_pain4 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_pain4 = {FRAME_pain401, FRAME_pain404, makron_frames_pain4, makron_run};
+
+mframe_t makron_frames_death2 [] =
+{
+	ai_move,	-15,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	-12,	NULL,
+	ai_move,	0,	makron_step_left,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			// 10
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	11,	NULL,
+	ai_move,	12,	NULL,
+	ai_move,	11,	makron_step_right,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			// 20
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			// 30
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	5,	NULL,
+	ai_move,	7,	NULL,
+	ai_move,	6,	makron_step_left,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-1,	NULL,
+	ai_move,	2,	NULL,			// 40
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,			// 50
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-6,	NULL,
+	ai_move,	-4,	NULL,
+	ai_move,	-6,	makron_step_right,
+	ai_move,	-4,	NULL,
+	ai_move,	-4,	makron_step_left,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			// 60
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	-2,	NULL,
+	ai_move,	-5,	NULL,
+	ai_move,	-3,	makron_step_right,
+	ai_move,	-8,	NULL,
+	ai_move,	-3,	makron_step_left,
+	ai_move,	-7,	NULL,
+	ai_move,	-4,	NULL,
+	ai_move,	-4,	makron_step_right,			// 70
+	ai_move,	-6,	NULL,			
+	ai_move,	-7,	NULL,
+	ai_move,	0,	makron_step_left,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,			// 80
+	ai_move,	0,	NULL,			
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-2,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	0,	NULL,			// 90
+	ai_move,	27,	makron_hit,			
+	ai_move,	26,	NULL,
+	ai_move,	0,	makron_brainsplorch,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL			// 95
+};
+mmove_t makron_move_death2 = {FRAME_death201, FRAME_death295, makron_frames_death2, makron_dead};
+
+mframe_t makron_frames_death3 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_death3 = {FRAME_death301, FRAME_death320, makron_frames_death3, NULL};
+
+mframe_t makron_frames_sight [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_sight= {FRAME_active01, FRAME_active13, makron_frames_sight, makron_run};
+
+void makronBFG (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MAKRON_BFG], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+	gi.sound (self, CHAN_VOICE, sound_attack_bfg, 1, ATTN_NORM, 0);
+	monster_fire_bfg (self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
+}	
+
+
+mframe_t makron_frames_attack3 []=
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	makronBFG,		// FIXME: BFG Attack here
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_attack3 = {FRAME_attak301, FRAME_attak308, makron_frames_attack3, makron_run};
+
+mframe_t makron_frames_attack4[]=
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	MakronHyperblaster,		// fire
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_attack4 = {FRAME_attak401, FRAME_attak426, makron_frames_attack4, makron_run};
+
+mframe_t makron_frames_attack5[]=
+{
+	ai_charge,	0,	makron_prerailgun,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	MakronSaveloc,
+	ai_move,	0,	MakronRailgun,		// Fire railgun
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t makron_move_attack5 = {FRAME_attak501, FRAME_attak516, makron_frames_attack5, makron_run};
+
+void MakronSaveloc (edict_t *self)
+{
+	VectorCopy (self->enemy->s.origin, self->pos1);	//save for aiming the shot
+	self->pos1[2] += self->enemy->viewheight;
+};
+
+// FIXME: He's not firing from the proper Z
+void MakronRailgun (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	forward, right;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MAKRON_RAILGUN_1], forward, right, start);
+	
+	// calc direction to where we targted
+	VectorSubtract (self->pos1, start, dir);
+	VectorNormalize (dir);
+
+	monster_fire_railgun (self, start, dir, 50, 100, MZ2_MAKRON_RAILGUN_1);
+}
+
+// FIXME: This is all wrong. He's not firing at the proper angles.
+void MakronHyperblaster (edict_t *self)
+{
+	vec3_t	dir;
+	vec3_t	vec;
+	vec3_t	start;
+	vec3_t	forward, right;
+	int		flash_number;
+
+	flash_number = MZ2_MAKRON_BLASTER_1 + (self->s.frame - FRAME_attak405);
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	if (self->enemy)
+	{
+		VectorCopy (self->enemy->s.origin, vec);
+		vec[2] += self->enemy->viewheight;
+		VectorSubtract (vec, start, vec);
+		vectoangles (vec, vec);
+		dir[0] = vec[0];
+	}
+	else
+	{
+		dir[0] = 0;
+	}
+	if (self->s.frame <= FRAME_attak413)
+		dir[1] = self->s.angles[1] - 10 * (self->s.frame - FRAME_attak413);
+	else
+		dir[1] = self->s.angles[1] + 10 * (self->s.frame - FRAME_attak421);
+	dir[2] = 0;
+
+	AngleVectors (dir, forward, NULL, NULL);
+
+	monster_fire_blaster (self, start, forward, 15, 1000, MZ2_MAKRON_BLASTER_1, EF_BLASTER);
+}	
+
+
+void makron_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+
+	if (self->health < (self->max_health / 2))
+			self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+			return;
+
+	// Lessen the chance of him going into his pain frames
+	if (damage <=25)
+		if (random()<0.2)
+			return;
+
+	self->pain_debounce_time = level.time + 3;
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+
+	if (damage <= 40)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain4, 1, ATTN_NONE,0);
+		self->monsterinfo.currentmove = &makron_move_pain4;
+	}
+	else if (damage <= 110)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain5, 1, ATTN_NONE,0);
+		self->monsterinfo.currentmove = &makron_move_pain5;
+	}
+	else
+	{
+		if (damage <= 150)
+			if (random() <= 0.45)
+			{
+				gi.sound (self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE,0);
+				self->monsterinfo.currentmove = &makron_move_pain6;
+			}
+		else
+			if (random() <= 0.35)
+			{
+				gi.sound (self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE,0);
+				self->monsterinfo.currentmove = &makron_move_pain6;
+			}
+	}
+};
+
+void makron_sight(edict_t *self, edict_t *other)
+{
+	self->monsterinfo.currentmove = &makron_move_sight;
+};
+
+void makron_attack(edict_t *self)
+{
+	vec3_t	vec;
+	float	range;
+	float	r;
+
+	r = random();
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	range = VectorLength (vec);
+
+
+	if (r <= 0.3)
+		self->monsterinfo.currentmove = &makron_move_attack3;
+	else if (r <= 0.6)
+		self->monsterinfo.currentmove = &makron_move_attack4;
+	else
+		self->monsterinfo.currentmove = &makron_move_attack5;
+}
+
+/*
+---
+Makron Torso. This needs to be spawned in
+---
+*/
+
+void makron_torso_think (edict_t *self)
+{
+	if (++self->s.frame < 365)
+		self->nextthink = level.time + FRAMETIME;
+	else
+	{		
+		self->s.frame = 346;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+void makron_torso (edict_t *ent)
+{
+	ent->movetype = MOVETYPE_NONE;
+	ent->solid = SOLID_NOT;
+	VectorSet (ent->mins, -8, -8, 0);
+	VectorSet (ent->maxs, 8, 8, 8);
+	ent->s.frame = 346;
+	ent->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
+	ent->think = makron_torso_think;
+	ent->nextthink = level.time + 2 * FRAMETIME;
+	ent->s.sound = gi.soundindex ("makron/spine.wav");
+	gi.linkentity (ent);
+}
+
+
+//
+// death
+//
+
+void makron_dead (edict_t *self)
+{
+	VectorSet (self->mins, -60, -60, 0);
+	VectorSet (self->maxs, 60, 60, 72);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+
+void makron_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	edict_t *tempent;
+
+	int		n;
+
+	self->s.sound = 0;
+	// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 1 /*4*/; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
+		ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	tempent = G_Spawn();
+	VectorCopy (self->s.origin, tempent->s.origin);
+	VectorCopy (self->s.angles, tempent->s.angles);
+	tempent->s.origin[1] -= 84;
+	makron_torso (tempent);
+
+	self->monsterinfo.currentmove = &makron_move_death2;
+	
+}
+
+qboolean Makron_CheckAttack (edict_t *self)
+{
+	vec3_t	spot1, spot2;
+	vec3_t	temp;
+	float	chance;
+	trace_t	tr;
+	qboolean	enemy_infront;
+	int			enemy_range;
+	float		enemy_yaw;
+
+	if (self->enemy->health > 0)
+	{
+	// see if any entities are in the way of the shot
+		VectorCopy (self->s.origin, spot1);
+		spot1[2] += self->viewheight;
+		VectorCopy (self->enemy->s.origin, spot2);
+		spot2[2] += self->enemy->viewheight;
+
+		tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
+
+		// do we have a clear shot?
+		if (tr.ent != self->enemy)
+			return false;
+	}
+	
+	enemy_infront = infront(self, self->enemy);
+	enemy_range = range(self, self->enemy);
+	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
+	enemy_yaw = vectoyaw(temp);
+
+	self->ideal_yaw = enemy_yaw;
+
+
+	// melee attack
+	if (enemy_range == RANGE_MELEE)
+	{
+		if (self->monsterinfo.melee)
+			self->monsterinfo.attack_state = AS_MELEE;
+		else
+			self->monsterinfo.attack_state = AS_MISSILE;
+		return true;
+	}
+	
+// missile attack
+	if (!self->monsterinfo.attack)
+		return false;
+		
+	if (level.time < self->monsterinfo.attack_finished)
+		return false;
+		
+	if (enemy_range == RANGE_FAR)
+		return false;
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MELEE)
+	{
+		chance = 0.8;
+	}
+	else if (enemy_range == RANGE_NEAR)
+	{
+		chance = 0.4;
+	}
+	else if (enemy_range == RANGE_MID)
+	{
+		chance = 0.2;
+	}
+	else
+	{
+		return false;
+	}
+
+	if (random () < chance)
+	{
+		self->monsterinfo.attack_state = AS_MISSILE;
+		self->monsterinfo.attack_finished = level.time + 2*random();
+		return true;
+	}
+
+	if (self->flags & FL_FLY)
+	{
+		if (random() < 0.3)
+			self->monsterinfo.attack_state = AS_SLIDING;
+		else
+			self->monsterinfo.attack_state = AS_STRAIGHT;
+	}
+
+	return false;
+}
+
+
+//
+// monster_makron
+//
+
+void MakronPrecache (void)
+{
+	sound_pain4 = gi.soundindex ("makron/pain3.wav");
+	sound_pain5 = gi.soundindex ("makron/pain2.wav");
+	sound_pain6 = gi.soundindex ("makron/pain1.wav");
+	sound_death = gi.soundindex ("makron/death.wav");
+	sound_step_left = gi.soundindex ("makron/step1.wav");
+	sound_step_right = gi.soundindex ("makron/step2.wav");
+	sound_attack_bfg = gi.soundindex ("makron/bfg_fire.wav");
+	sound_brainsplorch = gi.soundindex ("makron/brain1.wav");
+	sound_prerailgun = gi.soundindex ("makron/rail_up.wav");
+	sound_popup = gi.soundindex ("makron/popup.wav");
+	sound_taunt1 = gi.soundindex ("makron/voice4.wav");
+	sound_taunt2 = gi.soundindex ("makron/voice3.wav");
+	sound_taunt3 = gi.soundindex ("makron/voice.wav");
+	sound_hit = gi.soundindex ("makron/bhit.wav");
+
+	gi.modelindex ("models/monsters/boss3/rider/tris.md2");
+}
+
+/*QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_makron (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	MakronPrecache ();
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
+	VectorSet (self->mins, -30, -30, 0);
+	VectorSet (self->maxs, 30, 30, 90);
+
+	self->health = 3000;
+	self->gib_health = -2000;
+	self->mass = 500;
+
+	self->pain = makron_pain;
+	self->die = makron_die;
+	self->monsterinfo.stand = makron_stand;
+	self->monsterinfo.walk = makron_walk;
+	self->monsterinfo.run = makron_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = makron_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = makron_sight;
+	self->monsterinfo.checkattack = Makron_CheckAttack;
+
+	gi.linkentity (self);
+	
+//	self->monsterinfo.currentmove = &makron_move_stand;
+	self->monsterinfo.currentmove = &makron_move_sight;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start(self);
+}
+
+
+/*
+=================
+MakronSpawn
+
+=================
+*/
+void MakronSpawn (edict_t *self)
+{
+	vec3_t		vec;
+	edict_t		*player;
+
+	SP_monster_makron (self);
+
+	// jump at player
+	player = level.sight_client;
+	if (!player)
+		return;
+
+	VectorSubtract (player->s.origin, self->s.origin, vec);
+	self->s.angles[YAW] = vectoyaw(vec);
+	VectorNormalize (vec);
+	VectorMA (vec3_origin, 400, vec, self->velocity);
+	self->velocity[2] = 200;
+	self->groundentity = NULL;
+}
+
+/*
+=================
+MakronToss
+
+Jorg is just about dead, so set up to launch Makron out
+=================
+*/
+void MakronToss (edict_t *self)
+{
+	edict_t	*ent;
+
+	ent = G_Spawn ();
+	ent->nextthink = level.time + 0.8;
+	ent->think = MakronSpawn;
+	ent->target = self->target;
+	VectorCopy (self->s.origin, ent->s.origin);
+}
--- /dev/null
+++ b/game/m_boss32.h
@@ -1,0 +1,516 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/boss3/rider
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_attak101        	0
+#define FRAME_attak102        	1
+#define FRAME_attak103        	2
+#define FRAME_attak104        	3
+#define FRAME_attak105        	4
+#define FRAME_attak106        	5
+#define FRAME_attak107        	6
+#define FRAME_attak108        	7
+#define FRAME_attak109        	8
+#define FRAME_attak110        	9
+#define FRAME_attak111        	10
+#define FRAME_attak112        	11
+#define FRAME_attak113        	12
+#define FRAME_attak114        	13
+#define FRAME_attak115        	14
+#define FRAME_attak116        	15
+#define FRAME_attak117        	16
+#define FRAME_attak118        	17
+#define FRAME_attak201        	18
+#define FRAME_attak202        	19
+#define FRAME_attak203        	20
+#define FRAME_attak204        	21
+#define FRAME_attak205        	22
+#define FRAME_attak206        	23
+#define FRAME_attak207        	24
+#define FRAME_attak208        	25
+#define FRAME_attak209        	26
+#define FRAME_attak210        	27
+#define FRAME_attak211        	28
+#define FRAME_attak212        	29
+#define FRAME_attak213        	30
+#define FRAME_death01         	31
+#define FRAME_death02         	32
+#define FRAME_death03         	33
+#define FRAME_death04         	34
+#define FRAME_death05         	35
+#define FRAME_death06         	36
+#define FRAME_death07         	37
+#define FRAME_death08         	38
+#define FRAME_death09         	39
+#define FRAME_death10         	40
+#define FRAME_death11         	41
+#define FRAME_death12         	42
+#define FRAME_death13         	43
+#define FRAME_death14         	44
+#define FRAME_death15         	45
+#define FRAME_death16         	46
+#define FRAME_death17         	47
+#define FRAME_death18         	48
+#define FRAME_death19         	49
+#define FRAME_death20         	50
+#define FRAME_death21         	51
+#define FRAME_death22         	52
+#define FRAME_death23         	53
+#define FRAME_death24         	54
+#define FRAME_death25         	55
+#define FRAME_death26         	56
+#define FRAME_death27         	57
+#define FRAME_death28         	58
+#define FRAME_death29         	59
+#define FRAME_death30         	60
+#define FRAME_death31         	61
+#define FRAME_death32         	62
+#define FRAME_death33         	63
+#define FRAME_death34         	64
+#define FRAME_death35         	65
+#define FRAME_death36         	66
+#define FRAME_death37         	67
+#define FRAME_death38         	68
+#define FRAME_death39         	69
+#define FRAME_death40         	70
+#define FRAME_death41         	71
+#define FRAME_death42         	72
+#define FRAME_death43         	73
+#define FRAME_death44         	74
+#define FRAME_death45         	75
+#define FRAME_death46         	76
+#define FRAME_death47         	77
+#define FRAME_death48         	78
+#define FRAME_death49         	79
+#define FRAME_death50         	80
+#define FRAME_pain101         	81
+#define FRAME_pain102         	82
+#define FRAME_pain103         	83
+#define FRAME_pain201         	84
+#define FRAME_pain202         	85
+#define FRAME_pain203         	86
+#define FRAME_pain301         	87
+#define FRAME_pain302         	88
+#define FRAME_pain303         	89
+#define FRAME_pain304         	90
+#define FRAME_pain305         	91
+#define FRAME_pain306         	92
+#define FRAME_pain307         	93
+#define FRAME_pain308         	94
+#define FRAME_pain309         	95
+#define FRAME_pain310         	96
+#define FRAME_pain311         	97
+#define FRAME_pain312         	98
+#define FRAME_pain313         	99
+#define FRAME_pain314         	100
+#define FRAME_pain315         	101
+#define FRAME_pain316         	102
+#define FRAME_pain317         	103
+#define FRAME_pain318         	104
+#define FRAME_pain319         	105
+#define FRAME_pain320         	106
+#define FRAME_pain321         	107
+#define FRAME_pain322         	108
+#define FRAME_pain323         	109
+#define FRAME_pain324         	110
+#define FRAME_pain325         	111
+#define FRAME_stand01         	112
+#define FRAME_stand02         	113
+#define FRAME_stand03         	114
+#define FRAME_stand04         	115
+#define FRAME_stand05         	116
+#define FRAME_stand06         	117
+#define FRAME_stand07         	118
+#define FRAME_stand08         	119
+#define FRAME_stand09         	120
+#define FRAME_stand10         	121
+#define FRAME_stand11         	122
+#define FRAME_stand12         	123
+#define FRAME_stand13         	124
+#define FRAME_stand14         	125
+#define FRAME_stand15         	126
+#define FRAME_stand16         	127
+#define FRAME_stand17         	128
+#define FRAME_stand18         	129
+#define FRAME_stand19         	130
+#define FRAME_stand20         	131
+#define FRAME_stand21         	132
+#define FRAME_stand22         	133
+#define FRAME_stand23         	134
+#define FRAME_stand24         	135
+#define FRAME_stand25         	136
+#define FRAME_stand26         	137
+#define FRAME_stand27         	138
+#define FRAME_stand28         	139
+#define FRAME_stand29         	140
+#define FRAME_stand30         	141
+#define FRAME_stand31         	142
+#define FRAME_stand32         	143
+#define FRAME_stand33         	144
+#define FRAME_stand34         	145
+#define FRAME_stand35         	146
+#define FRAME_stand36         	147
+#define FRAME_stand37         	148
+#define FRAME_stand38         	149
+#define FRAME_stand39         	150
+#define FRAME_stand40         	151
+#define FRAME_stand41         	152
+#define FRAME_stand42         	153
+#define FRAME_stand43         	154
+#define FRAME_stand44         	155
+#define FRAME_stand45         	156
+#define FRAME_stand46         	157
+#define FRAME_stand47         	158
+#define FRAME_stand48         	159
+#define FRAME_stand49         	160
+#define FRAME_stand50         	161
+#define FRAME_stand51         	162
+#define FRAME_walk01          	163
+#define FRAME_walk02          	164
+#define FRAME_walk03          	165
+#define FRAME_walk04          	166
+#define FRAME_walk05          	167
+#define FRAME_walk06          	168
+#define FRAME_walk07          	169
+#define FRAME_walk08          	170
+#define FRAME_walk09          	171
+#define FRAME_walk10          	172
+#define FRAME_walk11          	173
+#define FRAME_walk12          	174
+#define FRAME_walk13          	175
+#define FRAME_walk14          	176
+#define FRAME_walk15          	177
+#define FRAME_walk16          	178
+#define FRAME_walk17          	179
+#define FRAME_walk18          	180
+#define FRAME_walk19          	181
+#define FRAME_walk20          	182
+#define FRAME_walk21          	183
+#define FRAME_walk22          	184
+#define FRAME_walk23          	185
+#define FRAME_walk24          	186
+#define FRAME_walk25          	187
+#define FRAME_active01        	188
+#define FRAME_active02        	189
+#define FRAME_active03        	190
+#define FRAME_active04        	191
+#define FRAME_active05        	192
+#define FRAME_active06        	193
+#define FRAME_active07        	194
+#define FRAME_active08        	195
+#define FRAME_active09        	196
+#define FRAME_active10        	197
+#define FRAME_active11        	198
+#define FRAME_active12        	199
+#define FRAME_active13        	200
+#define FRAME_attak301        	201
+#define FRAME_attak302        	202
+#define FRAME_attak303        	203
+#define FRAME_attak304        	204
+#define FRAME_attak305        	205
+#define FRAME_attak306        	206
+#define FRAME_attak307        	207
+#define FRAME_attak308        	208
+#define FRAME_attak401        	209
+#define FRAME_attak402        	210
+#define FRAME_attak403        	211
+#define FRAME_attak404        	212
+#define FRAME_attak405        	213
+#define FRAME_attak406        	214
+#define FRAME_attak407        	215
+#define FRAME_attak408        	216
+#define FRAME_attak409        	217
+#define FRAME_attak410        	218
+#define FRAME_attak411        	219
+#define FRAME_attak412        	220
+#define FRAME_attak413        	221
+#define FRAME_attak414        	222
+#define FRAME_attak415        	223
+#define FRAME_attak416        	224
+#define FRAME_attak417        	225
+#define FRAME_attak418        	226
+#define FRAME_attak419        	227
+#define FRAME_attak420        	228
+#define FRAME_attak421        	229
+#define FRAME_attak422        	230
+#define FRAME_attak423        	231
+#define FRAME_attak424        	232
+#define FRAME_attak425        	233
+#define FRAME_attak426        	234
+#define FRAME_attak501        	235
+#define FRAME_attak502        	236
+#define FRAME_attak503        	237
+#define FRAME_attak504        	238
+#define FRAME_attak505        	239
+#define FRAME_attak506        	240
+#define FRAME_attak507        	241
+#define FRAME_attak508        	242
+#define FRAME_attak509        	243
+#define FRAME_attak510        	244
+#define FRAME_attak511        	245
+#define FRAME_attak512        	246
+#define FRAME_attak513        	247
+#define FRAME_attak514        	248
+#define FRAME_attak515        	249
+#define FRAME_attak516        	250
+#define FRAME_death201        	251
+#define FRAME_death202        	252
+#define FRAME_death203        	253
+#define FRAME_death204        	254
+#define FRAME_death205        	255
+#define FRAME_death206        	256
+#define FRAME_death207        	257
+#define FRAME_death208        	258
+#define FRAME_death209        	259
+#define FRAME_death210        	260
+#define FRAME_death211        	261
+#define FRAME_death212        	262
+#define FRAME_death213        	263
+#define FRAME_death214        	264
+#define FRAME_death215        	265
+#define FRAME_death216        	266
+#define FRAME_death217        	267
+#define FRAME_death218        	268
+#define FRAME_death219        	269
+#define FRAME_death220        	270
+#define FRAME_death221        	271
+#define FRAME_death222        	272
+#define FRAME_death223        	273
+#define FRAME_death224        	274
+#define FRAME_death225        	275
+#define FRAME_death226        	276
+#define FRAME_death227        	277
+#define FRAME_death228        	278
+#define FRAME_death229        	279
+#define FRAME_death230        	280
+#define FRAME_death231        	281
+#define FRAME_death232        	282
+#define FRAME_death233        	283
+#define FRAME_death234        	284
+#define FRAME_death235        	285
+#define FRAME_death236        	286
+#define FRAME_death237        	287
+#define FRAME_death238        	288
+#define FRAME_death239        	289
+#define FRAME_death240        	290
+#define FRAME_death241        	291
+#define FRAME_death242        	292
+#define FRAME_death243        	293
+#define FRAME_death244        	294
+#define FRAME_death245        	295
+#define FRAME_death246        	296
+#define FRAME_death247        	297
+#define FRAME_death248        	298
+#define FRAME_death249        	299
+#define FRAME_death250        	300
+#define FRAME_death251        	301
+#define FRAME_death252        	302
+#define FRAME_death253        	303
+#define FRAME_death254        	304
+#define FRAME_death255        	305
+#define FRAME_death256        	306
+#define FRAME_death257        	307
+#define FRAME_death258        	308
+#define FRAME_death259        	309
+#define FRAME_death260        	310
+#define FRAME_death261        	311
+#define FRAME_death262        	312
+#define FRAME_death263        	313
+#define FRAME_death264        	314
+#define FRAME_death265        	315
+#define FRAME_death266        	316
+#define FRAME_death267        	317
+#define FRAME_death268        	318
+#define FRAME_death269        	319
+#define FRAME_death270        	320
+#define FRAME_death271        	321
+#define FRAME_death272        	322
+#define FRAME_death273        	323
+#define FRAME_death274        	324
+#define FRAME_death275        	325
+#define FRAME_death276        	326
+#define FRAME_death277        	327
+#define FRAME_death278        	328
+#define FRAME_death279        	329
+#define FRAME_death280        	330
+#define FRAME_death281        	331
+#define FRAME_death282        	332
+#define FRAME_death283        	333
+#define FRAME_death284        	334
+#define FRAME_death285        	335
+#define FRAME_death286        	336
+#define FRAME_death287        	337
+#define FRAME_death288        	338
+#define FRAME_death289        	339
+#define FRAME_death290        	340
+#define FRAME_death291        	341
+#define FRAME_death292        	342
+#define FRAME_death293        	343
+#define FRAME_death294        	344
+#define FRAME_death295        	345
+#define FRAME_death301        	346
+#define FRAME_death302        	347
+#define FRAME_death303        	348
+#define FRAME_death304        	349
+#define FRAME_death305        	350
+#define FRAME_death306        	351
+#define FRAME_death307        	352
+#define FRAME_death308        	353
+#define FRAME_death309        	354
+#define FRAME_death310        	355
+#define FRAME_death311        	356
+#define FRAME_death312        	357
+#define FRAME_death313        	358
+#define FRAME_death314        	359
+#define FRAME_death315        	360
+#define FRAME_death316        	361
+#define FRAME_death317        	362
+#define FRAME_death318        	363
+#define FRAME_death319        	364
+#define FRAME_death320        	365
+#define FRAME_jump01          	366
+#define FRAME_jump02          	367
+#define FRAME_jump03          	368
+#define FRAME_jump04          	369
+#define FRAME_jump05          	370
+#define FRAME_jump06          	371
+#define FRAME_jump07          	372
+#define FRAME_jump08          	373
+#define FRAME_jump09          	374
+#define FRAME_jump10          	375
+#define FRAME_jump11          	376
+#define FRAME_jump12          	377
+#define FRAME_jump13          	378
+#define FRAME_pain401         	379
+#define FRAME_pain402         	380
+#define FRAME_pain403         	381
+#define FRAME_pain404         	382
+#define FRAME_pain501         	383
+#define FRAME_pain502         	384
+#define FRAME_pain503         	385
+#define FRAME_pain504         	386
+#define FRAME_pain601         	387
+#define FRAME_pain602         	388
+#define FRAME_pain603         	389
+#define FRAME_pain604         	390
+#define FRAME_pain605         	391
+#define FRAME_pain606         	392
+#define FRAME_pain607         	393
+#define FRAME_pain608         	394
+#define FRAME_pain609         	395
+#define FRAME_pain610         	396
+#define FRAME_pain611         	397
+#define FRAME_pain612         	398
+#define FRAME_pain613         	399
+#define FRAME_pain614         	400
+#define FRAME_pain615         	401
+#define FRAME_pain616         	402
+#define FRAME_pain617         	403
+#define FRAME_pain618         	404
+#define FRAME_pain619         	405
+#define FRAME_pain620         	406
+#define FRAME_pain621         	407
+#define FRAME_pain622         	408
+#define FRAME_pain623         	409
+#define FRAME_pain624         	410
+#define FRAME_pain625         	411
+#define FRAME_pain626         	412
+#define FRAME_pain627         	413
+#define FRAME_stand201        	414
+#define FRAME_stand202        	415
+#define FRAME_stand203        	416
+#define FRAME_stand204        	417
+#define FRAME_stand205        	418
+#define FRAME_stand206        	419
+#define FRAME_stand207        	420
+#define FRAME_stand208        	421
+#define FRAME_stand209        	422
+#define FRAME_stand210        	423
+#define FRAME_stand211        	424
+#define FRAME_stand212        	425
+#define FRAME_stand213        	426
+#define FRAME_stand214        	427
+#define FRAME_stand215        	428
+#define FRAME_stand216        	429
+#define FRAME_stand217        	430
+#define FRAME_stand218        	431
+#define FRAME_stand219        	432
+#define FRAME_stand220        	433
+#define FRAME_stand221        	434
+#define FRAME_stand222        	435
+#define FRAME_stand223        	436
+#define FRAME_stand224        	437
+#define FRAME_stand225        	438
+#define FRAME_stand226        	439
+#define FRAME_stand227        	440
+#define FRAME_stand228        	441
+#define FRAME_stand229        	442
+#define FRAME_stand230        	443
+#define FRAME_stand231        	444
+#define FRAME_stand232        	445
+#define FRAME_stand233        	446
+#define FRAME_stand234        	447
+#define FRAME_stand235        	448
+#define FRAME_stand236        	449
+#define FRAME_stand237        	450
+#define FRAME_stand238        	451
+#define FRAME_stand239        	452
+#define FRAME_stand240        	453
+#define FRAME_stand241        	454
+#define FRAME_stand242        	455
+#define FRAME_stand243        	456
+#define FRAME_stand244        	457
+#define FRAME_stand245        	458
+#define FRAME_stand246        	459
+#define FRAME_stand247        	460
+#define FRAME_stand248        	461
+#define FRAME_stand249        	462
+#define FRAME_stand250        	463
+#define FRAME_stand251        	464
+#define FRAME_stand252        	465
+#define FRAME_stand253        	466
+#define FRAME_stand254        	467
+#define FRAME_stand255        	468
+#define FRAME_stand256        	469
+#define FRAME_stand257        	470
+#define FRAME_stand258        	471
+#define FRAME_stand259        	472
+#define FRAME_stand260        	473
+#define FRAME_walk201         	474
+#define FRAME_walk202         	475
+#define FRAME_walk203         	476
+#define FRAME_walk204         	477
+#define FRAME_walk205         	478
+#define FRAME_walk206         	479
+#define FRAME_walk207         	480
+#define FRAME_walk208         	481
+#define FRAME_walk209         	482
+#define FRAME_walk210         	483
+#define FRAME_walk211         	484
+#define FRAME_walk212         	485
+#define FRAME_walk213         	486
+#define FRAME_walk214         	487
+#define FRAME_walk215         	488
+#define FRAME_walk216         	489
+#define FRAME_walk217         	490
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_brain.c
@@ -1,0 +1,676 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+brain
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_brain.h"
+
+
+static int	sound_chest_open;
+static int	sound_tentacles_extend;
+static int	sound_tentacles_retract;
+static int	sound_death;
+static int	sound_idle1;
+static int	sound_idle2;
+static int	sound_idle3;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_sight;
+static int	sound_search;
+static int	sound_melee1;
+static int	sound_melee2;
+static int	sound_melee3;
+
+
+void brain_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void brain_search (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+}
+
+
+void brain_run (edict_t *self);
+void brain_dead (edict_t *self);
+
+
+//
+// STAND
+//
+
+mframe_t brain_frames_stand [] =
+{
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL
+};
+mmove_t brain_move_stand = {FRAME_stand01, FRAME_stand30, brain_frames_stand, NULL};
+
+void brain_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &brain_move_stand;
+}
+
+
+//
+// IDLE
+//
+
+mframe_t brain_frames_idle [] =
+{
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL
+};
+mmove_t brain_move_idle = {FRAME_stand31, FRAME_stand60, brain_frames_idle, brain_stand};
+
+void brain_idle (edict_t *self)
+{
+	gi.sound (self, CHAN_AUTO, sound_idle3, 1, ATTN_IDLE, 0);
+	self->monsterinfo.currentmove = &brain_move_idle;
+}
+
+
+//
+// WALK
+//
+mframe_t brain_frames_walk1 [] =
+{
+	ai_walk,	7,	NULL,
+	ai_walk,	2,	NULL,
+	ai_walk,	3,	NULL,
+	ai_walk,	3,	NULL,
+	ai_walk,	1,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	9,	NULL,
+	ai_walk,	-4,	NULL,
+	ai_walk,	-1,	NULL,
+	ai_walk,	2,	NULL
+};
+mmove_t brain_move_walk1 = {FRAME_walk101, FRAME_walk111, brain_frames_walk1, NULL};
+
+// walk2 is FUBAR, do not use
+#if 0
+void brain_walk2_cycle (edict_t *self)
+{
+	if (random() > 0.1)
+		self->monsterinfo.nextframe = FRAME_walk220;
+}
+
+mframe_t brain_frames_walk2 [] =
+{
+	ai_walk,	3,	NULL,
+	ai_walk,	-2,	NULL,
+	ai_walk,	-4,	NULL,
+	ai_walk,	-3,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	1,	NULL,
+	ai_walk,	12,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	-3,	NULL,
+	ai_walk,	0,	NULL,
+
+	ai_walk,	-2,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	1,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	10,	NULL,		// Cycle Start
+
+	ai_walk,	-1,	NULL,
+	ai_walk,	7,	NULL,
+	ai_walk,	0,	NULL,
+	ai_walk,	3,	NULL,
+	ai_walk,	-3,	NULL,
+	ai_walk,	2,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	-3,	NULL,
+	ai_walk,	2,	NULL,
+	ai_walk,	0,	NULL,
+
+	ai_walk,	4,	brain_walk2_cycle,
+	ai_walk,	-1,	NULL,
+	ai_walk,	-1,	NULL,
+	ai_walk,	-8,	NULL,		
+	ai_walk,	0,	NULL,
+	ai_walk,	1,	NULL,
+	ai_walk,	5,	NULL,
+	ai_walk,	2,	NULL,
+	ai_walk,	-1,	NULL,
+	ai_walk,	-5,	NULL
+};
+mmove_t brain_move_walk2 = {FRAME_walk201, FRAME_walk240, brain_frames_walk2, NULL};
+#endif
+
+void brain_walk (edict_t *self)
+{
+//	if (random() <= 0.5)
+		self->monsterinfo.currentmove = &brain_move_walk1;
+//	else
+//		self->monsterinfo.currentmove = &brain_move_walk2;
+}
+
+
+
+mframe_t brain_frames_defense [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t brain_move_defense = {FRAME_defens01, FRAME_defens08, brain_frames_defense, NULL};
+
+mframe_t brain_frames_pain3 [] =
+{
+	ai_move,	-2,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-4,	NULL
+};
+mmove_t brain_move_pain3 = {FRAME_pain301, FRAME_pain306, brain_frames_pain3, brain_run};
+
+mframe_t brain_frames_pain2 [] =
+{
+	ai_move,	-2,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	-2,	NULL
+};
+mmove_t brain_move_pain2 = {FRAME_pain201, FRAME_pain208, brain_frames_pain2, brain_run};
+
+mframe_t brain_frames_pain1 [] =
+{
+	ai_move,	-6,	NULL,
+	ai_move,	-2,	NULL,
+	ai_move,	-6,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	7,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	-1,	NULL
+};
+mmove_t brain_move_pain1 = {FRAME_pain101, FRAME_pain121, brain_frames_pain1, brain_run};
+
+
+//
+// DUCK
+//
+
+void brain_duck_down (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_DUCKED)
+		return;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	self->maxs[2] -= 32;
+	self->takedamage = DAMAGE_YES;
+	gi.linkentity (self);
+}
+
+void brain_duck_hold (edict_t *self)
+{
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+void brain_duck_up (edict_t *self)
+{
+	self->monsterinfo.aiflags &= ~AI_DUCKED;
+	self->maxs[2] += 32;
+	self->takedamage = DAMAGE_AIM;
+	gi.linkentity (self);
+}
+
+mframe_t brain_frames_duck [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	-2,	brain_duck_down,
+	ai_move,	17,	brain_duck_hold,
+	ai_move,	-3,	NULL,
+	ai_move,	-1,	brain_duck_up,
+	ai_move,	-5,	NULL,
+	ai_move,	-6,	NULL,
+	ai_move,	-6,	NULL
+};
+mmove_t brain_move_duck = {FRAME_duck01, FRAME_duck08, brain_frames_duck, brain_run};
+
+void brain_dodge (edict_t *self, edict_t *attacker, float eta)
+{
+	if (random() > 0.25)
+		return;
+
+	if (!self->enemy)
+		self->enemy = attacker;
+
+	self->monsterinfo.pausetime = level.time + eta + 0.5;
+	self->monsterinfo.currentmove = &brain_move_duck;
+}
+
+
+mframe_t brain_frames_death2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	9,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t brain_move_death2 = {FRAME_death201, FRAME_death205, brain_frames_death2, brain_dead};
+
+mframe_t brain_frames_death1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-2,	NULL,
+	ai_move,	9,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t brain_move_death1 = {FRAME_death101, FRAME_death118, brain_frames_death1, brain_dead};
+
+
+//
+// MELEE
+//
+
+void brain_swing_right (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_melee1, 1, ATTN_NORM, 0);
+}
+
+void brain_hit_right (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8);
+	if (fire_hit (self, aim, (15 + (rand() %5)), 40))
+		gi.sound (self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0);
+}
+
+void brain_swing_left (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_melee2, 1, ATTN_NORM, 0);
+}
+
+void brain_hit_left (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8);
+	if (fire_hit (self, aim, (15 + (rand() %5)), 40))
+		gi.sound (self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0);
+}
+
+mframe_t brain_frames_attack1 [] =
+{
+	ai_charge,	8,	NULL,
+	ai_charge,	3,	NULL,
+	ai_charge,	5,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	-3,	brain_swing_right,
+	ai_charge,	0,	NULL,
+	ai_charge,	-5,	NULL,
+	ai_charge,	-7,	brain_hit_right,
+	ai_charge,	0,	NULL,
+	ai_charge,	6,	brain_swing_left,
+	ai_charge,	1,	NULL,
+	ai_charge,	2,	brain_hit_left,
+	ai_charge,	-3,	NULL,
+	ai_charge,	6,	NULL,
+	ai_charge,	-1,	NULL,
+	ai_charge,	-3,	NULL,
+	ai_charge,	2,	NULL,
+	ai_charge,	-11,NULL
+};
+mmove_t brain_move_attack1 = {FRAME_attak101, FRAME_attak118, brain_frames_attack1, brain_run};
+
+void brain_chest_open (edict_t *self)
+{
+	self->spawnflags &= ~65536;
+	self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
+	gi.sound (self, CHAN_BODY, sound_chest_open, 1, ATTN_NORM, 0);
+}
+
+void brain_tentacle_attack (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, 0, 8);
+	if (fire_hit (self, aim, (10 + (rand() %5)), -600) && skill->value > 0)
+		self->spawnflags |= 65536;
+	gi.sound (self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0);
+}
+
+void brain_chest_closed (edict_t *self)
+{
+	self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
+	if (self->spawnflags & 65536)
+	{
+		self->spawnflags &= ~65536;
+		self->monsterinfo.currentmove = &brain_move_attack1;
+	}
+}
+
+mframe_t brain_frames_attack2 [] =
+{
+	ai_charge,	5,	NULL,
+	ai_charge,	-4,	NULL,
+	ai_charge,	-4,	NULL,
+	ai_charge,	-3,	NULL,
+	ai_charge,	0,	brain_chest_open,
+	ai_charge,	0,	NULL,
+	ai_charge,	13,	brain_tentacle_attack,
+	ai_charge,	0,	NULL,
+	ai_charge,	2,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	-9,	brain_chest_closed,
+	ai_charge,	0,	NULL,
+	ai_charge,	4,	NULL,
+	ai_charge,	3,	NULL,
+	ai_charge,	2,	NULL,
+	ai_charge,	-3,	NULL,
+	ai_charge,	-6,	NULL
+};
+mmove_t brain_move_attack2 = {FRAME_attak201, FRAME_attak217, brain_frames_attack2, brain_run};
+
+void brain_melee(edict_t *self)
+{
+	if (random() <= 0.5)
+		self->monsterinfo.currentmove = &brain_move_attack1;
+	else
+		self->monsterinfo.currentmove = &brain_move_attack2;
+}
+
+
+//
+// RUN
+//
+
+mframe_t brain_frames_run [] =
+{
+	ai_run,	9,	NULL,
+	ai_run,	2,	NULL,
+	ai_run,	3,	NULL,
+	ai_run,	3,	NULL,
+	ai_run,	1,	NULL,
+	ai_run,	0,	NULL,
+	ai_run,	0,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	-4,	NULL,
+	ai_run,	-1,	NULL,
+	ai_run,	2,	NULL
+};
+mmove_t brain_move_run = {FRAME_walk101, FRAME_walk111, brain_frames_run, NULL};
+
+void brain_run (edict_t *self)
+{
+	self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &brain_move_stand;
+	else
+		self->monsterinfo.currentmove = &brain_move_run;
+}
+
+
+void brain_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	float	r;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	r = random();
+	if (r < 0.33)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &brain_move_pain1;
+	}
+	else if (r < 0.66)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &brain_move_pain2;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &brain_move_pain3;
+	}
+}
+
+void brain_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+
+
+void brain_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	self->s.effects = 0;
+	self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	if (random() <= 0.5)
+		self->monsterinfo.currentmove = &brain_move_death1;
+	else
+		self->monsterinfo.currentmove = &brain_move_death2;
+}
+
+/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_brain (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_chest_open = gi.soundindex ("brain/brnatck1.wav");
+	sound_tentacles_extend = gi.soundindex ("brain/brnatck2.wav");
+	sound_tentacles_retract = gi.soundindex ("brain/brnatck3.wav");
+	sound_death = gi.soundindex ("brain/brndeth1.wav");
+	sound_idle1 = gi.soundindex ("brain/brnidle1.wav");
+	sound_idle2 = gi.soundindex ("brain/brnidle2.wav");
+	sound_idle3 = gi.soundindex ("brain/brnlens1.wav");
+	sound_pain1 = gi.soundindex ("brain/brnpain1.wav");
+	sound_pain2 = gi.soundindex ("brain/brnpain2.wav");
+	sound_sight = gi.soundindex ("brain/brnsght1.wav");
+	sound_search = gi.soundindex ("brain/brnsrch1.wav");
+	sound_melee1 = gi.soundindex ("brain/melee1.wav");
+	sound_melee2 = gi.soundindex ("brain/melee2.wav");
+	sound_melee3 = gi.soundindex ("brain/melee3.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/brain/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	self->health = 300;
+	self->gib_health = -150;
+	self->mass = 400;
+
+	self->pain = brain_pain;
+	self->die = brain_die;
+
+	self->monsterinfo.stand = brain_stand;
+	self->monsterinfo.walk = brain_walk;
+	self->monsterinfo.run = brain_run;
+	self->monsterinfo.dodge = brain_dodge;
+//	self->monsterinfo.attack = brain_attack;
+	self->monsterinfo.melee = brain_melee;
+	self->monsterinfo.sight = brain_sight;
+	self->monsterinfo.search = brain_search;
+	self->monsterinfo.idle = brain_idle;
+
+	self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
+	self->monsterinfo.power_armor_power = 100;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &brain_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_brain.h
@@ -1,0 +1,247 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/brain
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_walk101         	0
+#define FRAME_walk102         	1
+#define FRAME_walk103         	2
+#define FRAME_walk104         	3
+#define FRAME_walk105         	4
+#define FRAME_walk106         	5
+#define FRAME_walk107         	6
+#define FRAME_walk108         	7
+#define FRAME_walk109         	8
+#define FRAME_walk110         	9
+#define FRAME_walk111         	10
+#define FRAME_walk112         	11
+#define FRAME_walk113         	12
+#define FRAME_walk201         	13
+#define FRAME_walk202         	14
+#define FRAME_walk203         	15
+#define FRAME_walk204         	16
+#define FRAME_walk205         	17
+#define FRAME_walk206         	18
+#define FRAME_walk207         	19
+#define FRAME_walk208         	20
+#define FRAME_walk209         	21
+#define FRAME_walk210         	22
+#define FRAME_walk211         	23
+#define FRAME_walk212         	24
+#define FRAME_walk213         	25
+#define FRAME_walk214         	26
+#define FRAME_walk215         	27
+#define FRAME_walk216         	28
+#define FRAME_walk217         	29
+#define FRAME_walk218         	30
+#define FRAME_walk219         	31
+#define FRAME_walk220         	32
+#define FRAME_walk221         	33
+#define FRAME_walk222         	34
+#define FRAME_walk223         	35
+#define FRAME_walk224         	36
+#define FRAME_walk225         	37
+#define FRAME_walk226         	38
+#define FRAME_walk227         	39
+#define FRAME_walk228         	40
+#define FRAME_walk229         	41
+#define FRAME_walk230         	42
+#define FRAME_walk231         	43
+#define FRAME_walk232         	44
+#define FRAME_walk233         	45
+#define FRAME_walk234         	46
+#define FRAME_walk235         	47
+#define FRAME_walk236         	48
+#define FRAME_walk237         	49
+#define FRAME_walk238         	50
+#define FRAME_walk239         	51
+#define FRAME_walk240         	52
+#define FRAME_attak101        	53
+#define FRAME_attak102        	54
+#define FRAME_attak103        	55
+#define FRAME_attak104        	56
+#define FRAME_attak105        	57
+#define FRAME_attak106        	58
+#define FRAME_attak107        	59
+#define FRAME_attak108        	60
+#define FRAME_attak109        	61
+#define FRAME_attak110        	62
+#define FRAME_attak111        	63
+#define FRAME_attak112        	64
+#define FRAME_attak113        	65
+#define FRAME_attak114        	66
+#define FRAME_attak115        	67
+#define FRAME_attak116        	68
+#define FRAME_attak117        	69
+#define FRAME_attak118        	70
+#define FRAME_attak201        	71
+#define FRAME_attak202        	72
+#define FRAME_attak203        	73
+#define FRAME_attak204        	74
+#define FRAME_attak205        	75
+#define FRAME_attak206        	76
+#define FRAME_attak207        	77
+#define FRAME_attak208        	78
+#define FRAME_attak209        	79
+#define FRAME_attak210        	80
+#define FRAME_attak211        	81
+#define FRAME_attak212        	82
+#define FRAME_attak213        	83
+#define FRAME_attak214        	84
+#define FRAME_attak215        	85
+#define FRAME_attak216        	86
+#define FRAME_attak217        	87
+#define FRAME_pain101         	88
+#define FRAME_pain102         	89
+#define FRAME_pain103         	90
+#define FRAME_pain104         	91
+#define FRAME_pain105         	92
+#define FRAME_pain106         	93
+#define FRAME_pain107         	94
+#define FRAME_pain108         	95
+#define FRAME_pain109         	96
+#define FRAME_pain110         	97
+#define FRAME_pain111         	98
+#define FRAME_pain112         	99
+#define FRAME_pain113         	100
+#define FRAME_pain114         	101
+#define FRAME_pain115         	102
+#define FRAME_pain116         	103
+#define FRAME_pain117         	104
+#define FRAME_pain118         	105
+#define FRAME_pain119         	106
+#define FRAME_pain120         	107
+#define FRAME_pain121         	108
+#define FRAME_pain201         	109
+#define FRAME_pain202         	110
+#define FRAME_pain203         	111
+#define FRAME_pain204         	112
+#define FRAME_pain205         	113
+#define FRAME_pain206         	114
+#define FRAME_pain207         	115
+#define FRAME_pain208         	116
+#define FRAME_pain301         	117
+#define FRAME_pain302         	118
+#define FRAME_pain303         	119
+#define FRAME_pain304         	120
+#define FRAME_pain305         	121
+#define FRAME_pain306         	122
+#define FRAME_death101        	123
+#define FRAME_death102        	124
+#define FRAME_death103        	125
+#define FRAME_death104        	126
+#define FRAME_death105        	127
+#define FRAME_death106        	128
+#define FRAME_death107        	129
+#define FRAME_death108        	130
+#define FRAME_death109        	131
+#define FRAME_death110        	132
+#define FRAME_death111        	133
+#define FRAME_death112        	134
+#define FRAME_death113        	135
+#define FRAME_death114        	136
+#define FRAME_death115        	137
+#define FRAME_death116        	138
+#define FRAME_death117        	139
+#define FRAME_death118        	140
+#define FRAME_death201        	141
+#define FRAME_death202        	142
+#define FRAME_death203        	143
+#define FRAME_death204        	144
+#define FRAME_death205        	145
+#define FRAME_duck01          	146
+#define FRAME_duck02          	147
+#define FRAME_duck03          	148
+#define FRAME_duck04          	149
+#define FRAME_duck05          	150
+#define FRAME_duck06          	151
+#define FRAME_duck07          	152
+#define FRAME_duck08          	153
+#define FRAME_defens01        	154
+#define FRAME_defens02        	155
+#define FRAME_defens03        	156
+#define FRAME_defens04        	157
+#define FRAME_defens05        	158
+#define FRAME_defens06        	159
+#define FRAME_defens07        	160
+#define FRAME_defens08        	161
+#define FRAME_stand01         	162
+#define FRAME_stand02         	163
+#define FRAME_stand03         	164
+#define FRAME_stand04         	165
+#define FRAME_stand05         	166
+#define FRAME_stand06         	167
+#define FRAME_stand07         	168
+#define FRAME_stand08         	169
+#define FRAME_stand09         	170
+#define FRAME_stand10         	171
+#define FRAME_stand11         	172
+#define FRAME_stand12         	173
+#define FRAME_stand13         	174
+#define FRAME_stand14         	175
+#define FRAME_stand15         	176
+#define FRAME_stand16         	177
+#define FRAME_stand17         	178
+#define FRAME_stand18         	179
+#define FRAME_stand19         	180
+#define FRAME_stand20         	181
+#define FRAME_stand21         	182
+#define FRAME_stand22         	183
+#define FRAME_stand23         	184
+#define FRAME_stand24         	185
+#define FRAME_stand25         	186
+#define FRAME_stand26         	187
+#define FRAME_stand27         	188
+#define FRAME_stand28         	189
+#define FRAME_stand29         	190
+#define FRAME_stand30         	191
+#define FRAME_stand31         	192
+#define FRAME_stand32         	193
+#define FRAME_stand33         	194
+#define FRAME_stand34         	195
+#define FRAME_stand35         	196
+#define FRAME_stand36         	197
+#define FRAME_stand37         	198
+#define FRAME_stand38         	199
+#define FRAME_stand39         	200
+#define FRAME_stand40         	201
+#define FRAME_stand41         	202
+#define FRAME_stand42         	203
+#define FRAME_stand43         	204
+#define FRAME_stand44         	205
+#define FRAME_stand45         	206
+#define FRAME_stand46         	207
+#define FRAME_stand47         	208
+#define FRAME_stand48         	209
+#define FRAME_stand49         	210
+#define FRAME_stand50         	211
+#define FRAME_stand51         	212
+#define FRAME_stand52         	213
+#define FRAME_stand53         	214
+#define FRAME_stand54         	215
+#define FRAME_stand55         	216
+#define FRAME_stand56         	217
+#define FRAME_stand57         	218
+#define FRAME_stand58         	219
+#define FRAME_stand59         	220
+#define FRAME_stand60         	221
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_chick.c
@@ -1,0 +1,677 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+chick
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_chick.h"
+
+qboolean visible (edict_t *self, edict_t *other);
+
+void chick_stand (edict_t *self);
+void chick_run (edict_t *self);
+void chick_reslash(edict_t *self);
+void chick_rerocket(edict_t *self);
+void chick_attack1(edict_t *self);
+
+static int	sound_missile_prelaunch;
+static int	sound_missile_launch;
+static int	sound_melee_swing;
+static int	sound_melee_hit;
+static int	sound_missile_reload;
+static int	sound_death1;
+static int	sound_death2;
+static int	sound_fall_down;
+static int	sound_idle1;
+static int	sound_idle2;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_pain3;
+static int	sound_sight;
+static int	sound_search;
+
+
+void ChickMoan (edict_t *self)
+{
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_idle2, 1, ATTN_IDLE, 0);
+}
+
+mframe_t chick_frames_fidget [] =
+{
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  ChickMoan,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL
+};
+mmove_t chick_move_fidget = {FRAME_stand201, FRAME_stand230, chick_frames_fidget, chick_stand};
+
+void chick_fidget (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		return;
+	if (random() <= 0.3)
+		self->monsterinfo.currentmove = &chick_move_fidget;
+}
+
+mframe_t chick_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, chick_fidget,
+
+};
+mmove_t chick_move_stand = {FRAME_stand101, FRAME_stand130, chick_frames_stand, NULL};
+
+void chick_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &chick_move_stand;
+}
+
+mframe_t chick_frames_start_run [] =
+{
+	ai_run, 1,  NULL,
+	ai_run, 0,  NULL,
+	ai_run, 0,	 NULL,
+	ai_run, -1, NULL, 
+	ai_run, -1, NULL, 
+	ai_run, 0,  NULL,
+	ai_run, 1,  NULL,
+	ai_run, 3,  NULL,
+	ai_run, 6,	 NULL,
+	ai_run, 3,	 NULL
+};
+mmove_t chick_move_start_run = {FRAME_walk01, FRAME_walk10, chick_frames_start_run, chick_run};
+
+mframe_t chick_frames_run [] =
+{
+	ai_run, 6,	NULL,
+	ai_run, 8,  NULL,
+	ai_run, 13, NULL,
+	ai_run, 5,  NULL,
+	ai_run, 7,  NULL,
+	ai_run, 4,  NULL,
+	ai_run, 11, NULL,
+	ai_run, 5,  NULL,
+	ai_run, 9,  NULL,
+	ai_run, 7,  NULL
+
+};
+
+mmove_t chick_move_run = {FRAME_walk11, FRAME_walk20, chick_frames_run, NULL};
+
+mframe_t chick_frames_walk [] =
+{
+	ai_walk, 6,	 NULL,
+	ai_walk, 8,  NULL,
+	ai_walk, 13, NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 7,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 11, NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 9,  NULL,
+	ai_walk, 7,  NULL
+};
+
+mmove_t chick_move_walk = {FRAME_walk11, FRAME_walk20, chick_frames_walk, NULL};
+
+void chick_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &chick_move_walk;
+}
+
+void chick_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		self->monsterinfo.currentmove = &chick_move_stand;
+		return;
+	}
+
+	if (self->monsterinfo.currentmove == &chick_move_walk ||
+		self->monsterinfo.currentmove == &chick_move_start_run)
+	{
+		self->monsterinfo.currentmove = &chick_move_run;
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &chick_move_start_run;
+	}
+}
+
+mframe_t chick_frames_pain1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t chick_move_pain1 = {FRAME_pain101, FRAME_pain105, chick_frames_pain1, chick_run};
+
+mframe_t chick_frames_pain2 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t chick_move_pain2 = {FRAME_pain201, FRAME_pain205, chick_frames_pain2, chick_run};
+
+mframe_t chick_frames_pain3 [] =
+{
+	ai_move, 0,		NULL,
+	ai_move, 0,		NULL,
+	ai_move, -6,	NULL,
+	ai_move, 3,		NULL,
+	ai_move, 11,	NULL,
+	ai_move, 3,		NULL,
+	ai_move, 0,		NULL,
+	ai_move, 0,		NULL,
+	ai_move, 4,		NULL,
+	ai_move, 1,		NULL,
+	ai_move, 0,		NULL,
+	ai_move, -3,	NULL,
+	ai_move, -4,	NULL,
+	ai_move, 5,		NULL,
+	ai_move, 7,		NULL,
+	ai_move, -2,	NULL,
+	ai_move, 3,		NULL,
+	ai_move, -5,	NULL,
+	ai_move, -2,	NULL,
+	ai_move, -8,	NULL,
+	ai_move, 2,		NULL
+};
+mmove_t chick_move_pain3 = {FRAME_pain301, FRAME_pain321, chick_frames_pain3, chick_run};
+
+void chick_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	float	r;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	r = random();
+	if (r < 0.33)
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+	else if (r < 0.66)
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (damage <= 10)
+		self->monsterinfo.currentmove = &chick_move_pain1;
+	else if (damage <= 25)
+		self->monsterinfo.currentmove = &chick_move_pain2;
+	else
+		self->monsterinfo.currentmove = &chick_move_pain3;
+}
+
+void chick_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 16);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t chick_frames_death2 [] =
+{
+	ai_move, -6, NULL,
+	ai_move, 0,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, -5, NULL,
+	ai_move, 0, NULL,
+	ai_move, -1,  NULL,
+	ai_move, -2,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 10, NULL,
+	ai_move, 2,  NULL,
+	ai_move, 3,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 2, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 3,  NULL,
+	ai_move, 3,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, -3,  NULL,
+	ai_move, -5, NULL,
+	ai_move, 4, NULL,
+	ai_move, 15, NULL,
+	ai_move, 14, NULL,
+	ai_move, 1, NULL
+};
+mmove_t chick_move_death2 = {FRAME_death201, FRAME_death223, chick_frames_death2, chick_dead};
+
+mframe_t chick_frames_death1 [] =
+{
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, -7, NULL,
+	ai_move, 4,  NULL,
+	ai_move, 11, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL
+	
+};
+mmove_t chick_move_death1 = {FRAME_death101, FRAME_death112, chick_frames_death1, chick_dead};
+
+void chick_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	n = rand() % 2;
+	if (n == 0)
+	{
+		self->monsterinfo.currentmove = &chick_move_death1;
+		gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &chick_move_death2;
+		gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
+	}
+}
+
+
+void chick_duck_down (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_DUCKED)
+		return;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	self->maxs[2] -= 32;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.pausetime = level.time + 1;
+	gi.linkentity (self);
+}
+
+void chick_duck_hold (edict_t *self)
+{
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+void chick_duck_up (edict_t *self)
+{
+	self->monsterinfo.aiflags &= ~AI_DUCKED;
+	self->maxs[2] += 32;
+	self->takedamage = DAMAGE_AIM;
+	gi.linkentity (self);
+}
+
+mframe_t chick_frames_duck [] =
+{
+	ai_move, 0, chick_duck_down,
+	ai_move, 1, NULL,
+	ai_move, 4, chick_duck_hold,
+	ai_move, -4,  NULL,
+	ai_move, -5,  chick_duck_up,
+	ai_move, 3, NULL,
+	ai_move, 1,  NULL
+};
+mmove_t chick_move_duck = {FRAME_duck01, FRAME_duck07, chick_frames_duck, chick_run};
+
+void chick_dodge (edict_t *self, edict_t *attacker, float eta)
+{
+	if (random() > 0.25)
+		return;
+
+	if (!self->enemy)
+		self->enemy = attacker;
+
+	self->monsterinfo.currentmove = &chick_move_duck;
+}
+
+void ChickSlash (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->mins[0], 10);
+	gi.sound (self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0);
+	fire_hit (self, aim, (10 + (rand() %6)), 100);
+}
+
+
+void ChickRocket (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CHICK_ROCKET_1], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+
+	monster_fire_rocket (self, start, dir, 50, 500, MZ2_CHICK_ROCKET_1);
+}	
+
+void Chick_PreAttack1 (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_missile_prelaunch, 1, ATTN_NORM, 0);
+}
+
+void ChickReload (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0);
+}
+
+
+mframe_t chick_frames_start_attack1 [] =
+{
+	ai_charge, 0,	Chick_PreAttack1,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 4,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, -3,  NULL,
+	ai_charge, 3,	NULL,
+	ai_charge, 5,	NULL,
+	ai_charge, 7,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	chick_attack1
+};
+mmove_t chick_move_start_attack1 = {FRAME_attak101, FRAME_attak113, chick_frames_start_attack1, NULL};
+
+
+mframe_t chick_frames_attack1 [] =
+{
+	ai_charge, 19,	ChickRocket,
+	ai_charge, -6,	NULL,
+	ai_charge, -5,	NULL,
+	ai_charge, -2,	NULL,
+	ai_charge, -7,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, 10,	ChickReload,
+	ai_charge, 4,	NULL,
+	ai_charge, 5,	NULL,
+	ai_charge, 6,	NULL,
+	ai_charge, 6,	NULL,
+	ai_charge, 4,	NULL,
+	ai_charge, 3,	chick_rerocket
+
+};
+mmove_t chick_move_attack1 = {FRAME_attak114, FRAME_attak127, chick_frames_attack1, NULL};
+
+mframe_t chick_frames_end_attack1 [] =
+{
+	ai_charge, -3,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, -6,	NULL,
+	ai_charge, -4,	NULL,
+	ai_charge, -2,  NULL
+};
+mmove_t chick_move_end_attack1 = {FRAME_attak128, FRAME_attak132, chick_frames_end_attack1, chick_run};
+
+void chick_rerocket(edict_t *self)
+{
+	if (self->enemy->health > 0)
+	{
+		if (range (self, self->enemy) > RANGE_MELEE)
+			if ( visible (self, self->enemy) )
+				if (random() <= 0.6)
+				{
+					self->monsterinfo.currentmove = &chick_move_attack1;
+					return;
+				}
+	}	
+	self->monsterinfo.currentmove = &chick_move_end_attack1;
+}
+
+void chick_attack1(edict_t *self)
+{
+	self->monsterinfo.currentmove = &chick_move_attack1;
+}
+
+mframe_t chick_frames_slash [] =
+{
+	ai_charge, 1,	NULL,
+	ai_charge, 7,	ChickSlash,
+	ai_charge, -7,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, -1,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, -2,	chick_reslash
+};
+mmove_t chick_move_slash = {FRAME_attak204, FRAME_attak212, chick_frames_slash, NULL};
+
+mframe_t chick_frames_end_slash [] =
+{
+	ai_charge, -6,	NULL,
+	ai_charge, -1,	NULL,
+	ai_charge, -6,	NULL,
+	ai_charge, 0,	NULL
+};
+mmove_t chick_move_end_slash = {FRAME_attak213, FRAME_attak216, chick_frames_end_slash, chick_run};
+
+
+void chick_reslash(edict_t *self)
+{
+	if (self->enemy->health > 0)
+	{
+		if (range (self, self->enemy) == RANGE_MELEE)
+			if (random() <= 0.9)
+			{				
+				self->monsterinfo.currentmove = &chick_move_slash;
+				return;
+			}
+			else
+			{
+				self->monsterinfo.currentmove = &chick_move_end_slash;
+				return;
+			}
+	}
+	self->monsterinfo.currentmove = &chick_move_end_slash;
+}
+
+void chick_slash(edict_t *self)
+{
+	self->monsterinfo.currentmove = &chick_move_slash;
+}
+
+
+mframe_t chick_frames_start_slash [] =
+{	
+	ai_charge, 1,	NULL,
+	ai_charge, 8,	NULL,
+	ai_charge, 3,	NULL
+};
+mmove_t chick_move_start_slash = {FRAME_attak201, FRAME_attak203, chick_frames_start_slash, chick_slash};
+
+
+
+void chick_melee(edict_t *self)
+{
+	self->monsterinfo.currentmove = &chick_move_start_slash;
+}
+
+
+void chick_attack(edict_t *self)
+{
+	self->monsterinfo.currentmove = &chick_move_start_attack1;
+}
+
+void chick_sight(edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+/*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_chick (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_missile_prelaunch	= gi.soundindex ("chick/chkatck1.wav");	
+	sound_missile_launch	= gi.soundindex ("chick/chkatck2.wav");	
+	sound_melee_swing		= gi.soundindex ("chick/chkatck3.wav");	
+	sound_melee_hit			= gi.soundindex ("chick/chkatck4.wav");	
+	sound_missile_reload	= gi.soundindex ("chick/chkatck5.wav");	
+	sound_death1			= gi.soundindex ("chick/chkdeth1.wav");	
+	sound_death2			= gi.soundindex ("chick/chkdeth2.wav");	
+	sound_fall_down			= gi.soundindex ("chick/chkfall1.wav");	
+	sound_idle1				= gi.soundindex ("chick/chkidle1.wav");	
+	sound_idle2				= gi.soundindex ("chick/chkidle2.wav");	
+	sound_pain1				= gi.soundindex ("chick/chkpain1.wav");	
+	sound_pain2				= gi.soundindex ("chick/chkpain2.wav");	
+	sound_pain3				= gi.soundindex ("chick/chkpain3.wav");	
+	sound_sight				= gi.soundindex ("chick/chksght1.wav");	
+	sound_search			= gi.soundindex ("chick/chksrch1.wav");	
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 56);
+
+	self->health = 175;
+	self->gib_health = -70;
+	self->mass = 200;
+
+	self->pain = chick_pain;
+	self->die = chick_die;
+
+	self->monsterinfo.stand = chick_stand;
+	self->monsterinfo.walk = chick_walk;
+	self->monsterinfo.run = chick_run;
+	self->monsterinfo.dodge = chick_dodge;
+	self->monsterinfo.attack = chick_attack;
+	self->monsterinfo.melee = chick_melee;
+	self->monsterinfo.sight = chick_sight;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &chick_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_chick.h
@@ -1,0 +1,313 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/bitch
+
+// This file generated by qdata - Do NOT Modify
+
+#define FRAME_attak101        	0
+#define FRAME_attak102        	1
+#define FRAME_attak103        	2
+#define FRAME_attak104        	3
+#define FRAME_attak105        	4
+#define FRAME_attak106        	5
+#define FRAME_attak107        	6
+#define FRAME_attak108        	7
+#define FRAME_attak109        	8
+#define FRAME_attak110        	9
+#define FRAME_attak111        	10
+#define FRAME_attak112        	11
+#define FRAME_attak113        	12
+#define FRAME_attak114        	13
+#define FRAME_attak115        	14
+#define FRAME_attak116        	15
+#define FRAME_attak117        	16
+#define FRAME_attak118        	17
+#define FRAME_attak119        	18
+#define FRAME_attak120        	19
+#define FRAME_attak121        	20
+#define FRAME_attak122        	21
+#define FRAME_attak123        	22
+#define FRAME_attak124        	23
+#define FRAME_attak125        	24
+#define FRAME_attak126        	25
+#define FRAME_attak127        	26
+#define FRAME_attak128        	27
+#define FRAME_attak129        	28
+#define FRAME_attak130        	29
+#define FRAME_attak131        	30
+#define FRAME_attak132        	31
+#define FRAME_attak201        	32
+#define FRAME_attak202        	33
+#define FRAME_attak203        	34
+#define FRAME_attak204        	35
+#define FRAME_attak205        	36
+#define FRAME_attak206        	37
+#define FRAME_attak207        	38
+#define FRAME_attak208        	39
+#define FRAME_attak209        	40
+#define FRAME_attak210        	41
+#define FRAME_attak211        	42
+#define FRAME_attak212        	43
+#define FRAME_attak213        	44
+#define FRAME_attak214        	45
+#define FRAME_attak215        	46
+#define FRAME_attak216        	47
+#define FRAME_death101        	48
+#define FRAME_death102        	49
+#define FRAME_death103        	50
+#define FRAME_death104        	51
+#define FRAME_death105        	52
+#define FRAME_death106        	53
+#define FRAME_death107        	54
+#define FRAME_death108        	55
+#define FRAME_death109        	56
+#define FRAME_death110        	57
+#define FRAME_death111        	58
+#define FRAME_death112        	59
+#define FRAME_death201        	60
+#define FRAME_death202        	61
+#define FRAME_death203        	62
+#define FRAME_death204        	63
+#define FRAME_death205        	64
+#define FRAME_death206        	65
+#define FRAME_death207        	66
+#define FRAME_death208        	67
+#define FRAME_death209        	68
+#define FRAME_death210        	69
+#define FRAME_death211        	70
+#define FRAME_death212        	71
+#define FRAME_death213        	72
+#define FRAME_death214        	73
+#define FRAME_death215        	74
+#define FRAME_death216        	75
+#define FRAME_death217        	76
+#define FRAME_death218        	77
+#define FRAME_death219        	78
+#define FRAME_death220        	79
+#define FRAME_death221        	80
+#define FRAME_death222        	81
+#define FRAME_death223        	82
+#define FRAME_duck01          	83
+#define FRAME_duck02          	84
+#define FRAME_duck03          	85
+#define FRAME_duck04          	86
+#define FRAME_duck05          	87
+#define FRAME_duck06          	88
+#define FRAME_duck07          	89
+#define FRAME_pain101         	90
+#define FRAME_pain102         	91
+#define FRAME_pain103         	92
+#define FRAME_pain104         	93
+#define FRAME_pain105         	94
+#define FRAME_pain201         	95
+#define FRAME_pain202         	96
+#define FRAME_pain203         	97
+#define FRAME_pain204         	98
+#define FRAME_pain205         	99
+#define FRAME_pain301         	100
+#define FRAME_pain302         	101
+#define FRAME_pain303         	102
+#define FRAME_pain304         	103
+#define FRAME_pain305         	104
+#define FRAME_pain306         	105
+#define FRAME_pain307         	106
+#define FRAME_pain308         	107
+#define FRAME_pain309         	108
+#define FRAME_pain310         	109
+#define FRAME_pain311         	110
+#define FRAME_pain312         	111
+#define FRAME_pain313         	112
+#define FRAME_pain314         	113
+#define FRAME_pain315         	114
+#define FRAME_pain316         	115
+#define FRAME_pain317         	116
+#define FRAME_pain318         	117
+#define FRAME_pain319         	118
+#define FRAME_pain320         	119
+#define FRAME_pain321         	120
+#define FRAME_stand101        	121
+#define FRAME_stand102        	122
+#define FRAME_stand103        	123
+#define FRAME_stand104        	124
+#define FRAME_stand105        	125
+#define FRAME_stand106        	126
+#define FRAME_stand107        	127
+#define FRAME_stand108        	128
+#define FRAME_stand109        	129
+#define FRAME_stand110        	130
+#define FRAME_stand111        	131
+#define FRAME_stand112        	132
+#define FRAME_stand113        	133
+#define FRAME_stand114        	134
+#define FRAME_stand115        	135
+#define FRAME_stand116        	136
+#define FRAME_stand117        	137
+#define FRAME_stand118        	138
+#define FRAME_stand119        	139
+#define FRAME_stand120        	140
+#define FRAME_stand121        	141
+#define FRAME_stand122        	142
+#define FRAME_stand123        	143
+#define FRAME_stand124        	144
+#define FRAME_stand125        	145
+#define FRAME_stand126        	146
+#define FRAME_stand127        	147
+#define FRAME_stand128        	148
+#define FRAME_stand129        	149
+#define FRAME_stand130        	150
+#define FRAME_stand201        	151
+#define FRAME_stand202        	152
+#define FRAME_stand203        	153
+#define FRAME_stand204        	154
+#define FRAME_stand205        	155
+#define FRAME_stand206        	156
+#define FRAME_stand207        	157
+#define FRAME_stand208        	158
+#define FRAME_stand209        	159
+#define FRAME_stand210        	160
+#define FRAME_stand211        	161
+#define FRAME_stand212        	162
+#define FRAME_stand213        	163
+#define FRAME_stand214        	164
+#define FRAME_stand215        	165
+#define FRAME_stand216        	166
+#define FRAME_stand217        	167
+#define FRAME_stand218        	168
+#define FRAME_stand219        	169
+#define FRAME_stand220        	170
+#define FRAME_stand221        	171
+#define FRAME_stand222        	172
+#define FRAME_stand223        	173
+#define FRAME_stand224        	174
+#define FRAME_stand225        	175
+#define FRAME_stand226        	176
+#define FRAME_stand227        	177
+#define FRAME_stand228        	178
+#define FRAME_stand229        	179
+#define FRAME_stand230        	180
+#define FRAME_walk01          	181
+#define FRAME_walk02          	182
+#define FRAME_walk03          	183
+#define FRAME_walk04          	184
+#define FRAME_walk05          	185
+#define FRAME_walk06          	186
+#define FRAME_walk07          	187
+#define FRAME_walk08          	188
+#define FRAME_walk09          	189
+#define FRAME_walk10          	190
+#define FRAME_walk11          	191
+#define FRAME_walk12          	192
+#define FRAME_walk13          	193
+#define FRAME_walk14          	194
+#define FRAME_walk15          	195
+#define FRAME_walk16          	196
+#define FRAME_walk17          	197
+#define FRAME_walk18          	198
+#define FRAME_walk19          	199
+#define FRAME_walk20          	200
+#define FRAME_walk21          	201
+#define FRAME_walk22          	202
+#define FRAME_walk23          	203
+#define FRAME_walk24          	204
+#define FRAME_walk25          	205
+#define FRAME_walk26          	206
+#define FRAME_walk27          	207
+#define FRAME_recln201        	208
+#define FRAME_recln202        	209
+#define FRAME_recln203        	210
+#define FRAME_recln204        	211
+#define FRAME_recln205        	212
+#define FRAME_recln206        	213
+#define FRAME_recln207        	214
+#define FRAME_recln208        	215
+#define FRAME_recln209        	216
+#define FRAME_recln210        	217
+#define FRAME_recln211        	218
+#define FRAME_recln212        	219
+#define FRAME_recln213        	220
+#define FRAME_recln214        	221
+#define FRAME_recln215        	222
+#define FRAME_recln216        	223
+#define FRAME_recln217        	224
+#define FRAME_recln218        	225
+#define FRAME_recln219        	226
+#define FRAME_recln220        	227
+#define FRAME_recln221        	228
+#define FRAME_recln222        	229
+#define FRAME_recln223        	230
+#define FRAME_recln224        	231
+#define FRAME_recln225        	232
+#define FRAME_recln226        	233
+#define FRAME_recln227        	234
+#define FRAME_recln228        	235
+#define FRAME_recln229        	236
+#define FRAME_recln230        	237
+#define FRAME_recln231        	238
+#define FRAME_recln232        	239
+#define FRAME_recln233        	240
+#define FRAME_recln234        	241
+#define FRAME_recln235        	242
+#define FRAME_recln236        	243
+#define FRAME_recln237        	244
+#define FRAME_recln238        	245
+#define FRAME_recln239        	246
+#define FRAME_recln240        	247
+#define FRAME_recln101        	248
+#define FRAME_recln102        	249
+#define FRAME_recln103        	250
+#define FRAME_recln104        	251
+#define FRAME_recln105        	252
+#define FRAME_recln106        	253
+#define FRAME_recln107        	254
+#define FRAME_recln108        	255
+#define FRAME_recln109        	256
+#define FRAME_recln110        	257
+#define FRAME_recln111        	258
+#define FRAME_recln112        	259
+#define FRAME_recln113        	260
+#define FRAME_recln114        	261
+#define FRAME_recln115        	262
+#define FRAME_recln116        	263
+#define FRAME_recln117        	264
+#define FRAME_recln118        	265
+#define FRAME_recln119        	266
+#define FRAME_recln120        	267
+#define FRAME_recln121        	268
+#define FRAME_recln122        	269
+#define FRAME_recln123        	270
+#define FRAME_recln124        	271
+#define FRAME_recln125        	272
+#define FRAME_recln126        	273
+#define FRAME_recln127        	274
+#define FRAME_recln128        	275
+#define FRAME_recln129        	276
+#define FRAME_recln130        	277
+#define FRAME_recln131        	278
+#define FRAME_recln132        	279
+#define FRAME_recln133        	280
+#define FRAME_recln134        	281
+#define FRAME_recln135        	282
+#define FRAME_recln136        	283
+#define FRAME_recln137        	284
+#define FRAME_recln138        	285
+#define FRAME_recln139        	286
+#define FRAME_recln140        	287
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_flash.c
@@ -1,0 +1,488 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// m_flash.c
+
+#include "q_shared.h"
+
+// this file is included in both the game dll and quake2,
+// the game needs it to source shot locations, the client
+// needs it to position muzzle flashes
+vec3_t monster_flash_offset [] =
+{
+// flash 0 is not used
+	0.0, 0.0, 0.0,
+
+// MZ2_TANK_BLASTER_1				1
+	20.7, -18.5, 28.7,
+// MZ2_TANK_BLASTER_2				2
+	16.6, -21.5, 30.1,
+// MZ2_TANK_BLASTER_3				3
+	11.8, -23.9, 32.1,
+// MZ2_TANK_MACHINEGUN_1			4
+	22.9, -0.7, 25.3,
+// MZ2_TANK_MACHINEGUN_2			5
+	22.2, 6.2, 22.3,
+// MZ2_TANK_MACHINEGUN_3			6
+	19.4, 13.1, 18.6,
+// MZ2_TANK_MACHINEGUN_4			7
+	19.4, 18.8, 18.6,
+// MZ2_TANK_MACHINEGUN_5			8
+	17.9, 25.0, 18.6,
+// MZ2_TANK_MACHINEGUN_6			9
+	14.1, 30.5, 20.6,
+// MZ2_TANK_MACHINEGUN_7			10
+	9.3, 35.3, 22.1,
+// MZ2_TANK_MACHINEGUN_8			11
+	4.7, 38.4, 22.1,
+// MZ2_TANK_MACHINEGUN_9			12
+	-1.1, 40.4, 24.1,
+// MZ2_TANK_MACHINEGUN_10			13
+	-6.5, 41.2, 24.1,
+// MZ2_TANK_MACHINEGUN_11			14
+	3.2, 40.1, 24.7,
+// MZ2_TANK_MACHINEGUN_12			15
+	11.7, 36.7, 26.0,
+// MZ2_TANK_MACHINEGUN_13			16
+	18.9, 31.3, 26.0,
+// MZ2_TANK_MACHINEGUN_14			17
+	24.4, 24.4, 26.4,
+// MZ2_TANK_MACHINEGUN_15			18
+	27.1, 17.1, 27.2,
+// MZ2_TANK_MACHINEGUN_16			19
+	28.5, 9.1, 28.0,
+// MZ2_TANK_MACHINEGUN_17			20
+	27.1, 2.2, 28.0,
+// MZ2_TANK_MACHINEGUN_18			21
+	24.9, -2.8, 28.0,
+// MZ2_TANK_MACHINEGUN_19			22
+	21.6, -7.0, 26.4,
+// MZ2_TANK_ROCKET_1				23
+	6.2, 29.1, 49.1,
+// MZ2_TANK_ROCKET_2				24
+	6.9, 23.8, 49.1,
+// MZ2_TANK_ROCKET_3				25
+	8.3, 17.8, 49.5,
+
+// MZ2_INFANTRY_MACHINEGUN_1		26
+	26.6, 7.1, 13.1,
+// MZ2_INFANTRY_MACHINEGUN_2		27
+	18.2, 7.5, 15.4,
+// MZ2_INFANTRY_MACHINEGUN_3		28
+	17.2, 10.3, 17.9,
+// MZ2_INFANTRY_MACHINEGUN_4		29
+	17.0, 12.8, 20.1,
+// MZ2_INFANTRY_MACHINEGUN_5		30
+	15.1, 14.1, 21.8,
+// MZ2_INFANTRY_MACHINEGUN_6		31
+	11.8, 17.2, 23.1,
+// MZ2_INFANTRY_MACHINEGUN_7		32
+	11.4, 20.2, 21.0,
+// MZ2_INFANTRY_MACHINEGUN_8		33
+	9.0, 23.0, 18.9,
+// MZ2_INFANTRY_MACHINEGUN_9		34
+	13.9, 18.6, 17.7,
+// MZ2_INFANTRY_MACHINEGUN_10		35
+	15.4, 15.6, 15.8,
+// MZ2_INFANTRY_MACHINEGUN_11		36
+	10.2, 15.2, 25.1,
+// MZ2_INFANTRY_MACHINEGUN_12		37
+	-1.9, 15.1, 28.2,
+// MZ2_INFANTRY_MACHINEGUN_13		38
+	-12.4, 13.0, 20.2,
+
+// MZ2_SOLDIER_BLASTER_1			39
+	10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2,
+// MZ2_SOLDIER_BLASTER_2			40
+	21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_1			41
+	10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_2			42
+	21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_1			43
+	10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_2			44
+	21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2,
+
+// MZ2_GUNNER_MACHINEGUN_1			45
+	30.1 * 1.15, 3.9 * 1.15, 19.6 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_2			46
+	29.1 * 1.15, 2.5 * 1.15, 20.7 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_3			47
+	28.2 * 1.15, 2.5 * 1.15, 22.2 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_4			48
+	28.2 * 1.15, 3.6 * 1.15, 22.0 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_5			49
+	26.9 * 1.15, 2.0 * 1.15, 23.4 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_6			50
+	26.5 * 1.15, 0.6 * 1.15, 20.8 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_7			51
+	26.9 * 1.15, 0.5 * 1.15, 21.5 * 1.15,
+// MZ2_GUNNER_MACHINEGUN_8			52
+	29.0 * 1.15, 2.4 * 1.15, 19.5 * 1.15,
+// MZ2_GUNNER_GRENADE_1				53
+	4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
+// MZ2_GUNNER_GRENADE_2				54
+	4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
+// MZ2_GUNNER_GRENADE_3				55
+	4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
+// MZ2_GUNNER_GRENADE_4				56
+	4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15,
+
+// MZ2_CHICK_ROCKET_1				57
+//	-24.8, -9.0, 39.0,
+	24.8, -9.0, 39.0,			// PGM - this was incorrect in Q2
+
+// MZ2_FLYER_BLASTER_1				58
+	12.1, 13.4, -14.5,
+// MZ2_FLYER_BLASTER_2				59
+	12.1, -7.4, -14.5,
+
+// MZ2_MEDIC_BLASTER_1				60
+	12.1, 5.4, 16.5,
+
+// MZ2_GLADIATOR_RAILGUN_1			61
+	30.0, 18.0, 28.0,
+
+// MZ2_HOVER_BLASTER_1				62
+	32.5, -0.8, 10.0,
+
+// MZ2_ACTOR_MACHINEGUN_1			63
+	18.4, 7.4, 9.6,
+
+// MZ2_SUPERTANK_MACHINEGUN_1		64
+	30.0, 30.0, 88.5,
+// MZ2_SUPERTANK_MACHINEGUN_2		65
+	30.0, 30.0, 88.5,
+// MZ2_SUPERTANK_MACHINEGUN_3		66
+	30.0, 30.0, 88.5,
+// MZ2_SUPERTANK_MACHINEGUN_4		67
+	30.0, 30.0, 88.5,
+// MZ2_SUPERTANK_MACHINEGUN_5		68
+	30.0, 30.0, 88.5,
+// MZ2_SUPERTANK_MACHINEGUN_6		69
+	30.0, 30.0, 88.5,
+// MZ2_SUPERTANK_ROCKET_1			70
+	16.0, -22.5, 91.2,
+// MZ2_SUPERTANK_ROCKET_2			71
+	16.0, -33.4, 86.7,
+// MZ2_SUPERTANK_ROCKET_3			72
+	16.0, -42.8, 83.3,
+
+// --- Start Xian Stuff ---
+// MZ2_BOSS2_MACHINEGUN_L1			73
+	32,	-40,	70,
+// MZ2_BOSS2_MACHINEGUN_L2			74
+	32,	-40,	70,
+// MZ2_BOSS2_MACHINEGUN_L3			75
+	32,	-40,	70,
+// MZ2_BOSS2_MACHINEGUN_L4			76
+	32,	-40,	70,
+// MZ2_BOSS2_MACHINEGUN_L5			77
+	32,	-40,	70,
+// --- End Xian Stuff
+
+// MZ2_BOSS2_ROCKET_1				78
+	22.0, 16.0, 10.0,
+// MZ2_BOSS2_ROCKET_2				79
+	22.0, 8.0, 10.0,
+// MZ2_BOSS2_ROCKET_3				80
+	22.0, -8.0, 10.0,
+// MZ2_BOSS2_ROCKET_4				81
+	22.0, -16.0, 10.0,
+
+// MZ2_FLOAT_BLASTER_1				82
+	32.5, -0.8, 10,
+
+// MZ2_SOLDIER_BLASTER_3			83
+	20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_3			84
+	20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_3			85
+	20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2,
+// MZ2_SOLDIER_BLASTER_4			86
+	7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_4			87
+	7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_4			88
+	7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2,
+// MZ2_SOLDIER_BLASTER_5			89
+	30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_5			90
+	30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_5			91
+	30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2,
+// MZ2_SOLDIER_BLASTER_6			92
+	27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_6			93
+	27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_6			94
+	27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2,
+// MZ2_SOLDIER_BLASTER_7			95
+	28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_7			96
+	28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_7			97
+	28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2,
+// MZ2_SOLDIER_BLASTER_8			98
+//	34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2,
+	31.5 * 1.2, 9.6 * 1.2, 10.1 * 1.2,
+// MZ2_SOLDIER_SHOTGUN_8			99
+	34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2,
+// MZ2_SOLDIER_MACHINEGUN_8			100
+	34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2,
+
+// --- Xian shit below ---
+// MZ2_MAKRON_BFG					101
+	17,		-19.5,	62.9,
+// MZ2_MAKRON_BLASTER_1				102
+	-3.6,	-24.1,	59.5,
+// MZ2_MAKRON_BLASTER_2				103
+	-1.6,	-19.3,	59.5,
+// MZ2_MAKRON_BLASTER_3				104
+	-0.1,	-14.4,	59.5,		
+// MZ2_MAKRON_BLASTER_4				105
+	2.0,	-7.6,	59.5,	
+// MZ2_MAKRON_BLASTER_5				106
+	3.4,	1.3,	59.5,
+// MZ2_MAKRON_BLASTER_6				107
+	3.7,	11.1,	59.5,	
+// MZ2_MAKRON_BLASTER_7				108
+	-0.3,	22.3,	59.5,
+// MZ2_MAKRON_BLASTER_8				109
+	-6,		33,		59.5,
+// MZ2_MAKRON_BLASTER_9				110
+	-9.3,	36.4,	59.5,
+// MZ2_MAKRON_BLASTER_10			111
+	-7,		35,		59.5,
+// MZ2_MAKRON_BLASTER_11			112
+	-2.1,	29,		59.5,
+// MZ2_MAKRON_BLASTER_12			113
+	3.9,	17.3,	59.5,
+// MZ2_MAKRON_BLASTER_13			114
+	6.1,	5.8,	59.5,
+// MZ2_MAKRON_BLASTER_14			115
+	5.9,	-4.4,	59.5,
+// MZ2_MAKRON_BLASTER_15			116
+	4.2,	-14.1,	59.5,		
+// MZ2_MAKRON_BLASTER_16			117
+	2.4,	-18.8,	59.5,
+// MZ2_MAKRON_BLASTER_17			118
+	-1.8,	-25.5,	59.5,
+// MZ2_MAKRON_RAILGUN_1				119
+	-17.3,	7.8,	72.4,
+
+// MZ2_JORG_MACHINEGUN_L1			120
+	78.5,	-47.1,	96,			
+// MZ2_JORG_MACHINEGUN_L2			121
+	78.5,	-47.1,	96,			
+// MZ2_JORG_MACHINEGUN_L3			122
+	78.5,	-47.1,	96,			
+// MZ2_JORG_MACHINEGUN_L4			123
+	78.5,	-47.1,	96,			
+// MZ2_JORG_MACHINEGUN_L5			124
+	78.5,	-47.1,	96,			
+// MZ2_JORG_MACHINEGUN_L6			125
+	78.5,	-47.1,	96,			
+// MZ2_JORG_MACHINEGUN_R1			126
+	78.5,	46.7,  96,			
+// MZ2_JORG_MACHINEGUN_R2			127
+	78.5,	46.7,	96,			
+// MZ2_JORG_MACHINEGUN_R3			128
+	78.5,	46.7,	96,			
+// MZ2_JORG_MACHINEGUN_R4			129
+	78.5,	46.7,	96,			
+// MZ2_JORG_MACHINEGUN_R5			130
+	78.5,	46.7,	96,			
+// MZ2_JORG_MACHINEGUN_R6			131
+	78.5,	46.7,	96,			
+// MZ2_JORG_BFG_1					132
+	6.3,	-9,		111.2,
+
+// MZ2_BOSS2_MACHINEGUN_R1			73
+	32,	40,	70,
+// MZ2_BOSS2_MACHINEGUN_R2			74
+	32,	40,	70,
+// MZ2_BOSS2_MACHINEGUN_R3			75
+	32,	40,	70,
+// MZ2_BOSS2_MACHINEGUN_R4			76
+	32,	40,	70,
+// MZ2_BOSS2_MACHINEGUN_R5			77
+	32,	40,	70,
+
+// --- End Xian Shit ---
+
+// ROGUE
+// note that the above really ends at 137
+// carrier machineguns
+// MZ2_CARRIER_MACHINEGUN_L1
+	56,	-32, 32,
+// MZ2_CARRIER_MACHINEGUN_R1
+	56,	32, 32,
+// MZ2_CARRIER_GRENADE
+	42,	24, 50,
+// MZ2_TURRET_MACHINEGUN			141
+	16, 0, 0,
+// MZ2_TURRET_ROCKET				142
+	16, 0, 0,
+// MZ2_TURRET_BLASTER				143
+	16, 0, 0,
+// MZ2_STALKER_BLASTER				144
+	24, 0, 6,
+// MZ2_DAEDALUS_BLASTER				145
+	32.5, -0.8, 10.0,
+// MZ2_MEDIC_BLASTER_2				146
+	12.1, 5.4, 16.5,
+// MZ2_CARRIER_RAILGUN				147
+	32, 0, 6, 
+// MZ2_WIDOW_DISRUPTOR				148
+	57.72, 14.50, 88.81,
+// MZ2_WIDOW_BLASTER				149
+	56,	32, 32,
+// MZ2_WIDOW_RAIL					150
+	62, -20, 84, 
+// MZ2_WIDOW_PLASMABEAM				151		// PMM - not used!
+	32, 0, 6, 
+// MZ2_CARRIER_MACHINEGUN_L2		152
+	61,	-32, 12,
+// MZ2_CARRIER_MACHINEGUN_R2		153
+	61,	32, 12,
+// MZ2_WIDOW_RAIL_LEFT				154
+	17, -62, 91, 
+// MZ2_WIDOW_RAIL_RIGHT				155
+	68, 12, 86, 
+// MZ2_WIDOW_BLASTER_SWEEP1			156			pmm - the sweeps need to be in sequential order
+	47.5, 56, 89,
+// MZ2_WIDOW_BLASTER_SWEEP2			157
+	54, 52, 91,
+// MZ2_WIDOW_BLASTER_SWEEP3			158
+	58, 40, 91,
+// MZ2_WIDOW_BLASTER_SWEEP4			159
+	68, 30, 88,
+// MZ2_WIDOW_BLASTER_SWEEP5			160
+	74, 20, 88,
+// MZ2_WIDOW_BLASTER_SWEEP6			161
+	73, 11, 87,
+// MZ2_WIDOW_BLASTER_SWEEP7			162
+	73, 3, 87,
+// MZ2_WIDOW_BLASTER_SWEEP8			163
+	70, -12, 87,
+// MZ2_WIDOW_BLASTER_SWEEP9			164
+	67, -20, 90,
+// MZ2_WIDOW_BLASTER_100			165
+	-20, 76, 90,
+// MZ2_WIDOW_BLASTER_90				166
+	-8, 74, 90,
+// MZ2_WIDOW_BLASTER_80				167
+	0, 72, 90,
+// MZ2_WIDOW_BLASTER_70				168		d06
+	10, 71, 89,
+// MZ2_WIDOW_BLASTER_60				169		d07
+	23, 70, 87,
+// MZ2_WIDOW_BLASTER_50				170		d08
+	32, 64, 85,
+// MZ2_WIDOW_BLASTER_40				171
+	40, 58, 84,
+// MZ2_WIDOW_BLASTER_30				172		d10
+	48, 50, 83,
+// MZ2_WIDOW_BLASTER_20				173
+	54, 42, 82,
+// MZ2_WIDOW_BLASTER_10				174		d12
+	56, 34, 82,
+// MZ2_WIDOW_BLASTER_0				175
+	58, 26, 82,
+// MZ2_WIDOW_BLASTER_10L			176		d14
+	60, 16, 82,
+// MZ2_WIDOW_BLASTER_20L			177
+	59, 6, 81,
+// MZ2_WIDOW_BLASTER_30L			178		d16
+	58, -2, 80,
+// MZ2_WIDOW_BLASTER_40L			179
+	57, -10, 79,
+// MZ2_WIDOW_BLASTER_50L			180		d18
+	54, -18, 78,
+// MZ2_WIDOW_BLASTER_60L			181
+	42, -32, 80,
+// MZ2_WIDOW_BLASTER_70L			182		d20
+	36, -40, 78,
+// MZ2_WIDOW_RUN_1					183
+	68.4, 10.88, 82.08,
+// MZ2_WIDOW_RUN_2					184
+	68.51, 8.64, 85.14,
+// MZ2_WIDOW_RUN_3					185
+	68.66, 6.38, 88.78,
+// MZ2_WIDOW_RUN_4					186
+	68.73, 5.1, 84.47,
+// MZ2_WIDOW_RUN_5					187
+	68.82, 4.79, 80.52,
+// MZ2_WIDOW_RUN_6					188
+	68.77, 6.11, 85.37,
+// MZ2_WIDOW_RUN_7					189
+	68.67, 7.99, 90.24,
+// MZ2_WIDOW_RUN_8					190
+	68.55, 9.54, 87.36,
+// MZ2_CARRIER_ROCKET_1				191
+	0, 0, -5,
+// MZ2_CARRIER_ROCKET_2				192
+	0, 0, -5,
+// MZ2_CARRIER_ROCKET_3				193
+	0, 0, -5,
+// MZ2_CARRIER_ROCKET_4				194
+	0, 0, -5,
+// MZ2_WIDOW2_BEAMER_1				195
+//	72.13, -17.63, 93.77,
+	69.00, -17.63, 93.77,
+// MZ2_WIDOW2_BEAMER_2				196
+//	71.46, -17.08, 89.82,
+	69.00, -17.08, 89.82,
+// MZ2_WIDOW2_BEAMER_3				197
+//	71.47, -18.40, 90.70,
+	69.00, -18.40, 90.70,
+// MZ2_WIDOW2_BEAMER_4				198
+//	71.96, -18.34, 94.32,
+	69.00, -18.34, 94.32,
+// MZ2_WIDOW2_BEAMER_5				199
+//	72.25, -18.30, 97.98,
+	69.00, -18.30, 97.98,
+// MZ2_WIDOW2_BEAM_SWEEP_1			200
+	45.04, -59.02, 92.24,
+// MZ2_WIDOW2_BEAM_SWEEP_2			201
+	50.68, -54.70, 91.96,
+// MZ2_WIDOW2_BEAM_SWEEP_3			202
+	56.57, -47.72, 91.65,
+// MZ2_WIDOW2_BEAM_SWEEP_4			203
+	61.75, -38.75, 91.38,
+// MZ2_WIDOW2_BEAM_SWEEP_5			204
+	65.55, -28.76, 91.24,
+// MZ2_WIDOW2_BEAM_SWEEP_6			205
+	67.79, -18.90, 91.22,
+// MZ2_WIDOW2_BEAM_SWEEP_7			206
+	68.60, -9.52, 91.23,
+// MZ2_WIDOW2_BEAM_SWEEP_8			207
+	68.08, 0.18, 91.32,
+// MZ2_WIDOW2_BEAM_SWEEP_9			208
+	66.14, 9.79, 91.44,
+// MZ2_WIDOW2_BEAM_SWEEP_10			209
+	62.77, 18.91, 91.65,
+// MZ2_WIDOW2_BEAM_SWEEP_11			210
+	58.29, 27.11, 92.00,
+
+// end of table
+	0.0, 0.0, 0.0
+};
--- /dev/null
+++ b/game/m_flipper.c
@@ -1,0 +1,403 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+FLIPPER
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_flipper.h"
+
+
+static int	sound_chomp;
+static int	sound_attack;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_death;
+static int	sound_idle;
+static int	sound_search;
+static int	sound_sight;
+
+
+void flipper_stand (edict_t *self);
+
+mframe_t flipper_frames_stand [] =
+{
+	ai_stand, 0, NULL
+};
+	
+mmove_t	flipper_move_stand = {FRAME_flphor01, FRAME_flphor01, flipper_frames_stand, NULL};
+
+void flipper_stand (edict_t *self)
+{
+		self->monsterinfo.currentmove = &flipper_move_stand;
+}
+
+#define FLIPPER_RUN_SPEED	24
+
+mframe_t flipper_frames_run [] =
+{
+	ai_run, FLIPPER_RUN_SPEED, NULL,	// 6
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,	// 10
+
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,	// 20
+
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL,
+	ai_run, FLIPPER_RUN_SPEED, NULL		// 29
+};
+mmove_t flipper_move_run_loop = {FRAME_flpver06, FRAME_flpver29, flipper_frames_run, NULL};
+
+void flipper_run_loop (edict_t *self)
+{
+	self->monsterinfo.currentmove = &flipper_move_run_loop;
+}
+
+mframe_t flipper_frames_run_start [] =
+{
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, NULL
+};
+mmove_t flipper_move_run_start = {FRAME_flpver01, FRAME_flpver06, flipper_frames_run_start, flipper_run_loop};
+
+void flipper_run (edict_t *self)
+{
+	self->monsterinfo.currentmove = &flipper_move_run_start;
+}
+
+/* Standard Swimming */ 
+mframe_t flipper_frames_walk [] =
+{
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 4, NULL
+};
+mmove_t flipper_move_walk = {FRAME_flphor01, FRAME_flphor24, flipper_frames_walk, NULL};
+
+void flipper_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &flipper_move_walk;
+}
+
+mframe_t flipper_frames_start_run [] =
+{
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, NULL,
+	ai_run, 8, flipper_run
+};
+mmove_t flipper_move_start_run = {FRAME_flphor01, FRAME_flphor05, flipper_frames_start_run, NULL};
+
+void flipper_start_run (edict_t *self)
+{
+	self->monsterinfo.currentmove = &flipper_move_start_run;
+}
+
+mframe_t flipper_frames_pain2 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0, NULL
+};
+mmove_t flipper_move_pain2 = {FRAME_flppn101, FRAME_flppn105, flipper_frames_pain2, flipper_run};
+
+mframe_t flipper_frames_pain1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0, NULL
+};
+mmove_t flipper_move_pain1 = {FRAME_flppn201, FRAME_flppn205, flipper_frames_pain1, flipper_run};
+
+void flipper_bite (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, 0, 0);
+	fire_hit (self, aim, 5, 0);
+}
+
+void flipper_preattack (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_chomp, 1, ATTN_NORM, 0);
+}
+
+mframe_t flipper_frames_attack [] =
+{
+	ai_charge, 0,	flipper_preattack,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	flipper_bite,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	flipper_bite,
+	ai_charge, 0,	NULL
+};
+mmove_t flipper_move_attack = {FRAME_flpbit01, FRAME_flpbit20, flipper_frames_attack, flipper_run};
+
+void flipper_melee(edict_t *self)
+{
+	self->monsterinfo.currentmove = &flipper_move_attack;
+}
+
+void flipper_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	int		n;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+	
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	n = (rand() + 1) % 2;
+	if (n == 0)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &flipper_move_pain1;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &flipper_move_pain2;
+	}
+}
+
+void flipper_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t flipper_frames_death [] =
+{
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL
+};
+mmove_t flipper_move_death = {FRAME_flpdth01, FRAME_flpdth56, flipper_frames_death, flipper_dead};
+
+void flipper_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void flipper_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.currentmove = &flipper_move_death;
+}
+
+/*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_flipper (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1		= gi.soundindex ("flipper/flppain1.wav");	
+	sound_pain2		= gi.soundindex ("flipper/flppain2.wav");	
+	sound_death		= gi.soundindex ("flipper/flpdeth1.wav");	
+	sound_chomp		= gi.soundindex ("flipper/flpatck1.wav");
+	sound_attack	= gi.soundindex ("flipper/flpatck2.wav");
+	sound_idle		= gi.soundindex ("flipper/flpidle1.wav");
+	sound_search	= gi.soundindex ("flipper/flpsrch1.wav");
+	sound_sight		= gi.soundindex ("flipper/flpsght1.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/flipper/tris.md2");
+	VectorSet (self->mins, -16, -16, 0);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	self->health = 50;
+	self->gib_health = -30;
+	self->mass = 100;
+
+	self->pain = flipper_pain;
+	self->die = flipper_die;
+
+	self->monsterinfo.stand = flipper_stand;
+	self->monsterinfo.walk = flipper_walk;
+	self->monsterinfo.run = flipper_start_run;
+	self->monsterinfo.melee = flipper_melee;
+	self->monsterinfo.sight = flipper_sight;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &flipper_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	swimmonster_start (self);
+}
--- /dev/null
+++ b/game/m_flipper.h
@@ -1,0 +1,185 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/flipper
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_flpbit01        	0
+#define FRAME_flpbit02        	1
+#define FRAME_flpbit03        	2
+#define FRAME_flpbit04        	3
+#define FRAME_flpbit05        	4
+#define FRAME_flpbit06        	5
+#define FRAME_flpbit07        	6
+#define FRAME_flpbit08        	7
+#define FRAME_flpbit09        	8
+#define FRAME_flpbit10        	9
+#define FRAME_flpbit11        	10
+#define FRAME_flpbit12        	11
+#define FRAME_flpbit13        	12
+#define FRAME_flpbit14        	13
+#define FRAME_flpbit15        	14
+#define FRAME_flpbit16        	15
+#define FRAME_flpbit17        	16
+#define FRAME_flpbit18        	17
+#define FRAME_flpbit19        	18
+#define FRAME_flpbit20        	19
+#define FRAME_flptal01        	20
+#define FRAME_flptal02        	21
+#define FRAME_flptal03        	22
+#define FRAME_flptal04        	23
+#define FRAME_flptal05        	24
+#define FRAME_flptal06        	25
+#define FRAME_flptal07        	26
+#define FRAME_flptal08        	27
+#define FRAME_flptal09        	28
+#define FRAME_flptal10        	29
+#define FRAME_flptal11        	30
+#define FRAME_flptal12        	31
+#define FRAME_flptal13        	32
+#define FRAME_flptal14        	33
+#define FRAME_flptal15        	34
+#define FRAME_flptal16        	35
+#define FRAME_flptal17        	36
+#define FRAME_flptal18        	37
+#define FRAME_flptal19        	38
+#define FRAME_flptal20        	39
+#define FRAME_flptal21        	40
+#define FRAME_flphor01        	41
+#define FRAME_flphor02        	42
+#define FRAME_flphor03        	43
+#define FRAME_flphor04        	44
+#define FRAME_flphor05        	45
+#define FRAME_flphor06        	46
+#define FRAME_flphor07        	47
+#define FRAME_flphor08        	48
+#define FRAME_flphor09        	49
+#define FRAME_flphor10        	50
+#define FRAME_flphor11        	51
+#define FRAME_flphor12        	52
+#define FRAME_flphor13        	53
+#define FRAME_flphor14        	54
+#define FRAME_flphor15        	55
+#define FRAME_flphor16        	56
+#define FRAME_flphor17        	57
+#define FRAME_flphor18        	58
+#define FRAME_flphor19        	59
+#define FRAME_flphor20        	60
+#define FRAME_flphor21        	61
+#define FRAME_flphor22        	62
+#define FRAME_flphor23        	63
+#define FRAME_flphor24        	64
+#define FRAME_flpver01        	65
+#define FRAME_flpver02        	66
+#define FRAME_flpver03        	67
+#define FRAME_flpver04        	68
+#define FRAME_flpver05        	69
+#define FRAME_flpver06        	70
+#define FRAME_flpver07        	71
+#define FRAME_flpver08        	72
+#define FRAME_flpver09        	73
+#define FRAME_flpver10        	74
+#define FRAME_flpver11        	75
+#define FRAME_flpver12        	76
+#define FRAME_flpver13        	77
+#define FRAME_flpver14        	78
+#define FRAME_flpver15        	79
+#define FRAME_flpver16        	80
+#define FRAME_flpver17        	81
+#define FRAME_flpver18        	82
+#define FRAME_flpver19        	83
+#define FRAME_flpver20        	84
+#define FRAME_flpver21        	85
+#define FRAME_flpver22        	86
+#define FRAME_flpver23        	87
+#define FRAME_flpver24        	88
+#define FRAME_flpver25        	89
+#define FRAME_flpver26        	90
+#define FRAME_flpver27        	91
+#define FRAME_flpver28        	92
+#define FRAME_flpver29        	93
+#define FRAME_flppn101        	94
+#define FRAME_flppn102        	95
+#define FRAME_flppn103        	96
+#define FRAME_flppn104        	97
+#define FRAME_flppn105        	98
+#define FRAME_flppn201        	99
+#define FRAME_flppn202        	100
+#define FRAME_flppn203        	101
+#define FRAME_flppn204        	102
+#define FRAME_flppn205        	103
+#define FRAME_flpdth01        	104
+#define FRAME_flpdth02        	105
+#define FRAME_flpdth03        	106
+#define FRAME_flpdth04        	107
+#define FRAME_flpdth05        	108
+#define FRAME_flpdth06        	109
+#define FRAME_flpdth07        	110
+#define FRAME_flpdth08        	111
+#define FRAME_flpdth09        	112
+#define FRAME_flpdth10        	113
+#define FRAME_flpdth11        	114
+#define FRAME_flpdth12        	115
+#define FRAME_flpdth13        	116
+#define FRAME_flpdth14        	117
+#define FRAME_flpdth15        	118
+#define FRAME_flpdth16        	119
+#define FRAME_flpdth17        	120
+#define FRAME_flpdth18        	121
+#define FRAME_flpdth19        	122
+#define FRAME_flpdth20        	123
+#define FRAME_flpdth21        	124
+#define FRAME_flpdth22        	125
+#define FRAME_flpdth23        	126
+#define FRAME_flpdth24        	127
+#define FRAME_flpdth25        	128
+#define FRAME_flpdth26        	129
+#define FRAME_flpdth27        	130
+#define FRAME_flpdth28        	131
+#define FRAME_flpdth29        	132
+#define FRAME_flpdth30        	133
+#define FRAME_flpdth31        	134
+#define FRAME_flpdth32        	135
+#define FRAME_flpdth33        	136
+#define FRAME_flpdth34        	137
+#define FRAME_flpdth35        	138
+#define FRAME_flpdth36        	139
+#define FRAME_flpdth37        	140
+#define FRAME_flpdth38        	141
+#define FRAME_flpdth39        	142
+#define FRAME_flpdth40        	143
+#define FRAME_flpdth41        	144
+#define FRAME_flpdth42        	145
+#define FRAME_flpdth43        	146
+#define FRAME_flpdth44        	147
+#define FRAME_flpdth45        	148
+#define FRAME_flpdth46        	149
+#define FRAME_flpdth47        	150
+#define FRAME_flpdth48        	151
+#define FRAME_flpdth49        	152
+#define FRAME_flpdth50        	153
+#define FRAME_flpdth51        	154
+#define FRAME_flpdth52        	155
+#define FRAME_flpdth53        	156
+#define FRAME_flpdth54        	157
+#define FRAME_flpdth55        	158
+#define FRAME_flpdth56        	159
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_float.c
@@ -1,0 +1,663 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+floater
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_float.h"
+
+
+static int	sound_attack2;
+static int	sound_attack3;
+static int	sound_death1;
+static int	sound_idle;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_sight;
+
+
+void floater_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void floater_idle (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+
+//void floater_stand1 (edict_t *self);
+void floater_dead (edict_t *self);
+void floater_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+void floater_run (edict_t *self);
+void floater_wham (edict_t *self);
+void floater_zap (edict_t *self);
+
+
+void floater_fire_blaster (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	forward, right;
+	vec3_t	end;
+	vec3_t	dir;
+	int		effect;
+
+	if ((self->s.frame == FRAME_attak104) || (self->s.frame == FRAME_attak107))
+		effect = EF_HYPERBLASTER;
+	else
+		effect = 0;
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_FLOAT_BLASTER_1], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, end);
+	end[2] += self->enemy->viewheight;
+	VectorSubtract (end, start, dir);
+
+	monster_fire_blaster (self, start, dir, 1, 1000, MZ2_FLOAT_BLASTER_1, effect);
+}
+
+
+mframe_t floater_frames_stand1 [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	floater_move_stand1 = {FRAME_stand101, FRAME_stand152, floater_frames_stand1, NULL};
+
+mframe_t floater_frames_stand2 [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	floater_move_stand2 = {FRAME_stand201, FRAME_stand252, floater_frames_stand2, NULL};
+
+void floater_stand (edict_t *self)
+{
+	if (random() <= 0.5)		
+		self->monsterinfo.currentmove = &floater_move_stand1;
+	else
+		self->monsterinfo.currentmove = &floater_move_stand2;
+}
+
+mframe_t floater_frames_activate [] =
+{
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL,	
+	ai_move,	0,	NULL
+};
+mmove_t floater_move_activate = {FRAME_actvat01, FRAME_actvat31, floater_frames_activate, NULL};
+
+mframe_t floater_frames_attack1 [] =
+{
+	ai_charge,	0,	NULL,			// Blaster attack
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	floater_fire_blaster,			// BOOM (0, -25.8, 32.5)	-- LOOP Starts
+	ai_charge,	0,	floater_fire_blaster,
+	ai_charge,	0,	floater_fire_blaster,
+	ai_charge,	0,	floater_fire_blaster,
+	ai_charge,	0,	floater_fire_blaster,
+	ai_charge,	0,	floater_fire_blaster,
+	ai_charge,	0,	floater_fire_blaster,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL			//							-- LOOP Ends
+};
+mmove_t floater_move_attack1 = {FRAME_attak101, FRAME_attak114, floater_frames_attack1, floater_run};
+
+mframe_t floater_frames_attack2 [] =
+{
+	ai_charge,	0,	NULL,			// Claws
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	floater_wham,			// WHAM (0, -45, 29.6)		-- LOOP Starts
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,			//							-- LOOP Ends
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL
+};
+mmove_t floater_move_attack2 = {FRAME_attak201, FRAME_attak225, floater_frames_attack2, floater_run};
+
+mframe_t floater_frames_attack3 [] =
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	floater_zap,		//								-- LOOP Starts
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,		//								-- LOOP Ends
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL
+};
+mmove_t floater_move_attack3 = {FRAME_attak301, FRAME_attak334, floater_frames_attack3, floater_run};
+
+mframe_t floater_frames_death [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t floater_move_death = {FRAME_death01, FRAME_death13, floater_frames_death, floater_dead};
+
+mframe_t floater_frames_pain1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t floater_move_pain1 = {FRAME_pain101, FRAME_pain107, floater_frames_pain1, floater_run};
+
+mframe_t floater_frames_pain2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t floater_move_pain2 = {FRAME_pain201, FRAME_pain208, floater_frames_pain2, floater_run};
+
+mframe_t floater_frames_pain3 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t floater_move_pain3 = {FRAME_pain301, FRAME_pain312, floater_frames_pain3, floater_run};
+
+mframe_t floater_frames_walk [] =
+{
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL
+};
+mmove_t	floater_move_walk = {FRAME_stand101, FRAME_stand152, floater_frames_walk, NULL};
+
+mframe_t floater_frames_run [] =
+{
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL,
+	ai_run, 13, NULL
+};
+mmove_t	floater_move_run = {FRAME_stand101, FRAME_stand152, floater_frames_run, NULL};
+
+void floater_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &floater_move_stand1;
+	else
+		self->monsterinfo.currentmove = &floater_move_run;
+}
+
+void floater_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &floater_move_walk;
+}
+
+void floater_wham (edict_t *self)
+{
+	static	vec3_t	aim = {MELEE_DISTANCE, 0, 0};
+	gi.sound (self, CHAN_WEAPON, sound_attack3, 1, ATTN_NORM, 0);
+	fire_hit (self, aim, 5 + rand() % 6, -50);
+}
+
+void floater_zap (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	origin;
+	vec3_t	dir;
+	vec3_t	offset;
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, dir);
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	//FIXME use a flash and replace these two lines with the commented one
+	VectorSet (offset, 18.5, -0.9, 10);
+	G_ProjectSource (self->s.origin, offset, forward, right, origin);
+//	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, origin);
+
+	gi.sound (self, CHAN_WEAPON, sound_attack2, 1, ATTN_NORM, 0);
+
+	//FIXME use the flash, Luke
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_SPLASH);
+	gi.WriteByte (32);
+	gi.WritePosition (origin);
+	gi.WriteDir (dir);
+	gi.WriteByte (1);	//sparks
+	gi.multicast (origin, MULTICAST_PVS);
+
+	T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, 5 + rand() % 6, -10, DAMAGE_ENERGY, MOD_UNKNOWN);
+}
+
+void floater_attack(edict_t *self)
+{
+	self->monsterinfo.currentmove = &floater_move_attack1;
+}
+
+
+void floater_melee(edict_t *self)
+{
+	if (random() < 0.5)		
+		self->monsterinfo.currentmove = &floater_move_attack3;
+	else
+		self->monsterinfo.currentmove = &floater_move_attack2;
+}
+
+
+void floater_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	int		n;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	n = (rand() + 1) % 3;
+	if (n == 0)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &floater_move_pain1;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &floater_move_pain2;
+	}
+}
+
+void floater_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+void floater_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
+	BecomeExplosion1(self);
+}
+
+/*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_floater (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_attack2 = gi.soundindex ("floater/fltatck2.wav");
+	sound_attack3 = gi.soundindex ("floater/fltatck3.wav");
+	sound_death1 = gi.soundindex ("floater/fltdeth1.wav");
+	sound_idle = gi.soundindex ("floater/fltidle1.wav");
+	sound_pain1 = gi.soundindex ("floater/fltpain1.wav");
+	sound_pain2 = gi.soundindex ("floater/fltpain2.wav");
+	sound_sight = gi.soundindex ("floater/fltsght1.wav");
+
+	gi.soundindex ("floater/fltatck1.wav");
+
+	self->s.sound = gi.soundindex ("floater/fltsrch1.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/float/tris.md2");
+	VectorSet (self->mins, -24, -24, -24);
+	VectorSet (self->maxs, 24, 24, 32);
+
+	self->health = 200;
+	self->gib_health = -80;
+	self->mass = 300;
+
+	self->pain = floater_pain;
+	self->die = floater_die;
+
+	self->monsterinfo.stand = floater_stand;
+	self->monsterinfo.walk = floater_walk;
+	self->monsterinfo.run = floater_run;
+//	self->monsterinfo.dodge = floater_dodge;
+	self->monsterinfo.attack = floater_attack;
+	self->monsterinfo.melee = floater_melee;
+	self->monsterinfo.sight = floater_sight;
+	self->monsterinfo.idle = floater_idle;
+
+	gi.linkentity (self);
+
+	if (random() <= 0.5)		
+		self->monsterinfo.currentmove = &floater_move_stand1;	
+	else
+		self->monsterinfo.currentmove = &floater_move_stand2;	
+	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	flymonster_start (self);
+}
--- /dev/null
+++ b/game/m_float.h
@@ -1,0 +1,273 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/float
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_actvat01        	0
+#define FRAME_actvat02        	1
+#define FRAME_actvat03        	2
+#define FRAME_actvat04        	3
+#define FRAME_actvat05        	4
+#define FRAME_actvat06        	5
+#define FRAME_actvat07        	6
+#define FRAME_actvat08        	7
+#define FRAME_actvat09        	8
+#define FRAME_actvat10        	9
+#define FRAME_actvat11        	10
+#define FRAME_actvat12        	11
+#define FRAME_actvat13        	12
+#define FRAME_actvat14        	13
+#define FRAME_actvat15        	14
+#define FRAME_actvat16        	15
+#define FRAME_actvat17        	16
+#define FRAME_actvat18        	17
+#define FRAME_actvat19        	18
+#define FRAME_actvat20        	19
+#define FRAME_actvat21        	20
+#define FRAME_actvat22        	21
+#define FRAME_actvat23        	22
+#define FRAME_actvat24        	23
+#define FRAME_actvat25        	24
+#define FRAME_actvat26        	25
+#define FRAME_actvat27        	26
+#define FRAME_actvat28        	27
+#define FRAME_actvat29        	28
+#define FRAME_actvat30        	29
+#define FRAME_actvat31        	30
+#define FRAME_attak101        	31
+#define FRAME_attak102        	32
+#define FRAME_attak103        	33
+#define FRAME_attak104        	34
+#define FRAME_attak105        	35
+#define FRAME_attak106        	36
+#define FRAME_attak107        	37
+#define FRAME_attak108        	38
+#define FRAME_attak109        	39
+#define FRAME_attak110        	40
+#define FRAME_attak111        	41
+#define FRAME_attak112        	42
+#define FRAME_attak113        	43
+#define FRAME_attak114        	44
+#define FRAME_attak201        	45
+#define FRAME_attak202        	46
+#define FRAME_attak203        	47
+#define FRAME_attak204        	48
+#define FRAME_attak205        	49
+#define FRAME_attak206        	50
+#define FRAME_attak207        	51
+#define FRAME_attak208        	52
+#define FRAME_attak209        	53
+#define FRAME_attak210        	54
+#define FRAME_attak211        	55
+#define FRAME_attak212        	56
+#define FRAME_attak213        	57
+#define FRAME_attak214        	58
+#define FRAME_attak215        	59
+#define FRAME_attak216        	60
+#define FRAME_attak217        	61
+#define FRAME_attak218        	62
+#define FRAME_attak219        	63
+#define FRAME_attak220        	64
+#define FRAME_attak221        	65
+#define FRAME_attak222        	66
+#define FRAME_attak223        	67
+#define FRAME_attak224        	68
+#define FRAME_attak225        	69
+#define FRAME_attak301        	70
+#define FRAME_attak302        	71
+#define FRAME_attak303        	72
+#define FRAME_attak304        	73
+#define FRAME_attak305        	74
+#define FRAME_attak306        	75
+#define FRAME_attak307        	76
+#define FRAME_attak308        	77
+#define FRAME_attak309        	78
+#define FRAME_attak310        	79
+#define FRAME_attak311        	80
+#define FRAME_attak312        	81
+#define FRAME_attak313        	82
+#define FRAME_attak314        	83
+#define FRAME_attak315        	84
+#define FRAME_attak316        	85
+#define FRAME_attak317        	86
+#define FRAME_attak318        	87
+#define FRAME_attak319        	88
+#define FRAME_attak320        	89
+#define FRAME_attak321        	90
+#define FRAME_attak322        	91
+#define FRAME_attak323        	92
+#define FRAME_attak324        	93
+#define FRAME_attak325        	94
+#define FRAME_attak326        	95
+#define FRAME_attak327        	96
+#define FRAME_attak328        	97
+#define FRAME_attak329        	98
+#define FRAME_attak330        	99
+#define FRAME_attak331        	100
+#define FRAME_attak332        	101
+#define FRAME_attak333        	102
+#define FRAME_attak334        	103
+#define FRAME_death01         	104
+#define FRAME_death02         	105
+#define FRAME_death03         	106
+#define FRAME_death04         	107
+#define FRAME_death05         	108
+#define FRAME_death06         	109
+#define FRAME_death07         	110
+#define FRAME_death08         	111
+#define FRAME_death09         	112
+#define FRAME_death10         	113
+#define FRAME_death11         	114
+#define FRAME_death12         	115
+#define FRAME_death13         	116
+#define FRAME_pain101         	117
+#define FRAME_pain102         	118
+#define FRAME_pain103         	119
+#define FRAME_pain104         	120
+#define FRAME_pain105         	121
+#define FRAME_pain106         	122
+#define FRAME_pain107         	123
+#define FRAME_pain201         	124
+#define FRAME_pain202         	125
+#define FRAME_pain203         	126
+#define FRAME_pain204         	127
+#define FRAME_pain205         	128
+#define FRAME_pain206         	129
+#define FRAME_pain207         	130
+#define FRAME_pain208         	131
+#define FRAME_pain301         	132
+#define FRAME_pain302         	133
+#define FRAME_pain303         	134
+#define FRAME_pain304         	135
+#define FRAME_pain305         	136
+#define FRAME_pain306         	137
+#define FRAME_pain307         	138
+#define FRAME_pain308         	139
+#define FRAME_pain309         	140
+#define FRAME_pain310         	141
+#define FRAME_pain311         	142
+#define FRAME_pain312         	143
+#define FRAME_stand101        	144
+#define FRAME_stand102        	145
+#define FRAME_stand103        	146
+#define FRAME_stand104        	147
+#define FRAME_stand105        	148
+#define FRAME_stand106        	149
+#define FRAME_stand107        	150
+#define FRAME_stand108        	151
+#define FRAME_stand109        	152
+#define FRAME_stand110        	153
+#define FRAME_stand111        	154
+#define FRAME_stand112        	155
+#define FRAME_stand113        	156
+#define FRAME_stand114        	157
+#define FRAME_stand115        	158
+#define FRAME_stand116        	159
+#define FRAME_stand117        	160
+#define FRAME_stand118        	161
+#define FRAME_stand119        	162
+#define FRAME_stand120        	163
+#define FRAME_stand121        	164
+#define FRAME_stand122        	165
+#define FRAME_stand123        	166
+#define FRAME_stand124        	167
+#define FRAME_stand125        	168
+#define FRAME_stand126        	169
+#define FRAME_stand127        	170
+#define FRAME_stand128        	171
+#define FRAME_stand129        	172
+#define FRAME_stand130        	173
+#define FRAME_stand131        	174
+#define FRAME_stand132        	175
+#define FRAME_stand133        	176
+#define FRAME_stand134        	177
+#define FRAME_stand135        	178
+#define FRAME_stand136        	179
+#define FRAME_stand137        	180
+#define FRAME_stand138        	181
+#define FRAME_stand139        	182
+#define FRAME_stand140        	183
+#define FRAME_stand141        	184
+#define FRAME_stand142        	185
+#define FRAME_stand143        	186
+#define FRAME_stand144        	187
+#define FRAME_stand145        	188
+#define FRAME_stand146        	189
+#define FRAME_stand147        	190
+#define FRAME_stand148        	191
+#define FRAME_stand149        	192
+#define FRAME_stand150        	193
+#define FRAME_stand151        	194
+#define FRAME_stand152        	195
+#define FRAME_stand201        	196
+#define FRAME_stand202        	197
+#define FRAME_stand203        	198
+#define FRAME_stand204        	199
+#define FRAME_stand205        	200
+#define FRAME_stand206        	201
+#define FRAME_stand207        	202
+#define FRAME_stand208        	203
+#define FRAME_stand209        	204
+#define FRAME_stand210        	205
+#define FRAME_stand211        	206
+#define FRAME_stand212        	207
+#define FRAME_stand213        	208
+#define FRAME_stand214        	209
+#define FRAME_stand215        	210
+#define FRAME_stand216        	211
+#define FRAME_stand217        	212
+#define FRAME_stand218        	213
+#define FRAME_stand219        	214
+#define FRAME_stand220        	215
+#define FRAME_stand221        	216
+#define FRAME_stand222        	217
+#define FRAME_stand223        	218
+#define FRAME_stand224        	219
+#define FRAME_stand225        	220
+#define FRAME_stand226        	221
+#define FRAME_stand227        	222
+#define FRAME_stand228        	223
+#define FRAME_stand229        	224
+#define FRAME_stand230        	225
+#define FRAME_stand231        	226
+#define FRAME_stand232        	227
+#define FRAME_stand233        	228
+#define FRAME_stand234        	229
+#define FRAME_stand235        	230
+#define FRAME_stand236        	231
+#define FRAME_stand237        	232
+#define FRAME_stand238        	233
+#define FRAME_stand239        	234
+#define FRAME_stand240        	235
+#define FRAME_stand241        	236
+#define FRAME_stand242        	237
+#define FRAME_stand243        	238
+#define FRAME_stand244        	239
+#define FRAME_stand245        	240
+#define FRAME_stand246        	241
+#define FRAME_stand247        	242
+#define FRAME_stand248        	243
+#define FRAME_stand249        	244
+#define FRAME_stand250        	245
+#define FRAME_stand251        	246
+#define FRAME_stand252        	247
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_flyer.c
@@ -1,0 +1,626 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+flyer
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_flyer.h"
+
+qboolean visible (edict_t *self, edict_t *other);
+
+static int	nextmove;			// Used for start/stop frames
+
+static int	sound_sight;
+static int	sound_idle;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_slash;
+static int	sound_sproing;
+static int	sound_die;
+
+
+void flyer_check_melee(edict_t *self);
+void flyer_loop_melee (edict_t *self);
+void flyer_melee (edict_t *self);
+void flyer_setstart (edict_t *self);
+void flyer_stand (edict_t *self);
+void flyer_nextmove (edict_t *self);
+
+
+void flyer_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void flyer_idle (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+void flyer_pop_blades (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_sproing, 1, ATTN_NORM, 0);
+}
+
+
+mframe_t flyer_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	flyer_move_stand = {FRAME_stand01, FRAME_stand45, flyer_frames_stand, NULL};
+
+
+mframe_t flyer_frames_walk [] =
+{
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 5, NULL
+};
+mmove_t	flyer_move_walk = {FRAME_stand01, FRAME_stand45, flyer_frames_walk, NULL};
+
+mframe_t flyer_frames_run [] =
+{
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL,
+	ai_run, 10, NULL
+};
+mmove_t	flyer_move_run = {FRAME_stand01, FRAME_stand45, flyer_frames_run, NULL};
+
+void flyer_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &flyer_move_stand;
+	else
+		self->monsterinfo.currentmove = &flyer_move_run;
+}
+
+void flyer_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &flyer_move_walk;
+}
+
+void flyer_stand (edict_t *self)
+{
+		self->monsterinfo.currentmove = &flyer_move_stand;
+}
+
+mframe_t flyer_frames_start [] =
+{
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	flyer_nextmove
+};
+mmove_t flyer_move_start = {FRAME_start01, FRAME_start06, flyer_frames_start, NULL};
+
+mframe_t flyer_frames_stop [] =
+{
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	NULL,
+		ai_move, 0,	flyer_nextmove
+};
+mmove_t flyer_move_stop = {FRAME_stop01, FRAME_stop07, flyer_frames_stop, NULL};
+
+void flyer_stop (edict_t *self)
+{
+		self->monsterinfo.currentmove = &flyer_move_stop;
+}
+
+void flyer_start (edict_t *self)
+{
+		self->monsterinfo.currentmove = &flyer_move_start;
+}
+
+
+mframe_t flyer_frames_rollright [] =
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_rollright = {FRAME_rollr01, FRAME_rollr09, flyer_frames_rollright, NULL};
+
+mframe_t flyer_frames_rollleft [] =
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_rollleft = {FRAME_rollf01, FRAME_rollf09, flyer_frames_rollleft, NULL};
+
+mframe_t flyer_frames_pain3 [] =
+{	
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_pain3 = {FRAME_pain301, FRAME_pain304, flyer_frames_pain3, flyer_run};
+
+mframe_t flyer_frames_pain2 [] =
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_pain2 = {FRAME_pain201, FRAME_pain204, flyer_frames_pain2, flyer_run};
+
+mframe_t flyer_frames_pain1 [] =
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_pain1 = {FRAME_pain101, FRAME_pain109, flyer_frames_pain1, flyer_run};
+
+mframe_t flyer_frames_defense [] = 
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,		// Hold this frame
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_defense = {FRAME_defens01, FRAME_defens06, flyer_frames_defense, NULL};
+
+mframe_t flyer_frames_bankright [] =
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_bankright = {FRAME_bankr01, FRAME_bankr07, flyer_frames_bankright, NULL};
+
+mframe_t flyer_frames_bankleft [] =
+{
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL,
+		ai_move, 0, NULL
+};
+mmove_t flyer_move_bankleft = {FRAME_bankl01, FRAME_bankl07, flyer_frames_bankleft, NULL};		
+
+
+void flyer_fire (edict_t *self, int flash_number)
+{
+	vec3_t	start;
+	vec3_t	forward, right;
+	vec3_t	end;
+	vec3_t	dir;
+	int		effect;
+
+	if ((self->s.frame == FRAME_attak204) || (self->s.frame == FRAME_attak207) || (self->s.frame == FRAME_attak210))
+		effect = EF_HYPERBLASTER;
+	else
+		effect = 0;
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+	
+	VectorCopy (self->enemy->s.origin, end);
+	end[2] += self->enemy->viewheight;
+	VectorSubtract (end, start, dir);
+
+	monster_fire_blaster (self, start, dir, 1, 1000, flash_number, effect);
+}
+
+void flyer_fireleft (edict_t *self)
+{
+	flyer_fire (self, MZ2_FLYER_BLASTER_1);
+}
+
+void flyer_fireright (edict_t *self)
+{
+	flyer_fire (self, MZ2_FLYER_BLASTER_2);
+}
+
+
+mframe_t flyer_frames_attack2 [] =
+{
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, -10, flyer_fireleft,			// left gun
+		ai_charge, -10, flyer_fireright,		// right gun
+		ai_charge, -10, flyer_fireleft,			// left gun
+		ai_charge, -10, flyer_fireright,		// right gun
+		ai_charge, -10, flyer_fireleft,			// left gun
+		ai_charge, -10, flyer_fireright,		// right gun
+		ai_charge, -10, flyer_fireleft,			// left gun
+		ai_charge, -10, flyer_fireright,		// right gun
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL
+};
+mmove_t flyer_move_attack2 = {FRAME_attak201, FRAME_attak217, flyer_frames_attack2, flyer_run};
+
+
+void flyer_slash_left (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->mins[0], 0);
+	fire_hit (self, aim, 5, 0);
+	gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
+}
+
+void flyer_slash_right (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 0);
+	fire_hit (self, aim, 5, 0);
+	gi.sound (self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
+}
+
+mframe_t flyer_frames_start_melee [] =
+{
+		ai_charge, 0, flyer_pop_blades,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL
+};
+mmove_t flyer_move_start_melee = {FRAME_attak101, FRAME_attak106, flyer_frames_start_melee, flyer_loop_melee};
+
+mframe_t flyer_frames_end_melee [] =
+{
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL
+};
+mmove_t flyer_move_end_melee = {FRAME_attak119, FRAME_attak121, flyer_frames_end_melee, flyer_run};
+
+
+mframe_t flyer_frames_loop_melee [] =
+{
+		ai_charge, 0, NULL,		// Loop Start
+		ai_charge, 0, NULL,
+		ai_charge, 0, flyer_slash_left,		// Left Wing Strike
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, flyer_slash_right,	// Right Wing Strike
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL,
+		ai_charge, 0, NULL		// Loop Ends
+		
+};
+mmove_t flyer_move_loop_melee = {FRAME_attak107, FRAME_attak118, flyer_frames_loop_melee, flyer_check_melee};
+
+void flyer_loop_melee (edict_t *self)
+{
+/*	if (random() <= 0.5)	
+		self->monsterinfo.currentmove = &flyer_move_attack1;
+	else */
+	self->monsterinfo.currentmove = &flyer_move_loop_melee;
+}
+
+
+
+void flyer_attack (edict_t *self)
+{
+/*	if (random() <= 0.5)	
+		self->monsterinfo.currentmove = &flyer_move_attack1;
+	else */
+	self->monsterinfo.currentmove = &flyer_move_attack2;
+}
+
+void flyer_setstart (edict_t *self)
+{
+	nextmove = ACTION_run;
+	self->monsterinfo.currentmove = &flyer_move_start;
+}
+
+void flyer_nextmove (edict_t *self)
+{
+	if (nextmove == ACTION_attack1)
+		self->monsterinfo.currentmove = &flyer_move_start_melee;
+	else if (nextmove == ACTION_attack2)
+		self->monsterinfo.currentmove = &flyer_move_attack2;
+	else if (nextmove == ACTION_run)
+		self->monsterinfo.currentmove = &flyer_move_run;
+}
+
+void flyer_melee (edict_t *self)
+{
+//	flyer.nextmove = ACTION_attack1;
+//	self->monsterinfo.currentmove = &flyer_move_stop;
+	self->monsterinfo.currentmove = &flyer_move_start_melee;
+}
+
+void flyer_check_melee(edict_t *self)
+{
+	if (range (self, self->enemy) == RANGE_MELEE)
+		if (random() <= 0.8)
+			self->monsterinfo.currentmove = &flyer_move_loop_melee;
+		else
+			self->monsterinfo.currentmove = &flyer_move_end_melee;
+	else
+		self->monsterinfo.currentmove = &flyer_move_end_melee;
+}
+
+void flyer_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	int		n;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	n = rand() % 3;
+	if (n == 0)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &flyer_move_pain1;
+	}
+	else if (n == 1)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &flyer_move_pain2;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &flyer_move_pain3;
+	}
+}
+
+
+void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+	BecomeExplosion1(self);
+}
+	
+
+/*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_flyer (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	// fix a map bug in jail5.bsp
+	if (!Q_stricmp(level.mapname, "jail5") && (self->s.origin[2] == -104))
+	{
+		self->targetname = self->target;
+		self->target = NULL;
+	}
+
+	sound_sight = gi.soundindex ("flyer/flysght1.wav");
+	sound_idle = gi.soundindex ("flyer/flysrch1.wav");
+	sound_pain1 = gi.soundindex ("flyer/flypain1.wav");
+	sound_pain2 = gi.soundindex ("flyer/flypain2.wav");
+	sound_slash = gi.soundindex ("flyer/flyatck2.wav");
+	sound_sproing = gi.soundindex ("flyer/flyatck1.wav");
+	sound_die = gi.soundindex ("flyer/flydeth1.wav");
+
+	gi.soundindex ("flyer/flyatck3.wav");
+
+	self->s.modelindex = gi.modelindex ("models/monsters/flyer/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+
+	self->s.sound = gi.soundindex ("flyer/flyidle1.wav");
+
+	self->health = 50;
+	self->mass = 50;
+
+	self->pain = flyer_pain;
+	self->die = flyer_die;
+
+	self->monsterinfo.stand = flyer_stand;
+	self->monsterinfo.walk = flyer_walk;
+	self->monsterinfo.run = flyer_run;
+	self->monsterinfo.attack = flyer_attack;
+	self->monsterinfo.melee = flyer_melee;
+	self->monsterinfo.sight = flyer_sight;
+	self->monsterinfo.idle = flyer_idle;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &flyer_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	flymonster_start (self);
+}
--- /dev/null
+++ b/game/m_flyer.h
@@ -1,0 +1,182 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/flyer
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define ACTION_nothing			0
+#define ACTION_attack1			1
+#define ACTION_attack2			2
+#define ACTION_run				3
+#define ACTION_walk				4
+
+#define FRAME_start01         	0
+#define FRAME_start02         	1
+#define FRAME_start03         	2
+#define FRAME_start04         	3
+#define FRAME_start05         	4
+#define FRAME_start06         	5
+#define FRAME_stop01          	6
+#define FRAME_stop02          	7
+#define FRAME_stop03          	8
+#define FRAME_stop04          	9
+#define FRAME_stop05          	10
+#define FRAME_stop06          	11
+#define FRAME_stop07          	12
+#define FRAME_stand01         	13
+#define FRAME_stand02         	14
+#define FRAME_stand03         	15
+#define FRAME_stand04         	16
+#define FRAME_stand05         	17
+#define FRAME_stand06         	18
+#define FRAME_stand07         	19
+#define FRAME_stand08         	20
+#define FRAME_stand09         	21
+#define FRAME_stand10         	22
+#define FRAME_stand11         	23
+#define FRAME_stand12         	24
+#define FRAME_stand13         	25
+#define FRAME_stand14         	26
+#define FRAME_stand15         	27
+#define FRAME_stand16         	28
+#define FRAME_stand17         	29
+#define FRAME_stand18         	30
+#define FRAME_stand19         	31
+#define FRAME_stand20         	32
+#define FRAME_stand21         	33
+#define FRAME_stand22         	34
+#define FRAME_stand23         	35
+#define FRAME_stand24         	36
+#define FRAME_stand25         	37
+#define FRAME_stand26         	38
+#define FRAME_stand27         	39
+#define FRAME_stand28         	40
+#define FRAME_stand29         	41
+#define FRAME_stand30         	42
+#define FRAME_stand31         	43
+#define FRAME_stand32         	44
+#define FRAME_stand33         	45
+#define FRAME_stand34         	46
+#define FRAME_stand35         	47
+#define FRAME_stand36         	48
+#define FRAME_stand37         	49
+#define FRAME_stand38         	50
+#define FRAME_stand39         	51
+#define FRAME_stand40         	52
+#define FRAME_stand41         	53
+#define FRAME_stand42         	54
+#define FRAME_stand43         	55
+#define FRAME_stand44         	56
+#define FRAME_stand45         	57
+#define FRAME_attak101        	58
+#define FRAME_attak102        	59
+#define FRAME_attak103        	60
+#define FRAME_attak104        	61
+#define FRAME_attak105        	62
+#define FRAME_attak106        	63
+#define FRAME_attak107        	64
+#define FRAME_attak108        	65
+#define FRAME_attak109        	66
+#define FRAME_attak110        	67
+#define FRAME_attak111        	68
+#define FRAME_attak112        	69
+#define FRAME_attak113        	70
+#define FRAME_attak114        	71
+#define FRAME_attak115        	72
+#define FRAME_attak116        	73
+#define FRAME_attak117        	74
+#define FRAME_attak118        	75
+#define FRAME_attak119        	76
+#define FRAME_attak120        	77
+#define FRAME_attak121        	78
+#define FRAME_attak201        	79
+#define FRAME_attak202        	80
+#define FRAME_attak203        	81
+#define FRAME_attak204        	82
+#define FRAME_attak205        	83
+#define FRAME_attak206        	84
+#define FRAME_attak207        	85
+#define FRAME_attak208        	86
+#define FRAME_attak209        	87
+#define FRAME_attak210        	88
+#define FRAME_attak211        	89
+#define FRAME_attak212        	90
+#define FRAME_attak213        	91
+#define FRAME_attak214        	92
+#define FRAME_attak215        	93
+#define FRAME_attak216        	94
+#define FRAME_attak217        	95
+#define FRAME_bankl01         	96
+#define FRAME_bankl02         	97
+#define FRAME_bankl03         	98
+#define FRAME_bankl04         	99
+#define FRAME_bankl05         	100
+#define FRAME_bankl06         	101
+#define FRAME_bankl07         	102
+#define FRAME_bankr01         	103
+#define FRAME_bankr02         	104
+#define FRAME_bankr03         	105
+#define FRAME_bankr04         	106
+#define FRAME_bankr05         	107
+#define FRAME_bankr06         	108
+#define FRAME_bankr07         	109
+#define FRAME_rollf01         	110
+#define FRAME_rollf02         	111
+#define FRAME_rollf03         	112
+#define FRAME_rollf04         	113
+#define FRAME_rollf05         	114
+#define FRAME_rollf06         	115
+#define FRAME_rollf07         	116
+#define FRAME_rollf08         	117
+#define FRAME_rollf09         	118
+#define FRAME_rollr01         	119
+#define FRAME_rollr02         	120
+#define FRAME_rollr03         	121
+#define FRAME_rollr04         	122
+#define FRAME_rollr05         	123
+#define FRAME_rollr06         	124
+#define FRAME_rollr07         	125
+#define FRAME_rollr08         	126
+#define FRAME_rollr09         	127
+#define FRAME_defens01        	128
+#define FRAME_defens02        	129
+#define FRAME_defens03        	130
+#define FRAME_defens04        	131
+#define FRAME_defens05        	132
+#define FRAME_defens06        	133
+#define FRAME_pain101         	134
+#define FRAME_pain102         	135
+#define FRAME_pain103         	136
+#define FRAME_pain104         	137
+#define FRAME_pain105         	138
+#define FRAME_pain106         	139
+#define FRAME_pain107         	140
+#define FRAME_pain108         	141
+#define FRAME_pain109         	142
+#define FRAME_pain201         	143
+#define FRAME_pain202         	144
+#define FRAME_pain203         	145
+#define FRAME_pain204         	146
+#define FRAME_pain301         	147
+#define FRAME_pain302         	148
+#define FRAME_pain303         	149
+#define FRAME_pain304         	150
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_gladiator.c
@@ -1,0 +1,387 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+GLADIATOR
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_gladiator.h"
+
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_die;
+static int	sound_gun;
+static int	sound_cleaver_swing;
+static int	sound_cleaver_hit;
+static int	sound_cleaver_miss;
+static int	sound_idle;
+static int	sound_search;
+static int	sound_sight;
+
+
+void gladiator_idle (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+void gladiator_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void gladiator_search (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+}
+
+void gladiator_cleaver_swing (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_cleaver_swing, 1, ATTN_NORM, 0);
+}
+
+mframe_t gladiator_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t gladiator_move_stand = {FRAME_stand1, FRAME_stand7, gladiator_frames_stand, NULL};
+
+void gladiator_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &gladiator_move_stand;
+}
+
+
+mframe_t gladiator_frames_walk [] =
+{
+	ai_walk, 15, NULL,
+	ai_walk, 7,  NULL,
+	ai_walk, 6,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 8,  NULL,
+	ai_walk, 12, NULL,
+	ai_walk, 8,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 1,  NULL,
+	ai_walk, 8,  NULL
+};
+mmove_t gladiator_move_walk = {FRAME_walk1, FRAME_walk16, gladiator_frames_walk, NULL};
+
+void gladiator_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &gladiator_move_walk;
+}
+
+
+mframe_t gladiator_frames_run [] =
+{
+	ai_run, 23,	NULL,
+	ai_run, 14,	NULL,
+	ai_run, 14,	NULL,
+	ai_run, 21,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 13,	NULL
+};
+mmove_t gladiator_move_run = {FRAME_run1, FRAME_run6, gladiator_frames_run, NULL};
+
+void gladiator_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &gladiator_move_stand;
+	else
+		self->monsterinfo.currentmove = &gladiator_move_run;
+}
+
+
+void GaldiatorMelee (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
+	if (fire_hit (self, aim, (20 + (rand() %5)), 300))
+		gi.sound (self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_AUTO, sound_cleaver_miss, 1, ATTN_NORM, 0);
+}
+
+mframe_t gladiator_frames_attack_melee [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, gladiator_cleaver_swing,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GaldiatorMelee,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, gladiator_cleaver_swing,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GaldiatorMelee,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t gladiator_move_attack_melee = {FRAME_melee1, FRAME_melee17, gladiator_frames_attack_melee, gladiator_run};
+
+void gladiator_melee(edict_t *self)
+{
+	self->monsterinfo.currentmove = &gladiator_move_attack_melee;
+}
+
+
+void GladiatorGun (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	forward, right;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_GLADIATOR_RAILGUN_1], forward, right, start);
+
+	// calc direction to where we targted
+	VectorSubtract (self->pos1, start, dir);
+	VectorNormalize (dir);
+
+	monster_fire_railgun (self, start, dir, 50, 100, MZ2_GLADIATOR_RAILGUN_1);
+}
+
+mframe_t gladiator_frames_attack_gun [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GladiatorGun,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t gladiator_move_attack_gun = {FRAME_attack1, FRAME_attack9, gladiator_frames_attack_gun, gladiator_run};
+
+void gladiator_attack(edict_t *self)
+{
+	float	range;
+	vec3_t	v;
+
+	// a small safe zone
+	VectorSubtract (self->s.origin, self->enemy->s.origin, v);
+	range = VectorLength(v);
+	if (range <= (MELEE_DISTANCE + 32))
+		return;
+
+	// charge up the railgun
+	gi.sound (self, CHAN_WEAPON, sound_gun, 1, ATTN_NORM, 0);
+	VectorCopy (self->enemy->s.origin, self->pos1);	//save for aiming the shot
+	self->pos1[2] += self->enemy->viewheight;
+	self->monsterinfo.currentmove = &gladiator_move_attack_gun;
+}
+
+
+mframe_t gladiator_frames_pain [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t gladiator_move_pain = {FRAME_pain1, FRAME_pain6, gladiator_frames_pain, gladiator_run};
+
+mframe_t gladiator_frames_pain_air [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t gladiator_move_pain_air = {FRAME_painup1, FRAME_painup7, gladiator_frames_pain_air, gladiator_run};
+
+void gladiator_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+	{
+		if ((self->velocity[2] > 100) && (self->monsterinfo.currentmove == &gladiator_move_pain))
+			self->monsterinfo.currentmove = &gladiator_move_pain_air;
+		return;
+	}
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (self->velocity[2] > 100)
+		self->monsterinfo.currentmove = &gladiator_move_pain_air;
+	else
+		self->monsterinfo.currentmove = &gladiator_move_pain;
+	
+}
+
+
+void gladiator_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t gladiator_frames_death [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t gladiator_move_death = {FRAME_death1, FRAME_death22, gladiator_frames_death, gladiator_dead};
+
+void gladiator_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	self->monsterinfo.currentmove = &gladiator_move_death;
+}
+
+
+/*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_gladiator (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+
+	sound_pain1 = gi.soundindex ("gladiator/pain.wav");	
+	sound_pain2 = gi.soundindex ("gladiator/gldpain2.wav");	
+	sound_die = gi.soundindex ("gladiator/glddeth2.wav");	
+	sound_gun = gi.soundindex ("gladiator/railgun.wav");
+	sound_cleaver_swing = gi.soundindex ("gladiator/melee1.wav");
+	sound_cleaver_hit = gi.soundindex ("gladiator/melee2.wav");
+	sound_cleaver_miss = gi.soundindex ("gladiator/melee3.wav");
+	sound_idle = gi.soundindex ("gladiator/gldidle1.wav");
+	sound_search = gi.soundindex ("gladiator/gldsrch1.wav");
+	sound_sight = gi.soundindex ("gladiator/sight.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/gladiatr/tris.md2");
+	VectorSet (self->mins, -32, -32, -24);
+	VectorSet (self->maxs, 32, 32, 64);
+
+	self->health = 400;
+	self->gib_health = -175;
+	self->mass = 400;
+
+	self->pain = gladiator_pain;
+	self->die = gladiator_die;
+
+	self->monsterinfo.stand = gladiator_stand;
+	self->monsterinfo.walk = gladiator_walk;
+	self->monsterinfo.run = gladiator_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = gladiator_attack;
+	self->monsterinfo.melee = gladiator_melee;
+	self->monsterinfo.sight = gladiator_sight;
+	self->monsterinfo.idle = gladiator_idle;
+	self->monsterinfo.search = gladiator_search;
+
+	gi.linkentity (self);
+	self->monsterinfo.currentmove = &gladiator_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_gladiator.h
@@ -1,0 +1,115 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/gladiatr
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand1          	0
+#define FRAME_stand2          	1
+#define FRAME_stand3          	2
+#define FRAME_stand4          	3
+#define FRAME_stand5          	4
+#define FRAME_stand6          	5
+#define FRAME_stand7          	6
+#define FRAME_walk1           	7
+#define FRAME_walk2           	8
+#define FRAME_walk3           	9
+#define FRAME_walk4           	10
+#define FRAME_walk5           	11
+#define FRAME_walk6           	12
+#define FRAME_walk7           	13
+#define FRAME_walk8           	14
+#define FRAME_walk9           	15
+#define FRAME_walk10          	16
+#define FRAME_walk11          	17
+#define FRAME_walk12          	18
+#define FRAME_walk13          	19
+#define FRAME_walk14          	20
+#define FRAME_walk15          	21
+#define FRAME_walk16          	22
+#define FRAME_run1            	23
+#define FRAME_run2            	24
+#define FRAME_run3            	25
+#define FRAME_run4            	26
+#define FRAME_run5            	27
+#define FRAME_run6            	28
+#define FRAME_melee1          	29
+#define FRAME_melee2          	30
+#define FRAME_melee3          	31
+#define FRAME_melee4          	32
+#define FRAME_melee5          	33
+#define FRAME_melee6          	34
+#define FRAME_melee7          	35
+#define FRAME_melee8          	36
+#define FRAME_melee9          	37
+#define FRAME_melee10         	38
+#define FRAME_melee11         	39
+#define FRAME_melee12         	40
+#define FRAME_melee13         	41
+#define FRAME_melee14         	42
+#define FRAME_melee15         	43
+#define FRAME_melee16         	44
+#define FRAME_melee17         	45
+#define FRAME_attack1         	46
+#define FRAME_attack2         	47
+#define FRAME_attack3         	48
+#define FRAME_attack4         	49
+#define FRAME_attack5         	50
+#define FRAME_attack6         	51
+#define FRAME_attack7         	52
+#define FRAME_attack8         	53
+#define FRAME_attack9         	54
+#define FRAME_pain1           	55
+#define FRAME_pain2           	56
+#define FRAME_pain3           	57
+#define FRAME_pain4           	58
+#define FRAME_pain5           	59
+#define FRAME_pain6           	60
+#define FRAME_death1          	61
+#define FRAME_death2          	62
+#define FRAME_death3          	63
+#define FRAME_death4          	64
+#define FRAME_death5          	65
+#define FRAME_death6          	66
+#define FRAME_death7          	67
+#define FRAME_death8          	68
+#define FRAME_death9          	69
+#define FRAME_death10         	70
+#define FRAME_death11         	71
+#define FRAME_death12         	72
+#define FRAME_death13         	73
+#define FRAME_death14         	74
+#define FRAME_death15         	75
+#define FRAME_death16         	76
+#define FRAME_death17         	77
+#define FRAME_death18         	78
+#define FRAME_death19         	79
+#define FRAME_death20         	80
+#define FRAME_death21         	81
+#define FRAME_death22         	82
+#define FRAME_painup1         	83
+#define FRAME_painup2         	84
+#define FRAME_painup3         	85
+#define FRAME_painup4         	86
+#define FRAME_painup5         	87
+#define FRAME_painup6         	88
+#define FRAME_painup7         	89
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_gunner.c
@@ -1,0 +1,628 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+GUNNER
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_gunner.h"
+
+
+static int	sound_pain;
+static int	sound_pain2;
+static int	sound_death;
+static int	sound_idle;
+static int	sound_open;
+static int	sound_search;
+static int	sound_sight;
+
+
+void gunner_idlesound (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+void gunner_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void gunner_search (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+}
+
+
+qboolean visible (edict_t *self, edict_t *other);
+void GunnerGrenade (edict_t *self);
+void GunnerFire (edict_t *self);
+void gunner_fire_chain(edict_t *self);
+void gunner_refire_chain(edict_t *self);
+
+
+void gunner_stand (edict_t *self);
+
+mframe_t gunner_frames_fidget [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, gunner_idlesound,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand};
+
+void gunner_fidget (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		return;
+	if (random() <= 0.05)
+		self->monsterinfo.currentmove = &gunner_move_fidget;
+}
+
+mframe_t gunner_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, gunner_fidget,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, gunner_fidget,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, gunner_fidget
+};
+mmove_t	gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL};
+
+void gunner_stand (edict_t *self)
+{
+		self->monsterinfo.currentmove = &gunner_move_stand;
+}
+
+
+mframe_t gunner_frames_walk [] =
+{
+	ai_walk, 0, NULL,
+	ai_walk, 3, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 7, NULL,
+	ai_walk, 2, NULL,
+	ai_walk, 6, NULL,
+	ai_walk, 4, NULL,
+	ai_walk, 2, NULL,
+	ai_walk, 7, NULL,
+	ai_walk, 5, NULL,
+	ai_walk, 7, NULL,
+	ai_walk, 4, NULL
+};
+mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL};
+
+void gunner_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &gunner_move_walk;
+}
+
+mframe_t gunner_frames_run [] =
+{
+	ai_run, 26, NULL,
+	ai_run, 9,  NULL,
+	ai_run, 9,  NULL,
+	ai_run, 9,  NULL,
+	ai_run, 15, NULL,
+	ai_run, 10, NULL,
+	ai_run, 13, NULL,
+	ai_run, 6,  NULL
+};
+
+mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL};
+
+void gunner_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &gunner_move_stand;
+	else
+		self->monsterinfo.currentmove = &gunner_move_run;
+}
+
+mframe_t gunner_frames_runandshoot [] =
+{
+	ai_run, 32, NULL,
+	ai_run, 15, NULL,
+	ai_run, 10, NULL,
+	ai_run, 18, NULL,
+	ai_run, 8,  NULL,
+	ai_run, 20, NULL
+};
+
+mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL};
+
+void gunner_runandshoot (edict_t *self)
+{
+	self->monsterinfo.currentmove = &gunner_move_runandshoot;
+}
+
+mframe_t gunner_frames_pain3 [] =
+{
+	ai_move, -3, NULL,
+	ai_move, 1,	 NULL,
+	ai_move, 1,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 1,	 NULL
+};
+mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run};
+
+mframe_t gunner_frames_pain2 [] =
+{
+	ai_move, -2, NULL,
+	ai_move, 11, NULL,
+	ai_move, 6,	 NULL,
+	ai_move, 2,	 NULL,
+	ai_move, -1, NULL,
+	ai_move, -7, NULL,
+	ai_move, -2, NULL,
+	ai_move, -7, NULL
+};
+mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run};
+
+mframe_t gunner_frames_pain1 [] =
+{
+	ai_move, 2,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, -5, NULL,
+	ai_move, 3,	 NULL,
+	ai_move, -1, NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 1,	 NULL,
+	ai_move, 1,	 NULL,
+	ai_move, 2,	 NULL,
+	ai_move, 1,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, -2, NULL,
+	ai_move, -2, NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL
+};
+mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run};
+
+void gunner_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (rand()&1)
+		gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (damage <= 10)
+		self->monsterinfo.currentmove = &gunner_move_pain3;
+	else if (damage <= 25)
+		self->monsterinfo.currentmove = &gunner_move_pain2;
+	else
+		self->monsterinfo.currentmove = &gunner_move_pain1;
+}
+
+void gunner_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t gunner_frames_death [] =
+{
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, -7, NULL,
+	ai_move, -3, NULL,
+	ai_move, -5, NULL,
+	ai_move, 8,	 NULL,
+	ai_move, 6,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL
+};
+mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead};
+
+void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.currentmove = &gunner_move_death;
+}
+
+
+void gunner_duck_down (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_DUCKED)
+		return;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	if (skill->value >= 2)
+	{
+		if (random() > 0.5)
+			GunnerGrenade (self);
+	}
+
+	self->maxs[2] -= 32;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.pausetime = level.time + 1;
+	gi.linkentity (self);
+}
+
+void gunner_duck_hold (edict_t *self)
+{
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+void gunner_duck_up (edict_t *self)
+{
+	self->monsterinfo.aiflags &= ~AI_DUCKED;
+	self->maxs[2] += 32;
+	self->takedamage = DAMAGE_AIM;
+	gi.linkentity (self);
+}
+
+mframe_t gunner_frames_duck [] =
+{
+	ai_move, 1,  gunner_duck_down,
+	ai_move, 1,  NULL,
+	ai_move, 1,  gunner_duck_hold,
+	ai_move, 0,  NULL,
+	ai_move, -1, NULL,
+	ai_move, -1, NULL,
+	ai_move, 0,  gunner_duck_up,
+	ai_move, -1, NULL
+};
+mmove_t	gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run};
+
+void gunner_dodge (edict_t *self, edict_t *attacker, float eta)
+{
+	if (random() > 0.25)
+		return;
+
+	if (!self->enemy)
+		self->enemy = attacker;
+
+	self->monsterinfo.currentmove = &gunner_move_duck;
+}
+
+
+void gunner_opengun (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
+}
+
+void GunnerFire (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	forward, right;
+	vec3_t	target;
+	vec3_t	aim;
+	int		flash_number;
+
+	flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	// project enemy back a bit and target there
+	VectorCopy (self->enemy->s.origin, target);
+	VectorMA (target, -0.2, self->enemy->velocity, target);
+	target[2] += self->enemy->viewheight;
+
+	VectorSubtract (target, start, aim);
+	VectorNormalize (aim);
+	monster_fire_bullet (self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+}
+
+void GunnerGrenade (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	forward, right;
+	vec3_t	aim;
+	int		flash_number;
+
+	if (self->s.frame == FRAME_attak105)
+		flash_number = MZ2_GUNNER_GRENADE_1;
+	else if (self->s.frame == FRAME_attak108)
+		flash_number = MZ2_GUNNER_GRENADE_2;
+	else if (self->s.frame == FRAME_attak111)
+		flash_number = MZ2_GUNNER_GRENADE_3;
+	else // (self->s.frame == FRAME_attak114)
+		flash_number = MZ2_GUNNER_GRENADE_4;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	//FIXME : do a spread -225 -75 75 225 degrees around forward
+	VectorCopy (forward, aim);
+
+	monster_fire_grenade (self, start, aim, 50, 600, flash_number);
+}
+
+mframe_t gunner_frames_attack_chain [] =
+{
+	/*
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	*/
+	ai_charge, 0, gunner_opengun,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain};
+
+mframe_t gunner_frames_fire_chain [] =
+{
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire,
+	ai_charge,   0, GunnerFire
+};
+mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain};
+
+mframe_t gunner_frames_endfire_chain [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run};
+
+mframe_t gunner_frames_attack_grenade [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GunnerGrenade,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GunnerGrenade,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GunnerGrenade,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, GunnerGrenade,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run};
+
+void gunner_attack(edict_t *self)
+{
+	if (range (self, self->enemy) == RANGE_MELEE)
+	{
+		self->monsterinfo.currentmove = &gunner_move_attack_chain;
+	}
+	else
+	{
+		if (random() <= 0.5)
+			self->monsterinfo.currentmove = &gunner_move_attack_grenade;
+		else
+			self->monsterinfo.currentmove = &gunner_move_attack_chain;
+	}
+}
+
+void gunner_fire_chain(edict_t *self)
+{
+	self->monsterinfo.currentmove = &gunner_move_fire_chain;
+}
+
+void gunner_refire_chain(edict_t *self)
+{
+	if (self->enemy->health > 0)
+		if ( visible (self, self->enemy) )
+			if (random() <= 0.5)
+			{
+				self->monsterinfo.currentmove = &gunner_move_fire_chain;
+				return;
+			}
+	self->monsterinfo.currentmove = &gunner_move_endfire_chain;
+}
+
+/*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_gunner (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_death = gi.soundindex ("gunner/death1.wav");	
+	sound_pain = gi.soundindex ("gunner/gunpain2.wav");	
+	sound_pain2 = gi.soundindex ("gunner/gunpain1.wav");	
+	sound_idle = gi.soundindex ("gunner/gunidle1.wav");	
+	sound_open = gi.soundindex ("gunner/gunatck1.wav");	
+	sound_search = gi.soundindex ("gunner/gunsrch1.wav");	
+	sound_sight = gi.soundindex ("gunner/sight1.wav");	
+
+	gi.soundindex ("gunner/gunatck2.wav");
+	gi.soundindex ("gunner/gunatck3.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	self->health = 175;
+	self->gib_health = -70;
+	self->mass = 200;
+
+	self->pain = gunner_pain;
+	self->die = gunner_die;
+
+	self->monsterinfo.stand = gunner_stand;
+	self->monsterinfo.walk = gunner_walk;
+	self->monsterinfo.run = gunner_run;
+	self->monsterinfo.dodge = gunner_dodge;
+	self->monsterinfo.attack = gunner_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = gunner_sight;
+	self->monsterinfo.search = gunner_search;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &gunner_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_gunner.h
@@ -1,0 +1,234 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/gunner
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand01         	0
+#define FRAME_stand02         	1
+#define FRAME_stand03         	2
+#define FRAME_stand04         	3
+#define FRAME_stand05         	4
+#define FRAME_stand06         	5
+#define FRAME_stand07         	6
+#define FRAME_stand08         	7
+#define FRAME_stand09         	8
+#define FRAME_stand10         	9
+#define FRAME_stand11         	10
+#define FRAME_stand12         	11
+#define FRAME_stand13         	12
+#define FRAME_stand14         	13
+#define FRAME_stand15         	14
+#define FRAME_stand16         	15
+#define FRAME_stand17         	16
+#define FRAME_stand18         	17
+#define FRAME_stand19         	18
+#define FRAME_stand20         	19
+#define FRAME_stand21         	20
+#define FRAME_stand22         	21
+#define FRAME_stand23         	22
+#define FRAME_stand24         	23
+#define FRAME_stand25         	24
+#define FRAME_stand26         	25
+#define FRAME_stand27         	26
+#define FRAME_stand28         	27
+#define FRAME_stand29         	28
+#define FRAME_stand30         	29
+#define FRAME_stand31         	30
+#define FRAME_stand32         	31
+#define FRAME_stand33         	32
+#define FRAME_stand34         	33
+#define FRAME_stand35         	34
+#define FRAME_stand36         	35
+#define FRAME_stand37         	36
+#define FRAME_stand38         	37
+#define FRAME_stand39         	38
+#define FRAME_stand40         	39
+#define FRAME_stand41         	40
+#define FRAME_stand42         	41
+#define FRAME_stand43         	42
+#define FRAME_stand44         	43
+#define FRAME_stand45         	44
+#define FRAME_stand46         	45
+#define FRAME_stand47         	46
+#define FRAME_stand48         	47
+#define FRAME_stand49         	48
+#define FRAME_stand50         	49
+#define FRAME_stand51         	50
+#define FRAME_stand52         	51
+#define FRAME_stand53         	52
+#define FRAME_stand54         	53
+#define FRAME_stand55         	54
+#define FRAME_stand56         	55
+#define FRAME_stand57         	56
+#define FRAME_stand58         	57
+#define FRAME_stand59         	58
+#define FRAME_stand60         	59
+#define FRAME_stand61         	60
+#define FRAME_stand62         	61
+#define FRAME_stand63         	62
+#define FRAME_stand64         	63
+#define FRAME_stand65         	64
+#define FRAME_stand66         	65
+#define FRAME_stand67         	66
+#define FRAME_stand68         	67
+#define FRAME_stand69         	68
+#define FRAME_stand70         	69
+#define FRAME_walk01          	70
+#define FRAME_walk02          	71
+#define FRAME_walk03          	72
+#define FRAME_walk04          	73
+#define FRAME_walk05          	74
+#define FRAME_walk06          	75
+#define FRAME_walk07          	76
+#define FRAME_walk08          	77
+#define FRAME_walk09          	78
+#define FRAME_walk10          	79
+#define FRAME_walk11          	80
+#define FRAME_walk12          	81
+#define FRAME_walk13          	82
+#define FRAME_walk14          	83
+#define FRAME_walk15          	84
+#define FRAME_walk16          	85
+#define FRAME_walk17          	86
+#define FRAME_walk18          	87
+#define FRAME_walk19          	88
+#define FRAME_walk20          	89
+#define FRAME_walk21          	90
+#define FRAME_walk22          	91
+#define FRAME_walk23          	92
+#define FRAME_walk24          	93
+#define FRAME_run01           	94
+#define FRAME_run02           	95
+#define FRAME_run03           	96
+#define FRAME_run04           	97
+#define FRAME_run05           	98
+#define FRAME_run06           	99
+#define FRAME_run07           	100
+#define FRAME_run08           	101
+#define FRAME_runs01          	102
+#define FRAME_runs02          	103
+#define FRAME_runs03          	104
+#define FRAME_runs04          	105
+#define FRAME_runs05          	106
+#define FRAME_runs06          	107
+#define FRAME_attak101        	108
+#define FRAME_attak102        	109
+#define FRAME_attak103        	110
+#define FRAME_attak104        	111
+#define FRAME_attak105        	112
+#define FRAME_attak106        	113
+#define FRAME_attak107        	114
+#define FRAME_attak108        	115
+#define FRAME_attak109        	116
+#define FRAME_attak110        	117
+#define FRAME_attak111        	118
+#define FRAME_attak112        	119
+#define FRAME_attak113        	120
+#define FRAME_attak114        	121
+#define FRAME_attak115        	122
+#define FRAME_attak116        	123
+#define FRAME_attak117        	124
+#define FRAME_attak118        	125
+#define FRAME_attak119        	126
+#define FRAME_attak120        	127
+#define FRAME_attak121        	128
+#define FRAME_attak201        	129
+#define FRAME_attak202        	130
+#define FRAME_attak203        	131
+#define FRAME_attak204        	132
+#define FRAME_attak205        	133
+#define FRAME_attak206        	134
+#define FRAME_attak207        	135
+#define FRAME_attak208        	136
+#define FRAME_attak209        	137
+#define FRAME_attak210        	138
+#define FRAME_attak211        	139
+#define FRAME_attak212        	140
+#define FRAME_attak213        	141
+#define FRAME_attak214        	142
+#define FRAME_attak215        	143
+#define FRAME_attak216        	144
+#define FRAME_attak217        	145
+#define FRAME_attak218        	146
+#define FRAME_attak219        	147
+#define FRAME_attak220        	148
+#define FRAME_attak221        	149
+#define FRAME_attak222        	150
+#define FRAME_attak223        	151
+#define FRAME_attak224        	152
+#define FRAME_attak225        	153
+#define FRAME_attak226        	154
+#define FRAME_attak227        	155
+#define FRAME_attak228        	156
+#define FRAME_attak229        	157
+#define FRAME_attak230        	158
+#define FRAME_pain101         	159
+#define FRAME_pain102         	160
+#define FRAME_pain103         	161
+#define FRAME_pain104         	162
+#define FRAME_pain105         	163
+#define FRAME_pain106         	164
+#define FRAME_pain107         	165
+#define FRAME_pain108         	166
+#define FRAME_pain109         	167
+#define FRAME_pain110         	168
+#define FRAME_pain111         	169
+#define FRAME_pain112         	170
+#define FRAME_pain113         	171
+#define FRAME_pain114         	172
+#define FRAME_pain115         	173
+#define FRAME_pain116         	174
+#define FRAME_pain117         	175
+#define FRAME_pain118         	176
+#define FRAME_pain201         	177
+#define FRAME_pain202         	178
+#define FRAME_pain203         	179
+#define FRAME_pain204         	180
+#define FRAME_pain205         	181
+#define FRAME_pain206         	182
+#define FRAME_pain207         	183
+#define FRAME_pain208         	184
+#define FRAME_pain301         	185
+#define FRAME_pain302         	186
+#define FRAME_pain303         	187
+#define FRAME_pain304         	188
+#define FRAME_pain305         	189
+#define FRAME_death01         	190
+#define FRAME_death02         	191
+#define FRAME_death03         	192
+#define FRAME_death04         	193
+#define FRAME_death05         	194
+#define FRAME_death06         	195
+#define FRAME_death07         	196
+#define FRAME_death08         	197
+#define FRAME_death09         	198
+#define FRAME_death10         	199
+#define FRAME_death11         	200
+#define FRAME_duck01          	201
+#define FRAME_duck02          	202
+#define FRAME_duck03          	203
+#define FRAME_duck04          	204
+#define FRAME_duck05          	205
+#define FRAME_duck06          	206
+#define FRAME_duck07          	207
+#define FRAME_duck08          	208
+
+#define MODEL_SCALE		1.150000
--- /dev/null
+++ b/game/m_hover.c
@@ -1,0 +1,620 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+hover
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_hover.h"
+
+qboolean visible (edict_t *self, edict_t *other);
+
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_death1;
+static int	sound_death2;
+static int	sound_sight;
+static int	sound_search1;
+static int	sound_search2;
+
+
+void hover_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void hover_search (edict_t *self)
+{
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
+}
+
+
+void hover_run (edict_t *self);
+void hover_stand (edict_t *self);
+void hover_dead (edict_t *self);
+void hover_attack (edict_t *self);
+void hover_reattack (edict_t *self);
+void hover_fire_blaster (edict_t *self);
+void hover_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
+
+mframe_t hover_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	hover_move_stand = {FRAME_stand01, FRAME_stand30, hover_frames_stand, NULL};
+
+mframe_t hover_frames_stop1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_stop1 = {FRAME_stop101, FRAME_stop109, hover_frames_stop1, NULL};
+
+mframe_t hover_frames_stop2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_stop2 = {FRAME_stop201, FRAME_stop208, hover_frames_stop2, NULL};
+
+mframe_t hover_frames_takeoff [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	-2,	NULL,
+	ai_move,	5,	NULL,
+	ai_move,	-1,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-1,	NULL,
+	ai_move,	-1,	NULL,
+	ai_move,	-1,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	-6,	NULL,
+	ai_move,	-9,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_takeoff = {FRAME_takeof01, FRAME_takeof30, hover_frames_takeoff, NULL};
+
+mframe_t hover_frames_pain3 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_pain3 = {FRAME_pain301, FRAME_pain309, hover_frames_pain3, hover_run};
+
+mframe_t hover_frames_pain2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_pain2 = {FRAME_pain201, FRAME_pain212, hover_frames_pain2, hover_run};
+
+mframe_t hover_frames_pain1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	-8,	NULL,
+	ai_move,	-4,	NULL,
+	ai_move,	-6,	NULL,
+	ai_move,	-4,	NULL,
+	ai_move,	-3,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	7,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	5,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	4,	NULL
+};
+mmove_t hover_move_pain1 = {FRAME_pain101, FRAME_pain128, hover_frames_pain1, hover_run};
+
+mframe_t hover_frames_land [] =
+{
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_land = {FRAME_land01, FRAME_land01, hover_frames_land, NULL};
+
+mframe_t hover_frames_forward [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_forward = {FRAME_forwrd01, FRAME_forwrd35, hover_frames_forward, NULL};
+
+mframe_t hover_frames_walk [] =
+{
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL,
+	ai_walk,	4,	NULL
+};
+mmove_t hover_move_walk = {FRAME_forwrd01, FRAME_forwrd35, hover_frames_walk, NULL};
+
+mframe_t hover_frames_run [] =
+{
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL,
+	ai_run,	10,	NULL
+};
+mmove_t hover_move_run = {FRAME_forwrd01, FRAME_forwrd35, hover_frames_run, NULL};
+
+mframe_t hover_frames_death1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	-10,NULL,
+	ai_move,	3,	NULL,
+	ai_move,	5,	NULL,
+	ai_move,	4,	NULL,
+	ai_move,	7,	NULL
+};
+mmove_t hover_move_death1 = {FRAME_death101, FRAME_death111, hover_frames_death1, hover_dead};
+
+mframe_t hover_frames_backward [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t hover_move_backward = {FRAME_backwd01, FRAME_backwd24, hover_frames_backward, NULL};
+
+mframe_t hover_frames_start_attack [] =
+{
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL
+};
+mmove_t hover_move_start_attack = {FRAME_attak101, FRAME_attak103, hover_frames_start_attack, hover_attack};
+
+mframe_t hover_frames_attack1 [] =
+{
+	ai_charge,	-10,	hover_fire_blaster,
+	ai_charge,	-10,	hover_fire_blaster,
+	ai_charge,	0,		hover_reattack,
+};
+mmove_t hover_move_attack1 = {FRAME_attak104, FRAME_attak106, hover_frames_attack1, NULL};
+
+
+mframe_t hover_frames_end_attack [] =
+{
+	ai_charge,	1,	NULL,
+	ai_charge,	1,	NULL
+};
+mmove_t hover_move_end_attack = {FRAME_attak107, FRAME_attak108, hover_frames_end_attack, hover_run};
+
+void hover_reattack (edict_t *self)
+{
+	if (self->enemy->health > 0 )
+		if (visible (self, self->enemy) )
+			if (random() <= 0.6)		
+			{
+				self->monsterinfo.currentmove = &hover_move_attack1;
+				return;
+			}
+	self->monsterinfo.currentmove = &hover_move_end_attack;
+}
+
+
+void hover_fire_blaster (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	forward, right;
+	vec3_t	end;
+	vec3_t	dir;
+	int		effect;
+
+	if (self->s.frame == FRAME_attak104)
+		effect = EF_HYPERBLASTER;
+	else
+		effect = 0;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_HOVER_BLASTER_1], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, end);
+	end[2] += self->enemy->viewheight;
+	VectorSubtract (end, start, dir);
+
+	monster_fire_blaster (self, start, dir, 1, 1000, MZ2_HOVER_BLASTER_1, effect);
+}
+
+
+void hover_stand (edict_t *self)
+{
+		self->monsterinfo.currentmove = &hover_move_stand;
+}
+
+void hover_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &hover_move_stand;
+	else
+		self->monsterinfo.currentmove = &hover_move_run;
+}
+
+void hover_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &hover_move_walk;
+}
+
+void hover_start_attack (edict_t *self)
+{
+	self->monsterinfo.currentmove = &hover_move_start_attack;
+}
+
+void hover_attack(edict_t *self)
+{
+	self->monsterinfo.currentmove = &hover_move_attack1;
+}
+
+
+void hover_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (damage <= 25)
+	{
+		if (random() < 0.5)
+		{
+			gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+			self->monsterinfo.currentmove = &hover_move_pain3;
+		}
+		else
+		{
+			gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+			self->monsterinfo.currentmove = &hover_move_pain2;
+		}
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &hover_move_pain1;
+	}
+}
+
+void hover_deadthink (edict_t *self)
+{
+	if (!self->groundentity && level.time < self->timestamp)
+	{
+		self->nextthink = level.time + FRAMETIME;
+		return;
+	}
+	BecomeExplosion1(self);
+}
+
+void hover_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->think = hover_deadthink;
+	self->nextthink = level.time + FRAMETIME;
+	self->timestamp = level.time + 15;
+	gi.linkentity (self);
+}
+
+void hover_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.currentmove = &hover_move_death1;
+}
+
+/*QUAKED monster_hover (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_hover (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1 = gi.soundindex ("hover/hovpain1.wav");	
+	sound_pain2 = gi.soundindex ("hover/hovpain2.wav");	
+	sound_death1 = gi.soundindex ("hover/hovdeth1.wav");	
+	sound_death2 = gi.soundindex ("hover/hovdeth2.wav");	
+	sound_sight = gi.soundindex ("hover/hovsght1.wav");	
+	sound_search1 = gi.soundindex ("hover/hovsrch1.wav");	
+	sound_search2 = gi.soundindex ("hover/hovsrch2.wav");	
+
+	gi.soundindex ("hover/hovatck1.wav");	
+
+	self->s.sound = gi.soundindex ("hover/hovidle1.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex("models/monsters/hover/tris.md2");
+	VectorSet (self->mins, -24, -24, -24);
+	VectorSet (self->maxs, 24, 24, 32);
+
+	self->health = 240;
+	self->gib_health = -100;
+	self->mass = 150;
+
+	self->pain = hover_pain;
+	self->die = hover_die;
+
+	self->monsterinfo.stand = hover_stand;
+	self->monsterinfo.walk = hover_walk;
+	self->monsterinfo.run = hover_run;
+//	self->monsterinfo.dodge = hover_dodge;
+	self->monsterinfo.attack = hover_start_attack;
+	self->monsterinfo.sight = hover_sight;
+	self->monsterinfo.search = hover_search;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &hover_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	flymonster_start (self);
+}
--- /dev/null
+++ b/game/m_hover.h
@@ -1,0 +1,230 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/hover
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand01         	0
+#define FRAME_stand02         	1
+#define FRAME_stand03         	2
+#define FRAME_stand04         	3
+#define FRAME_stand05         	4
+#define FRAME_stand06         	5
+#define FRAME_stand07         	6
+#define FRAME_stand08         	7
+#define FRAME_stand09         	8
+#define FRAME_stand10         	9
+#define FRAME_stand11         	10
+#define FRAME_stand12         	11
+#define FRAME_stand13         	12
+#define FRAME_stand14         	13
+#define FRAME_stand15         	14
+#define FRAME_stand16         	15
+#define FRAME_stand17         	16
+#define FRAME_stand18         	17
+#define FRAME_stand19         	18
+#define FRAME_stand20         	19
+#define FRAME_stand21         	20
+#define FRAME_stand22         	21
+#define FRAME_stand23         	22
+#define FRAME_stand24         	23
+#define FRAME_stand25         	24
+#define FRAME_stand26         	25
+#define FRAME_stand27         	26
+#define FRAME_stand28         	27
+#define FRAME_stand29         	28
+#define FRAME_stand30         	29
+#define FRAME_forwrd01        	30
+#define FRAME_forwrd02        	31
+#define FRAME_forwrd03        	32
+#define FRAME_forwrd04        	33
+#define FRAME_forwrd05        	34
+#define FRAME_forwrd06        	35
+#define FRAME_forwrd07        	36
+#define FRAME_forwrd08        	37
+#define FRAME_forwrd09        	38
+#define FRAME_forwrd10        	39
+#define FRAME_forwrd11        	40
+#define FRAME_forwrd12        	41
+#define FRAME_forwrd13        	42
+#define FRAME_forwrd14        	43
+#define FRAME_forwrd15        	44
+#define FRAME_forwrd16        	45
+#define FRAME_forwrd17        	46
+#define FRAME_forwrd18        	47
+#define FRAME_forwrd19        	48
+#define FRAME_forwrd20        	49
+#define FRAME_forwrd21        	50
+#define FRAME_forwrd22        	51
+#define FRAME_forwrd23        	52
+#define FRAME_forwrd24        	53
+#define FRAME_forwrd25        	54
+#define FRAME_forwrd26        	55
+#define FRAME_forwrd27        	56
+#define FRAME_forwrd28        	57
+#define FRAME_forwrd29        	58
+#define FRAME_forwrd30        	59
+#define FRAME_forwrd31        	60
+#define FRAME_forwrd32        	61
+#define FRAME_forwrd33        	62
+#define FRAME_forwrd34        	63
+#define FRAME_forwrd35        	64
+#define FRAME_stop101         	65
+#define FRAME_stop102         	66
+#define FRAME_stop103         	67
+#define FRAME_stop104         	68
+#define FRAME_stop105         	69
+#define FRAME_stop106         	70
+#define FRAME_stop107         	71
+#define FRAME_stop108         	72
+#define FRAME_stop109         	73
+#define FRAME_stop201         	74
+#define FRAME_stop202         	75
+#define FRAME_stop203         	76
+#define FRAME_stop204         	77
+#define FRAME_stop205         	78
+#define FRAME_stop206         	79
+#define FRAME_stop207         	80
+#define FRAME_stop208         	81
+#define FRAME_takeof01        	82
+#define FRAME_takeof02        	83
+#define FRAME_takeof03        	84
+#define FRAME_takeof04        	85
+#define FRAME_takeof05        	86
+#define FRAME_takeof06        	87
+#define FRAME_takeof07        	88
+#define FRAME_takeof08        	89
+#define FRAME_takeof09        	90
+#define FRAME_takeof10        	91
+#define FRAME_takeof11        	92
+#define FRAME_takeof12        	93
+#define FRAME_takeof13        	94
+#define FRAME_takeof14        	95
+#define FRAME_takeof15        	96
+#define FRAME_takeof16        	97
+#define FRAME_takeof17        	98
+#define FRAME_takeof18        	99
+#define FRAME_takeof19        	100
+#define FRAME_takeof20        	101
+#define FRAME_takeof21        	102
+#define FRAME_takeof22        	103
+#define FRAME_takeof23        	104
+#define FRAME_takeof24        	105
+#define FRAME_takeof25        	106
+#define FRAME_takeof26        	107
+#define FRAME_takeof27        	108
+#define FRAME_takeof28        	109
+#define FRAME_takeof29        	110
+#define FRAME_takeof30        	111
+#define FRAME_land01          	112
+#define FRAME_pain101         	113
+#define FRAME_pain102         	114
+#define FRAME_pain103         	115
+#define FRAME_pain104         	116
+#define FRAME_pain105         	117
+#define FRAME_pain106         	118
+#define FRAME_pain107         	119
+#define FRAME_pain108         	120
+#define FRAME_pain109         	121
+#define FRAME_pain110         	122
+#define FRAME_pain111         	123
+#define FRAME_pain112         	124
+#define FRAME_pain113         	125
+#define FRAME_pain114         	126
+#define FRAME_pain115         	127
+#define FRAME_pain116         	128
+#define FRAME_pain117         	129
+#define FRAME_pain118         	130
+#define FRAME_pain119         	131
+#define FRAME_pain120         	132
+#define FRAME_pain121         	133
+#define FRAME_pain122         	134
+#define FRAME_pain123         	135
+#define FRAME_pain124         	136
+#define FRAME_pain125         	137
+#define FRAME_pain126         	138
+#define FRAME_pain127         	139
+#define FRAME_pain128         	140
+#define FRAME_pain201         	141
+#define FRAME_pain202         	142
+#define FRAME_pain203         	143
+#define FRAME_pain204         	144
+#define FRAME_pain205         	145
+#define FRAME_pain206         	146
+#define FRAME_pain207         	147
+#define FRAME_pain208         	148
+#define FRAME_pain209         	149
+#define FRAME_pain210         	150
+#define FRAME_pain211         	151
+#define FRAME_pain212         	152
+#define FRAME_pain301         	153
+#define FRAME_pain302         	154
+#define FRAME_pain303         	155
+#define FRAME_pain304         	156
+#define FRAME_pain305         	157
+#define FRAME_pain306         	158
+#define FRAME_pain307         	159
+#define FRAME_pain308         	160
+#define FRAME_pain309         	161
+#define FRAME_death101        	162
+#define FRAME_death102        	163
+#define FRAME_death103        	164
+#define FRAME_death104        	165
+#define FRAME_death105        	166
+#define FRAME_death106        	167
+#define FRAME_death107        	168
+#define FRAME_death108        	169
+#define FRAME_death109        	170
+#define FRAME_death110        	171
+#define FRAME_death111        	172
+#define FRAME_backwd01        	173
+#define FRAME_backwd02        	174
+#define FRAME_backwd03        	175
+#define FRAME_backwd04        	176
+#define FRAME_backwd05        	177
+#define FRAME_backwd06        	178
+#define FRAME_backwd07        	179
+#define FRAME_backwd08        	180
+#define FRAME_backwd09        	181
+#define FRAME_backwd10        	182
+#define FRAME_backwd11        	183
+#define FRAME_backwd12        	184
+#define FRAME_backwd13        	185
+#define FRAME_backwd14        	186
+#define FRAME_backwd15        	187
+#define FRAME_backwd16        	188
+#define FRAME_backwd17        	189
+#define FRAME_backwd18        	190
+#define FRAME_backwd19        	191
+#define FRAME_backwd20        	192
+#define FRAME_backwd21        	193
+#define FRAME_backwd22        	194
+#define FRAME_backwd23        	195
+#define FRAME_backwd24        	196
+#define FRAME_attak101        	197
+#define FRAME_attak102        	198
+#define FRAME_attak103        	199
+#define FRAME_attak104        	200
+#define FRAME_attak105        	201
+#define FRAME_attak106        	202
+#define FRAME_attak107        	203
+#define FRAME_attak108        	204
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_infantry.c
@@ -1,0 +1,607 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+INFANTRY
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_infantry.h"
+
+void InfantryMachineGun (edict_t *self);
+
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_die1;
+static int	sound_die2;
+
+static int	sound_gunshot;
+static int	sound_weapon_cock;
+static int	sound_punch_swing;
+static int	sound_punch_hit;
+static int	sound_sight;
+static int	sound_search;
+static int	sound_idle;
+
+
+mframe_t infantry_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t infantry_move_stand = {FRAME_stand50, FRAME_stand71, infantry_frames_stand, NULL};
+
+void infantry_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &infantry_move_stand;
+}
+
+
+mframe_t infantry_frames_fidget [] =
+{
+	ai_stand, 1,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 3,  NULL,
+	ai_stand, 6,  NULL,
+	ai_stand, 3,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, -1, NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, -2, NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, -1, NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, -1, NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, -1, NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 1,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, -1, NULL,
+	ai_stand, -1, NULL,
+	ai_stand, 0,  NULL,
+	ai_stand, -3, NULL,
+	ai_stand, -2, NULL,
+	ai_stand, -3, NULL,
+	ai_stand, -3, NULL,
+	ai_stand, -2, NULL
+};
+mmove_t infantry_move_fidget = {FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand};
+
+void infantry_fidget (edict_t *self)
+{
+	self->monsterinfo.currentmove = &infantry_move_fidget;
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+mframe_t infantry_frames_walk [] =
+{
+	ai_walk, 5,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 6,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 5,  NULL
+};
+mmove_t infantry_move_walk = {FRAME_walk03, FRAME_walk14, infantry_frames_walk, NULL};
+
+void infantry_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &infantry_move_walk;
+}
+
+mframe_t infantry_frames_run [] =
+{
+	ai_run, 10, NULL,
+	ai_run, 20, NULL,
+	ai_run, 5,  NULL,
+	ai_run, 7,  NULL,
+	ai_run, 30, NULL,
+	ai_run, 35, NULL,
+	ai_run, 2,  NULL,
+	ai_run, 6,  NULL
+};
+mmove_t infantry_move_run = {FRAME_run01, FRAME_run08, infantry_frames_run, NULL};
+
+void infantry_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &infantry_move_stand;
+	else
+		self->monsterinfo.currentmove = &infantry_move_run;
+}
+
+
+mframe_t infantry_frames_pain1 [] =
+{
+	ai_move, -3, NULL,
+	ai_move, -2, NULL,
+	ai_move, -1, NULL,
+	ai_move, -2, NULL,
+	ai_move, -1, NULL,
+	ai_move, 1,  NULL,
+	ai_move, -1, NULL,
+	ai_move, 1,  NULL,
+	ai_move, 6,  NULL,
+	ai_move, 2,  NULL
+};
+mmove_t infantry_move_pain1 = {FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run};
+
+mframe_t infantry_frames_pain2 [] =
+{
+	ai_move, -3, NULL,
+	ai_move, -3, NULL,
+	ai_move, 0,  NULL,
+	ai_move, -1, NULL,
+	ai_move, -2, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 2,  NULL,
+	ai_move, 5,  NULL,
+	ai_move, 2,  NULL
+};
+mmove_t infantry_move_pain2 = {FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run};
+
+void infantry_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	int		n;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+	
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	n = rand() % 2;
+	if (n == 0)
+	{
+		self->monsterinfo.currentmove = &infantry_move_pain1;
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &infantry_move_pain2;
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+	}
+}
+
+
+vec3_t	aimangles[] =
+{
+	0.0, 5.0, 0.0,
+	10.0, 15.0, 0.0,
+	20.0, 25.0, 0.0,
+	25.0, 35.0, 0.0,
+	30.0, 40.0, 0.0,
+	30.0, 45.0, 0.0,
+	25.0, 50.0, 0.0,
+	20.0, 40.0, 0.0,
+	15.0, 35.0, 0.0,
+	40.0, 35.0, 0.0,
+	70.0, 35.0, 0.0,
+	90.0, 35.0, 0.0
+};
+
+void InfantryMachineGun (edict_t *self)
+{
+	vec3_t	start, target;
+	vec3_t	forward, right;
+	vec3_t	vec;
+	int		flash_number;
+
+	if (self->s.frame == FRAME_attak111)
+	{
+		flash_number = MZ2_INFANTRY_MACHINEGUN_1;
+		AngleVectors (self->s.angles, forward, right, NULL);
+		G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+		if (self->enemy)
+		{
+			VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
+			target[2] += self->enemy->viewheight;
+			VectorSubtract (target, start, forward);
+			VectorNormalize (forward);
+		}
+		else
+		{
+			AngleVectors (self->s.angles, forward, right, NULL);
+		}
+	}
+	else
+	{
+		flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self->s.frame - FRAME_death211);
+
+		AngleVectors (self->s.angles, forward, right, NULL);
+		G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+		VectorSubtract (self->s.angles, aimangles[flash_number-MZ2_INFANTRY_MACHINEGUN_2], vec);
+		AngleVectors (vec, forward, NULL, NULL);
+	}
+
+	monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+}
+
+void infantry_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void infantry_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	gi.linkentity (self);
+
+	M_FlyCheck (self);
+}
+
+mframe_t infantry_frames_death1 [] =
+{
+	ai_move, -4, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, -1, NULL,
+	ai_move, -4, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, -1, NULL,
+	ai_move, 3,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, -2, NULL,
+	ai_move, 2,  NULL,
+	ai_move, 2,  NULL,
+	ai_move, 9,  NULL,
+	ai_move, 9,  NULL,
+	ai_move, 5,  NULL,
+	ai_move, -3, NULL,
+	ai_move, -3, NULL
+};
+mmove_t infantry_move_death1 = {FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead};
+
+// Off with his head
+mframe_t infantry_frames_death2 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 5,   NULL,
+	ai_move, -1,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 4,   NULL,
+	ai_move, 3,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -2,  InfantryMachineGun,
+	ai_move, -2,  InfantryMachineGun,
+	ai_move, -3,  InfantryMachineGun,
+	ai_move, -1,  InfantryMachineGun,
+	ai_move, -2,  InfantryMachineGun,
+	ai_move, 0,   InfantryMachineGun,
+	ai_move, 2,   InfantryMachineGun,
+	ai_move, 2,   InfantryMachineGun,
+	ai_move, 3,   InfantryMachineGun,
+	ai_move, -10, InfantryMachineGun,
+	ai_move, -7,  InfantryMachineGun,
+	ai_move, -8,  InfantryMachineGun,
+	ai_move, -6,  NULL,
+	ai_move, 4,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t infantry_move_death2 = {FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead};
+
+mframe_t infantry_frames_death3 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -6,  NULL,
+	ai_move, -11, NULL,
+	ai_move, -3,  NULL,
+	ai_move, -11, NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t infantry_move_death3 = {FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead};
+
+
+void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	n = rand() % 3;
+	if (n == 0)
+	{
+		self->monsterinfo.currentmove = &infantry_move_death1;
+		gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
+	}
+	else if (n == 1)
+	{
+		self->monsterinfo.currentmove = &infantry_move_death2;
+		gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &infantry_move_death3;
+		gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
+	}
+}
+
+
+void infantry_duck_down (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_DUCKED)
+		return;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	self->maxs[2] -= 32;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.pausetime = level.time + 1;
+	gi.linkentity (self);
+}
+
+void infantry_duck_hold (edict_t *self)
+{
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+void infantry_duck_up (edict_t *self)
+{
+	self->monsterinfo.aiflags &= ~AI_DUCKED;
+	self->maxs[2] += 32;
+	self->takedamage = DAMAGE_AIM;
+	gi.linkentity (self);
+}
+
+mframe_t infantry_frames_duck [] =
+{
+	ai_move, -2, infantry_duck_down,
+	ai_move, -5, infantry_duck_hold,
+	ai_move, 3,  NULL,
+	ai_move, 4,  infantry_duck_up,
+	ai_move, 0,  NULL
+};
+mmove_t infantry_move_duck = {FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run};
+
+void infantry_dodge (edict_t *self, edict_t *attacker, float eta)
+{
+	if (random() > 0.25)
+		return;
+
+	if (!self->enemy)
+		self->enemy = attacker;
+
+	self->monsterinfo.currentmove = &infantry_move_duck;
+}
+
+
+void infantry_cock_gun (edict_t *self)
+{
+	int		n;
+
+	gi.sound (self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0);
+	n = (rand() & 15) + 3 + 7;
+	self->monsterinfo.pausetime = level.time + n * FRAMETIME;
+}
+
+void infantry_fire (edict_t *self)
+{
+	InfantryMachineGun (self);
+
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+mframe_t infantry_frames_attack1 [] =
+{
+	ai_charge, 4,  NULL,
+	ai_charge, -1, NULL,
+	ai_charge, -1, NULL,
+	ai_charge, 0,  infantry_cock_gun,
+	ai_charge, -1, NULL,
+	ai_charge, 1,  NULL,
+	ai_charge, 1,  NULL,
+	ai_charge, 2,  NULL,
+	ai_charge, -2, NULL,
+	ai_charge, -3, NULL,
+	ai_charge, 1,  infantry_fire,
+	ai_charge, 5,  NULL,
+	ai_charge, -1, NULL,
+	ai_charge, -2, NULL,
+	ai_charge, -3, NULL
+};
+mmove_t infantry_move_attack1 = {FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run};
+
+
+void infantry_swing (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0);
+}
+
+void infantry_smack (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, 0, 0);
+	if (fire_hit (self, aim, (5 + (rand() % 5)), 50))
+		gi.sound (self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0);
+}
+
+mframe_t infantry_frames_attack2 [] =
+{
+	ai_charge, 3, NULL,
+	ai_charge, 6, NULL,
+	ai_charge, 0, infantry_swing,
+	ai_charge, 8, NULL,
+	ai_charge, 5, NULL,
+	ai_charge, 8, infantry_smack,
+	ai_charge, 6, NULL,
+	ai_charge, 3, NULL,
+};
+mmove_t infantry_move_attack2 = {FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run};
+
+void infantry_attack(edict_t *self)
+{
+	if (range (self, self->enemy) == RANGE_MELEE)
+		self->monsterinfo.currentmove = &infantry_move_attack2;
+	else
+		self->monsterinfo.currentmove = &infantry_move_attack1;
+}
+
+
+/*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_infantry (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1 = gi.soundindex ("infantry/infpain1.wav");
+	sound_pain2 = gi.soundindex ("infantry/infpain2.wav");
+	sound_die1 = gi.soundindex ("infantry/infdeth1.wav");
+	sound_die2 = gi.soundindex ("infantry/infdeth2.wav");
+
+	sound_gunshot = gi.soundindex ("infantry/infatck1.wav");
+	sound_weapon_cock = gi.soundindex ("infantry/infatck3.wav");
+	sound_punch_swing = gi.soundindex ("infantry/infatck2.wav");
+	sound_punch_hit = gi.soundindex ("infantry/melee2.wav");
+	
+	sound_sight = gi.soundindex ("infantry/infsght1.wav");
+	sound_search = gi.soundindex ("infantry/infsrch1.wav");
+	sound_idle = gi.soundindex ("infantry/infidle1.wav");
+	
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	self->health = 100;
+	self->gib_health = -40;
+	self->mass = 200;
+
+	self->pain = infantry_pain;
+	self->die = infantry_die;
+
+	self->monsterinfo.stand = infantry_stand;
+	self->monsterinfo.walk = infantry_walk;
+	self->monsterinfo.run = infantry_run;
+	self->monsterinfo.dodge = infantry_dodge;
+	self->monsterinfo.attack = infantry_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = infantry_sight;
+	self->monsterinfo.idle = infantry_fidget;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &infantry_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_infantry.h
@@ -1,0 +1,232 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/infantry
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_gun02           	0
+#define FRAME_stand01         	1
+#define FRAME_stand02         	2
+#define FRAME_stand03         	3
+#define FRAME_stand04         	4
+#define FRAME_stand05         	5
+#define FRAME_stand06         	6
+#define FRAME_stand07         	7
+#define FRAME_stand08         	8
+#define FRAME_stand09         	9
+#define FRAME_stand10         	10
+#define FRAME_stand11         	11
+#define FRAME_stand12         	12
+#define FRAME_stand13         	13
+#define FRAME_stand14         	14
+#define FRAME_stand15         	15
+#define FRAME_stand16         	16
+#define FRAME_stand17         	17
+#define FRAME_stand18         	18
+#define FRAME_stand19         	19
+#define FRAME_stand20         	20
+#define FRAME_stand21         	21
+#define FRAME_stand22         	22
+#define FRAME_stand23         	23
+#define FRAME_stand24         	24
+#define FRAME_stand25         	25
+#define FRAME_stand26         	26
+#define FRAME_stand27         	27
+#define FRAME_stand28         	28
+#define FRAME_stand29         	29
+#define FRAME_stand30         	30
+#define FRAME_stand31         	31
+#define FRAME_stand32         	32
+#define FRAME_stand33         	33
+#define FRAME_stand34         	34
+#define FRAME_stand35         	35
+#define FRAME_stand36         	36
+#define FRAME_stand37         	37
+#define FRAME_stand38         	38
+#define FRAME_stand39         	39
+#define FRAME_stand40         	40
+#define FRAME_stand41         	41
+#define FRAME_stand42         	42
+#define FRAME_stand43         	43
+#define FRAME_stand44         	44
+#define FRAME_stand45         	45
+#define FRAME_stand46         	46
+#define FRAME_stand47         	47
+#define FRAME_stand48         	48
+#define FRAME_stand49         	49
+#define FRAME_stand50         	50
+#define FRAME_stand51         	51
+#define FRAME_stand52         	52
+#define FRAME_stand53         	53
+#define FRAME_stand54         	54
+#define FRAME_stand55         	55
+#define FRAME_stand56         	56
+#define FRAME_stand57         	57
+#define FRAME_stand58         	58
+#define FRAME_stand59         	59
+#define FRAME_stand60         	60
+#define FRAME_stand61         	61
+#define FRAME_stand62         	62
+#define FRAME_stand63         	63
+#define FRAME_stand64         	64
+#define FRAME_stand65         	65
+#define FRAME_stand66         	66
+#define FRAME_stand67         	67
+#define FRAME_stand68         	68
+#define FRAME_stand69         	69
+#define FRAME_stand70         	70
+#define FRAME_stand71         	71
+#define FRAME_walk01          	72
+#define FRAME_walk02          	73
+#define FRAME_walk03          	74
+#define FRAME_walk04          	75
+#define FRAME_walk05          	76
+#define FRAME_walk06          	77
+#define FRAME_walk07          	78
+#define FRAME_walk08          	79
+#define FRAME_walk09          	80
+#define FRAME_walk10          	81
+#define FRAME_walk11          	82
+#define FRAME_walk12          	83
+#define FRAME_walk13          	84
+#define FRAME_walk14          	85
+#define FRAME_walk15          	86
+#define FRAME_walk16          	87
+#define FRAME_walk17          	88
+#define FRAME_walk18          	89
+#define FRAME_walk19          	90
+#define FRAME_walk20          	91
+#define FRAME_run01           	92
+#define FRAME_run02           	93
+#define FRAME_run03           	94
+#define FRAME_run04           	95
+#define FRAME_run05           	96
+#define FRAME_run06           	97
+#define FRAME_run07           	98
+#define FRAME_run08           	99
+#define FRAME_pain101         	100
+#define FRAME_pain102         	101
+#define FRAME_pain103         	102
+#define FRAME_pain104         	103
+#define FRAME_pain105         	104
+#define FRAME_pain106         	105
+#define FRAME_pain107         	106
+#define FRAME_pain108         	107
+#define FRAME_pain109         	108
+#define FRAME_pain110         	109
+#define FRAME_pain201         	110
+#define FRAME_pain202         	111
+#define FRAME_pain203         	112
+#define FRAME_pain204         	113
+#define FRAME_pain205         	114
+#define FRAME_pain206         	115
+#define FRAME_pain207         	116
+#define FRAME_pain208         	117
+#define FRAME_pain209         	118
+#define FRAME_pain210         	119
+#define FRAME_duck01          	120
+#define FRAME_duck02          	121
+#define FRAME_duck03          	122
+#define FRAME_duck04          	123
+#define FRAME_duck05          	124
+#define FRAME_death101        	125
+#define FRAME_death102        	126
+#define FRAME_death103        	127
+#define FRAME_death104        	128
+#define FRAME_death105        	129
+#define FRAME_death106        	130
+#define FRAME_death107        	131
+#define FRAME_death108        	132
+#define FRAME_death109        	133
+#define FRAME_death110        	134
+#define FRAME_death111        	135
+#define FRAME_death112        	136
+#define FRAME_death113        	137
+#define FRAME_death114        	138
+#define FRAME_death115        	139
+#define FRAME_death116        	140
+#define FRAME_death117        	141
+#define FRAME_death118        	142
+#define FRAME_death119        	143
+#define FRAME_death120        	144
+#define FRAME_death201        	145
+#define FRAME_death202        	146
+#define FRAME_death203        	147
+#define FRAME_death204        	148
+#define FRAME_death205        	149
+#define FRAME_death206        	150
+#define FRAME_death207        	151
+#define FRAME_death208        	152
+#define FRAME_death209        	153
+#define FRAME_death210        	154
+#define FRAME_death211        	155
+#define FRAME_death212        	156
+#define FRAME_death213        	157
+#define FRAME_death214        	158
+#define FRAME_death215        	159
+#define FRAME_death216        	160
+#define FRAME_death217        	161
+#define FRAME_death218        	162
+#define FRAME_death219        	163
+#define FRAME_death220        	164
+#define FRAME_death221        	165
+#define FRAME_death222        	166
+#define FRAME_death223        	167
+#define FRAME_death224        	168
+#define FRAME_death225        	169
+#define FRAME_death301        	170
+#define FRAME_death302        	171
+#define FRAME_death303        	172
+#define FRAME_death304        	173
+#define FRAME_death305        	174
+#define FRAME_death306        	175
+#define FRAME_death307        	176
+#define FRAME_death308        	177
+#define FRAME_death309        	178
+#define FRAME_block01         	179
+#define FRAME_block02         	180
+#define FRAME_block03         	181
+#define FRAME_block04         	182
+#define FRAME_block05         	183
+#define FRAME_attak101        	184
+#define FRAME_attak102        	185
+#define FRAME_attak103        	186
+#define FRAME_attak104        	187
+#define FRAME_attak105        	188
+#define FRAME_attak106        	189
+#define FRAME_attak107        	190
+#define FRAME_attak108        	191
+#define FRAME_attak109        	192
+#define FRAME_attak110        	193
+#define FRAME_attak111        	194
+#define FRAME_attak112        	195
+#define FRAME_attak113        	196
+#define FRAME_attak114        	197
+#define FRAME_attak115        	198
+#define FRAME_attak201        	199
+#define FRAME_attak202        	200
+#define FRAME_attak203        	201
+#define FRAME_attak204        	202
+#define FRAME_attak205        	203
+#define FRAME_attak206        	204
+#define FRAME_attak207        	205
+#define FRAME_attak208        	206
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_insane.c
@@ -1,0 +1,693 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+insane
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_insane.h"
+
+
+static int	sound_fist;
+static int	sound_shake;
+static int	sound_moan;
+static int	sound_scream[8];
+
+void insane_fist (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_fist, 1, ATTN_IDLE, 0);
+}
+
+void insane_shake (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_shake, 1, ATTN_IDLE, 0);
+}
+
+void insane_moan (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_moan, 1, ATTN_IDLE, 0);
+}
+
+void insane_scream (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_scream[rand()%8], 1, ATTN_IDLE, 0);
+}
+
+
+void insane_stand (edict_t *self);
+void insane_dead (edict_t *self);
+void insane_cross (edict_t *self);
+void insane_walk (edict_t *self);
+void insane_run (edict_t *self);
+void insane_checkdown (edict_t *self);
+void insane_checkup (edict_t *self);
+void insane_onground (edict_t *self);
+
+
+mframe_t insane_frames_stand_normal [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, insane_checkdown
+};
+mmove_t insane_move_stand_normal = {FRAME_stand60, FRAME_stand65, insane_frames_stand_normal, insane_stand};
+
+mframe_t insane_frames_stand_insane [] =
+{
+	ai_stand,	0,	insane_shake,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	NULL,
+	ai_stand,	0,	insane_checkdown
+};
+mmove_t insane_move_stand_insane = {FRAME_stand65, FRAME_stand94, insane_frames_stand_insane, insane_stand};
+
+mframe_t insane_frames_uptodown [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	insane_moan,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+
+	ai_move,	2.7,	NULL,
+	ai_move,	4.1,	NULL,
+	ai_move,	6,		NULL,
+	ai_move,	7.6,	NULL,
+	ai_move,	3.6,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	insane_fist,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	insane_fist,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t insane_move_uptodown = {FRAME_stand1, FRAME_stand40, insane_frames_uptodown, insane_onground};
+
+
+mframe_t insane_frames_downtoup [] =
+{
+	ai_move,	-0.7,	NULL,			// 41
+	ai_move,	-1.2,	NULL,			// 42
+	ai_move,	-1.5,		NULL,		// 43
+	ai_move,	-4.5,		NULL,		// 44
+	ai_move,	-3.5,	NULL,			// 45
+	ai_move,	-0.2,	NULL,			// 46
+	ai_move,	0,	NULL,			// 47
+	ai_move,	-1.3,	NULL,			// 48
+	ai_move,	-3,	NULL,				// 49
+	ai_move,	-2,	NULL,			// 50
+	ai_move,	0,	NULL,				// 51
+	ai_move,	0,	NULL,				// 52
+	ai_move,	0,	NULL,				// 53
+	ai_move,	-3.3,	NULL,			// 54
+	ai_move,	-1.6,	NULL,			// 55
+	ai_move,	-0.3,	NULL,			// 56
+	ai_move,	0,	NULL,				// 57
+	ai_move,	0,	NULL,				// 58
+	ai_move,	0,	NULL				// 59
+};
+mmove_t insane_move_downtoup = {FRAME_stand41, FRAME_stand59, insane_frames_downtoup, insane_stand};
+
+mframe_t insane_frames_jumpdown [] =
+{
+	ai_move,	0.2,	NULL,
+	ai_move,	11.5,	NULL,
+	ai_move,	5.1,	NULL,
+	ai_move,	7.1,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t insane_move_jumpdown = {FRAME_stand96, FRAME_stand100, insane_frames_jumpdown, insane_onground};
+
+
+mframe_t insane_frames_down [] =
+{
+	ai_move,	0,		NULL,		// 100
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,		// 110
+	ai_move,	-1.7,		NULL,
+	ai_move,	-1.6,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		insane_fist,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,		// 120
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,		// 130
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		insane_moan,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,		// 140
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,		// 150
+	ai_move,	0.5,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	-0.2,		insane_scream,
+	ai_move,	0,		NULL,
+	ai_move,	0.2,		NULL,
+	ai_move,	0.4,		NULL,
+	ai_move,	0.6,		NULL,
+	ai_move,	0.8,		NULL,
+	ai_move,	0.7,		NULL,
+	ai_move,	0,		insane_checkup		// 160
+};
+mmove_t insane_move_down = {FRAME_stand100, FRAME_stand160, insane_frames_down, insane_onground};
+
+mframe_t insane_frames_walk_normal [] =
+{
+	ai_walk,	0,		insane_scream,
+	ai_walk,	2.5,	NULL,
+	ai_walk,	3.5,	NULL,
+	ai_walk,	1.7,	NULL,
+	ai_walk,	2.3,	NULL,
+	ai_walk,	2.4,	NULL,
+	ai_walk,	2.2,	NULL,
+	ai_walk,	4.2,	NULL,
+	ai_walk,	5.6,	NULL,
+	ai_walk,	3.3,	NULL,
+	ai_walk,	2.4,	NULL,
+	ai_walk,	0.9,	NULL,
+	ai_walk,	0,		NULL
+};
+mmove_t insane_move_walk_normal = {FRAME_walk27, FRAME_walk39, insane_frames_walk_normal, insane_walk};
+mmove_t insane_move_run_normal = {FRAME_walk27, FRAME_walk39, insane_frames_walk_normal, insane_run};
+
+mframe_t insane_frames_walk_insane [] =
+{
+	ai_walk,	0,		insane_scream,		// walk 1
+	ai_walk,	3.4,	NULL,		// walk 2
+	ai_walk,	3.6,	NULL,		// 3
+	ai_walk,	2.9,	NULL,		// 4
+	ai_walk,	2.2,	NULL,		// 5
+	ai_walk,	2.6,	NULL,		// 6
+	ai_walk,	0,		NULL,		// 7
+	ai_walk,	0.7,	NULL,		// 8
+	ai_walk,	4.8,	NULL,		// 9
+	ai_walk,	5.3,	NULL,		// 10
+	ai_walk,	1.1,	NULL,		// 11
+	ai_walk,	2,		NULL,		// 12
+	ai_walk,	0.5,	NULL,		// 13
+	ai_walk,	0,		NULL,		// 14
+	ai_walk,	0,		NULL,		// 15
+	ai_walk,	4.9,	NULL,		// 16
+	ai_walk,	6.7,	NULL,		// 17
+	ai_walk,	3.8,	NULL,		// 18
+	ai_walk,	2,		NULL,		// 19
+	ai_walk,	0.2,	NULL,		// 20
+	ai_walk,	0,		NULL,		// 21
+	ai_walk,	3.4,	NULL,		// 22
+	ai_walk,	6.4,	NULL,		// 23
+	ai_walk,	5,		NULL,		// 24
+	ai_walk,	1.8,	NULL,		// 25
+	ai_walk,	0,		NULL		// 26
+};
+mmove_t insane_move_walk_insane = {FRAME_walk1, FRAME_walk26, insane_frames_walk_insane, insane_walk};
+mmove_t insane_move_run_insane = {FRAME_walk1, FRAME_walk26, insane_frames_walk_insane, insane_run};
+
+mframe_t insane_frames_stand_pain [] =
+{
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL
+};
+mmove_t insane_move_stand_pain = {FRAME_st_pain2, FRAME_st_pain12, insane_frames_stand_pain, insane_run};
+
+mframe_t insane_frames_stand_death [] =
+{
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL
+};
+mmove_t insane_move_stand_death = {FRAME_st_death2, FRAME_st_death18, insane_frames_stand_death, insane_dead};
+
+mframe_t insane_frames_crawl [] =
+{
+	ai_walk,	0,		insane_scream,
+	ai_walk,	1.5,	NULL,
+	ai_walk,	2.1,	NULL,
+	ai_walk,	3.6,	NULL,
+	ai_walk,	2,		NULL,
+	ai_walk,	0.9,	NULL,
+	ai_walk,	3,		NULL,
+	ai_walk,	3.4,	NULL,
+	ai_walk,	2.4,	NULL
+};
+mmove_t insane_move_crawl = {FRAME_crawl1, FRAME_crawl9, insane_frames_crawl, NULL};
+mmove_t insane_move_runcrawl = {FRAME_crawl1, FRAME_crawl9, insane_frames_crawl, NULL};
+
+mframe_t insane_frames_crawl_pain [] =
+{
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL
+};
+mmove_t insane_move_crawl_pain = {FRAME_cr_pain2, FRAME_cr_pain10, insane_frames_crawl_pain, insane_run};
+
+mframe_t insane_frames_crawl_death [] =
+{
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL
+};
+mmove_t insane_move_crawl_death = {FRAME_cr_death10, FRAME_cr_death16, insane_frames_crawl_death, insane_dead};
+
+mframe_t insane_frames_cross [] =
+{
+	ai_move,	0,		insane_moan,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL
+};
+mmove_t insane_move_cross = {FRAME_cross1, FRAME_cross15, insane_frames_cross, insane_cross};
+
+mframe_t insane_frames_struggle_cross [] =
+{
+	ai_move,	0,		insane_scream,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL,
+	ai_move,	0,		NULL
+};
+mmove_t insane_move_struggle_cross = {FRAME_cross16, FRAME_cross30, insane_frames_struggle_cross, insane_cross};
+
+void insane_cross (edict_t *self)
+{
+	if (random() < 0.8)		
+		self->monsterinfo.currentmove = &insane_move_cross;
+	else
+		self->monsterinfo.currentmove = &insane_move_struggle_cross;
+}
+
+void insane_walk (edict_t *self)
+{
+	if ( self->spawnflags & 16 )			// Hold Ground?
+		if (self->s.frame == FRAME_cr_pain10)
+		{
+			self->monsterinfo.currentmove = &insane_move_down;
+			return;
+		}
+	if (self->spawnflags & 4)
+		self->monsterinfo.currentmove = &insane_move_crawl;
+	else
+		if (random() <= 0.5)
+			self->monsterinfo.currentmove = &insane_move_walk_normal;
+		else
+			self->monsterinfo.currentmove = &insane_move_walk_insane;
+}
+
+void insane_run (edict_t *self)
+{
+	if ( self->spawnflags & 16 )			// Hold Ground?
+		if (self->s.frame == FRAME_cr_pain10)
+		{
+			self->monsterinfo.currentmove = &insane_move_down;
+			return;
+		}
+	if (self->spawnflags & 4)				// Crawling?
+		self->monsterinfo.currentmove = &insane_move_runcrawl;
+	else
+		if (random() <= 0.5)				// Else, mix it up
+			self->monsterinfo.currentmove = &insane_move_run_normal;
+		else
+			self->monsterinfo.currentmove = &insane_move_run_insane;
+}
+
+
+void insane_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	int	l,r;
+
+//	if (self->health < (self->max_health / 2))
+//		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	r = 1 + (rand()&1);
+	if (self->health < 25)
+		l = 25;
+	else if (self->health < 50)
+		l = 50;
+	else if (self->health < 75)
+		l = 75;
+	else
+		l = 100;
+	gi.sound (self, CHAN_VOICE, gi.soundindex (va("player/male/pain%i_%i.wav", l, r)), 1, ATTN_IDLE, 0);
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	// Don't go into pain frames if crucified.
+	if (self->spawnflags & 8)
+	{
+		self->monsterinfo.currentmove = &insane_move_struggle_cross;			
+		return;
+	}
+	
+	if  ( ((self->s.frame >= FRAME_crawl1) && (self->s.frame <= FRAME_crawl9)) || ((self->s.frame >= FRAME_stand99) && (self->s.frame <= FRAME_stand160)) )
+	{
+		self->monsterinfo.currentmove = &insane_move_crawl_pain;
+	}
+	else
+		self->monsterinfo.currentmove = &insane_move_stand_pain;
+
+}
+
+void insane_onground (edict_t *self)
+{
+	self->monsterinfo.currentmove = &insane_move_down;
+}
+
+void insane_checkdown (edict_t *self)
+{
+//	if ( (self->s.frame == FRAME_stand94) || (self->s.frame == FRAME_stand65) )
+	if (self->spawnflags & 32)				// Always stand
+		return;
+	if (random() < 0.3)
+		if (random() < 0.5)
+			self->monsterinfo.currentmove = &insane_move_uptodown;
+		else
+			self->monsterinfo.currentmove = &insane_move_jumpdown; 
+}
+
+void insane_checkup (edict_t *self)
+{
+	// If Hold_Ground and Crawl are set
+	if ( (self->spawnflags & 4) && (self->spawnflags & 16) )
+		return;
+	if (random() < 0.5)
+		self->monsterinfo.currentmove = &insane_move_downtoup;				
+
+}
+
+void insane_stand (edict_t *self)
+{
+	if (self->spawnflags & 8)			// If crucified
+	{
+		self->monsterinfo.currentmove = &insane_move_cross;
+		self->monsterinfo.aiflags |= AI_STAND_GROUND;
+	}
+	// If Hold_Ground and Crawl are set
+	else if ( (self->spawnflags & 4) && (self->spawnflags & 16) )
+		self->monsterinfo.currentmove = &insane_move_down;
+	else
+		if (random() < 0.5)
+			self->monsterinfo.currentmove = &insane_move_stand_normal;
+		else
+			self->monsterinfo.currentmove = &insane_move_stand_insane;
+}
+
+void insane_dead (edict_t *self)
+{
+	if (self->spawnflags & 8)
+	{
+		self->flags |= FL_FLY;
+	}
+	else
+	{
+		VectorSet (self->mins, -16, -16, -24);
+		VectorSet (self->maxs, 16, 16, -8);
+		self->movetype = MOVETYPE_TOSS;
+	}
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+
+void insane_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_IDLE, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+	gi.sound (self, CHAN_VOICE, gi.soundindex(va("player/male/death%i.wav", (rand()%4)+1)), 1, ATTN_IDLE, 0);
+
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	if (self->spawnflags & 8)
+	{
+		insane_dead (self);
+	}
+	else
+	{
+		if ( ((self->s.frame >= FRAME_crawl1) && (self->s.frame <= FRAME_crawl9)) || ((self->s.frame >= FRAME_stand99) && (self->s.frame <= FRAME_stand160)) )		
+			self->monsterinfo.currentmove = &insane_move_crawl_death;
+		else
+			self->monsterinfo.currentmove = &insane_move_stand_death;
+	}
+}
+
+
+/*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND
+*/
+void SP_misc_insane (edict_t *self)
+{
+//	static int skin = 0;	//@@
+
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_fist = gi.soundindex ("insane/insane11.wav");
+	sound_shake = gi.soundindex ("insane/insane5.wav");
+	sound_moan = gi.soundindex ("insane/insane7.wav");
+	sound_scream[0] = gi.soundindex ("insane/insane1.wav");
+	sound_scream[1] = gi.soundindex ("insane/insane2.wav");
+	sound_scream[2] = gi.soundindex ("insane/insane3.wav");
+	sound_scream[3] = gi.soundindex ("insane/insane4.wav");
+	sound_scream[4] = gi.soundindex ("insane/insane6.wav");
+	sound_scream[5] = gi.soundindex ("insane/insane8.wav");
+	sound_scream[6] = gi.soundindex ("insane/insane9.wav");
+	sound_scream[7] = gi.soundindex ("insane/insane10.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex("models/monsters/insane/tris.md2");
+
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+
+	self->health = 100;
+	self->gib_health = -50;
+	self->mass = 300;
+
+	self->pain = insane_pain;
+	self->die = insane_die;
+
+	self->monsterinfo.stand = insane_stand;
+	self->monsterinfo.walk = insane_walk;
+	self->monsterinfo.run = insane_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = NULL;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = NULL;
+	self->monsterinfo.aiflags |= AI_GOOD_GUY;
+
+//@@
+//	self->s.skinnum = skin;
+//	skin++;
+//	if (skin > 12)
+//		skin = 0;
+
+	gi.linkentity (self);
+
+	if (self->spawnflags & 16)				// Stand Ground
+		self->monsterinfo.aiflags |= AI_STAND_GROUND;
+
+	self->monsterinfo.currentmove = &insane_move_stand_normal;
+	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	if (self->spawnflags & 8)					// Crucified ?
+	{
+		VectorSet (self->mins, -16, 0, 0);
+		VectorSet (self->maxs, 16, 8, 32);
+		self->flags |= FL_NO_KNOCKBACK;
+		flymonster_start (self);
+	}
+	else
+	{
+		walkmonster_start (self);
+		self->s.skinnum = rand()%3;
+	}
+}
--- /dev/null
+++ b/game/m_insane.h
@@ -1,0 +1,307 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/insane
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand1          	0
+#define FRAME_stand2          	1
+#define FRAME_stand3          	2
+#define FRAME_stand4          	3
+#define FRAME_stand5          	4
+#define FRAME_stand6          	5
+#define FRAME_stand7          	6
+#define FRAME_stand8          	7
+#define FRAME_stand9          	8
+#define FRAME_stand10         	9
+#define FRAME_stand11         	10
+#define FRAME_stand12         	11
+#define FRAME_stand13         	12
+#define FRAME_stand14         	13
+#define FRAME_stand15         	14
+#define FRAME_stand16         	15
+#define FRAME_stand17         	16
+#define FRAME_stand18         	17
+#define FRAME_stand19         	18
+#define FRAME_stand20         	19
+#define FRAME_stand21         	20
+#define FRAME_stand22         	21
+#define FRAME_stand23         	22
+#define FRAME_stand24         	23
+#define FRAME_stand25         	24
+#define FRAME_stand26         	25
+#define FRAME_stand27         	26
+#define FRAME_stand28         	27
+#define FRAME_stand29         	28
+#define FRAME_stand30         	29
+#define FRAME_stand31         	30
+#define FRAME_stand32         	31
+#define FRAME_stand33         	32
+#define FRAME_stand34         	33
+#define FRAME_stand35         	34
+#define FRAME_stand36         	35
+#define FRAME_stand37         	36
+#define FRAME_stand38         	37
+#define FRAME_stand39         	38
+#define FRAME_stand40         	39
+#define FRAME_stand41         	40
+#define FRAME_stand42         	41
+#define FRAME_stand43         	42
+#define FRAME_stand44         	43
+#define FRAME_stand45         	44
+#define FRAME_stand46         	45
+#define FRAME_stand47         	46
+#define FRAME_stand48         	47
+#define FRAME_stand49         	48
+#define FRAME_stand50         	49
+#define FRAME_stand51         	50
+#define FRAME_stand52         	51
+#define FRAME_stand53         	52
+#define FRAME_stand54         	53
+#define FRAME_stand55         	54
+#define FRAME_stand56         	55
+#define FRAME_stand57         	56
+#define FRAME_stand58         	57
+#define FRAME_stand59         	58
+#define FRAME_stand60         	59
+#define FRAME_stand61         	60
+#define FRAME_stand62         	61
+#define FRAME_stand63         	62
+#define FRAME_stand64         	63
+#define FRAME_stand65         	64
+#define FRAME_stand66         	65
+#define FRAME_stand67         	66
+#define FRAME_stand68         	67
+#define FRAME_stand69         	68
+#define FRAME_stand70         	69
+#define FRAME_stand71         	70
+#define FRAME_stand72         	71
+#define FRAME_stand73         	72
+#define FRAME_stand74         	73
+#define FRAME_stand75         	74
+#define FRAME_stand76         	75
+#define FRAME_stand77         	76
+#define FRAME_stand78         	77
+#define FRAME_stand79         	78
+#define FRAME_stand80         	79
+#define FRAME_stand81         	80
+#define FRAME_stand82         	81
+#define FRAME_stand83         	82
+#define FRAME_stand84         	83
+#define FRAME_stand85         	84
+#define FRAME_stand86         	85
+#define FRAME_stand87         	86
+#define FRAME_stand88         	87
+#define FRAME_stand89         	88
+#define FRAME_stand90         	89
+#define FRAME_stand91         	90
+#define FRAME_stand92         	91
+#define FRAME_stand93         	92
+#define FRAME_stand94         	93
+#define FRAME_stand95         	94
+#define FRAME_stand96         	95
+#define FRAME_stand97         	96
+#define FRAME_stand98         	97
+#define FRAME_stand99         	98
+#define FRAME_stand100        	99
+#define FRAME_stand101        	100
+#define FRAME_stand102        	101
+#define FRAME_stand103        	102
+#define FRAME_stand104        	103
+#define FRAME_stand105        	104
+#define FRAME_stand106        	105
+#define FRAME_stand107        	106
+#define FRAME_stand108        	107
+#define FRAME_stand109        	108
+#define FRAME_stand110        	109
+#define FRAME_stand111        	110
+#define FRAME_stand112        	111
+#define FRAME_stand113        	112
+#define FRAME_stand114        	113
+#define FRAME_stand115        	114
+#define FRAME_stand116        	115
+#define FRAME_stand117        	116
+#define FRAME_stand118        	117
+#define FRAME_stand119        	118
+#define FRAME_stand120        	119
+#define FRAME_stand121        	120
+#define FRAME_stand122        	121
+#define FRAME_stand123        	122
+#define FRAME_stand124        	123
+#define FRAME_stand125        	124
+#define FRAME_stand126        	125
+#define FRAME_stand127        	126
+#define FRAME_stand128        	127
+#define FRAME_stand129        	128
+#define FRAME_stand130        	129
+#define FRAME_stand131        	130
+#define FRAME_stand132        	131
+#define FRAME_stand133        	132
+#define FRAME_stand134        	133
+#define FRAME_stand135        	134
+#define FRAME_stand136        	135
+#define FRAME_stand137        	136
+#define FRAME_stand138        	137
+#define FRAME_stand139        	138
+#define FRAME_stand140        	139
+#define FRAME_stand141        	140
+#define FRAME_stand142        	141
+#define FRAME_stand143        	142
+#define FRAME_stand144        	143
+#define FRAME_stand145        	144
+#define FRAME_stand146        	145
+#define FRAME_stand147        	146
+#define FRAME_stand148        	147
+#define FRAME_stand149        	148
+#define FRAME_stand150        	149
+#define FRAME_stand151        	150
+#define FRAME_stand152        	151
+#define FRAME_stand153        	152
+#define FRAME_stand154        	153
+#define FRAME_stand155        	154
+#define FRAME_stand156        	155
+#define FRAME_stand157        	156
+#define FRAME_stand158        	157
+#define FRAME_stand159        	158
+#define FRAME_stand160        	159
+#define FRAME_walk27          	160
+#define FRAME_walk28          	161
+#define FRAME_walk29          	162
+#define FRAME_walk30          	163
+#define FRAME_walk31          	164
+#define FRAME_walk32          	165
+#define FRAME_walk33          	166
+#define FRAME_walk34          	167
+#define FRAME_walk35          	168
+#define FRAME_walk36          	169
+#define FRAME_walk37          	170
+#define FRAME_walk38          	171
+#define FRAME_walk39          	172
+#define FRAME_walk1           	173
+#define FRAME_walk2           	174
+#define FRAME_walk3           	175
+#define FRAME_walk4           	176
+#define FRAME_walk5           	177
+#define FRAME_walk6           	178
+#define FRAME_walk7           	179
+#define FRAME_walk8           	180
+#define FRAME_walk9           	181
+#define FRAME_walk10          	182
+#define FRAME_walk11          	183
+#define FRAME_walk12          	184
+#define FRAME_walk13          	185
+#define FRAME_walk14          	186
+#define FRAME_walk15          	187
+#define FRAME_walk16          	188
+#define FRAME_walk17          	189
+#define FRAME_walk18          	190
+#define FRAME_walk19          	191
+#define FRAME_walk20          	192
+#define FRAME_walk21          	193
+#define FRAME_walk22          	194
+#define FRAME_walk23          	195
+#define FRAME_walk24          	196
+#define FRAME_walk25          	197
+#define FRAME_walk26          	198
+#define FRAME_st_pain2        	199
+#define FRAME_st_pain3        	200
+#define FRAME_st_pain4        	201
+#define FRAME_st_pain5        	202
+#define FRAME_st_pain6        	203
+#define FRAME_st_pain7        	204
+#define FRAME_st_pain8        	205
+#define FRAME_st_pain9        	206
+#define FRAME_st_pain10       	207
+#define FRAME_st_pain11       	208
+#define FRAME_st_pain12       	209
+#define FRAME_st_death2       	210
+#define FRAME_st_death3       	211
+#define FRAME_st_death4       	212
+#define FRAME_st_death5       	213
+#define FRAME_st_death6       	214
+#define FRAME_st_death7       	215
+#define FRAME_st_death8       	216
+#define FRAME_st_death9       	217
+#define FRAME_st_death10      	218
+#define FRAME_st_death11      	219
+#define FRAME_st_death12      	220
+#define FRAME_st_death13      	221
+#define FRAME_st_death14      	222
+#define FRAME_st_death15      	223
+#define FRAME_st_death16      	224
+#define FRAME_st_death17      	225
+#define FRAME_st_death18      	226
+#define FRAME_crawl1          	227
+#define FRAME_crawl2          	228
+#define FRAME_crawl3          	229
+#define FRAME_crawl4          	230
+#define FRAME_crawl5          	231
+#define FRAME_crawl6          	232
+#define FRAME_crawl7          	233
+#define FRAME_crawl8          	234
+#define FRAME_crawl9          	235
+#define FRAME_cr_pain2        	236
+#define FRAME_cr_pain3        	237
+#define FRAME_cr_pain4        	238
+#define FRAME_cr_pain5        	239
+#define FRAME_cr_pain6        	240
+#define FRAME_cr_pain7        	241
+#define FRAME_cr_pain8        	242
+#define FRAME_cr_pain9        	243
+#define FRAME_cr_pain10       	244
+#define FRAME_cr_death10      	245
+#define FRAME_cr_death11      	246
+#define FRAME_cr_death12      	247
+#define FRAME_cr_death13      	248
+#define FRAME_cr_death14      	249
+#define FRAME_cr_death15      	250
+#define FRAME_cr_death16      	251
+#define FRAME_cross1          	252
+#define FRAME_cross2          	253
+#define FRAME_cross3          	254
+#define FRAME_cross4          	255
+#define FRAME_cross5          	256
+#define FRAME_cross6          	257
+#define FRAME_cross7          	258
+#define FRAME_cross8          	259
+#define FRAME_cross9          	260
+#define FRAME_cross10         	261
+#define FRAME_cross11         	262
+#define FRAME_cross12         	263
+#define FRAME_cross13         	264
+#define FRAME_cross14         	265
+#define FRAME_cross15         	266
+#define FRAME_cross16         	267
+#define FRAME_cross17         	268
+#define FRAME_cross18         	269
+#define FRAME_cross19         	270
+#define FRAME_cross20         	271
+#define FRAME_cross21         	272
+#define FRAME_cross22         	273
+#define FRAME_cross23         	274
+#define FRAME_cross24         	275
+#define FRAME_cross25         	276
+#define FRAME_cross26         	277
+#define FRAME_cross27         	278
+#define FRAME_cross28         	279
+#define FRAME_cross29         	280
+#define FRAME_cross30         	281
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_medic.c
@@ -1,0 +1,769 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+MEDIC
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_medic.h"
+
+qboolean visible (edict_t *self, edict_t *other);
+
+
+static int	sound_idle1;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_die;
+static int	sound_sight;
+static int	sound_search;
+static int	sound_hook_launch;
+static int	sound_hook_hit;
+static int	sound_hook_heal;
+static int	sound_hook_retract;
+
+
+edict_t *medic_FindDeadMonster (edict_t *self)
+{
+	edict_t	*ent = NULL;
+	edict_t	*best = NULL;
+
+	while ((ent = findradius(ent, self->s.origin, 1024)) != NULL)
+	{
+		if (ent == self)
+			continue;
+		if (!(ent->svflags & SVF_MONSTER))
+			continue;
+		if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
+			continue;
+		if (ent->owner)
+			continue;
+		if (ent->health > 0)
+			continue;
+		if (ent->nextthink)
+			continue;
+		if (!visible(self, ent))
+			continue;
+		if (!best)
+		{
+			best = ent;
+			continue;
+		}
+		if (ent->max_health <= best->max_health)
+			continue;
+		best = ent;
+	}
+
+	return best;
+}
+
+void medic_idle (edict_t *self)
+{
+	edict_t	*ent;
+
+	gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
+
+	ent = medic_FindDeadMonster(self);
+	if (ent)
+	{
+		self->enemy = ent;
+		self->enemy->owner = self;
+		self->monsterinfo.aiflags |= AI_MEDIC;
+		FoundTarget (self);
+	}
+}
+
+void medic_search (edict_t *self)
+{
+	edict_t	*ent;
+
+	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
+
+	if (!self->oldenemy)
+	{
+		ent = medic_FindDeadMonster(self);
+		if (ent)
+		{
+			self->oldenemy = self->enemy;
+			self->enemy = ent;
+			self->enemy->owner = self;
+			self->monsterinfo.aiflags |= AI_MEDIC;
+			FoundTarget (self);
+		}
+	}
+}
+
+void medic_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+
+mframe_t medic_frames_stand [] =
+{
+	ai_stand, 0, medic_idle,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+};
+mmove_t medic_move_stand = {FRAME_wait1, FRAME_wait90, medic_frames_stand, NULL};
+
+void medic_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &medic_move_stand;
+}
+
+
+mframe_t medic_frames_walk [] =
+{
+	ai_walk, 6.2,	NULL,
+	ai_walk, 18.1,  NULL,
+	ai_walk, 1,		NULL,
+	ai_walk, 9,		NULL,
+	ai_walk, 10,	NULL,
+	ai_walk, 9,		NULL,
+	ai_walk, 11,	NULL,
+	ai_walk, 11.6,  NULL,
+	ai_walk, 2,		NULL,
+	ai_walk, 9.9,	NULL,
+	ai_walk, 14,	NULL,
+	ai_walk, 9.3,	NULL
+};
+mmove_t medic_move_walk = {FRAME_walk1, FRAME_walk12, medic_frames_walk, NULL};
+
+void medic_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &medic_move_walk;
+}
+
+
+mframe_t medic_frames_run [] =
+{
+	ai_run, 18,		NULL,
+	ai_run, 22.5,	NULL,
+	ai_run, 25.4,	NULL,
+	ai_run, 23.4,	NULL,
+	ai_run, 24,		NULL,
+	ai_run, 35.6,	NULL
+	
+};
+mmove_t medic_move_run = {FRAME_run1, FRAME_run6, medic_frames_run, NULL};
+
+void medic_run (edict_t *self)
+{
+	if (!(self->monsterinfo.aiflags & AI_MEDIC))
+	{
+		edict_t	*ent;
+
+		ent = medic_FindDeadMonster(self);
+		if (ent)
+		{
+			self->oldenemy = self->enemy;
+			self->enemy = ent;
+			self->enemy->owner = self;
+			self->monsterinfo.aiflags |= AI_MEDIC;
+			FoundTarget (self);
+			return;
+		}
+	}
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &medic_move_stand;
+	else
+		self->monsterinfo.currentmove = &medic_move_run;
+}
+
+
+mframe_t medic_frames_pain1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t medic_move_pain1 = {FRAME_paina1, FRAME_paina8, medic_frames_pain1, medic_run};
+
+mframe_t medic_frames_pain2 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t medic_move_pain2 = {FRAME_painb1, FRAME_painb15, medic_frames_pain2, medic_run};
+
+void medic_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (random() < 0.5)
+	{
+		self->monsterinfo.currentmove = &medic_move_pain1;
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &medic_move_pain2;
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+	}
+}
+
+void medic_fire_blaster (edict_t *self)
+{
+	vec3_t	start;
+	vec3_t	forward, right;
+	vec3_t	end;
+	vec3_t	dir;
+	int		effect;
+
+	if ((self->s.frame == FRAME_attack9) || (self->s.frame == FRAME_attack12))
+		effect = EF_BLASTER;
+	else if ((self->s.frame == FRAME_attack19) || (self->s.frame == FRAME_attack22) || (self->s.frame == FRAME_attack25) || (self->s.frame == FRAME_attack28))
+		effect = EF_HYPERBLASTER;
+	else
+		effect = 0;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, end);
+	end[2] += self->enemy->viewheight;
+	VectorSubtract (end, start, dir);
+
+	monster_fire_blaster (self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect);
+}
+
+
+void medic_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t medic_frames_death [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t medic_move_death = {FRAME_death1, FRAME_death30, medic_frames_death, medic_dead};
+
+void medic_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	// if we had a pending patient, free him up for another medic
+	if ((self->enemy) && (self->enemy->owner == self))
+		self->enemy->owner = NULL;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	self->monsterinfo.currentmove = &medic_move_death;
+}
+
+
+void medic_duck_down (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_DUCKED)
+		return;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	self->maxs[2] -= 32;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.pausetime = level.time + 1;
+	gi.linkentity (self);
+}
+
+void medic_duck_hold (edict_t *self)
+{
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+void medic_duck_up (edict_t *self)
+{
+	self->monsterinfo.aiflags &= ~AI_DUCKED;
+	self->maxs[2] += 32;
+	self->takedamage = DAMAGE_AIM;
+	gi.linkentity (self);
+}
+
+mframe_t medic_frames_duck [] =
+{
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	medic_duck_down,
+	ai_move, -1,	medic_duck_hold,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	medic_duck_up,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL,
+	ai_move, -1,	NULL
+};
+mmove_t medic_move_duck = {FRAME_duck1, FRAME_duck16, medic_frames_duck, medic_run};
+
+void medic_dodge (edict_t *self, edict_t *attacker, float eta)
+{
+	if (random() > 0.25)
+		return;
+
+	if (!self->enemy)
+		self->enemy = attacker;
+
+	self->monsterinfo.currentmove = &medic_move_duck;
+}
+
+mframe_t medic_frames_attackHyperBlaster [] =
+{
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	medic_fire_blaster
+};
+mmove_t medic_move_attackHyperBlaster = {FRAME_attack15, FRAME_attack30, medic_frames_attackHyperBlaster, medic_run};
+
+
+void medic_continue (edict_t *self)
+{
+	if (visible (self, self->enemy) )
+		if (random() <= 0.95)
+			self->monsterinfo.currentmove = &medic_move_attackHyperBlaster;
+}
+
+
+mframe_t medic_frames_attackBlaster [] =
+{
+	ai_charge, 0,	NULL,
+	ai_charge, 5,	NULL,
+	ai_charge, 5,	NULL,
+	ai_charge, 3,	NULL,
+	ai_charge, 2,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	medic_fire_blaster,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	medic_fire_blaster,	
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	medic_continue	// Change to medic_continue... Else, go to frame 32
+};
+mmove_t medic_move_attackBlaster = {FRAME_attack1, FRAME_attack14, medic_frames_attackBlaster, medic_run};
+
+
+void medic_hook_launch (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0);
+}
+
+void ED_CallSpawn (edict_t *ent);
+
+static vec3_t	medic_cable_offsets[] =
+{
+	45.0,  -9.2, 15.5,
+	48.4,  -9.7, 15.2,
+	47.8,  -9.8, 15.8,
+	47.3,  -9.3, 14.3,
+	45.4, -10.1, 13.1,
+	41.9, -12.7, 12.0,
+	37.8, -15.8, 11.2,
+	34.3, -18.4, 10.7,
+	32.7, -19.7, 10.4,
+	32.7, -19.7, 10.4
+};
+
+void medic_cable_attack (edict_t *self)
+{
+	vec3_t	offset, start, end, f, r;
+	trace_t	tr;
+	vec3_t	dir, angles;
+	float	distance;
+
+	if (!self->enemy->inuse)
+		return;
+
+	AngleVectors (self->s.angles, f, r, NULL);
+	VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
+	G_ProjectSource (self->s.origin, offset, f, r, start);
+
+	// check for max distance
+	VectorSubtract (start, self->enemy->s.origin, dir);
+	distance = VectorLength(dir);
+	if (distance > 256)
+		return;
+
+	// check for min/max pitch
+	vectoangles (dir, angles);
+	if (angles[0] < -180)
+		angles[0] += 360;
+	if (fabs(angles[0]) > 45)
+		return;
+
+	tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);
+	if (tr.fraction != 1.0 && tr.ent != self->enemy)
+		return;
+
+	if (self->s.frame == FRAME_attack43)
+	{
+		gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
+		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
+	}
+	else if (self->s.frame == FRAME_attack50)
+	{
+		self->enemy->spawnflags = 0;
+		self->enemy->monsterinfo.aiflags = 0;
+		self->enemy->target = NULL;
+		self->enemy->targetname = NULL;
+		self->enemy->combattarget = NULL;
+		self->enemy->deathtarget = NULL;
+		self->enemy->owner = self;
+		ED_CallSpawn (self->enemy);
+		self->enemy->owner = NULL;
+		if (self->enemy->think)
+		{
+			self->enemy->nextthink = level.time;
+			self->enemy->think (self->enemy);
+		}
+		self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
+		if (self->oldenemy && self->oldenemy->client)
+		{
+			self->enemy->enemy = self->oldenemy;
+			FoundTarget (self->enemy);
+		}
+	}
+	else
+	{
+		if (self->s.frame == FRAME_attack44)
+			gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
+	}
+
+	// adjust start for beam origin being in middle of a segment
+	VectorMA (start, 8, f, start);
+
+	// adjust end z for end spot since the monster is currently dead
+	VectorCopy (self->enemy->s.origin, end);
+	end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
+	gi.WriteShort (self - g_edicts);
+	gi.WritePosition (start);
+	gi.WritePosition (end);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+}
+
+void medic_hook_retract (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0);
+	self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
+}
+
+mframe_t medic_frames_attackCable [] =
+{
+	ai_move, 2,		NULL,
+	ai_move, 3,		NULL,
+	ai_move, 5,		NULL,
+	ai_move, 4.4,	NULL,
+	ai_charge, 4.7,	NULL,
+	ai_charge, 5,	NULL,
+	ai_charge, 6,	NULL,
+	ai_charge, 4,	NULL,
+	ai_charge, 0,	NULL,
+	ai_move, 0,		medic_hook_launch,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, 0,		medic_cable_attack,
+	ai_move, -15,	medic_hook_retract,
+	ai_move, -1.5,	NULL,
+	ai_move, -1.2,	NULL,
+	ai_move, -3,	NULL,
+	ai_move, -2,	NULL,
+	ai_move, 0.3,	NULL,
+	ai_move, 0.7,	NULL,
+	ai_move, 1.2,	NULL,
+	ai_move, 1.3,	NULL
+};
+mmove_t medic_move_attackCable = {FRAME_attack33, FRAME_attack60, medic_frames_attackCable, medic_run};
+
+
+void medic_attack(edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_MEDIC)
+		self->monsterinfo.currentmove = &medic_move_attackCable;
+	else
+		self->monsterinfo.currentmove = &medic_move_attackBlaster;
+}
+
+qboolean medic_checkattack (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_MEDIC)
+	{
+		medic_attack(self);
+		return true;
+	}
+
+	return M_CheckAttack (self);
+}
+
+
+/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_medic (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_idle1 = gi.soundindex ("medic/idle.wav");
+	sound_pain1 = gi.soundindex ("medic/medpain1.wav");
+	sound_pain2 = gi.soundindex ("medic/medpain2.wav");
+	sound_die = gi.soundindex ("medic/meddeth1.wav");
+	sound_sight = gi.soundindex ("medic/medsght1.wav");
+	sound_search = gi.soundindex ("medic/medsrch1.wav");
+	sound_hook_launch = gi.soundindex ("medic/medatck2.wav");
+	sound_hook_hit = gi.soundindex ("medic/medatck3.wav");
+	sound_hook_heal = gi.soundindex ("medic/medatck4.wav");
+	sound_hook_retract = gi.soundindex ("medic/medatck5.wav");
+
+	gi.soundindex ("medic/medatck1.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2");
+	VectorSet (self->mins, -24, -24, -24);
+	VectorSet (self->maxs, 24, 24, 32);
+
+	self->health = 300;
+	self->gib_health = -130;
+	self->mass = 400;
+
+	self->pain = medic_pain;
+	self->die = medic_die;
+
+	self->monsterinfo.stand = medic_stand;
+	self->monsterinfo.walk = medic_walk;
+	self->monsterinfo.run = medic_run;
+	self->monsterinfo.dodge = medic_dodge;
+	self->monsterinfo.attack = medic_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = medic_sight;
+	self->monsterinfo.idle = medic_idle;
+	self->monsterinfo.search = medic_search;
+	self->monsterinfo.checkattack = medic_checkattack;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &medic_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_medic.h
@@ -1,0 +1,262 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/medic
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_walk1           	0
+#define FRAME_walk2           	1
+#define FRAME_walk3           	2
+#define FRAME_walk4           	3
+#define FRAME_walk5           	4
+#define FRAME_walk6           	5
+#define FRAME_walk7           	6
+#define FRAME_walk8           	7
+#define FRAME_walk9           	8
+#define FRAME_walk10          	9
+#define FRAME_walk11          	10
+#define FRAME_walk12          	11
+#define FRAME_wait1           	12
+#define FRAME_wait2           	13
+#define FRAME_wait3           	14
+#define FRAME_wait4           	15
+#define FRAME_wait5           	16
+#define FRAME_wait6           	17
+#define FRAME_wait7           	18
+#define FRAME_wait8           	19
+#define FRAME_wait9           	20
+#define FRAME_wait10          	21
+#define FRAME_wait11          	22
+#define FRAME_wait12          	23
+#define FRAME_wait13          	24
+#define FRAME_wait14          	25
+#define FRAME_wait15          	26
+#define FRAME_wait16          	27
+#define FRAME_wait17          	28
+#define FRAME_wait18          	29
+#define FRAME_wait19          	30
+#define FRAME_wait20          	31
+#define FRAME_wait21          	32
+#define FRAME_wait22          	33
+#define FRAME_wait23          	34
+#define FRAME_wait24          	35
+#define FRAME_wait25          	36
+#define FRAME_wait26          	37
+#define FRAME_wait27          	38
+#define FRAME_wait28          	39
+#define FRAME_wait29          	40
+#define FRAME_wait30          	41
+#define FRAME_wait31          	42
+#define FRAME_wait32          	43
+#define FRAME_wait33          	44
+#define FRAME_wait34          	45
+#define FRAME_wait35          	46
+#define FRAME_wait36          	47
+#define FRAME_wait37          	48
+#define FRAME_wait38          	49
+#define FRAME_wait39          	50
+#define FRAME_wait40          	51
+#define FRAME_wait41          	52
+#define FRAME_wait42          	53
+#define FRAME_wait43          	54
+#define FRAME_wait44          	55
+#define FRAME_wait45          	56
+#define FRAME_wait46          	57
+#define FRAME_wait47          	58
+#define FRAME_wait48          	59
+#define FRAME_wait49          	60
+#define FRAME_wait50          	61
+#define FRAME_wait51          	62
+#define FRAME_wait52          	63
+#define FRAME_wait53          	64
+#define FRAME_wait54          	65
+#define FRAME_wait55          	66
+#define FRAME_wait56          	67
+#define FRAME_wait57          	68
+#define FRAME_wait58          	69
+#define FRAME_wait59          	70
+#define FRAME_wait60          	71
+#define FRAME_wait61          	72
+#define FRAME_wait62          	73
+#define FRAME_wait63          	74
+#define FRAME_wait64          	75
+#define FRAME_wait65          	76
+#define FRAME_wait66          	77
+#define FRAME_wait67          	78
+#define FRAME_wait68          	79
+#define FRAME_wait69          	80
+#define FRAME_wait70          	81
+#define FRAME_wait71          	82
+#define FRAME_wait72          	83
+#define FRAME_wait73          	84
+#define FRAME_wait74          	85
+#define FRAME_wait75          	86
+#define FRAME_wait76          	87
+#define FRAME_wait77          	88
+#define FRAME_wait78          	89
+#define FRAME_wait79          	90
+#define FRAME_wait80          	91
+#define FRAME_wait81          	92
+#define FRAME_wait82          	93
+#define FRAME_wait83          	94
+#define FRAME_wait84          	95
+#define FRAME_wait85          	96
+#define FRAME_wait86          	97
+#define FRAME_wait87          	98
+#define FRAME_wait88          	99
+#define FRAME_wait89          	100
+#define FRAME_wait90          	101
+#define FRAME_run1            	102
+#define FRAME_run2            	103
+#define FRAME_run3            	104
+#define FRAME_run4            	105
+#define FRAME_run5            	106
+#define FRAME_run6            	107
+#define FRAME_paina1          	108
+#define FRAME_paina2          	109
+#define FRAME_paina3          	110
+#define FRAME_paina4          	111
+#define FRAME_paina5          	112
+#define FRAME_paina6          	113
+#define FRAME_paina7          	114
+#define FRAME_paina8          	115
+#define FRAME_painb1          	116
+#define FRAME_painb2          	117
+#define FRAME_painb3          	118
+#define FRAME_painb4          	119
+#define FRAME_painb5          	120
+#define FRAME_painb6          	121
+#define FRAME_painb7          	122
+#define FRAME_painb8          	123
+#define FRAME_painb9          	124
+#define FRAME_painb10         	125
+#define FRAME_painb11         	126
+#define FRAME_painb12         	127
+#define FRAME_painb13         	128
+#define FRAME_painb14         	129
+#define FRAME_painb15         	130
+#define FRAME_duck1           	131
+#define FRAME_duck2           	132
+#define FRAME_duck3           	133
+#define FRAME_duck4           	134
+#define FRAME_duck5           	135
+#define FRAME_duck6           	136
+#define FRAME_duck7           	137
+#define FRAME_duck8           	138
+#define FRAME_duck9           	139
+#define FRAME_duck10          	140
+#define FRAME_duck11          	141
+#define FRAME_duck12          	142
+#define FRAME_duck13          	143
+#define FRAME_duck14          	144
+#define FRAME_duck15          	145
+#define FRAME_duck16          	146
+#define FRAME_death1          	147
+#define FRAME_death2          	148
+#define FRAME_death3          	149
+#define FRAME_death4          	150
+#define FRAME_death5          	151
+#define FRAME_death6          	152
+#define FRAME_death7          	153
+#define FRAME_death8          	154
+#define FRAME_death9          	155
+#define FRAME_death10         	156
+#define FRAME_death11         	157
+#define FRAME_death12         	158
+#define FRAME_death13         	159
+#define FRAME_death14         	160
+#define FRAME_death15         	161
+#define FRAME_death16         	162
+#define FRAME_death17         	163
+#define FRAME_death18         	164
+#define FRAME_death19         	165
+#define FRAME_death20         	166
+#define FRAME_death21         	167
+#define FRAME_death22         	168
+#define FRAME_death23         	169
+#define FRAME_death24         	170
+#define FRAME_death25         	171
+#define FRAME_death26         	172
+#define FRAME_death27         	173
+#define FRAME_death28         	174
+#define FRAME_death29         	175
+#define FRAME_death30         	176
+#define FRAME_attack1         	177
+#define FRAME_attack2         	178
+#define FRAME_attack3         	179
+#define FRAME_attack4         	180
+#define FRAME_attack5         	181
+#define FRAME_attack6         	182
+#define FRAME_attack7         	183
+#define FRAME_attack8         	184
+#define FRAME_attack9         	185
+#define FRAME_attack10        	186
+#define FRAME_attack11        	187
+#define FRAME_attack12        	188
+#define FRAME_attack13        	189
+#define FRAME_attack14        	190
+#define FRAME_attack15        	191
+#define FRAME_attack16        	192
+#define FRAME_attack17        	193
+#define FRAME_attack18        	194
+#define FRAME_attack19        	195
+#define FRAME_attack20        	196
+#define FRAME_attack21        	197
+#define FRAME_attack22        	198
+#define FRAME_attack23        	199
+#define FRAME_attack24        	200
+#define FRAME_attack25        	201
+#define FRAME_attack26        	202
+#define FRAME_attack27        	203
+#define FRAME_attack28        	204
+#define FRAME_attack29        	205
+#define FRAME_attack30        	206
+#define FRAME_attack31        	207
+#define FRAME_attack32        	208
+#define FRAME_attack33        	209
+#define FRAME_attack34        	210
+#define FRAME_attack35        	211
+#define FRAME_attack36        	212
+#define FRAME_attack37        	213
+#define FRAME_attack38        	214
+#define FRAME_attack39        	215
+#define FRAME_attack40        	216
+#define FRAME_attack41        	217
+#define FRAME_attack42        	218
+#define FRAME_attack43        	219
+#define FRAME_attack44        	220
+#define FRAME_attack45        	221
+#define FRAME_attack46        	222
+#define FRAME_attack47        	223
+#define FRAME_attack48        	224
+#define FRAME_attack49        	225
+#define FRAME_attack50        	226
+#define FRAME_attack51        	227
+#define FRAME_attack52        	228
+#define FRAME_attack53        	229
+#define FRAME_attack54        	230
+#define FRAME_attack55        	231
+#define FRAME_attack56        	232
+#define FRAME_attack57        	233
+#define FRAME_attack58        	234
+#define FRAME_attack59        	235
+#define FRAME_attack60        	236
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_move.c
@@ -1,0 +1,556 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// m_move.c -- monster movement
+
+#include "g_local.h"
+
+#define	STEPSIZE	18
+
+/*
+=============
+M_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 M_CheckBottom (edict_t *ent)
+{
+	vec3_t	mins, maxs, start, stop;
+	trace_t	trace;
+	int		x, y;
+	float	mid, bottom;
+	
+	VectorAdd (ent->s.origin, ent->mins, mins);
+	VectorAdd (ent->s.origin, ent->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 (gi.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 = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
+
+	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 = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
+			
+			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
+=============
+*/
+//FIXME since we need to test end position contents here, can we avoid doing
+//it again later in catagorize position?
+qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
+{
+	float		dz;
+	vec3_t		oldorg, neworg, end;
+	trace_t		trace;
+	int			i;
+	float		stepsize;
+	vec3_t		test;
+	int			contents;
+
+// try the move	
+	VectorCopy (ent->s.origin, oldorg);
+	VectorAdd (ent->s.origin, move, neworg);
+
+// flying monsters don't step up
+	if ( ent->flags & (FL_SWIM | FL_FLY) )
+	{
+	// try one move with vertical motion, then one without
+		for (i=0 ; i<2 ; i++)
+		{
+			VectorAdd (ent->s.origin, move, neworg);
+			if (i == 0 && ent->enemy)
+			{
+				if (!ent->goalentity)
+					ent->goalentity = ent->enemy;
+				dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
+				if (ent->goalentity->client)
+				{
+					if (dz > 40)
+						neworg[2] -= 8;
+					if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
+						if (dz < 30)
+							neworg[2] += 8;
+				}
+				else
+				{
+					if (dz > 8)
+						neworg[2] -= 8;
+					else if (dz > 0)
+						neworg[2] -= dz;
+					else if (dz < -8)
+						neworg[2] += 8;
+					else
+						neworg[2] += dz;
+				}
+			}
+			trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
+	
+			// fly monsters don't enter water voluntarily
+			if (ent->flags & FL_FLY)
+			{
+				if (!ent->waterlevel)
+				{
+					test[0] = trace.endpos[0];
+					test[1] = trace.endpos[1];
+					test[2] = trace.endpos[2] + ent->mins[2] + 1;
+					contents = gi.pointcontents(test);
+					if (contents & MASK_WATER)
+						return false;
+				}
+			}
+
+			// swim monsters don't exit water voluntarily
+			if (ent->flags & FL_SWIM)
+			{
+				if (ent->waterlevel < 2)
+				{
+					test[0] = trace.endpos[0];
+					test[1] = trace.endpos[1];
+					test[2] = trace.endpos[2] + ent->mins[2] + 1;
+					contents = gi.pointcontents(test);
+					if (!(contents & MASK_WATER))
+						return false;
+				}
+			}
+
+			if (trace.fraction == 1)
+			{
+				VectorCopy (trace.endpos, ent->s.origin);
+				if (relink)
+				{
+					gi.linkentity (ent);
+					G_TouchTriggers (ent);
+				}
+				return true;
+			}
+			
+			if (!ent->enemy)
+				break;
+		}
+		
+		return false;
+	}
+
+// push down from a step height above the wished position
+	if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
+		stepsize = STEPSIZE;
+	else
+		stepsize = 1;
+
+	neworg[2] += stepsize;
+	VectorCopy (neworg, end);
+	end[2] -= stepsize*2;
+
+	trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
+
+	if (trace.allsolid)
+		return false;
+
+	if (trace.startsolid)
+	{
+		neworg[2] -= stepsize;
+		trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
+		if (trace.allsolid || trace.startsolid)
+			return false;
+	}
+
+
+	// don't go in to water
+	if (ent->waterlevel == 0)
+	{
+		test[0] = trace.endpos[0];
+		test[1] = trace.endpos[1];
+		test[2] = trace.endpos[2] + ent->mins[2] + 1;	
+		contents = gi.pointcontents(test);
+
+		if (contents & MASK_WATER)
+			return false;
+	}
+
+	if (trace.fraction == 1)
+	{
+	// if monster had the ground pulled out, go ahead and fall
+		if ( ent->flags & FL_PARTIALGROUND )
+		{
+			VectorAdd (ent->s.origin, move, ent->s.origin);
+			if (relink)
+			{
+				gi.linkentity (ent);
+				G_TouchTriggers (ent);
+			}
+			ent->groundentity = NULL;
+			return true;
+		}
+	
+		return false;		// walked off an edge
+	}
+
+// check point traces down for dangling corners
+	VectorCopy (trace.endpos, ent->s.origin);
+	
+	if (!M_CheckBottom (ent))
+	{
+		if ( ent->flags & FL_PARTIALGROUND )
+		{	// entity had floor mostly pulled out from underneath it
+			// and is trying to correct
+			if (relink)
+			{
+				gi.linkentity (ent);
+				G_TouchTriggers (ent);
+			}
+			return true;
+		}
+		VectorCopy (oldorg, ent->s.origin);
+		return false;
+	}
+
+	if ( ent->flags & FL_PARTIALGROUND )
+	{
+		ent->flags &= ~FL_PARTIALGROUND;
+	}
+	ent->groundentity = trace.ent;
+	ent->groundentity_linkcount = trace.ent->linkcount;
+
+// the move is ok
+	if (relink)
+	{
+		gi.linkentity (ent);
+		G_TouchTriggers (ent);
+	}
+	return true;
+}
+
+
+//============================================================================
+
+/*
+===============
+M_ChangeYaw
+
+===============
+*/
+void M_ChangeYaw (edict_t *ent)
+{
+	float	ideal;
+	float	current;
+	float	move;
+	float	speed;
+	
+	current = anglemod(ent->s.angles[YAW]);
+	ideal = ent->ideal_yaw;
+
+	if (current == ideal)
+		return;
+
+	move = ideal - current;
+	speed = ent->yaw_speed;
+	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->s.angles[YAW] = anglemod (current + move);
+}
+
+
+/*
+======================
+SV_StepDirection
+
+Turns to the movement direction, and walks the current distance if
+facing it.
+
+======================
+*/
+qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
+{
+	vec3_t		move, oldorigin;
+	float		delta;
+	
+	ent->ideal_yaw = yaw;
+	M_ChangeYaw (ent);
+	
+	yaw = yaw*M_PI*2 / 360;
+	move[0] = cos(yaw)*dist;
+	move[1] = sin(yaw)*dist;
+	move[2] = 0;
+
+	VectorCopy (ent->s.origin, oldorigin);
+	if (SV_movestep (ent, move, false))
+	{
+		delta = ent->s.angles[YAW] - ent->ideal_yaw;
+		if (delta > 45 && delta < 315)
+		{		// not turned far enough, so don't take the step
+			VectorCopy (oldorigin, ent->s.origin);
+		}
+		gi.linkentity (ent);
+		G_TouchTriggers (ent);
+		return true;
+	}
+	gi.linkentity (ent);
+	G_TouchTriggers (ent);
+	return false;
+}
+
+/*
+======================
+SV_FixCheckBottom
+
+======================
+*/
+void SV_FixCheckBottom (edict_t *ent)
+{
+	ent->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;
+
+	//FIXME: how did we get here with no enemy
+	if (!enemy)
+		return;
+
+	olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
+	turnaround = anglemod(olddir - 180);
+
+	deltax = enemy->s.origin[0] - actor->s.origin[0];
+	deltay = enemy->s.origin[1] - actor->s.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->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 (!M_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->absmin[i] > ent->absmax[i] + dist)
+			return false;
+		if (goal->absmax[i] < ent->absmin[i] - dist)
+			return false;
+	}
+	return true;
+}
+
+
+/*
+======================
+M_MoveToGoal
+======================
+*/
+void M_MoveToGoal (edict_t *ent, float dist)
+{
+	edict_t		*goal;
+	
+	goal = ent->goalentity;
+
+	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
+		return;
+
+// if the next step hits the enemy, return immediately
+	if (ent->enemy &&  SV_CloseEnough (ent, ent->enemy, dist) )
+		return;
+
+// bump around...
+	if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
+	{
+		if (ent->inuse)
+			SV_NewChaseDir (ent, goal, dist);
+	}
+}
+
+
+/*
+===============
+M_walkmove
+===============
+*/
+qboolean M_walkmove (edict_t *ent, float yaw, float dist)
+{
+	vec3_t	move;
+	
+	if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
+		return false;
+
+	yaw = yaw*M_PI*2 / 360;
+	
+	move[0] = cos(yaw)*dist;
+	move[1] = sin(yaw)*dist;
+	move[2] = 0;
+
+	return SV_movestep(ent, move, true);
+}
--- /dev/null
+++ b/game/m_mutant.c
@@ -1,0 +1,663 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+mutant
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_mutant.h"
+
+
+static int	sound_swing;
+static int	sound_hit;
+static int	sound_hit2;
+static int	sound_death;
+static int	sound_idle;
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_sight;
+static int	sound_search;
+static int	sound_step1;
+static int	sound_step2;
+static int	sound_step3;
+static int	sound_thud;
+
+//
+// SOUNDS
+//
+
+void mutant_step (edict_t *self)
+{
+	int		n;
+	n = (rand() + 1) % 3;
+	if (n == 0)
+		gi.sound (self, CHAN_VOICE, sound_step1, 1, ATTN_NORM, 0);		
+	else if (n == 1)
+		gi.sound (self, CHAN_VOICE, sound_step2, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_step3, 1, ATTN_NORM, 0);
+}
+
+void mutant_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void mutant_search (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+}
+
+void mutant_swing (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0);
+}
+
+
+//
+// STAND
+//
+
+mframe_t mutant_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 10
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 20
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 30
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 40
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,		// 50
+
+	ai_stand, 0, NULL
+};
+mmove_t mutant_move_stand = {FRAME_stand101, FRAME_stand151, mutant_frames_stand, NULL};
+
+void mutant_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &mutant_move_stand;
+}
+
+
+//
+// IDLE
+//
+
+void mutant_idle_loop (edict_t *self)
+{
+	if (random() < 0.75)
+		self->monsterinfo.nextframe = FRAME_stand155;
+}
+
+mframe_t mutant_frames_idle [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,					// scratch loop start
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, mutant_idle_loop,		// scratch loop end
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t mutant_move_idle = {FRAME_stand152, FRAME_stand164, mutant_frames_idle, mutant_stand};
+
+void mutant_idle (edict_t *self)
+{
+	self->monsterinfo.currentmove = &mutant_move_idle;
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+
+//
+// WALK
+//
+
+void mutant_walk (edict_t *self);
+
+mframe_t mutant_frames_walk [] =
+{
+	ai_walk,	3,		NULL,
+	ai_walk,	1,		NULL,
+	ai_walk,	5,		NULL,
+	ai_walk,	10,		NULL,
+	ai_walk,	13,		NULL,
+	ai_walk,	10,		NULL,
+	ai_walk,	0,		NULL,
+	ai_walk,	5,		NULL,
+	ai_walk,	6,		NULL,
+	ai_walk,	16,		NULL,
+	ai_walk,	15,		NULL,
+	ai_walk,	6,		NULL
+};
+mmove_t mutant_move_walk = {FRAME_walk05, FRAME_walk16, mutant_frames_walk, NULL};
+
+void mutant_walk_loop (edict_t *self)
+{
+	self->monsterinfo.currentmove = &mutant_move_walk;
+}
+
+mframe_t mutant_frames_start_walk [] =
+{
+	ai_walk,	5,		NULL,
+	ai_walk,	5,		NULL,
+	ai_walk,	-2,		NULL,
+	ai_walk,	1,		NULL
+};
+mmove_t mutant_move_start_walk = {FRAME_walk01, FRAME_walk04, mutant_frames_start_walk, mutant_walk_loop};
+
+void mutant_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &mutant_move_start_walk;
+}
+
+
+//
+// RUN
+//
+
+mframe_t mutant_frames_run [] =
+{
+	ai_run,	40,		NULL,
+	ai_run,	40,		mutant_step,
+	ai_run,	24,		NULL,
+	ai_run,	5,		mutant_step,
+	ai_run,	17,		NULL,
+	ai_run,	10,		NULL
+};
+mmove_t mutant_move_run = {FRAME_run03, FRAME_run08, mutant_frames_run, NULL};
+
+void mutant_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &mutant_move_stand;
+	else
+		self->monsterinfo.currentmove = &mutant_move_run;
+}
+
+
+//
+// MELEE
+//
+
+void mutant_hit_left (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8);
+	if (fire_hit (self, aim, (10 + (rand() %5)), 100))
+		gi.sound (self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
+}
+
+void mutant_hit_right (edict_t *self)
+{
+	vec3_t	aim;
+
+	VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8);
+	if (fire_hit (self, aim, (10 + (rand() %5)), 100))
+		gi.sound (self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
+}
+
+void mutant_check_refire (edict_t *self)
+{
+	if (!self->enemy || !self->enemy->inuse || self->enemy->health <= 0)
+		return;
+
+	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+		self->monsterinfo.nextframe = FRAME_attack09;
+}
+
+mframe_t mutant_frames_attack [] =
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	mutant_hit_left,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	mutant_hit_right,
+	ai_charge,	0,	mutant_check_refire
+};
+mmove_t mutant_move_attack = {FRAME_attack09, FRAME_attack15, mutant_frames_attack, mutant_run};
+
+void mutant_melee (edict_t *self)
+{
+	self->monsterinfo.currentmove = &mutant_move_attack;
+}
+
+
+//
+// ATTACK
+//
+
+void mutant_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
+{
+	if (self->health <= 0)
+	{
+		self->touch = NULL;
+		return;
+	}
+
+	if (other->takedamage)
+	{
+		if (VectorLength(self->velocity) > 400)
+		{
+			vec3_t	point;
+			vec3_t	normal;
+			int		damage;
+
+			VectorCopy (self->velocity, normal);
+			VectorNormalize(normal);
+			VectorMA (self->s.origin, self->maxs[0], normal, point);
+			damage = 40 + 10 * random();
+			T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_UNKNOWN);
+		}
+	}
+
+	if (!M_CheckBottom (self))
+	{
+		if (self->groundentity)
+		{
+			self->monsterinfo.nextframe = FRAME_attack02;
+			self->touch = NULL;
+		}
+		return;
+	}
+
+	self->touch = NULL;
+}
+
+void mutant_jump_takeoff (edict_t *self)
+{
+	vec3_t	forward;
+
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+	AngleVectors (self->s.angles, forward, NULL, NULL);
+	self->s.origin[2] += 1;
+	VectorScale (forward, 600, self->velocity);
+	self->velocity[2] = 250;
+	self->groundentity = NULL;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	self->monsterinfo.attack_finished = level.time + 3;
+	self->touch = mutant_jump_touch;
+}
+
+void mutant_check_landing (edict_t *self)
+{
+	if (self->groundentity)
+	{
+		gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
+		self->monsterinfo.attack_finished = 0;
+		self->monsterinfo.aiflags &= ~AI_DUCKED;
+		return;
+	}
+
+	if (level.time > self->monsterinfo.attack_finished)
+		self->monsterinfo.nextframe = FRAME_attack02;
+	else
+		self->monsterinfo.nextframe = FRAME_attack05;
+}
+
+mframe_t mutant_frames_jump [] =
+{
+	ai_charge,	 0,	NULL,
+	ai_charge,	17,	NULL,
+	ai_charge,	15,	mutant_jump_takeoff,
+	ai_charge,	15,	NULL,
+	ai_charge,	15,	mutant_check_landing,
+	ai_charge,	 0,	NULL,
+	ai_charge,	 3,	NULL,
+	ai_charge,	 0,	NULL
+};
+mmove_t mutant_move_jump = {FRAME_attack01, FRAME_attack08, mutant_frames_jump, mutant_run};
+
+void mutant_jump (edict_t *self)
+{
+	self->monsterinfo.currentmove = &mutant_move_jump;
+}
+
+
+//
+// CHECKATTACK
+//
+
+qboolean mutant_check_melee (edict_t *self)
+{
+	if (range (self, self->enemy) == RANGE_MELEE)
+		return true;
+	return false;
+}
+
+qboolean mutant_check_jump (edict_t *self)
+{
+	vec3_t	v;
+	float	distance;
+
+	if (self->absmin[2] > (self->enemy->absmin[2] + 0.75 * self->enemy->size[2]))
+		return false;
+
+	if (self->absmax[2] < (self->enemy->absmin[2] + 0.25 * self->enemy->size[2]))
+		return false;
+
+	v[0] = self->s.origin[0] - self->enemy->s.origin[0];
+	v[1] = self->s.origin[1] - self->enemy->s.origin[1];
+	v[2] = 0;
+	distance = VectorLength(v);
+
+	if (distance < 100)
+		return false;
+	if (distance > 100)
+	{
+		if (random() < 0.9)
+			return false;
+	}
+
+	return true;
+}
+
+qboolean mutant_checkattack (edict_t *self)
+{
+	if (!self->enemy || self->enemy->health <= 0)
+		return false;
+
+	if (mutant_check_melee(self))
+	{
+		self->monsterinfo.attack_state = AS_MELEE;
+		return true;
+	}
+
+	if (mutant_check_jump(self))
+	{
+		self->monsterinfo.attack_state = AS_MISSILE;
+		// FIXME play a jump sound here
+		return true;
+	}
+
+	return false;
+}
+
+
+//
+// PAIN
+//
+
+mframe_t mutant_frames_pain1 [] =
+{
+	ai_move,	4,	NULL,
+	ai_move,	-3,	NULL,
+	ai_move,	-8,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	5,	NULL
+};
+mmove_t mutant_move_pain1 = {FRAME_pain101, FRAME_pain105, mutant_frames_pain1, mutant_run};
+
+mframe_t mutant_frames_pain2 [] =
+{
+	ai_move,	-24,NULL,
+	ai_move,	11,	NULL,
+	ai_move,	5,	NULL,
+	ai_move,	-2,	NULL,
+	ai_move,	6,	NULL,
+	ai_move,	4,	NULL
+};
+mmove_t mutant_move_pain2 = {FRAME_pain201, FRAME_pain206, mutant_frames_pain2, mutant_run};
+
+mframe_t mutant_frames_pain3 [] =
+{
+	ai_move,	-22,NULL,
+	ai_move,	3,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	1,	NULL,
+	ai_move,	6,	NULL,
+	ai_move,	3,	NULL,
+	ai_move,	2,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	1,	NULL
+};
+mmove_t mutant_move_pain3 = {FRAME_pain301, FRAME_pain311, mutant_frames_pain3, mutant_run};
+
+void mutant_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	float	r;
+
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	r = random();
+	if (r < 0.33)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &mutant_move_pain1;
+	}
+	else if (r < 0.66)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &mutant_move_pain2;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+		self->monsterinfo.currentmove = &mutant_move_pain3;
+	}
+}
+
+
+//
+// DEATH
+//
+
+void mutant_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	gi.linkentity (self);
+
+	M_FlyCheck (self);
+}
+
+mframe_t mutant_frames_death1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t mutant_move_death1 = {FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead};
+
+mframe_t mutant_frames_death2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t mutant_move_death2 = {FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead};
+
+void mutant_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->s.skinnum = 1;
+
+	if (random() < 0.5)
+		self->monsterinfo.currentmove = &mutant_move_death1;
+	else
+		self->monsterinfo.currentmove = &mutant_move_death2;
+}
+
+
+//
+// SPAWN
+//
+
+/*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_mutant (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_swing = gi.soundindex ("mutant/mutatck1.wav");
+	sound_hit = gi.soundindex ("mutant/mutatck2.wav");
+	sound_hit2 = gi.soundindex ("mutant/mutatck3.wav");
+	sound_death = gi.soundindex ("mutant/mutdeth1.wav");
+	sound_idle = gi.soundindex ("mutant/mutidle1.wav");
+	sound_pain1 = gi.soundindex ("mutant/mutpain1.wav");
+	sound_pain2 = gi.soundindex ("mutant/mutpain2.wav");
+	sound_sight = gi.soundindex ("mutant/mutsght1.wav");
+	sound_search = gi.soundindex ("mutant/mutsrch1.wav");
+	sound_step1 = gi.soundindex ("mutant/step1.wav");
+	sound_step2 = gi.soundindex ("mutant/step2.wav");
+	sound_step3 = gi.soundindex ("mutant/step3.wav");
+	sound_thud = gi.soundindex ("mutant/thud1.wav");
+	
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/mutant/tris.md2");
+	VectorSet (self->mins, -32, -32, -24);
+	VectorSet (self->maxs, 32, 32, 48);
+
+	self->health = 300;
+	self->gib_health = -120;
+	self->mass = 300;
+
+	self->pain = mutant_pain;
+	self->die = mutant_die;
+
+	self->monsterinfo.stand = mutant_stand;
+	self->monsterinfo.walk = mutant_walk;
+	self->monsterinfo.run = mutant_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = mutant_jump;
+	self->monsterinfo.melee = mutant_melee;
+	self->monsterinfo.sight = mutant_sight;
+	self->monsterinfo.search = mutant_search;
+	self->monsterinfo.idle = mutant_idle;
+	self->monsterinfo.checkattack = mutant_checkattack;
+
+	gi.linkentity (self);
+	
+	self->monsterinfo.currentmove = &mutant_move_stand;
+
+	self->monsterinfo.scale = MODEL_SCALE;
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_mutant.h
@@ -1,0 +1,174 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/mutant
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_attack01        	0
+#define FRAME_attack02        	1
+#define FRAME_attack03        	2
+#define FRAME_attack04        	3
+#define FRAME_attack05        	4
+#define FRAME_attack06        	5
+#define FRAME_attack07        	6
+#define FRAME_attack08        	7
+#define FRAME_attack09        	8
+#define FRAME_attack10        	9
+#define FRAME_attack11        	10
+#define FRAME_attack12        	11
+#define FRAME_attack13        	12
+#define FRAME_attack14        	13
+#define FRAME_attack15        	14
+#define FRAME_death101        	15
+#define FRAME_death102        	16
+#define FRAME_death103        	17
+#define FRAME_death104        	18
+#define FRAME_death105        	19
+#define FRAME_death106        	20
+#define FRAME_death107        	21
+#define FRAME_death108        	22
+#define FRAME_death109        	23
+#define FRAME_death201        	24
+#define FRAME_death202        	25
+#define FRAME_death203        	26
+#define FRAME_death204        	27
+#define FRAME_death205        	28
+#define FRAME_death206        	29
+#define FRAME_death207        	30
+#define FRAME_death208        	31
+#define FRAME_death209        	32
+#define FRAME_death210        	33
+#define FRAME_pain101         	34
+#define FRAME_pain102         	35
+#define FRAME_pain103         	36
+#define FRAME_pain104         	37
+#define FRAME_pain105         	38
+#define FRAME_pain201         	39
+#define FRAME_pain202         	40
+#define FRAME_pain203         	41
+#define FRAME_pain204         	42
+#define FRAME_pain205         	43
+#define FRAME_pain206         	44
+#define FRAME_pain301         	45
+#define FRAME_pain302         	46
+#define FRAME_pain303         	47
+#define FRAME_pain304         	48
+#define FRAME_pain305         	49
+#define FRAME_pain306         	50
+#define FRAME_pain307         	51
+#define FRAME_pain308         	52
+#define FRAME_pain309         	53
+#define FRAME_pain310         	54
+#define FRAME_pain311         	55
+#define FRAME_run03           	56
+#define FRAME_run04           	57
+#define FRAME_run05           	58
+#define FRAME_run06           	59
+#define FRAME_run07           	60
+#define FRAME_run08           	61
+#define FRAME_stand101        	62
+#define FRAME_stand102        	63
+#define FRAME_stand103        	64
+#define FRAME_stand104        	65
+#define FRAME_stand105        	66
+#define FRAME_stand106        	67
+#define FRAME_stand107        	68
+#define FRAME_stand108        	69
+#define FRAME_stand109        	70
+#define FRAME_stand110        	71
+#define FRAME_stand111        	72
+#define FRAME_stand112        	73
+#define FRAME_stand113        	74
+#define FRAME_stand114        	75
+#define FRAME_stand115        	76
+#define FRAME_stand116        	77
+#define FRAME_stand117        	78
+#define FRAME_stand118        	79
+#define FRAME_stand119        	80
+#define FRAME_stand120        	81
+#define FRAME_stand121        	82
+#define FRAME_stand122        	83
+#define FRAME_stand123        	84
+#define FRAME_stand124        	85
+#define FRAME_stand125        	86
+#define FRAME_stand126        	87
+#define FRAME_stand127        	88
+#define FRAME_stand128        	89
+#define FRAME_stand129        	90
+#define FRAME_stand130        	91
+#define FRAME_stand131        	92
+#define FRAME_stand132        	93
+#define FRAME_stand133        	94
+#define FRAME_stand134        	95
+#define FRAME_stand135        	96
+#define FRAME_stand136        	97
+#define FRAME_stand137        	98
+#define FRAME_stand138        	99
+#define FRAME_stand139        	100
+#define FRAME_stand140        	101
+#define FRAME_stand141        	102
+#define FRAME_stand142        	103
+#define FRAME_stand143        	104
+#define FRAME_stand144        	105
+#define FRAME_stand145        	106
+#define FRAME_stand146        	107
+#define FRAME_stand147        	108
+#define FRAME_stand148        	109
+#define FRAME_stand149        	110
+#define FRAME_stand150        	111
+#define FRAME_stand151        	112
+#define FRAME_stand152        	113
+#define FRAME_stand153        	114
+#define FRAME_stand154        	115
+#define FRAME_stand155        	116
+#define FRAME_stand156        	117
+#define FRAME_stand157        	118
+#define FRAME_stand158        	119
+#define FRAME_stand159        	120
+#define FRAME_stand160        	121
+#define FRAME_stand161        	122
+#define FRAME_stand162        	123
+#define FRAME_stand163        	124
+#define FRAME_stand164        	125
+#define FRAME_walk01          	126
+#define FRAME_walk02          	127
+#define FRAME_walk03          	128
+#define FRAME_walk04          	129
+#define FRAME_walk05          	130
+#define FRAME_walk06          	131
+#define FRAME_walk07          	132
+#define FRAME_walk08          	133
+#define FRAME_walk09          	134
+#define FRAME_walk10          	135
+#define FRAME_walk11          	136
+#define FRAME_walk12          	137
+#define FRAME_walk13          	138
+#define FRAME_walk14          	139
+#define FRAME_walk15          	140
+#define FRAME_walk16          	141
+#define FRAME_walk17          	142
+#define FRAME_walk18          	143
+#define FRAME_walk19          	144
+#define FRAME_walk20          	145
+#define FRAME_walk21          	146
+#define FRAME_walk22          	147
+#define FRAME_walk23          	148
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_parasite.c
@@ -1,0 +1,552 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+parasite
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_parasite.h"
+
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_die;
+static int	sound_launch;
+static int	sound_impact;
+static int	sound_suck;
+static int	sound_reelin;
+static int	sound_sight;
+static int	sound_tap;
+static int	sound_scratch;
+static int	sound_search;
+
+
+void parasite_stand (edict_t *self);
+void parasite_start_run (edict_t *self);
+void parasite_run (edict_t *self);
+void parasite_walk (edict_t *self);
+void parasite_start_walk (edict_t *self);
+void parasite_end_fidget (edict_t *self);
+void parasite_do_fidget (edict_t *self);
+void parasite_refidget (edict_t *self);
+
+
+void parasite_launch (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_launch, 1, ATTN_NORM, 0);
+}
+
+void parasite_reel_in (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_reelin, 1, ATTN_NORM, 0);
+}
+
+void parasite_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_WEAPON, sound_sight, 1, ATTN_NORM, 0);
+}
+
+void parasite_tap (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_tap, 1, ATTN_IDLE, 0);
+}
+
+void parasite_scratch (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_scratch, 1, ATTN_IDLE, 0);
+}
+
+void parasite_search (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_search, 1, ATTN_IDLE, 0);
+}
+
+
+mframe_t parasite_frames_start_fidget [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t parasite_move_start_fidget = {FRAME_stand18, FRAME_stand21, parasite_frames_start_fidget, parasite_do_fidget};
+
+mframe_t parasite_frames_fidget [] =
+{	
+	ai_stand, 0, parasite_scratch,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_scratch,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t parasite_move_fidget = {FRAME_stand22, FRAME_stand27, parasite_frames_fidget, parasite_refidget};
+
+mframe_t parasite_frames_end_fidget [] =
+{
+	ai_stand, 0, parasite_scratch,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t parasite_move_end_fidget = {FRAME_stand28, FRAME_stand35, parasite_frames_end_fidget, parasite_stand};
+
+void parasite_end_fidget (edict_t *self)
+{
+	self->monsterinfo.currentmove = &parasite_move_end_fidget;
+}
+
+void parasite_do_fidget (edict_t *self)
+{
+	self->monsterinfo.currentmove = &parasite_move_fidget;
+}
+
+void parasite_refidget (edict_t *self)
+{ 
+	if (random() <= 0.8)
+		self->monsterinfo.currentmove = &parasite_move_fidget;
+	else
+		self->monsterinfo.currentmove = &parasite_move_end_fidget;
+}
+
+void parasite_idle (edict_t *self)
+{ 
+	self->monsterinfo.currentmove = &parasite_move_start_fidget;
+}
+
+
+mframe_t parasite_frames_stand [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_tap,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_tap,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_tap,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_tap,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_tap,
+	ai_stand, 0, NULL,
+	ai_stand, 0, parasite_tap
+};
+mmove_t	parasite_move_stand = {FRAME_stand01, FRAME_stand17, parasite_frames_stand, parasite_stand};
+
+void parasite_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &parasite_move_stand;
+}
+
+
+mframe_t parasite_frames_run [] =
+{
+	ai_run, 30, NULL,
+	ai_run, 30, NULL,
+	ai_run, 22, NULL,
+	ai_run, 19, NULL,
+	ai_run, 24, NULL,
+	ai_run, 28, NULL,
+	ai_run, 25, NULL
+};
+mmove_t parasite_move_run = {FRAME_run03, FRAME_run09, parasite_frames_run, NULL};
+
+mframe_t parasite_frames_start_run [] =
+{
+	ai_run, 0,	NULL,
+	ai_run, 30, NULL,
+};
+mmove_t parasite_move_start_run = {FRAME_run01, FRAME_run02, parasite_frames_start_run, parasite_run};
+
+mframe_t parasite_frames_stop_run [] =
+{	
+	ai_run, 20, NULL,
+	ai_run, 20,	NULL,
+	ai_run, 12, NULL,
+	ai_run, 10, NULL,
+	ai_run, 0,  NULL,
+	ai_run, 0,  NULL
+};
+mmove_t parasite_move_stop_run = {FRAME_run10, FRAME_run15, parasite_frames_stop_run, NULL};
+
+void parasite_start_run (edict_t *self)
+{	
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &parasite_move_stand;
+	else
+		self->monsterinfo.currentmove = &parasite_move_start_run;
+}
+
+void parasite_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &parasite_move_stand;
+	else
+		self->monsterinfo.currentmove = &parasite_move_run;
+}
+
+
+mframe_t parasite_frames_walk [] =
+{
+	ai_walk, 30, NULL,
+	ai_walk, 30, NULL,
+	ai_walk, 22, NULL,
+	ai_walk, 19, NULL,
+	ai_walk, 24, NULL,
+	ai_walk, 28, NULL,
+	ai_walk, 25, NULL
+};
+mmove_t parasite_move_walk = {FRAME_run03, FRAME_run09, parasite_frames_walk, parasite_walk};
+
+mframe_t parasite_frames_start_walk [] =
+{
+	ai_walk, 0,	NULL,
+	ai_walk, 30, parasite_walk
+};
+mmove_t parasite_move_start_walk = {FRAME_run01, FRAME_run02, parasite_frames_start_walk, NULL};
+
+mframe_t parasite_frames_stop_walk [] =
+{	
+	ai_walk, 20, NULL,
+	ai_walk, 20,	NULL,
+	ai_walk, 12, NULL,
+	ai_walk, 10, NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL
+};
+mmove_t parasite_move_stop_walk = {FRAME_run10, FRAME_run15, parasite_frames_stop_walk, NULL};
+
+void parasite_start_walk (edict_t *self)
+{	
+	self->monsterinfo.currentmove = &parasite_move_start_walk;
+}
+
+void parasite_walk (edict_t *self)
+{
+	self->monsterinfo.currentmove = &parasite_move_walk;
+}
+
+
+mframe_t parasite_frames_pain1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0,	NULL,
+	ai_move, 0,	NULL,
+	ai_move, 6,	NULL,
+	ai_move, 16, NULL,
+	ai_move, -6, NULL,
+	ai_move, -7, NULL,
+	ai_move, 0, NULL
+};
+mmove_t parasite_move_pain1 = {FRAME_pain101, FRAME_pain111, parasite_frames_pain1, parasite_start_run};
+
+void parasite_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+		self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+		return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+
+	self->monsterinfo.currentmove = &parasite_move_pain1;
+}
+
+
+static qboolean parasite_drain_attack_ok (vec3_t start, vec3_t end)
+{
+	vec3_t	dir, angles;
+
+	// check for max distance
+	VectorSubtract (start, end, dir);
+	if (VectorLength(dir) > 256)
+		return false;
+
+	// check for min/max pitch
+	vectoangles (dir, angles);
+	if (angles[0] < -180)
+		angles[0] += 360;
+	if (fabs(angles[0]) > 30)
+		return false;
+
+	return true;
+}
+
+void parasite_drain_attack (edict_t *self)
+{
+	vec3_t	offset, start, f, r, end, dir;
+	trace_t	tr;
+	int damage;
+
+	AngleVectors (self->s.angles, f, r, NULL);
+	VectorSet (offset, 24, 0, 6);
+	G_ProjectSource (self->s.origin, offset, f, r, start);
+
+	VectorCopy (self->enemy->s.origin, end);
+	if (!parasite_drain_attack_ok(start, end))
+	{
+		end[2] = self->enemy->s.origin[2] + self->enemy->maxs[2] - 8;
+		if (!parasite_drain_attack_ok(start, end))
+		{
+			end[2] = self->enemy->s.origin[2] + self->enemy->mins[2] + 8;
+			if (!parasite_drain_attack_ok(start, end))
+				return;
+		}
+	}
+	VectorCopy (self->enemy->s.origin, end);
+
+	tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
+	if (tr.ent != self->enemy)
+		return;
+
+	if (self->s.frame == FRAME_drain03)
+	{
+		damage = 5;
+		gi.sound (self->enemy, CHAN_AUTO, sound_impact, 1, ATTN_NORM, 0);
+	}
+	else
+	{
+		if (self->s.frame == FRAME_drain04)
+			gi.sound (self, CHAN_WEAPON, sound_suck, 1, ATTN_NORM, 0);
+		damage = 2;
+	}
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_PARASITE_ATTACK);
+	gi.WriteShort (self - g_edicts);
+	gi.WritePosition (start);
+	gi.WritePosition (end);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	VectorSubtract (start, end, dir);
+	T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN);
+}
+
+mframe_t parasite_frames_drain [] =
+{
+	ai_charge, 0,	parasite_launch,
+	ai_charge, 0,	NULL,
+	ai_charge, 15,	parasite_drain_attack,			// Target hits
+	ai_charge, 0,	parasite_drain_attack,			// drain
+	ai_charge, 0,	parasite_drain_attack,			// drain
+	ai_charge, 0,	parasite_drain_attack,			// drain
+	ai_charge, 0,	parasite_drain_attack,			// drain
+	ai_charge, -2,  parasite_drain_attack,			// drain
+	ai_charge, -2,	parasite_drain_attack,			// drain
+	ai_charge, -3,	parasite_drain_attack,			// drain
+	ai_charge, -2,	parasite_drain_attack,			// drain
+	ai_charge, 0,	parasite_drain_attack,			// drain
+	ai_charge, -1,  parasite_drain_attack,			// drain
+	ai_charge, 0,	parasite_reel_in,				// let go
+	ai_charge, -2,	NULL,
+	ai_charge, -2,	NULL,
+	ai_charge, -3,	NULL,
+	ai_charge, 0,	NULL
+};
+mmove_t parasite_move_drain = {FRAME_drain01, FRAME_drain18, parasite_frames_drain, parasite_start_run};
+
+
+mframe_t parasite_frames_break [] =
+{
+	ai_charge, 0,	NULL,
+	ai_charge, -3,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, 2,	NULL,
+	ai_charge, -3,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, 1,	NULL,
+	ai_charge, 3,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, -18,	NULL,
+	ai_charge, 3,	NULL,
+	ai_charge, 9,	NULL,
+	ai_charge, 6,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, -18,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 8,	NULL,
+	ai_charge, 9,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, -18,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,		// airborne
+	ai_charge, 0,	NULL,		// airborne
+	ai_charge, 0,	NULL,		// slides
+	ai_charge, 0,	NULL,		// slides
+	ai_charge, 0,	NULL,		// slides
+	ai_charge, 0,	NULL,		// slides
+	ai_charge, 4,	NULL,
+	ai_charge, 11,	NULL,		
+	ai_charge, -2,	NULL,
+	ai_charge, -5,	NULL,
+	ai_charge, 1,	NULL
+};
+mmove_t parasite_move_break = {FRAME_break01, FRAME_break32, parasite_frames_break, parasite_start_run};
+
+/*
+=== 
+Break Stuff Ends
+===
+*/
+
+void parasite_attack (edict_t *self)
+{
+//	if (random() <= 0.2)
+//		self->monsterinfo.currentmove = &parasite_move_break;
+//	else
+		self->monsterinfo.currentmove = &parasite_move_drain;
+}
+
+
+
+/*
+===
+Death Stuff Starts
+===
+*/
+
+void parasite_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t parasite_frames_death [] =
+{
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL,
+	ai_move, 0,	 NULL
+};
+mmove_t parasite_move_death = {FRAME_death101, FRAME_death107, parasite_frames_death, parasite_dead};
+
+void parasite_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 2; n++)
+			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.currentmove = &parasite_move_death;
+}
+
+/*
+===
+End Death Stuff
+===
+*/
+
+/*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_parasite (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1 = gi.soundindex ("parasite/parpain1.wav");	
+	sound_pain2 = gi.soundindex ("parasite/parpain2.wav");	
+	sound_die = gi.soundindex ("parasite/pardeth1.wav");	
+	sound_launch = gi.soundindex("parasite/paratck1.wav");
+	sound_impact = gi.soundindex("parasite/paratck2.wav");
+	sound_suck = gi.soundindex("parasite/paratck3.wav");
+	sound_reelin = gi.soundindex("parasite/paratck4.wav");
+	sound_sight = gi.soundindex("parasite/parsght1.wav");
+	sound_tap = gi.soundindex("parasite/paridle1.wav");
+	sound_scratch = gi.soundindex("parasite/paridle2.wav");
+	sound_search = gi.soundindex("parasite/parsrch1.wav");
+
+	self->s.modelindex = gi.modelindex ("models/monsters/parasite/tris.md2");
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 24);
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+
+	self->health = 175;
+	self->gib_health = -50;
+	self->mass = 250;
+
+	self->pain = parasite_pain;
+	self->die = parasite_die;
+
+	self->monsterinfo.stand = parasite_stand;
+	self->monsterinfo.walk = parasite_start_walk;
+	self->monsterinfo.run = parasite_start_run;
+	self->monsterinfo.attack = parasite_attack;
+	self->monsterinfo.sight = parasite_sight;
+	self->monsterinfo.idle = parasite_idle;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.currentmove = &parasite_move_stand;	
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start (self);
+}
--- /dev/null
+++ b/game/m_parasite.h
@@ -1,0 +1,143 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/parasite
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_break01           0
+#define FRAME_break02           1
+#define FRAME_break03           2
+#define FRAME_break04           3
+#define FRAME_break05           4
+#define FRAME_break06           5
+#define FRAME_break07           6
+#define FRAME_break08           7
+#define FRAME_break09           8
+#define FRAME_break10           9
+#define FRAME_break11           10
+#define FRAME_break12           11
+#define FRAME_break13           12
+#define FRAME_break14           13
+#define FRAME_break15           14
+#define FRAME_break16           15
+#define FRAME_break17           16
+#define FRAME_break18           17
+#define FRAME_break19           18
+#define FRAME_break20           19
+#define FRAME_break21           20
+#define FRAME_break22           21
+#define FRAME_break23           22
+#define FRAME_break24           23
+#define FRAME_break25           24
+#define FRAME_break26           25
+#define FRAME_break27           26
+#define FRAME_break28           27
+#define FRAME_break29           28
+#define FRAME_break30           29
+#define FRAME_break31           30
+#define FRAME_break32           31
+#define FRAME_death101          32
+#define FRAME_death102          33
+#define FRAME_death103          34
+#define FRAME_death104          35
+#define FRAME_death105          36
+#define FRAME_death106          37
+#define FRAME_death107          38
+#define FRAME_drain01           39
+#define FRAME_drain02           40
+#define FRAME_drain03           41
+#define FRAME_drain04           42
+#define FRAME_drain05           43
+#define FRAME_drain06           44
+#define FRAME_drain07           45
+#define FRAME_drain08           46
+#define FRAME_drain09           47
+#define FRAME_drain10           48
+#define FRAME_drain11           49
+#define FRAME_drain12           50
+#define FRAME_drain13           51
+#define FRAME_drain14           52
+#define FRAME_drain15           53
+#define FRAME_drain16           54
+#define FRAME_drain17           55
+#define FRAME_drain18           56
+#define FRAME_pain101           57
+#define FRAME_pain102           58
+#define FRAME_pain103           59
+#define FRAME_pain104           60
+#define FRAME_pain105           61
+#define FRAME_pain106           62
+#define FRAME_pain107           63
+#define FRAME_pain108           64
+#define FRAME_pain109           65
+#define FRAME_pain110           66
+#define FRAME_pain111           67
+#define FRAME_run01             68
+#define FRAME_run02             69
+#define FRAME_run03             70
+#define FRAME_run04             71
+#define FRAME_run05             72
+#define FRAME_run06             73
+#define FRAME_run07             74
+#define FRAME_run08             75
+#define FRAME_run09             76
+#define FRAME_run10             77
+#define FRAME_run11             78
+#define FRAME_run12             79
+#define FRAME_run13             80
+#define FRAME_run14             81
+#define FRAME_run15             82
+#define FRAME_stand01           83
+#define FRAME_stand02           84
+#define FRAME_stand03           85
+#define FRAME_stand04           86
+#define FRAME_stand05           87
+#define FRAME_stand06           88
+#define FRAME_stand07           89
+#define FRAME_stand08           90
+#define FRAME_stand09           91
+#define FRAME_stand10           92
+#define FRAME_stand11           93
+#define FRAME_stand12           94
+#define FRAME_stand13           95
+#define FRAME_stand14           96
+#define FRAME_stand15           97
+#define FRAME_stand16           98
+#define FRAME_stand17           99
+#define FRAME_stand18           100
+#define FRAME_stand19           101
+#define FRAME_stand20           102
+#define FRAME_stand21           103
+#define FRAME_stand22           104
+#define FRAME_stand23           105
+#define FRAME_stand24           106
+#define FRAME_stand25           107
+#define FRAME_stand26           108
+#define FRAME_stand27           109
+#define FRAME_stand28           110
+#define FRAME_stand29           111
+#define FRAME_stand30           112
+#define FRAME_stand31           113
+#define FRAME_stand32           114
+#define FRAME_stand33           115
+#define FRAME_stand34           116
+#define FRAME_stand35           117
+
+#define MODEL_SCALE             1.000000
--- /dev/null
+++ b/game/m_player.h
@@ -1,0 +1,224 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/player_x/frames
+
+// This file generated by qdata - Do NOT Modify
+
+#define FRAME_stand01         	0
+#define FRAME_stand02         	1
+#define FRAME_stand03         	2
+#define FRAME_stand04         	3
+#define FRAME_stand05         	4
+#define FRAME_stand06         	5
+#define FRAME_stand07         	6
+#define FRAME_stand08         	7
+#define FRAME_stand09         	8
+#define FRAME_stand10         	9
+#define FRAME_stand11         	10
+#define FRAME_stand12         	11
+#define FRAME_stand13         	12
+#define FRAME_stand14         	13
+#define FRAME_stand15         	14
+#define FRAME_stand16         	15
+#define FRAME_stand17         	16
+#define FRAME_stand18         	17
+#define FRAME_stand19         	18
+#define FRAME_stand20         	19
+#define FRAME_stand21         	20
+#define FRAME_stand22         	21
+#define FRAME_stand23         	22
+#define FRAME_stand24         	23
+#define FRAME_stand25         	24
+#define FRAME_stand26         	25
+#define FRAME_stand27         	26
+#define FRAME_stand28         	27
+#define FRAME_stand29         	28
+#define FRAME_stand30         	29
+#define FRAME_stand31         	30
+#define FRAME_stand32         	31
+#define FRAME_stand33         	32
+#define FRAME_stand34         	33
+#define FRAME_stand35         	34
+#define FRAME_stand36         	35
+#define FRAME_stand37         	36
+#define FRAME_stand38         	37
+#define FRAME_stand39         	38
+#define FRAME_stand40         	39
+#define FRAME_run1            	40
+#define FRAME_run2            	41
+#define FRAME_run3            	42
+#define FRAME_run4            	43
+#define FRAME_run5            	44
+#define FRAME_run6            	45
+#define FRAME_attack1         	46
+#define FRAME_attack2         	47
+#define FRAME_attack3         	48
+#define FRAME_attack4         	49
+#define FRAME_attack5         	50
+#define FRAME_attack6         	51
+#define FRAME_attack7         	52
+#define FRAME_attack8         	53
+#define FRAME_pain101         	54
+#define FRAME_pain102         	55
+#define FRAME_pain103         	56
+#define FRAME_pain104         	57
+#define FRAME_pain201         	58
+#define FRAME_pain202         	59
+#define FRAME_pain203         	60
+#define FRAME_pain204         	61
+#define FRAME_pain301         	62
+#define FRAME_pain302         	63
+#define FRAME_pain303         	64
+#define FRAME_pain304         	65
+#define FRAME_jump1           	66
+#define FRAME_jump2           	67
+#define FRAME_jump3           	68
+#define FRAME_jump4           	69
+#define FRAME_jump5           	70
+#define FRAME_jump6           	71
+#define FRAME_flip01          	72
+#define FRAME_flip02          	73
+#define FRAME_flip03          	74
+#define FRAME_flip04          	75
+#define FRAME_flip05          	76
+#define FRAME_flip06          	77
+#define FRAME_flip07          	78
+#define FRAME_flip08          	79
+#define FRAME_flip09          	80
+#define FRAME_flip10          	81
+#define FRAME_flip11          	82
+#define FRAME_flip12          	83
+#define FRAME_salute01        	84
+#define FRAME_salute02        	85
+#define FRAME_salute03        	86
+#define FRAME_salute04        	87
+#define FRAME_salute05        	88
+#define FRAME_salute06        	89
+#define FRAME_salute07        	90
+#define FRAME_salute08        	91
+#define FRAME_salute09        	92
+#define FRAME_salute10        	93
+#define FRAME_salute11        	94
+#define FRAME_taunt01         	95
+#define FRAME_taunt02         	96
+#define FRAME_taunt03         	97
+#define FRAME_taunt04         	98
+#define FRAME_taunt05         	99
+#define FRAME_taunt06         	100
+#define FRAME_taunt07         	101
+#define FRAME_taunt08         	102
+#define FRAME_taunt09         	103
+#define FRAME_taunt10         	104
+#define FRAME_taunt11         	105
+#define FRAME_taunt12         	106
+#define FRAME_taunt13         	107
+#define FRAME_taunt14         	108
+#define FRAME_taunt15         	109
+#define FRAME_taunt16         	110
+#define FRAME_taunt17         	111
+#define FRAME_wave01          	112
+#define FRAME_wave02          	113
+#define FRAME_wave03          	114
+#define FRAME_wave04          	115
+#define FRAME_wave05          	116
+#define FRAME_wave06          	117
+#define FRAME_wave07          	118
+#define FRAME_wave08          	119
+#define FRAME_wave09          	120
+#define FRAME_wave10          	121
+#define FRAME_wave11          	122
+#define FRAME_point01         	123
+#define FRAME_point02         	124
+#define FRAME_point03         	125
+#define FRAME_point04         	126
+#define FRAME_point05         	127
+#define FRAME_point06         	128
+#define FRAME_point07         	129
+#define FRAME_point08         	130
+#define FRAME_point09         	131
+#define FRAME_point10         	132
+#define FRAME_point11         	133
+#define FRAME_point12         	134
+#define FRAME_crstnd01        	135
+#define FRAME_crstnd02        	136
+#define FRAME_crstnd03        	137
+#define FRAME_crstnd04        	138
+#define FRAME_crstnd05        	139
+#define FRAME_crstnd06        	140
+#define FRAME_crstnd07        	141
+#define FRAME_crstnd08        	142
+#define FRAME_crstnd09        	143
+#define FRAME_crstnd10        	144
+#define FRAME_crstnd11        	145
+#define FRAME_crstnd12        	146
+#define FRAME_crstnd13        	147
+#define FRAME_crstnd14        	148
+#define FRAME_crstnd15        	149
+#define FRAME_crstnd16        	150
+#define FRAME_crstnd17        	151
+#define FRAME_crstnd18        	152
+#define FRAME_crstnd19        	153
+#define FRAME_crwalk1         	154
+#define FRAME_crwalk2         	155
+#define FRAME_crwalk3         	156
+#define FRAME_crwalk4         	157
+#define FRAME_crwalk5         	158
+#define FRAME_crwalk6         	159
+#define FRAME_crattak1        	160
+#define FRAME_crattak2        	161
+#define FRAME_crattak3        	162
+#define FRAME_crattak4        	163
+#define FRAME_crattak5        	164
+#define FRAME_crattak6        	165
+#define FRAME_crattak7        	166
+#define FRAME_crattak8        	167
+#define FRAME_crattak9        	168
+#define FRAME_crpain1         	169
+#define FRAME_crpain2         	170
+#define FRAME_crpain3         	171
+#define FRAME_crpain4         	172
+#define FRAME_crdeath1        	173
+#define FRAME_crdeath2        	174
+#define FRAME_crdeath3        	175
+#define FRAME_crdeath4        	176
+#define FRAME_crdeath5        	177
+#define FRAME_death101        	178
+#define FRAME_death102        	179
+#define FRAME_death103        	180
+#define FRAME_death104        	181
+#define FRAME_death105        	182
+#define FRAME_death106        	183
+#define FRAME_death201        	184
+#define FRAME_death202        	185
+#define FRAME_death203        	186
+#define FRAME_death204        	187
+#define FRAME_death205        	188
+#define FRAME_death206        	189
+#define FRAME_death301        	190
+#define FRAME_death302        	191
+#define FRAME_death303        	192
+#define FRAME_death304        	193
+#define FRAME_death305        	194
+#define FRAME_death306        	195
+#define FRAME_death307        	196
+#define FRAME_death308        	197
+
+#define MODEL_SCALE		1.000000
+
--- /dev/null
+++ b/game/m_rider.h
@@ -1,0 +1,66 @@
+// G:\quake2\baseq2\models/monsters/boss3/rider
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_stand201        	0
+#define FRAME_stand202        	1
+#define FRAME_stand203        	2
+#define FRAME_stand204        	3
+#define FRAME_stand205        	4
+#define FRAME_stand206        	5
+#define FRAME_stand207        	6
+#define FRAME_stand208        	7
+#define FRAME_stand209        	8
+#define FRAME_stand210        	9
+#define FRAME_stand211        	10
+#define FRAME_stand212        	11
+#define FRAME_stand213        	12
+#define FRAME_stand214        	13
+#define FRAME_stand215        	14
+#define FRAME_stand216        	15
+#define FRAME_stand217        	16
+#define FRAME_stand218        	17
+#define FRAME_stand219        	18
+#define FRAME_stand220        	19
+#define FRAME_stand221        	20
+#define FRAME_stand222        	21
+#define FRAME_stand223        	22
+#define FRAME_stand224        	23
+#define FRAME_stand225        	24
+#define FRAME_stand226        	25
+#define FRAME_stand227        	26
+#define FRAME_stand228        	27
+#define FRAME_stand229        	28
+#define FRAME_stand230        	29
+#define FRAME_stand231        	30
+#define FRAME_stand232        	31
+#define FRAME_stand233        	32
+#define FRAME_stand234        	33
+#define FRAME_stand235        	34
+#define FRAME_stand236        	35
+#define FRAME_stand237        	36
+#define FRAME_stand238        	37
+#define FRAME_stand239        	38
+#define FRAME_stand240        	39
+#define FRAME_stand241        	40
+#define FRAME_stand242        	41
+#define FRAME_stand243        	42
+#define FRAME_stand244        	43
+#define FRAME_stand245        	44
+#define FRAME_stand246        	45
+#define FRAME_stand247        	46
+#define FRAME_stand248        	47
+#define FRAME_stand249        	48
+#define FRAME_stand250        	49
+#define FRAME_stand251        	50
+#define FRAME_stand252        	51
+#define FRAME_stand253        	52
+#define FRAME_stand254        	53
+#define FRAME_stand255        	54
+#define FRAME_stand256        	55
+#define FRAME_stand257        	56
+#define FRAME_stand258        	57
+#define FRAME_stand259        	58
+#define FRAME_stand260        	59
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_soldier.c
@@ -1,0 +1,1299 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+SOLDIER
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_soldier.h"
+
+
+static int	sound_idle;
+static int	sound_sight1;
+static int	sound_sight2;
+static int	sound_pain_light;
+static int	sound_pain;
+static int	sound_pain_ss;
+static int	sound_death_light;
+static int	sound_death;
+static int	sound_death_ss;
+static int	sound_cock;
+
+
+void soldier_idle (edict_t *self)
+{
+	if (random() > 0.8)
+		gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+void soldier_cock (edict_t *self)
+{
+	if (self->s.frame == FRAME_stand322)
+		gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0);
+	else
+		gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0);
+}
+
+
+// STAND
+
+void soldier_stand (edict_t *self);
+
+mframe_t soldier_frames_stand1 [] =
+{
+	ai_stand, 0, soldier_idle,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t soldier_move_stand1 = {FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand};
+
+mframe_t soldier_frames_stand3 [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, soldier_cock,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t soldier_move_stand3 = {FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand};
+
+#if 0
+mframe_t soldier_frames_stand4 [] =
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 4, NULL,
+	ai_stand, 1, NULL,
+	ai_stand, -1, NULL,
+	ai_stand, -2, NULL,
+
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t soldier_move_stand4 = {FRAME_stand401, FRAME_stand452, soldier_frames_stand4, NULL};
+#endif
+
+void soldier_stand (edict_t *self)
+{
+	if ((self->monsterinfo.currentmove == &soldier_move_stand3) || (random() < 0.8))
+		self->monsterinfo.currentmove = &soldier_move_stand1;
+	else
+		self->monsterinfo.currentmove = &soldier_move_stand3;
+}
+
+
+//
+// WALK
+//
+
+void soldier_walk1_random (edict_t *self)
+{
+	if (random() > 0.1)
+		self->monsterinfo.nextframe = FRAME_walk101;
+}
+
+mframe_t soldier_frames_walk1 [] =
+{
+	ai_walk, 3,  NULL,
+	ai_walk, 6,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 2,  NULL,
+	ai_walk, 1,  NULL,
+	ai_walk, 6,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 3,  NULL,
+	ai_walk, -1, soldier_walk1_random,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL,
+	ai_walk, 0,  NULL
+};
+mmove_t soldier_move_walk1 = {FRAME_walk101, FRAME_walk133, soldier_frames_walk1, NULL};
+
+mframe_t soldier_frames_walk2 [] =
+{
+	ai_walk, 4,  NULL,
+	ai_walk, 4,  NULL,
+	ai_walk, 9,  NULL,
+	ai_walk, 8,  NULL,
+	ai_walk, 5,  NULL,
+	ai_walk, 1,  NULL,
+	ai_walk, 3,  NULL,
+	ai_walk, 7,  NULL,
+	ai_walk, 6,  NULL,
+	ai_walk, 7,  NULL
+};
+mmove_t soldier_move_walk2 = {FRAME_walk209, FRAME_walk218, soldier_frames_walk2, NULL};
+
+void soldier_walk (edict_t *self)
+{
+	if (random() < 0.5)
+		self->monsterinfo.currentmove = &soldier_move_walk1;
+	else
+		self->monsterinfo.currentmove = &soldier_move_walk2;
+}
+
+
+//
+// RUN
+//
+
+void soldier_run (edict_t *self);
+
+mframe_t soldier_frames_start_run [] =
+{
+	ai_run, 7,  NULL,
+	ai_run, 5,  NULL
+};
+mmove_t soldier_move_start_run = {FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run};
+
+mframe_t soldier_frames_run [] =
+{
+	ai_run, 10, NULL,
+	ai_run, 11, NULL,
+	ai_run, 11, NULL,
+	ai_run, 16, NULL,
+	ai_run, 10, NULL,
+	ai_run, 15, NULL
+};
+mmove_t soldier_move_run = {FRAME_run03, FRAME_run08, soldier_frames_run, NULL};
+
+void soldier_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		self->monsterinfo.currentmove = &soldier_move_stand1;
+		return;
+	}
+
+	if (self->monsterinfo.currentmove == &soldier_move_walk1 ||
+		self->monsterinfo.currentmove == &soldier_move_walk2 ||
+		self->monsterinfo.currentmove == &soldier_move_start_run)
+	{
+		self->monsterinfo.currentmove = &soldier_move_run;
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &soldier_move_start_run;
+	}
+}
+
+
+//
+// PAIN
+//
+
+mframe_t soldier_frames_pain1 [] =
+{
+	ai_move, -3, NULL,
+	ai_move, 4,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 0,  NULL
+};
+mmove_t soldier_move_pain1 = {FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run};
+
+mframe_t soldier_frames_pain2 [] =
+{
+	ai_move, -13, NULL,
+	ai_move, -1,  NULL,
+	ai_move, 2,   NULL,
+	ai_move, 4,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 3,   NULL,
+	ai_move, 2,   NULL
+};
+mmove_t soldier_move_pain2 = {FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run};
+
+mframe_t soldier_frames_pain3 [] =
+{
+	ai_move, -8, NULL,
+	ai_move, 10, NULL,
+	ai_move, -4, NULL,
+	ai_move, -1, NULL,
+	ai_move, -3, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 3,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 1,  NULL,
+	ai_move, 2,  NULL,
+	ai_move, 4,  NULL,
+	ai_move, 3,  NULL,
+	ai_move, 2,  NULL
+};
+mmove_t soldier_move_pain3 = {FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run};
+
+mframe_t soldier_frames_pain4 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -10, NULL,
+	ai_move, -6,  NULL,
+	ai_move, 8,   NULL,
+	ai_move, 4,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 5,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, -1,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, 3,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t soldier_move_pain4 = {FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run};
+
+
+void soldier_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	float	r;
+	int		n;
+
+	if (self->health < (self->max_health / 2))
+			self->s.skinnum |= 1;
+
+	if (level.time < self->pain_debounce_time)
+	{
+		if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldier_move_pain1) || (self->monsterinfo.currentmove == &soldier_move_pain2) || (self->monsterinfo.currentmove == &soldier_move_pain3)))
+			self->monsterinfo.currentmove = &soldier_move_pain4;
+		return;
+	}
+
+	self->pain_debounce_time = level.time + 3;
+
+	n = self->s.skinnum | 1;
+	if (n == 1)
+		gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0);
+	else if (n == 3)
+		gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0);
+
+	if (self->velocity[2] > 100)
+	{
+		self->monsterinfo.currentmove = &soldier_move_pain4;
+		return;
+	}
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	r = random();
+
+	if (r < 0.33)
+		self->monsterinfo.currentmove = &soldier_move_pain1;
+	else if (r < 0.66)
+		self->monsterinfo.currentmove = &soldier_move_pain2;
+	else
+		self->monsterinfo.currentmove = &soldier_move_pain3;
+}
+
+
+//
+// ATTACK
+//
+
+static int blaster_flash [] = {MZ2_SOLDIER_BLASTER_1, MZ2_SOLDIER_BLASTER_2, MZ2_SOLDIER_BLASTER_3, MZ2_SOLDIER_BLASTER_4, MZ2_SOLDIER_BLASTER_5, MZ2_SOLDIER_BLASTER_6, MZ2_SOLDIER_BLASTER_7, MZ2_SOLDIER_BLASTER_8};
+static int shotgun_flash [] = {MZ2_SOLDIER_SHOTGUN_1, MZ2_SOLDIER_SHOTGUN_2, MZ2_SOLDIER_SHOTGUN_3, MZ2_SOLDIER_SHOTGUN_4, MZ2_SOLDIER_SHOTGUN_5, MZ2_SOLDIER_SHOTGUN_6, MZ2_SOLDIER_SHOTGUN_7, MZ2_SOLDIER_SHOTGUN_8};
+static int machinegun_flash [] = {MZ2_SOLDIER_MACHINEGUN_1, MZ2_SOLDIER_MACHINEGUN_2, MZ2_SOLDIER_MACHINEGUN_3, MZ2_SOLDIER_MACHINEGUN_4, MZ2_SOLDIER_MACHINEGUN_5, MZ2_SOLDIER_MACHINEGUN_6, MZ2_SOLDIER_MACHINEGUN_7, MZ2_SOLDIER_MACHINEGUN_8};
+
+void soldier_fire (edict_t *self, int flash_number)
+{
+	vec3_t	start;
+	vec3_t	forward, right, up;
+	vec3_t	aim;
+	vec3_t	dir;
+	vec3_t	end;
+	float	r, u;
+	int		flash_index;
+
+	if (self->s.skinnum < 2)
+		flash_index = blaster_flash[flash_number];
+	else if (self->s.skinnum < 4)
+		flash_index = shotgun_flash[flash_number];
+	else
+		flash_index = machinegun_flash[flash_number];
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start);
+
+	if (flash_number == 5 || flash_number == 6)
+	{
+		VectorCopy (forward, aim);
+	}
+	else
+	{
+		VectorCopy (self->enemy->s.origin, end);
+		end[2] += self->enemy->viewheight;
+		VectorSubtract (end, start, aim);
+		vectoangles (aim, dir);
+		AngleVectors (dir, forward, right, up);
+
+		r = crandom()*1000;
+		u = crandom()*500;
+		VectorMA (start, 8192, forward, end);
+		VectorMA (end, r, right, end);
+		VectorMA (end, u, up, end);
+
+		VectorSubtract (end, start, aim);
+		VectorNormalize (aim);
+	}
+
+	if (self->s.skinnum <= 1)
+	{
+		monster_fire_blaster (self, start, aim, 5, 600, flash_index, EF_BLASTER);
+	}
+	else if (self->s.skinnum <= 3)
+	{
+		monster_fire_shotgun (self, start, aim, 2, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SHOTGUN_COUNT, flash_index);
+	}
+	else
+	{
+		if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
+			self->monsterinfo.pausetime = level.time + (3 + rand() % 8) * FRAMETIME;
+
+		monster_fire_bullet (self, start, aim, 2, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index);
+
+		if (level.time >= self->monsterinfo.pausetime)
+			self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+		else
+			self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+	}
+}
+
+// ATTACK1 (blaster/shotgun)
+
+void soldier_fire1 (edict_t *self)
+{
+	soldier_fire (self, 0);
+}
+
+void soldier_attack1_refire1 (edict_t *self)
+{
+	if (self->s.skinnum > 1)
+		return;
+
+	if (self->enemy->health <= 0)
+		return;
+
+	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+		self->monsterinfo.nextframe = FRAME_attak102;
+	else
+		self->monsterinfo.nextframe = FRAME_attak110;
+}
+
+void soldier_attack1_refire2 (edict_t *self)
+{
+	if (self->s.skinnum < 2)
+		return;
+
+	if (self->enemy->health <= 0)
+		return;
+
+	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+		self->monsterinfo.nextframe = FRAME_attak102;
+}
+
+mframe_t soldier_frames_attack1 [] =
+{
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  soldier_fire1,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  soldier_attack1_refire1,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  soldier_cock,
+	ai_charge, 0,  soldier_attack1_refire2,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL
+};
+mmove_t soldier_move_attack1 = {FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run};
+
+// ATTACK2 (blaster/shotgun)
+
+void soldier_fire2 (edict_t *self)
+{
+	soldier_fire (self, 1);
+}
+
+void soldier_attack2_refire1 (edict_t *self)
+{
+	if (self->s.skinnum > 1)
+		return;
+
+	if (self->enemy->health <= 0)
+		return;
+
+	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+		self->monsterinfo.nextframe = FRAME_attak204;
+	else
+		self->monsterinfo.nextframe = FRAME_attak216;
+}
+
+void soldier_attack2_refire2 (edict_t *self)
+{
+	if (self->s.skinnum < 2)
+		return;
+
+	if (self->enemy->health <= 0)
+		return;
+
+	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+		self->monsterinfo.nextframe = FRAME_attak204;
+}
+
+mframe_t soldier_frames_attack2 [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_fire2,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_attack2_refire1,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_cock,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_attack2_refire2,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t soldier_move_attack2 = {FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run};
+
+// ATTACK3 (duck and shoot)
+
+void soldier_duck_down (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_DUCKED)
+		return;
+	self->monsterinfo.aiflags |= AI_DUCKED;
+	self->maxs[2] -= 32;
+	self->takedamage = DAMAGE_YES;
+	self->monsterinfo.pausetime = level.time + 1;
+	gi.linkentity (self);
+}
+
+void soldier_duck_up (edict_t *self)
+{
+	self->monsterinfo.aiflags &= ~AI_DUCKED;
+	self->maxs[2] += 32;
+	self->takedamage = DAMAGE_AIM;
+	gi.linkentity (self);
+}
+
+void soldier_fire3 (edict_t *self)
+{
+	soldier_duck_down (self);
+	soldier_fire (self, 2);
+}
+
+void soldier_attack3_refire (edict_t *self)
+{
+	if ((level.time + 0.4) < self->monsterinfo.pausetime)
+		self->monsterinfo.nextframe = FRAME_attak303;
+}
+
+mframe_t soldier_frames_attack3 [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_fire3,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_attack3_refire,
+	ai_charge, 0, soldier_duck_up,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t soldier_move_attack3 = {FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run};
+
+// ATTACK4 (machinegun)
+
+void soldier_fire4 (edict_t *self)
+{
+	soldier_fire (self, 3);
+//
+//	if (self->enemy->health <= 0)
+//		return;
+//
+//	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+//		self->monsterinfo.nextframe = FRAME_attak402;
+}
+
+mframe_t soldier_frames_attack4 [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_fire4,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t soldier_move_attack4 = {FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run};
+
+#if 0
+// ATTACK5 (prone)
+
+void soldier_fire5 (edict_t *self)
+{
+	soldier_fire (self, 4);
+}
+
+void soldier_attack5_refire (edict_t *self)
+{
+	if (self->enemy->health <= 0)
+		return;
+
+	if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
+		self->monsterinfo.nextframe = FRAME_attak505;
+}
+
+mframe_t soldier_frames_attack5 [] =
+{
+	ai_charge, 8, NULL,
+	ai_charge, 8, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_fire5,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, soldier_attack5_refire
+};
+mmove_t soldier_move_attack5 = {FRAME_attak501, FRAME_attak508, soldier_frames_attack5, soldier_run};
+#endif
+
+// ATTACK6 (run & shoot)
+
+void soldier_fire8 (edict_t *self)
+{
+	soldier_fire (self, 7);
+}
+
+void soldier_attack6_refire (edict_t *self)
+{
+	if (self->enemy->health <= 0)
+		return;
+
+	if (range(self, self->enemy) < RANGE_MID)
+		return;
+
+	if (skill->value == 3)
+		self->monsterinfo.nextframe = FRAME_runs03;
+}
+
+mframe_t soldier_frames_attack6 [] =
+{
+	ai_charge, 10, NULL,
+	ai_charge,  4, NULL,
+	ai_charge, 12, NULL,
+	ai_charge, 11, soldier_fire8,
+	ai_charge, 13, NULL,
+	ai_charge, 18, NULL,
+	ai_charge, 15, NULL,
+	ai_charge, 14, NULL,
+	ai_charge, 11, NULL,
+	ai_charge,  8, NULL,
+	ai_charge, 11, NULL,
+	ai_charge, 12, NULL,
+	ai_charge, 12, NULL,
+	ai_charge, 17, soldier_attack6_refire
+};
+mmove_t soldier_move_attack6 = {FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run};
+
+void soldier_attack(edict_t *self)
+{
+	if (self->s.skinnum < 4)
+	{
+		if (random() < 0.5)
+			self->monsterinfo.currentmove = &soldier_move_attack1;
+		else
+			self->monsterinfo.currentmove = &soldier_move_attack2;
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &soldier_move_attack4;
+	}
+}
+
+
+//
+// SIGHT
+//
+
+void soldier_sight(edict_t *self, edict_t *other)
+{
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0);
+
+	if ((skill->value > 0) && (range(self, self->enemy) >= RANGE_MID))
+	{
+		if (random() > 0.5)
+			self->monsterinfo.currentmove = &soldier_move_attack6;
+	}
+}
+
+//
+// DUCK
+//
+
+void soldier_duck_hold (edict_t *self)
+{
+	if (level.time >= self->monsterinfo.pausetime)
+		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+	else
+		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
+}
+
+mframe_t soldier_frames_duck [] =
+{
+	ai_move, 5, soldier_duck_down,
+	ai_move, -1, soldier_duck_hold,
+	ai_move, 1,  NULL,
+	ai_move, 0,  soldier_duck_up,
+	ai_move, 5,  NULL
+};
+mmove_t soldier_move_duck = {FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run};
+
+void soldier_dodge (edict_t *self, edict_t *attacker, float eta)
+{
+	float	r;
+
+	r = random();
+	if (r > 0.25)
+		return;
+
+	if (!self->enemy)
+		self->enemy = attacker;
+
+	if (skill->value == 0)
+	{
+		self->monsterinfo.currentmove = &soldier_move_duck;
+		return;
+	}
+
+	self->monsterinfo.pausetime = level.time + eta + 0.3;
+	r = random();
+
+	if (skill->value == 1)
+	{
+		if (r > 0.33)
+			self->monsterinfo.currentmove = &soldier_move_duck;
+		else
+			self->monsterinfo.currentmove = &soldier_move_attack3;
+		return;
+	}
+
+	if (skill->value >= 2)
+	{
+		if (r > 0.66)
+			self->monsterinfo.currentmove = &soldier_move_duck;
+		else
+			self->monsterinfo.currentmove = &soldier_move_attack3;
+		return;
+	}
+
+	self->monsterinfo.currentmove = &soldier_move_attack3;
+}
+
+
+//
+// DEATH
+//
+
+void soldier_fire6 (edict_t *self)
+{
+	soldier_fire (self, 5);
+}
+
+void soldier_fire7 (edict_t *self)
+{
+	soldier_fire (self, 6);
+}
+
+void soldier_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, -8);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t soldier_frames_death1 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, -10, NULL,
+	ai_move, -10, NULL,
+	ai_move, -10, NULL,
+	ai_move, -5,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   soldier_fire6,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   soldier_fire7,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t soldier_move_death1 = {FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead};
+
+mframe_t soldier_frames_death2 [] =
+{
+	ai_move, -5,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t soldier_move_death2 = {FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead};
+
+mframe_t soldier_frames_death3 [] =
+{
+	ai_move, -5,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+};
+mmove_t soldier_move_death3 = {FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead};
+
+mframe_t soldier_frames_death4 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t soldier_move_death4 = {FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead};
+
+mframe_t soldier_frames_death5 [] =
+{
+	ai_move, -5,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t soldier_move_death5 = {FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead};
+
+mframe_t soldier_frames_death6 [] =
+{
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t soldier_move_death6 = {FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead};
+
+void soldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 3; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+	self->s.skinnum |= 1;
+
+	if (self->s.skinnum == 1)
+		gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0);
+	else if (self->s.skinnum == 3)
+		gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	else // (self->s.skinnum == 5)
+		gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0);
+
+	if (fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4)
+	{
+		// head shot
+		self->monsterinfo.currentmove = &soldier_move_death3;
+		return;
+	}
+
+	n = rand() % 5;
+	if (n == 0)
+		self->monsterinfo.currentmove = &soldier_move_death1;
+	else if (n == 1)
+		self->monsterinfo.currentmove = &soldier_move_death2;
+	else if (n == 2)
+		self->monsterinfo.currentmove = &soldier_move_death4;
+	else if (n == 3)
+		self->monsterinfo.currentmove = &soldier_move_death5;
+	else
+		self->monsterinfo.currentmove = &soldier_move_death6;
+}
+
+
+//
+// SPAWN
+//
+
+void SP_monster_soldier_x (edict_t *self)
+{
+
+	self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2");
+	self->monsterinfo.scale = MODEL_SCALE;
+	VectorSet (self->mins, -16, -16, -24);
+	VectorSet (self->maxs, 16, 16, 32);
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+
+	sound_idle =	gi.soundindex ("soldier/solidle1.wav");
+	sound_sight1 =	gi.soundindex ("soldier/solsght1.wav");
+	sound_sight2 =	gi.soundindex ("soldier/solsrch1.wav");
+	sound_cock =	gi.soundindex ("infantry/infatck3.wav");
+
+	self->mass = 100;
+
+	self->pain = soldier_pain;
+	self->die = soldier_die;
+
+	self->monsterinfo.stand = soldier_stand;
+	self->monsterinfo.walk = soldier_walk;
+	self->monsterinfo.run = soldier_run;
+	self->monsterinfo.dodge = soldier_dodge;
+	self->monsterinfo.attack = soldier_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = soldier_sight;
+
+	gi.linkentity (self);
+
+	self->monsterinfo.stand (self);
+
+	walkmonster_start (self);
+}
+
+
+/*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_soldier_light (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	SP_monster_soldier_x (self);
+
+	sound_pain_light = gi.soundindex ("soldier/solpain2.wav");
+	sound_death_light =	gi.soundindex ("soldier/soldeth2.wav");
+	gi.modelindex ("models/objects/laser/tris.md2");
+	gi.soundindex ("misc/lasfly.wav");
+	gi.soundindex ("soldier/solatck2.wav");
+
+	self->s.skinnum = 0;
+	self->health = 20;
+	self->gib_health = -30;
+}
+
+/*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_soldier (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	SP_monster_soldier_x (self);
+
+	sound_pain = gi.soundindex ("soldier/solpain1.wav");
+	sound_death = gi.soundindex ("soldier/soldeth1.wav");
+	gi.soundindex ("soldier/solatck1.wav");
+
+	self->s.skinnum = 2;
+	self->health = 30;
+	self->gib_health = -30;
+}
+
+/*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_soldier_ss (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	SP_monster_soldier_x (self);
+
+	sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
+	sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
+	gi.soundindex ("soldier/solatck3.wav");
+
+	self->s.skinnum = 4;
+	self->health = 40;
+	self->gib_health = -30;
+}
--- /dev/null
+++ b/game/m_soldier.h
@@ -1,0 +1,500 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/soldier
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_attak101        	0
+#define FRAME_attak102        	1
+#define FRAME_attak103        	2
+#define FRAME_attak104        	3
+#define FRAME_attak105        	4
+#define FRAME_attak106        	5
+#define FRAME_attak107        	6
+#define FRAME_attak108        	7
+#define FRAME_attak109        	8
+#define FRAME_attak110        	9
+#define FRAME_attak111        	10
+#define FRAME_attak112        	11
+#define FRAME_attak201        	12
+#define FRAME_attak202        	13
+#define FRAME_attak203        	14
+#define FRAME_attak204        	15
+#define FRAME_attak205        	16
+#define FRAME_attak206        	17
+#define FRAME_attak207        	18
+#define FRAME_attak208        	19
+#define FRAME_attak209        	20
+#define FRAME_attak210        	21
+#define FRAME_attak211        	22
+#define FRAME_attak212        	23
+#define FRAME_attak213        	24
+#define FRAME_attak214        	25
+#define FRAME_attak215        	26
+#define FRAME_attak216        	27
+#define FRAME_attak217        	28
+#define FRAME_attak218        	29
+#define FRAME_attak301        	30
+#define FRAME_attak302        	31
+#define FRAME_attak303        	32
+#define FRAME_attak304        	33
+#define FRAME_attak305        	34
+#define FRAME_attak306        	35
+#define FRAME_attak307        	36
+#define FRAME_attak308        	37
+#define FRAME_attak309        	38
+#define FRAME_attak401        	39
+#define FRAME_attak402        	40
+#define FRAME_attak403        	41
+#define FRAME_attak404        	42
+#define FRAME_attak405        	43
+#define FRAME_attak406        	44
+#define FRAME_duck01          	45
+#define FRAME_duck02          	46
+#define FRAME_duck03          	47
+#define FRAME_duck04          	48
+#define FRAME_duck05          	49
+#define FRAME_pain101         	50
+#define FRAME_pain102         	51
+#define FRAME_pain103         	52
+#define FRAME_pain104         	53
+#define FRAME_pain105         	54
+#define FRAME_pain201         	55
+#define FRAME_pain202         	56
+#define FRAME_pain203         	57
+#define FRAME_pain204         	58
+#define FRAME_pain205         	59
+#define FRAME_pain206         	60
+#define FRAME_pain207         	61
+#define FRAME_pain301         	62
+#define FRAME_pain302         	63
+#define FRAME_pain303         	64
+#define FRAME_pain304         	65
+#define FRAME_pain305         	66
+#define FRAME_pain306         	67
+#define FRAME_pain307         	68
+#define FRAME_pain308         	69
+#define FRAME_pain309         	70
+#define FRAME_pain310         	71
+#define FRAME_pain311         	72
+#define FRAME_pain312         	73
+#define FRAME_pain313         	74
+#define FRAME_pain314         	75
+#define FRAME_pain315         	76
+#define FRAME_pain316         	77
+#define FRAME_pain317         	78
+#define FRAME_pain318         	79
+#define FRAME_pain401         	80
+#define FRAME_pain402         	81
+#define FRAME_pain403         	82
+#define FRAME_pain404         	83
+#define FRAME_pain405         	84
+#define FRAME_pain406         	85
+#define FRAME_pain407         	86
+#define FRAME_pain408         	87
+#define FRAME_pain409         	88
+#define FRAME_pain410         	89
+#define FRAME_pain411         	90
+#define FRAME_pain412         	91
+#define FRAME_pain413         	92
+#define FRAME_pain414         	93
+#define FRAME_pain415         	94
+#define FRAME_pain416         	95
+#define FRAME_pain417         	96
+#define FRAME_run01           	97
+#define FRAME_run02           	98
+#define FRAME_run03           	99
+#define FRAME_run04           	100
+#define FRAME_run05           	101
+#define FRAME_run06           	102
+#define FRAME_run07           	103
+#define FRAME_run08           	104
+#define FRAME_run09           	105
+#define FRAME_run10           	106
+#define FRAME_run11           	107
+#define FRAME_run12           	108
+#define FRAME_runs01          	109
+#define FRAME_runs02          	110
+#define FRAME_runs03          	111
+#define FRAME_runs04          	112
+#define FRAME_runs05          	113
+#define FRAME_runs06          	114
+#define FRAME_runs07          	115
+#define FRAME_runs08          	116
+#define FRAME_runs09          	117
+#define FRAME_runs10          	118
+#define FRAME_runs11          	119
+#define FRAME_runs12          	120
+#define FRAME_runs13          	121
+#define FRAME_runs14          	122
+#define FRAME_runs15          	123
+#define FRAME_runs16          	124
+#define FRAME_runs17          	125
+#define FRAME_runs18          	126
+#define FRAME_runt01          	127
+#define FRAME_runt02          	128
+#define FRAME_runt03          	129
+#define FRAME_runt04          	130
+#define FRAME_runt05          	131
+#define FRAME_runt06          	132
+#define FRAME_runt07          	133
+#define FRAME_runt08          	134
+#define FRAME_runt09          	135
+#define FRAME_runt10          	136
+#define FRAME_runt11          	137
+#define FRAME_runt12          	138
+#define FRAME_runt13          	139
+#define FRAME_runt14          	140
+#define FRAME_runt15          	141
+#define FRAME_runt16          	142
+#define FRAME_runt17          	143
+#define FRAME_runt18          	144
+#define FRAME_runt19          	145
+#define FRAME_stand101        	146
+#define FRAME_stand102        	147
+#define FRAME_stand103        	148
+#define FRAME_stand104        	149
+#define FRAME_stand105        	150
+#define FRAME_stand106        	151
+#define FRAME_stand107        	152
+#define FRAME_stand108        	153
+#define FRAME_stand109        	154
+#define FRAME_stand110        	155
+#define FRAME_stand111        	156
+#define FRAME_stand112        	157
+#define FRAME_stand113        	158
+#define FRAME_stand114        	159
+#define FRAME_stand115        	160
+#define FRAME_stand116        	161
+#define FRAME_stand117        	162
+#define FRAME_stand118        	163
+#define FRAME_stand119        	164
+#define FRAME_stand120        	165
+#define FRAME_stand121        	166
+#define FRAME_stand122        	167
+#define FRAME_stand123        	168
+#define FRAME_stand124        	169
+#define FRAME_stand125        	170
+#define FRAME_stand126        	171
+#define FRAME_stand127        	172
+#define FRAME_stand128        	173
+#define FRAME_stand129        	174
+#define FRAME_stand130        	175
+#define FRAME_stand301        	176
+#define FRAME_stand302        	177
+#define FRAME_stand303        	178
+#define FRAME_stand304        	179
+#define FRAME_stand305        	180
+#define FRAME_stand306        	181
+#define FRAME_stand307        	182
+#define FRAME_stand308        	183
+#define FRAME_stand309        	184
+#define FRAME_stand310        	185
+#define FRAME_stand311        	186
+#define FRAME_stand312        	187
+#define FRAME_stand313        	188
+#define FRAME_stand314        	189
+#define FRAME_stand315        	190
+#define FRAME_stand316        	191
+#define FRAME_stand317        	192
+#define FRAME_stand318        	193
+#define FRAME_stand319        	194
+#define FRAME_stand320        	195
+#define FRAME_stand321        	196
+#define FRAME_stand322        	197
+#define FRAME_stand323        	198
+#define FRAME_stand324        	199
+#define FRAME_stand325        	200
+#define FRAME_stand326        	201
+#define FRAME_stand327        	202
+#define FRAME_stand328        	203
+#define FRAME_stand329        	204
+#define FRAME_stand330        	205
+#define FRAME_stand331        	206
+#define FRAME_stand332        	207
+#define FRAME_stand333        	208
+#define FRAME_stand334        	209
+#define FRAME_stand335        	210
+#define FRAME_stand336        	211
+#define FRAME_stand337        	212
+#define FRAME_stand338        	213
+#define FRAME_stand339        	214
+#define FRAME_walk101         	215
+#define FRAME_walk102         	216
+#define FRAME_walk103         	217
+#define FRAME_walk104         	218
+#define FRAME_walk105         	219
+#define FRAME_walk106         	220
+#define FRAME_walk107         	221
+#define FRAME_walk108         	222
+#define FRAME_walk109         	223
+#define FRAME_walk110         	224
+#define FRAME_walk111         	225
+#define FRAME_walk112         	226
+#define FRAME_walk113         	227
+#define FRAME_walk114         	228
+#define FRAME_walk115         	229
+#define FRAME_walk116         	230
+#define FRAME_walk117         	231
+#define FRAME_walk118         	232
+#define FRAME_walk119         	233
+#define FRAME_walk120         	234
+#define FRAME_walk121         	235
+#define FRAME_walk122         	236
+#define FRAME_walk123         	237
+#define FRAME_walk124         	238
+#define FRAME_walk125         	239
+#define FRAME_walk126         	240
+#define FRAME_walk127         	241
+#define FRAME_walk128         	242
+#define FRAME_walk129         	243
+#define FRAME_walk130         	244
+#define FRAME_walk131         	245
+#define FRAME_walk132         	246
+#define FRAME_walk133         	247
+#define FRAME_walk201         	248
+#define FRAME_walk202         	249
+#define FRAME_walk203         	250
+#define FRAME_walk204         	251
+#define FRAME_walk205         	252
+#define FRAME_walk206         	253
+#define FRAME_walk207         	254
+#define FRAME_walk208         	255
+#define FRAME_walk209         	256
+#define FRAME_walk210         	257
+#define FRAME_walk211         	258
+#define FRAME_walk212         	259
+#define FRAME_walk213         	260
+#define FRAME_walk214         	261
+#define FRAME_walk215         	262
+#define FRAME_walk216         	263
+#define FRAME_walk217         	264
+#define FRAME_walk218         	265
+#define FRAME_walk219         	266
+#define FRAME_walk220         	267
+#define FRAME_walk221         	268
+#define FRAME_walk222         	269
+#define FRAME_walk223         	270
+#define FRAME_walk224         	271
+#define FRAME_death101        	272
+#define FRAME_death102        	273
+#define FRAME_death103        	274
+#define FRAME_death104        	275
+#define FRAME_death105        	276
+#define FRAME_death106        	277
+#define FRAME_death107        	278
+#define FRAME_death108        	279
+#define FRAME_death109        	280
+#define FRAME_death110        	281
+#define FRAME_death111        	282
+#define FRAME_death112        	283
+#define FRAME_death113        	284
+#define FRAME_death114        	285
+#define FRAME_death115        	286
+#define FRAME_death116        	287
+#define FRAME_death117        	288
+#define FRAME_death118        	289
+#define FRAME_death119        	290
+#define FRAME_death120        	291
+#define FRAME_death121        	292
+#define FRAME_death122        	293
+#define FRAME_death123        	294
+#define FRAME_death124        	295
+#define FRAME_death125        	296
+#define FRAME_death126        	297
+#define FRAME_death127        	298
+#define FRAME_death128        	299
+#define FRAME_death129        	300
+#define FRAME_death130        	301
+#define FRAME_death131        	302
+#define FRAME_death132        	303
+#define FRAME_death133        	304
+#define FRAME_death134        	305
+#define FRAME_death135        	306
+#define FRAME_death136        	307
+#define FRAME_death201        	308
+#define FRAME_death202        	309
+#define FRAME_death203        	310
+#define FRAME_death204        	311
+#define FRAME_death205        	312
+#define FRAME_death206        	313
+#define FRAME_death207        	314
+#define FRAME_death208        	315
+#define FRAME_death209        	316
+#define FRAME_death210        	317
+#define FRAME_death211        	318
+#define FRAME_death212        	319
+#define FRAME_death213        	320
+#define FRAME_death214        	321
+#define FRAME_death215        	322
+#define FRAME_death216        	323
+#define FRAME_death217        	324
+#define FRAME_death218        	325
+#define FRAME_death219        	326
+#define FRAME_death220        	327
+#define FRAME_death221        	328
+#define FRAME_death222        	329
+#define FRAME_death223        	330
+#define FRAME_death224        	331
+#define FRAME_death225        	332
+#define FRAME_death226        	333
+#define FRAME_death227        	334
+#define FRAME_death228        	335
+#define FRAME_death229        	336
+#define FRAME_death230        	337
+#define FRAME_death231        	338
+#define FRAME_death232        	339
+#define FRAME_death233        	340
+#define FRAME_death234        	341
+#define FRAME_death235        	342
+#define FRAME_death301        	343
+#define FRAME_death302        	344
+#define FRAME_death303        	345
+#define FRAME_death304        	346
+#define FRAME_death305        	347
+#define FRAME_death306        	348
+#define FRAME_death307        	349
+#define FRAME_death308        	350
+#define FRAME_death309        	351
+#define FRAME_death310        	352
+#define FRAME_death311        	353
+#define FRAME_death312        	354
+#define FRAME_death313        	355
+#define FRAME_death314        	356
+#define FRAME_death315        	357
+#define FRAME_death316        	358
+#define FRAME_death317        	359
+#define FRAME_death318        	360
+#define FRAME_death319        	361
+#define FRAME_death320        	362
+#define FRAME_death321        	363
+#define FRAME_death322        	364
+#define FRAME_death323        	365
+#define FRAME_death324        	366
+#define FRAME_death325        	367
+#define FRAME_death326        	368
+#define FRAME_death327        	369
+#define FRAME_death328        	370
+#define FRAME_death329        	371
+#define FRAME_death330        	372
+#define FRAME_death331        	373
+#define FRAME_death332        	374
+#define FRAME_death333        	375
+#define FRAME_death334        	376
+#define FRAME_death335        	377
+#define FRAME_death336        	378
+#define FRAME_death337        	379
+#define FRAME_death338        	380
+#define FRAME_death339        	381
+#define FRAME_death340        	382
+#define FRAME_death341        	383
+#define FRAME_death342        	384
+#define FRAME_death343        	385
+#define FRAME_death344        	386
+#define FRAME_death345        	387
+#define FRAME_death401        	388
+#define FRAME_death402        	389
+#define FRAME_death403        	390
+#define FRAME_death404        	391
+#define FRAME_death405        	392
+#define FRAME_death406        	393
+#define FRAME_death407        	394
+#define FRAME_death408        	395
+#define FRAME_death409        	396
+#define FRAME_death410        	397
+#define FRAME_death411        	398
+#define FRAME_death412        	399
+#define FRAME_death413        	400
+#define FRAME_death414        	401
+#define FRAME_death415        	402
+#define FRAME_death416        	403
+#define FRAME_death417        	404
+#define FRAME_death418        	405
+#define FRAME_death419        	406
+#define FRAME_death420        	407
+#define FRAME_death421        	408
+#define FRAME_death422        	409
+#define FRAME_death423        	410
+#define FRAME_death424        	411
+#define FRAME_death425        	412
+#define FRAME_death426        	413
+#define FRAME_death427        	414
+#define FRAME_death428        	415
+#define FRAME_death429        	416
+#define FRAME_death430        	417
+#define FRAME_death431        	418
+#define FRAME_death432        	419
+#define FRAME_death433        	420
+#define FRAME_death434        	421
+#define FRAME_death435        	422
+#define FRAME_death436        	423
+#define FRAME_death437        	424
+#define FRAME_death438        	425
+#define FRAME_death439        	426
+#define FRAME_death440        	427
+#define FRAME_death441        	428
+#define FRAME_death442        	429
+#define FRAME_death443        	430
+#define FRAME_death444        	431
+#define FRAME_death445        	432
+#define FRAME_death446        	433
+#define FRAME_death447        	434
+#define FRAME_death448        	435
+#define FRAME_death449        	436
+#define FRAME_death450        	437
+#define FRAME_death451        	438
+#define FRAME_death452        	439
+#define FRAME_death453        	440
+#define FRAME_death501        	441
+#define FRAME_death502        	442
+#define FRAME_death503        	443
+#define FRAME_death504        	444
+#define FRAME_death505        	445
+#define FRAME_death506        	446
+#define FRAME_death507        	447
+#define FRAME_death508        	448
+#define FRAME_death509        	449
+#define FRAME_death510        	450
+#define FRAME_death511        	451
+#define FRAME_death512        	452
+#define FRAME_death513        	453
+#define FRAME_death514        	454
+#define FRAME_death515        	455
+#define FRAME_death516        	456
+#define FRAME_death517        	457
+#define FRAME_death518        	458
+#define FRAME_death519        	459
+#define FRAME_death520        	460
+#define FRAME_death521        	461
+#define FRAME_death522        	462
+#define FRAME_death523        	463
+#define FRAME_death524        	464
+#define FRAME_death601        	465
+#define FRAME_death602        	466
+#define FRAME_death603        	467
+#define FRAME_death604        	468
+#define FRAME_death605        	469
+#define FRAME_death606        	470
+#define FRAME_death607        	471
+#define FRAME_death608        	472
+#define FRAME_death609        	473
+#define FRAME_death610        	474
+
+#define MODEL_SCALE		1.200000
--- /dev/null
+++ b/game/m_supertank.c
@@ -1,0 +1,717 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+SUPERTANK
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_supertank.h"
+
+qboolean visible (edict_t *self, edict_t *other);
+
+static int	sound_pain1;
+static int	sound_pain2;
+static int	sound_pain3;
+static int	sound_death;
+static int	sound_search1;
+static int	sound_search2;
+
+static	int	tread_sound;
+
+void BossExplode (edict_t *self);
+
+void TreadSound (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, tread_sound, 1, ATTN_NORM, 0);
+}
+
+void supertank_search (edict_t *self)
+{
+	if (random() < 0.5)
+		gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
+	else
+		gi.sound (self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
+}
+
+
+void supertank_dead (edict_t *self);
+void supertankRocket (edict_t *self);
+void supertankMachineGun (edict_t *self);
+void supertank_reattack1(edict_t *self);
+
+
+//
+// stand
+//
+
+mframe_t supertank_frames_stand []=
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	supertank_move_stand = {FRAME_stand_1, FRAME_stand_60, supertank_frames_stand, NULL};
+	
+void supertank_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &supertank_move_stand;
+}
+
+
+mframe_t supertank_frames_run [] =
+{
+	ai_run, 12,	TreadSound,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL,
+	ai_run, 12,	NULL
+};
+mmove_t	supertank_move_run = {FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_run, NULL};
+
+//
+// walk
+//
+
+
+mframe_t supertank_frames_forward [] =
+{
+	ai_walk, 4,	TreadSound,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	NULL
+};
+mmove_t	supertank_move_forward = {FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_forward, NULL};
+
+void supertank_forward (edict_t *self)
+{
+		self->monsterinfo.currentmove = &supertank_move_forward;
+}
+
+void supertank_walk (edict_t *self)
+{
+		self->monsterinfo.currentmove = &supertank_move_forward;
+}
+
+void supertank_run (edict_t *self)
+{
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+		self->monsterinfo.currentmove = &supertank_move_stand;
+	else
+		self->monsterinfo.currentmove = &supertank_move_run;
+}
+
+mframe_t supertank_frames_turn_right [] =
+{
+	ai_move,	0,	TreadSound,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_turn_right = {FRAME_right_1, FRAME_right_18, supertank_frames_turn_right, supertank_run};
+
+mframe_t supertank_frames_turn_left [] =
+{
+	ai_move,	0,	TreadSound,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_turn_left = {FRAME_left_1, FRAME_left_18, supertank_frames_turn_left, supertank_run};
+
+
+mframe_t supertank_frames_pain3 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_pain3 = {FRAME_pain3_9, FRAME_pain3_12, supertank_frames_pain3, supertank_run};
+
+mframe_t supertank_frames_pain2 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_pain2 = {FRAME_pain2_5, FRAME_pain2_8, supertank_frames_pain2, supertank_run};
+
+mframe_t supertank_frames_pain1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_pain1 = {FRAME_pain1_1, FRAME_pain1_4, supertank_frames_pain1, supertank_run};
+
+mframe_t supertank_frames_death1 [] =
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	BossExplode
+};
+mmove_t supertank_move_death = {FRAME_death_1, FRAME_death_24, supertank_frames_death1, supertank_dead};
+
+mframe_t supertank_frames_backward[] =
+{
+	ai_walk, 0,	TreadSound,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL,
+	ai_walk, 0,	NULL
+};
+mmove_t	supertank_move_backward = {FRAME_backwd_1, FRAME_backwd_18, supertank_frames_backward, NULL};
+
+mframe_t supertank_frames_attack4[]=
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_attack4 = {FRAME_attak4_1, FRAME_attak4_6, supertank_frames_attack4, supertank_run};
+
+mframe_t supertank_frames_attack3[]=
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_attack3 = {FRAME_attak3_1, FRAME_attak3_27, supertank_frames_attack3, supertank_run};
+
+mframe_t supertank_frames_attack2[]=
+{
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	NULL,
+	ai_charge,	0,	supertankRocket,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	supertankRocket,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	supertankRocket,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_attack2 = {FRAME_attak2_1, FRAME_attak2_27, supertank_frames_attack2, supertank_run};
+
+mframe_t supertank_frames_attack1[]=
+{
+	ai_charge,	0,	supertankMachineGun,
+	ai_charge,	0,	supertankMachineGun,
+	ai_charge,	0,	supertankMachineGun,
+	ai_charge,	0,	supertankMachineGun,
+	ai_charge,	0,	supertankMachineGun,
+	ai_charge,	0,	supertankMachineGun,
+
+};
+mmove_t supertank_move_attack1 = {FRAME_attak1_1, FRAME_attak1_6, supertank_frames_attack1, supertank_reattack1};
+
+mframe_t supertank_frames_end_attack1[]=
+{
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL,
+	ai_move,	0,	NULL
+};
+mmove_t supertank_move_end_attack1 = {FRAME_attak1_7, FRAME_attak1_20, supertank_frames_end_attack1, supertank_run};
+
+
+void supertank_reattack1(edict_t *self)
+{
+	if (visible(self, self->enemy))
+		if (random() < 0.9)
+			self->monsterinfo.currentmove = &supertank_move_attack1;
+		else
+			self->monsterinfo.currentmove = &supertank_move_end_attack1;	
+	else
+		self->monsterinfo.currentmove = &supertank_move_end_attack1;
+}
+
+void supertank_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+
+	if (self->health < (self->max_health / 2))
+			self->s.skinnum = 1;
+
+	if (level.time < self->pain_debounce_time)
+			return;
+
+	// Lessen the chance of him going into his pain frames
+	if (damage <=25)
+		if (random()<0.2)
+			return;
+
+	// Don't go into pain if he's firing his rockets
+	if (skill->value >= 2)
+		if ( (self->s.frame >= FRAME_attak2_1) && (self->s.frame <= FRAME_attak2_14) )
+			return;
+
+	self->pain_debounce_time = level.time + 3;
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (damage <= 10)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM,0);
+		self->monsterinfo.currentmove = &supertank_move_pain1;
+	}
+	else if (damage <= 25)
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM,0);
+		self->monsterinfo.currentmove = &supertank_move_pain2;
+	}
+	else
+	{
+		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM,0);
+		self->monsterinfo.currentmove = &supertank_move_pain3;
+	}
+};
+
+
+void supertankRocket (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+	int		flash_number;
+
+	if (self->s.frame == FRAME_attak2_8)
+		flash_number = MZ2_SUPERTANK_ROCKET_1;
+	else if (self->s.frame == FRAME_attak2_11)
+		flash_number = MZ2_SUPERTANK_ROCKET_2;
+	else // (self->s.frame == FRAME_attak2_14)
+		flash_number = MZ2_SUPERTANK_ROCKET_3;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+
+	monster_fire_rocket (self, start, dir, 50, 500, flash_number);
+}	
+
+void supertankMachineGun (edict_t *self)
+{
+	vec3_t	dir;
+	vec3_t	vec;
+	vec3_t	start;
+	vec3_t	forward, right;
+	int		flash_number;
+
+	flash_number = MZ2_SUPERTANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak1_1);
+
+	//FIXME!!!
+	dir[0] = 0;
+	dir[1] = self->s.angles[1];
+	dir[2] = 0;
+
+	AngleVectors (dir, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	if (self->enemy)
+	{
+		VectorCopy (self->enemy->s.origin, vec);
+		VectorMA (vec, 0, self->enemy->velocity, vec);
+		vec[2] += self->enemy->viewheight;
+		VectorSubtract (vec, start, forward);
+		VectorNormalize (forward);
+  }
+
+	monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+}	
+
+
+void supertank_attack(edict_t *self)
+{
+	vec3_t	vec;
+	float	range;
+	//float	r;
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	range = VectorLength (vec);
+
+	//r = random();
+
+	// Attack 1 == Chaingun
+	// Attack 2 == Rocket Launcher
+
+	if (range <= 160)
+	{
+		self->monsterinfo.currentmove = &supertank_move_attack1;
+	}
+	else
+	{	// fire rockets more often at distance
+		if (random() < 0.3)
+			self->monsterinfo.currentmove = &supertank_move_attack1;
+		else
+			self->monsterinfo.currentmove = &supertank_move_attack2;
+	}
+}
+
+
+//
+// death
+//
+
+void supertank_dead (edict_t *self)
+{
+	VectorSet (self->mins, -60, -60, 0);
+	VectorSet (self->maxs, 60, 60, 72);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+
+void BossExplode (edict_t *self)
+{
+	vec3_t	org;
+	int		n;
+
+	self->think = BossExplode;
+	VectorCopy (self->s.origin, org);
+	org[2] += 24 + (rand()&15);
+	switch (self->count++)
+	{
+	case 0:
+		org[0] -= 24;
+		org[1] -= 24;
+		break;
+	case 1:
+		org[0] += 24;
+		org[1] += 24;
+		break;
+	case 2:
+		org[0] += 24;
+		org[1] -= 24;
+		break;
+	case 3:
+		org[0] -= 24;
+		org[1] += 24;
+		break;
+	case 4:
+		org[0] -= 48;
+		org[1] -= 48;
+		break;
+	case 5:
+		org[0] += 48;
+		org[1] += 48;
+		break;
+	case 6:
+		org[0] -= 48;
+		org[1] += 48;
+		break;
+	case 7:
+		org[0] += 48;
+		org[1] -= 48;
+		break;
+	case 8:
+		self->s.sound = 0;
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", 500, GIB_ORGANIC);
+		for (n= 0; n < 8; n++)
+			ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", 500, GIB_METALLIC);
+		ThrowGib (self, "models/objects/gibs/chest/tris.md2", 500, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/gear/tris.md2", 500, GIB_METALLIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	gi.WriteByte (svc_temp_entity);
+	gi.WriteByte (TE_EXPLOSION1);
+	gi.WritePosition (org);
+	gi.multicast (self->s.origin, MULTICAST_PVS);
+
+	self->nextthink = level.time + 0.1;
+}
+
+
+void supertank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_NO;
+	self->count = 0;
+	self->monsterinfo.currentmove = &supertank_move_death;
+}
+
+//
+// monster_supertank
+//
+
+/*QUAKED monster_supertank (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_supertank (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	sound_pain1 = gi.soundindex ("bosstank/btkpain1.wav");
+	sound_pain2 = gi.soundindex ("bosstank/btkpain2.wav");
+	sound_pain3 = gi.soundindex ("bosstank/btkpain3.wav");
+	sound_death = gi.soundindex ("bosstank/btkdeth1.wav");
+	sound_search1 = gi.soundindex ("bosstank/btkunqv1.wav");
+	sound_search2 = gi.soundindex ("bosstank/btkunqv2.wav");
+
+//	self->s.sound = gi.soundindex ("bosstank/btkengn1.wav");
+	tread_sound = gi.soundindex ("bosstank/btkengn1.wav");
+
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+	self->s.modelindex = gi.modelindex ("models/monsters/boss1/tris.md2");
+	VectorSet (self->mins, -64, -64, 0);
+	VectorSet (self->maxs, 64, 64, 112);
+
+	self->health = 1500;
+	self->gib_health = -500;
+	self->mass = 800;
+
+	self->pain = supertank_pain;
+	self->die = supertank_die;
+	self->monsterinfo.stand = supertank_stand;
+	self->monsterinfo.walk = supertank_walk;
+	self->monsterinfo.run = supertank_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = supertank_attack;
+	self->monsterinfo.search = supertank_search;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = NULL;
+
+	gi.linkentity (self);
+	
+	self->monsterinfo.currentmove = &supertank_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start(self);
+}
--- /dev/null
+++ b/game/m_supertank.h
@@ -1,0 +1,279 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/boss1/backup
+
+// This file generated by ModelGen - Do NOT Modify
+
+#define FRAME_attak1_1        	0
+#define FRAME_attak1_2        	1
+#define FRAME_attak1_3        	2
+#define FRAME_attak1_4        	3
+#define FRAME_attak1_5        	4
+#define FRAME_attak1_6        	5
+#define FRAME_attak1_7        	6
+#define FRAME_attak1_8        	7
+#define FRAME_attak1_9        	8
+#define FRAME_attak1_10       	9
+#define FRAME_attak1_11       	10
+#define FRAME_attak1_12       	11
+#define FRAME_attak1_13       	12
+#define FRAME_attak1_14       	13
+#define FRAME_attak1_15       	14
+#define FRAME_attak1_16       	15
+#define FRAME_attak1_17       	16
+#define FRAME_attak1_18       	17
+#define FRAME_attak1_19       	18
+#define FRAME_attak1_20       	19
+#define FRAME_attak2_1        	20
+#define FRAME_attak2_2        	21
+#define FRAME_attak2_3        	22
+#define FRAME_attak2_4        	23
+#define FRAME_attak2_5        	24
+#define FRAME_attak2_6        	25
+#define FRAME_attak2_7        	26
+#define FRAME_attak2_8        	27
+#define FRAME_attak2_9        	28
+#define FRAME_attak2_10       	29
+#define FRAME_attak2_11       	30
+#define FRAME_attak2_12       	31
+#define FRAME_attak2_13       	32
+#define FRAME_attak2_14       	33
+#define FRAME_attak2_15       	34
+#define FRAME_attak2_16       	35
+#define FRAME_attak2_17       	36
+#define FRAME_attak2_18       	37
+#define FRAME_attak2_19       	38
+#define FRAME_attak2_20       	39
+#define FRAME_attak2_21       	40
+#define FRAME_attak2_22       	41
+#define FRAME_attak2_23       	42
+#define FRAME_attak2_24       	43
+#define FRAME_attak2_25       	44
+#define FRAME_attak2_26       	45
+#define FRAME_attak2_27       	46
+#define FRAME_attak3_1        	47
+#define FRAME_attak3_2        	48
+#define FRAME_attak3_3        	49
+#define FRAME_attak3_4        	50
+#define FRAME_attak3_5        	51
+#define FRAME_attak3_6        	52
+#define FRAME_attak3_7        	53
+#define FRAME_attak3_8        	54
+#define FRAME_attak3_9        	55
+#define FRAME_attak3_10       	56
+#define FRAME_attak3_11       	57
+#define FRAME_attak3_12       	58
+#define FRAME_attak3_13       	59
+#define FRAME_attak3_14       	60
+#define FRAME_attak3_15       	61
+#define FRAME_attak3_16       	62
+#define FRAME_attak3_17       	63
+#define FRAME_attak3_18       	64
+#define FRAME_attak3_19       	65
+#define FRAME_attak3_20       	66
+#define FRAME_attak3_21       	67
+#define FRAME_attak3_22       	68
+#define FRAME_attak3_23       	69
+#define FRAME_attak3_24       	70
+#define FRAME_attak3_25       	71
+#define FRAME_attak3_26       	72
+#define FRAME_attak3_27       	73
+#define FRAME_attak4_1        	74
+#define FRAME_attak4_2        	75
+#define FRAME_attak4_3        	76
+#define FRAME_attak4_4        	77
+#define FRAME_attak4_5        	78
+#define FRAME_attak4_6        	79
+#define FRAME_backwd_1        	80
+#define FRAME_backwd_2        	81
+#define FRAME_backwd_3        	82
+#define FRAME_backwd_4        	83
+#define FRAME_backwd_5        	84
+#define FRAME_backwd_6        	85
+#define FRAME_backwd_7        	86
+#define FRAME_backwd_8        	87
+#define FRAME_backwd_9        	88
+#define FRAME_backwd_10       	89
+#define FRAME_backwd_11       	90
+#define FRAME_backwd_12       	91
+#define FRAME_backwd_13       	92
+#define FRAME_backwd_14       	93
+#define FRAME_backwd_15       	94
+#define FRAME_backwd_16       	95
+#define FRAME_backwd_17       	96
+#define FRAME_backwd_18       	97
+#define FRAME_death_1         	98
+#define FRAME_death_2         	99
+#define FRAME_death_3         	100
+#define FRAME_death_4         	101
+#define FRAME_death_5         	102
+#define FRAME_death_6         	103
+#define FRAME_death_7         	104
+#define FRAME_death_8         	105
+#define FRAME_death_9         	106
+#define FRAME_death_10        	107
+#define FRAME_death_11        	108
+#define FRAME_death_12        	109
+#define FRAME_death_13        	110
+#define FRAME_death_14        	111
+#define FRAME_death_15        	112
+#define FRAME_death_16        	113
+#define FRAME_death_17        	114
+#define FRAME_death_18        	115
+#define FRAME_death_19        	116
+#define FRAME_death_20        	117
+#define FRAME_death_21        	118
+#define FRAME_death_22        	119
+#define FRAME_death_23        	120
+#define FRAME_death_24        	121
+#define FRAME_death_31        	122
+#define FRAME_death_32        	123
+#define FRAME_death_33        	124
+#define FRAME_death_45        	125
+#define FRAME_death_46        	126
+#define FRAME_death_47        	127
+#define FRAME_forwrd_1        	128
+#define FRAME_forwrd_2        	129
+#define FRAME_forwrd_3        	130
+#define FRAME_forwrd_4        	131
+#define FRAME_forwrd_5        	132
+#define FRAME_forwrd_6        	133
+#define FRAME_forwrd_7        	134
+#define FRAME_forwrd_8        	135
+#define FRAME_forwrd_9        	136
+#define FRAME_forwrd_10       	137
+#define FRAME_forwrd_11       	138
+#define FRAME_forwrd_12       	139
+#define FRAME_forwrd_13       	140
+#define FRAME_forwrd_14       	141
+#define FRAME_forwrd_15       	142
+#define FRAME_forwrd_16       	143
+#define FRAME_forwrd_17       	144
+#define FRAME_forwrd_18       	145
+#define FRAME_left_1          	146
+#define FRAME_left_2          	147
+#define FRAME_left_3          	148
+#define FRAME_left_4          	149
+#define FRAME_left_5          	150
+#define FRAME_left_6          	151
+#define FRAME_left_7          	152
+#define FRAME_left_8          	153
+#define FRAME_left_9          	154
+#define FRAME_left_10         	155
+#define FRAME_left_11         	156
+#define FRAME_left_12         	157
+#define FRAME_left_13         	158
+#define FRAME_left_14         	159
+#define FRAME_left_15         	160
+#define FRAME_left_16         	161
+#define FRAME_left_17         	162
+#define FRAME_left_18         	163
+#define FRAME_pain1_1         	164
+#define FRAME_pain1_2         	165
+#define FRAME_pain1_3         	166
+#define FRAME_pain1_4         	167
+#define FRAME_pain2_5         	168
+#define FRAME_pain2_6         	169
+#define FRAME_pain2_7         	170
+#define FRAME_pain2_8         	171
+#define FRAME_pain3_9         	172
+#define FRAME_pain3_10        	173
+#define FRAME_pain3_11        	174
+#define FRAME_pain3_12        	175
+#define FRAME_right_1         	176
+#define FRAME_right_2         	177
+#define FRAME_right_3         	178
+#define FRAME_right_4         	179
+#define FRAME_right_5         	180
+#define FRAME_right_6         	181
+#define FRAME_right_7         	182
+#define FRAME_right_8         	183
+#define FRAME_right_9         	184
+#define FRAME_right_10        	185
+#define FRAME_right_11        	186
+#define FRAME_right_12        	187
+#define FRAME_right_13        	188
+#define FRAME_right_14        	189
+#define FRAME_right_15        	190
+#define FRAME_right_16        	191
+#define FRAME_right_17        	192
+#define FRAME_right_18        	193
+#define FRAME_stand_1         	194
+#define FRAME_stand_2         	195
+#define FRAME_stand_3         	196
+#define FRAME_stand_4         	197
+#define FRAME_stand_5         	198
+#define FRAME_stand_6         	199
+#define FRAME_stand_7         	200
+#define FRAME_stand_8         	201
+#define FRAME_stand_9         	202
+#define FRAME_stand_10        	203
+#define FRAME_stand_11        	204
+#define FRAME_stand_12        	205
+#define FRAME_stand_13        	206
+#define FRAME_stand_14        	207
+#define FRAME_stand_15        	208
+#define FRAME_stand_16        	209
+#define FRAME_stand_17        	210
+#define FRAME_stand_18        	211
+#define FRAME_stand_19        	212
+#define FRAME_stand_20        	213
+#define FRAME_stand_21        	214
+#define FRAME_stand_22        	215
+#define FRAME_stand_23        	216
+#define FRAME_stand_24        	217
+#define FRAME_stand_25        	218
+#define FRAME_stand_26        	219
+#define FRAME_stand_27        	220
+#define FRAME_stand_28        	221
+#define FRAME_stand_29        	222
+#define FRAME_stand_30        	223
+#define FRAME_stand_31        	224
+#define FRAME_stand_32        	225
+#define FRAME_stand_33        	226
+#define FRAME_stand_34        	227
+#define FRAME_stand_35        	228
+#define FRAME_stand_36        	229
+#define FRAME_stand_37        	230
+#define FRAME_stand_38        	231
+#define FRAME_stand_39        	232
+#define FRAME_stand_40        	233
+#define FRAME_stand_41        	234
+#define FRAME_stand_42        	235
+#define FRAME_stand_43        	236
+#define FRAME_stand_44        	237
+#define FRAME_stand_45        	238
+#define FRAME_stand_46        	239
+#define FRAME_stand_47        	240
+#define FRAME_stand_48        	241
+#define FRAME_stand_49        	242
+#define FRAME_stand_50        	243
+#define FRAME_stand_51        	244
+#define FRAME_stand_52        	245
+#define FRAME_stand_53        	246
+#define FRAME_stand_54        	247
+#define FRAME_stand_55        	248
+#define FRAME_stand_56        	249
+#define FRAME_stand_57        	250
+#define FRAME_stand_58        	251
+#define FRAME_stand_59        	252
+#define FRAME_stand_60        	253
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/m_tank.c
@@ -1,0 +1,856 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+==============================================================================
+
+TANK
+
+==============================================================================
+*/
+
+#include "g_local.h"
+#include "m_tank.h"
+
+
+void tank_refire_rocket (edict_t *self);
+void tank_doattack_rocket (edict_t *self);
+void tank_reattack_blaster (edict_t *self);
+
+static int	sound_thud;
+static int	sound_pain;
+static int	sound_idle;
+static int	sound_die;
+static int	sound_step;
+static int	sound_sight;
+static int	sound_windup;
+static int	sound_strike;
+
+//
+// misc
+//
+
+void tank_sight (edict_t *self, edict_t *other)
+{
+	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+}
+
+
+void tank_footstep (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
+}
+
+void tank_thud (edict_t *self)
+{
+	gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
+}
+
+void tank_windup (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
+}
+
+void tank_idle (edict_t *self)
+{
+	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+}
+
+
+//
+// stand
+//
+
+mframe_t tank_frames_stand []=
+{
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL,
+	ai_stand, 0, NULL
+};
+mmove_t	tank_move_stand = {FRAME_stand01, FRAME_stand30, tank_frames_stand, NULL};
+	
+void tank_stand (edict_t *self)
+{
+	self->monsterinfo.currentmove = &tank_move_stand;
+}
+
+
+//
+// walk
+//
+
+void tank_walk (edict_t *self);
+
+mframe_t tank_frames_start_walk [] =
+{
+	ai_walk,  0, NULL,
+	ai_walk,  6, NULL,
+	ai_walk,  6, NULL,
+	ai_walk, 11, tank_footstep
+};
+mmove_t	tank_move_start_walk = {FRAME_walk01, FRAME_walk04, tank_frames_start_walk, tank_walk};
+
+mframe_t tank_frames_walk [] =
+{
+	ai_walk, 4,	NULL,
+	ai_walk, 5,	NULL,
+	ai_walk, 3,	NULL,
+	ai_walk, 2,	NULL,
+	ai_walk, 5,	NULL,
+	ai_walk, 5,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 4,	tank_footstep,
+	ai_walk, 3,	NULL,
+	ai_walk, 5,	NULL,
+	ai_walk, 4,	NULL,
+	ai_walk, 5,	NULL,
+	ai_walk, 7,	NULL,
+	ai_walk, 7,	NULL,
+	ai_walk, 6,	NULL,
+	ai_walk, 6,	tank_footstep
+};
+mmove_t	tank_move_walk = {FRAME_walk05, FRAME_walk20, tank_frames_walk, NULL};
+
+mframe_t tank_frames_stop_walk [] =
+{
+	ai_walk,  3, NULL,
+	ai_walk,  3, NULL,
+	ai_walk,  2, NULL,
+	ai_walk,  2, NULL,
+	ai_walk,  4, tank_footstep
+};
+mmove_t	tank_move_stop_walk = {FRAME_walk21, FRAME_walk25, tank_frames_stop_walk, tank_stand};
+
+void tank_walk (edict_t *self)
+{
+		self->monsterinfo.currentmove = &tank_move_walk;
+}
+
+
+//
+// run
+//
+
+void tank_run (edict_t *self);
+
+mframe_t tank_frames_start_run [] =
+{
+	ai_run,  0, NULL,
+	ai_run,  6, NULL,
+	ai_run,  6, NULL,
+	ai_run, 11, tank_footstep
+};
+mmove_t	tank_move_start_run = {FRAME_walk01, FRAME_walk04, tank_frames_start_run, tank_run};
+
+mframe_t tank_frames_run [] =
+{
+	ai_run, 4,	NULL,
+	ai_run, 5,	NULL,
+	ai_run, 3,	NULL,
+	ai_run, 2,	NULL,
+	ai_run, 5,	NULL,
+	ai_run, 5,	NULL,
+	ai_run, 4,	NULL,
+	ai_run, 4,	tank_footstep,
+	ai_run, 3,	NULL,
+	ai_run, 5,	NULL,
+	ai_run, 4,	NULL,
+	ai_run, 5,	NULL,
+	ai_run, 7,	NULL,
+	ai_run, 7,	NULL,
+	ai_run, 6,	NULL,
+	ai_run, 6,	tank_footstep
+};
+mmove_t	tank_move_run = {FRAME_walk05, FRAME_walk20, tank_frames_run, NULL};
+
+mframe_t tank_frames_stop_run [] =
+{
+	ai_run,  3, NULL,
+	ai_run,  3, NULL,
+	ai_run,  2, NULL,
+	ai_run,  2, NULL,
+	ai_run,  4, tank_footstep
+};
+mmove_t	tank_move_stop_run = {FRAME_walk21, FRAME_walk25, tank_frames_stop_run, tank_walk};
+
+void tank_run (edict_t *self)
+{
+	if (self->enemy && self->enemy->client)
+		self->monsterinfo.aiflags |= AI_BRUTAL;
+	else
+		self->monsterinfo.aiflags &= ~AI_BRUTAL;
+
+	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+	{
+		self->monsterinfo.currentmove = &tank_move_stand;
+		return;
+	}
+
+	if (self->monsterinfo.currentmove == &tank_move_walk ||
+		self->monsterinfo.currentmove == &tank_move_start_run)
+	{
+		self->monsterinfo.currentmove = &tank_move_run;
+	}
+	else
+	{
+		self->monsterinfo.currentmove = &tank_move_start_run;
+	}
+}
+
+//
+// pain
+//
+
+mframe_t tank_frames_pain1 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t tank_move_pain1 = {FRAME_pain101, FRAME_pain104, tank_frames_pain1, tank_run};
+
+mframe_t tank_frames_pain2 [] =
+{
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL,
+	ai_move, 0, NULL
+};
+mmove_t tank_move_pain2 = {FRAME_pain201, FRAME_pain205, tank_frames_pain2, tank_run};
+
+mframe_t tank_frames_pain3 [] =
+{
+	ai_move, -7, NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 2,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 3,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 2,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  NULL,
+	ai_move, 0,  tank_footstep
+};
+mmove_t	tank_move_pain3 = {FRAME_pain301, FRAME_pain316, tank_frames_pain3, tank_run};
+
+
+void tank_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	if (self->health < (self->max_health / 2))
+			self->s.skinnum |= 1;
+
+	if (damage <= 10)
+		return;
+
+	if (level.time < self->pain_debounce_time)
+			return;
+
+	if (damage <= 30)
+		if (random() > 0.2)
+			return;
+	
+	// If hard or nightmare, don't go into pain while attacking
+	if ( skill->value >= 2)
+	{
+		if ( (self->s.frame >= FRAME_attak301) && (self->s.frame <= FRAME_attak330) )
+			return;
+		if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak116) )
+			return;
+	}
+
+	self->pain_debounce_time = level.time + 3;
+	gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+
+	if (skill->value == 3)
+		return;		// no pain anims in nightmare
+
+	if (damage <= 30)
+		self->monsterinfo.currentmove = &tank_move_pain1;
+	else if (damage <= 60)
+		self->monsterinfo.currentmove = &tank_move_pain2;
+	else
+		self->monsterinfo.currentmove = &tank_move_pain3;
+};
+
+
+//
+// attacks
+//
+
+void TankBlaster (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	end;
+	vec3_t	dir;
+	int		flash_number;
+
+	if (self->s.frame == FRAME_attak110)
+		flash_number = MZ2_TANK_BLASTER_1;
+	else if (self->s.frame == FRAME_attak113)
+		flash_number = MZ2_TANK_BLASTER_2;
+	else // (self->s.frame == FRAME_attak116)
+		flash_number = MZ2_TANK_BLASTER_3;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, end);
+	end[2] += self->enemy->viewheight;
+	VectorSubtract (end, start, dir);
+
+	monster_fire_blaster (self, start, dir, 30, 800, flash_number, EF_BLASTER);
+}	
+
+void TankStrike (edict_t *self)
+{
+	gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
+}	
+
+void TankRocket (edict_t *self)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	dir;
+	vec3_t	vec;
+	int		flash_number;
+
+	if (self->s.frame == FRAME_attak324)
+		flash_number = MZ2_TANK_ROCKET_1;
+	else if (self->s.frame == FRAME_attak327)
+		flash_number = MZ2_TANK_ROCKET_2;
+	else // (self->s.frame == FRAME_attak330)
+		flash_number = MZ2_TANK_ROCKET_3;
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	VectorCopy (self->enemy->s.origin, vec);
+	vec[2] += self->enemy->viewheight;
+	VectorSubtract (vec, start, dir);
+	VectorNormalize (dir);
+
+	monster_fire_rocket (self, start, dir, 50, 550, flash_number);
+}	
+
+void TankMachineGun (edict_t *self)
+{
+	vec3_t	dir;
+	vec3_t	vec;
+	vec3_t	start;
+	vec3_t	forward, right;
+	int		flash_number;
+
+	flash_number = MZ2_TANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak406);
+
+	AngleVectors (self->s.angles, forward, right, NULL);
+	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+	if (self->enemy)
+	{
+		VectorCopy (self->enemy->s.origin, vec);
+		vec[2] += self->enemy->viewheight;
+		VectorSubtract (vec, start, vec);
+		vectoangles (vec, vec);
+		dir[0] = vec[0];
+	}
+	else
+	{
+		dir[0] = 0;
+	}
+	if (self->s.frame <= FRAME_attak415)
+		dir[1] = self->s.angles[1] - 8 * (self->s.frame - FRAME_attak411);
+	else
+		dir[1] = self->s.angles[1] + 8 * (self->s.frame - FRAME_attak419);
+	dir[2] = 0;
+
+	AngleVectors (dir, forward, NULL, NULL);
+
+	monster_fire_bullet (self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+}	
+
+
+mframe_t tank_frames_attack_blast [] =
+{
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, -1,	NULL,
+	ai_charge, -2,	NULL,
+	ai_charge, -1,	NULL,
+	ai_charge, -1,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	TankBlaster,		// 10
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	TankBlaster,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	TankBlaster			// 16
+};
+mmove_t tank_move_attack_blast = {FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster};
+
+mframe_t tank_frames_reattack_blast [] =
+{
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	TankBlaster,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	NULL,
+	ai_charge, 0,	TankBlaster			// 16
+};
+mmove_t tank_move_reattack_blast = {FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster};
+
+mframe_t tank_frames_attack_post_blast [] =	
+{
+	ai_move, 0,		NULL,				// 17
+	ai_move, 0,		NULL,
+	ai_move, 2,		NULL,
+	ai_move, 3,		NULL,
+	ai_move, 2,		NULL,
+	ai_move, -2,	tank_footstep		// 22
+};
+mmove_t tank_move_attack_post_blast = {FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run};
+
+void tank_reattack_blaster (edict_t *self)
+{
+	if (skill->value >= 2)
+		if (visible (self, self->enemy))
+			if (self->enemy->health > 0)
+				if (random() <= 0.6)
+				{
+					self->monsterinfo.currentmove = &tank_move_reattack_blast;
+					return;
+				}
+	self->monsterinfo.currentmove = &tank_move_attack_post_blast;
+}
+
+
+void tank_poststrike (edict_t *self)
+{
+	self->enemy = NULL;
+	tank_run (self);
+}
+
+mframe_t tank_frames_attack_strike [] =
+{
+	ai_move, 3,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 6,   NULL,
+	ai_move, 7,   NULL,
+	ai_move, 9,   tank_footstep,
+	ai_move, 2,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 2,   tank_footstep,
+	ai_move, 2,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -2,  NULL,
+	ai_move, -2,  NULL,
+	ai_move, 0,   tank_windup,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   TankStrike,
+	ai_move, 0,   NULL,
+	ai_move, -1,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, -1,  NULL,
+	ai_move, -3,  NULL,
+	ai_move, -10, NULL,
+	ai_move, -10, NULL,
+	ai_move, -2,  NULL,
+	ai_move, -3,  NULL,
+	ai_move, -2,  tank_footstep
+};
+mmove_t tank_move_attack_strike = {FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike};
+
+mframe_t tank_frames_attack_pre_rocket [] =
+{
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,			// 10
+
+	ai_charge, 0,  NULL,
+	ai_charge, 1,  NULL,
+	ai_charge, 2,  NULL,
+	ai_charge, 7,  NULL,
+	ai_charge, 7,  NULL,
+	ai_charge, 7,  tank_footstep,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,			// 20
+
+	ai_charge, -3, NULL
+};
+mmove_t tank_move_attack_pre_rocket = {FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket};
+
+mframe_t tank_frames_attack_fire_rocket [] =
+{
+	ai_charge, -3, NULL,			// Loop Start	22 
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  TankRocket,		// 24
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  TankRocket,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, -1, TankRocket		// 30	Loop End
+};
+mmove_t tank_move_attack_fire_rocket = {FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket};
+
+mframe_t tank_frames_attack_post_rocket [] =
+{	
+	ai_charge, 0,  NULL,			// 31
+	ai_charge, -1, NULL,
+	ai_charge, -1, NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 2,  NULL,
+	ai_charge, 3,  NULL,
+	ai_charge, 4,  NULL,
+	ai_charge, 2,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,			// 40
+
+	ai_charge, 0,  NULL,
+	ai_charge, -9, NULL,
+	ai_charge, -8, NULL,
+	ai_charge, -7, NULL,
+	ai_charge, -1, NULL,
+	ai_charge, -1, tank_footstep,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,			// 50
+
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL,
+	ai_charge, 0,  NULL
+};
+mmove_t tank_move_attack_post_rocket = {FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run};
+
+mframe_t tank_frames_attack_chain [] =
+{
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	NULL,      0, TankMachineGun,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL,
+	ai_charge, 0, NULL
+};
+mmove_t tank_move_attack_chain = {FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run};
+
+void tank_refire_rocket (edict_t *self)
+{
+	// Only on hard or nightmare
+	if ( skill->value >= 2 )
+		if (self->enemy->health > 0)
+			if (visible(self, self->enemy) )
+				if (random() <= 0.4)
+				{
+					self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
+					return;
+				}
+	self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
+}
+
+void tank_doattack_rocket (edict_t *self)
+{
+	self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
+}
+
+void tank_attack(edict_t *self)
+{
+	vec3_t	vec;
+	float	range;
+	float	r;
+
+	if (self->enemy->health < 0)
+	{
+		self->monsterinfo.currentmove = &tank_move_attack_strike;
+		self->monsterinfo.aiflags &= ~AI_BRUTAL;
+		return;
+	}
+
+	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
+	range = VectorLength (vec);
+
+	r = random();
+
+	if (range <= 125)
+	{
+		if (r < 0.4)
+			self->monsterinfo.currentmove = &tank_move_attack_chain;
+		else 
+			self->monsterinfo.currentmove = &tank_move_attack_blast;
+	}
+	else if (range <= 250)
+	{
+		if (r < 0.5)
+			self->monsterinfo.currentmove = &tank_move_attack_chain;
+		else
+			self->monsterinfo.currentmove = &tank_move_attack_blast;
+	}
+	else
+	{
+		if (r < 0.33)
+			self->monsterinfo.currentmove = &tank_move_attack_chain;
+		else if (r < 0.66)
+		{
+			self->monsterinfo.currentmove = &tank_move_attack_pre_rocket;
+			self->pain_debounce_time = level.time + 5.0;	// no pain for a while
+		}
+		else
+			self->monsterinfo.currentmove = &tank_move_attack_blast;
+	}
+}
+
+
+//
+// death
+//
+
+void tank_dead (edict_t *self)
+{
+	VectorSet (self->mins, -16, -16, -16);
+	VectorSet (self->maxs, 16, 16, -0);
+	self->movetype = MOVETYPE_TOSS;
+	self->svflags |= SVF_DEADMONSTER;
+	self->nextthink = 0;
+	gi.linkentity (self);
+}
+
+mframe_t tank_frames_death1 [] =
+{
+	ai_move, -7,  NULL,
+	ai_move, -2,  NULL,
+	ai_move, -2,  NULL,
+	ai_move, 1,   NULL,
+	ai_move, 3,   NULL,
+	ai_move, 6,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 1,   NULL,
+	ai_move, 2,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -2,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -3,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, -4,  NULL,
+	ai_move, -6,  NULL,
+	ai_move, -4,  NULL,
+	ai_move, -5,  NULL,
+	ai_move, -7,  NULL,
+	ai_move, -15, tank_thud,
+	ai_move, -5,  NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL,
+	ai_move, 0,   NULL
+};
+mmove_t	tank_move_death = {FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead};
+
+void tank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+// check for gib
+	if (self->health <= self->gib_health)
+	{
+		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 1 /*4*/; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
+		ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
+		ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
+		self->deadflag = DEAD_DEAD;
+		return;
+	}
+
+	if (self->deadflag == DEAD_DEAD)
+		return;
+
+// regular death
+	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+	self->deadflag = DEAD_DEAD;
+	self->takedamage = DAMAGE_YES;
+
+	self->monsterinfo.currentmove = &tank_move_death;
+	
+}
+
+
+//
+// monster_tank
+//
+
+/*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
+*/
+/*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
+*/
+void SP_monster_tank (edict_t *self)
+{
+	if (deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
+	VectorSet (self->mins, -32, -32, -16);
+	VectorSet (self->maxs, 32, 32, 72);
+	self->movetype = MOVETYPE_STEP;
+	self->solid = SOLID_BBOX;
+
+	sound_pain = gi.soundindex ("tank/tnkpain2.wav");
+	sound_thud = gi.soundindex ("tank/tnkdeth2.wav");
+	sound_idle = gi.soundindex ("tank/tnkidle1.wav");
+	sound_die = gi.soundindex ("tank/death.wav");
+	sound_step = gi.soundindex ("tank/step.wav");
+	sound_windup = gi.soundindex ("tank/tnkatck4.wav");
+	sound_strike = gi.soundindex ("tank/tnkatck5.wav");
+	sound_sight = gi.soundindex ("tank/sight1.wav");
+
+	gi.soundindex ("tank/tnkatck1.wav");
+	gi.soundindex ("tank/tnkatk2a.wav");
+	gi.soundindex ("tank/tnkatk2b.wav");
+	gi.soundindex ("tank/tnkatk2c.wav");
+	gi.soundindex ("tank/tnkatk2d.wav");
+	gi.soundindex ("tank/tnkatk2e.wav");
+	gi.soundindex ("tank/tnkatck3.wav");
+
+	if (strcmp(self->classname, "monster_tank_commander") == 0)
+	{
+		self->health = 1000;
+		self->gib_health = -225;
+	}
+	else
+	{
+		self->health = 750;
+		self->gib_health = -200;
+	}
+
+	self->mass = 500;
+
+	self->pain = tank_pain;
+	self->die = tank_die;
+	self->monsterinfo.stand = tank_stand;
+	self->monsterinfo.walk = tank_walk;
+	self->monsterinfo.run = tank_run;
+	self->monsterinfo.dodge = NULL;
+	self->monsterinfo.attack = tank_attack;
+	self->monsterinfo.melee = NULL;
+	self->monsterinfo.sight = tank_sight;
+	self->monsterinfo.idle = tank_idle;
+
+	gi.linkentity (self);
+	
+	self->monsterinfo.currentmove = &tank_move_stand;
+	self->monsterinfo.scale = MODEL_SCALE;
+
+	walkmonster_start(self);
+
+	if (strcmp(self->classname, "monster_tank_commander") == 0)
+		self->s.skinnum = 2;
+}
--- /dev/null
+++ b/game/m_tank.h
@@ -1,0 +1,319 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// G:\quake2\baseq2\models/monsters/tank
+
+// This file generated by qdata - Do NOT Modify
+
+#define FRAME_stand01         	0
+#define FRAME_stand02         	1
+#define FRAME_stand03         	2
+#define FRAME_stand04         	3
+#define FRAME_stand05         	4
+#define FRAME_stand06         	5
+#define FRAME_stand07         	6
+#define FRAME_stand08         	7
+#define FRAME_stand09         	8
+#define FRAME_stand10         	9
+#define FRAME_stand11         	10
+#define FRAME_stand12         	11
+#define FRAME_stand13         	12
+#define FRAME_stand14         	13
+#define FRAME_stand15         	14
+#define FRAME_stand16         	15
+#define FRAME_stand17         	16
+#define FRAME_stand18         	17
+#define FRAME_stand19         	18
+#define FRAME_stand20         	19
+#define FRAME_stand21         	20
+#define FRAME_stand22         	21
+#define FRAME_stand23         	22
+#define FRAME_stand24         	23
+#define FRAME_stand25         	24
+#define FRAME_stand26         	25
+#define FRAME_stand27         	26
+#define FRAME_stand28         	27
+#define FRAME_stand29         	28
+#define FRAME_stand30         	29
+#define FRAME_walk01          	30
+#define FRAME_walk02          	31
+#define FRAME_walk03          	32
+#define FRAME_walk04          	33
+#define FRAME_walk05          	34
+#define FRAME_walk06          	35
+#define FRAME_walk07          	36
+#define FRAME_walk08          	37
+#define FRAME_walk09          	38
+#define FRAME_walk10          	39
+#define FRAME_walk11          	40
+#define FRAME_walk12          	41
+#define FRAME_walk13          	42
+#define FRAME_walk14          	43
+#define FRAME_walk15          	44
+#define FRAME_walk16          	45
+#define FRAME_walk17          	46
+#define FRAME_walk18          	47
+#define FRAME_walk19          	48
+#define FRAME_walk20          	49
+#define FRAME_walk21          	50
+#define FRAME_walk22          	51
+#define FRAME_walk23          	52
+#define FRAME_walk24          	53
+#define FRAME_walk25          	54
+#define FRAME_attak101        	55
+#define FRAME_attak102        	56
+#define FRAME_attak103        	57
+#define FRAME_attak104        	58
+#define FRAME_attak105        	59
+#define FRAME_attak106        	60
+#define FRAME_attak107        	61
+#define FRAME_attak108        	62
+#define FRAME_attak109        	63
+#define FRAME_attak110        	64
+#define FRAME_attak111        	65
+#define FRAME_attak112        	66
+#define FRAME_attak113        	67
+#define FRAME_attak114        	68
+#define FRAME_attak115        	69
+#define FRAME_attak116        	70
+#define FRAME_attak117        	71
+#define FRAME_attak118        	72
+#define FRAME_attak119        	73
+#define FRAME_attak120        	74
+#define FRAME_attak121        	75
+#define FRAME_attak122        	76
+#define FRAME_attak201        	77
+#define FRAME_attak202        	78
+#define FRAME_attak203        	79
+#define FRAME_attak204        	80
+#define FRAME_attak205        	81
+#define FRAME_attak206        	82
+#define FRAME_attak207        	83
+#define FRAME_attak208        	84
+#define FRAME_attak209        	85
+#define FRAME_attak210        	86
+#define FRAME_attak211        	87
+#define FRAME_attak212        	88
+#define FRAME_attak213        	89
+#define FRAME_attak214        	90
+#define FRAME_attak215        	91
+#define FRAME_attak216        	92
+#define FRAME_attak217        	93
+#define FRAME_attak218        	94
+#define FRAME_attak219        	95
+#define FRAME_attak220        	96
+#define FRAME_attak221        	97
+#define FRAME_attak222        	98
+#define FRAME_attak223        	99
+#define FRAME_attak224        	100
+#define FRAME_attak225        	101
+#define FRAME_attak226        	102
+#define FRAME_attak227        	103
+#define FRAME_attak228        	104
+#define FRAME_attak229        	105
+#define FRAME_attak230        	106
+#define FRAME_attak231        	107
+#define FRAME_attak232        	108
+#define FRAME_attak233        	109
+#define FRAME_attak234        	110
+#define FRAME_attak235        	111
+#define FRAME_attak236        	112
+#define FRAME_attak237        	113
+#define FRAME_attak238        	114
+#define FRAME_attak301        	115
+#define FRAME_attak302        	116
+#define FRAME_attak303        	117
+#define FRAME_attak304        	118
+#define FRAME_attak305        	119
+#define FRAME_attak306        	120
+#define FRAME_attak307        	121
+#define FRAME_attak308        	122
+#define FRAME_attak309        	123
+#define FRAME_attak310        	124
+#define FRAME_attak311        	125
+#define FRAME_attak312        	126
+#define FRAME_attak313        	127
+#define FRAME_attak314        	128
+#define FRAME_attak315        	129
+#define FRAME_attak316        	130
+#define FRAME_attak317        	131
+#define FRAME_attak318        	132
+#define FRAME_attak319        	133
+#define FRAME_attak320        	134
+#define FRAME_attak321        	135
+#define FRAME_attak322        	136
+#define FRAME_attak323        	137
+#define FRAME_attak324        	138
+#define FRAME_attak325        	139
+#define FRAME_attak326        	140
+#define FRAME_attak327        	141
+#define FRAME_attak328        	142
+#define FRAME_attak329        	143
+#define FRAME_attak330        	144
+#define FRAME_attak331        	145
+#define FRAME_attak332        	146
+#define FRAME_attak333        	147
+#define FRAME_attak334        	148
+#define FRAME_attak335        	149
+#define FRAME_attak336        	150
+#define FRAME_attak337        	151
+#define FRAME_attak338        	152
+#define FRAME_attak339        	153
+#define FRAME_attak340        	154
+#define FRAME_attak341        	155
+#define FRAME_attak342        	156
+#define FRAME_attak343        	157
+#define FRAME_attak344        	158
+#define FRAME_attak345        	159
+#define FRAME_attak346        	160
+#define FRAME_attak347        	161
+#define FRAME_attak348        	162
+#define FRAME_attak349        	163
+#define FRAME_attak350        	164
+#define FRAME_attak351        	165
+#define FRAME_attak352        	166
+#define FRAME_attak353        	167
+#define FRAME_attak401        	168
+#define FRAME_attak402        	169
+#define FRAME_attak403        	170
+#define FRAME_attak404        	171
+#define FRAME_attak405        	172
+#define FRAME_attak406        	173
+#define FRAME_attak407        	174
+#define FRAME_attak408        	175
+#define FRAME_attak409        	176
+#define FRAME_attak410        	177
+#define FRAME_attak411        	178
+#define FRAME_attak412        	179
+#define FRAME_attak413        	180
+#define FRAME_attak414        	181
+#define FRAME_attak415        	182
+#define FRAME_attak416        	183
+#define FRAME_attak417        	184
+#define FRAME_attak418        	185
+#define FRAME_attak419        	186
+#define FRAME_attak420        	187
+#define FRAME_attak421        	188
+#define FRAME_attak422        	189
+#define FRAME_attak423        	190
+#define FRAME_attak424        	191
+#define FRAME_attak425        	192
+#define FRAME_attak426        	193
+#define FRAME_attak427        	194
+#define FRAME_attak428        	195
+#define FRAME_attak429        	196
+#define FRAME_pain101         	197
+#define FRAME_pain102         	198
+#define FRAME_pain103         	199
+#define FRAME_pain104         	200
+#define FRAME_pain201         	201
+#define FRAME_pain202         	202
+#define FRAME_pain203         	203
+#define FRAME_pain204         	204
+#define FRAME_pain205         	205
+#define FRAME_pain301         	206
+#define FRAME_pain302         	207
+#define FRAME_pain303         	208
+#define FRAME_pain304         	209
+#define FRAME_pain305         	210
+#define FRAME_pain306         	211
+#define FRAME_pain307         	212
+#define FRAME_pain308         	213
+#define FRAME_pain309         	214
+#define FRAME_pain310         	215
+#define FRAME_pain311         	216
+#define FRAME_pain312         	217
+#define FRAME_pain313         	218
+#define FRAME_pain314         	219
+#define FRAME_pain315         	220
+#define FRAME_pain316         	221
+#define FRAME_death101        	222
+#define FRAME_death102        	223
+#define FRAME_death103        	224
+#define FRAME_death104        	225
+#define FRAME_death105        	226
+#define FRAME_death106        	227
+#define FRAME_death107        	228
+#define FRAME_death108        	229
+#define FRAME_death109        	230
+#define FRAME_death110        	231
+#define FRAME_death111        	232
+#define FRAME_death112        	233
+#define FRAME_death113        	234
+#define FRAME_death114        	235
+#define FRAME_death115        	236
+#define FRAME_death116        	237
+#define FRAME_death117        	238
+#define FRAME_death118        	239
+#define FRAME_death119        	240
+#define FRAME_death120        	241
+#define FRAME_death121        	242
+#define FRAME_death122        	243
+#define FRAME_death123        	244
+#define FRAME_death124        	245
+#define FRAME_death125        	246
+#define FRAME_death126        	247
+#define FRAME_death127        	248
+#define FRAME_death128        	249
+#define FRAME_death129        	250
+#define FRAME_death130        	251
+#define FRAME_death131        	252
+#define FRAME_death132        	253
+#define FRAME_recln101        	254
+#define FRAME_recln102        	255
+#define FRAME_recln103        	256
+#define FRAME_recln104        	257
+#define FRAME_recln105        	258
+#define FRAME_recln106        	259
+#define FRAME_recln107        	260
+#define FRAME_recln108        	261
+#define FRAME_recln109        	262
+#define FRAME_recln110        	263
+#define FRAME_recln111        	264
+#define FRAME_recln112        	265
+#define FRAME_recln113        	266
+#define FRAME_recln114        	267
+#define FRAME_recln115        	268
+#define FRAME_recln116        	269
+#define FRAME_recln117        	270
+#define FRAME_recln118        	271
+#define FRAME_recln119        	272
+#define FRAME_recln120        	273
+#define FRAME_recln121        	274
+#define FRAME_recln122        	275
+#define FRAME_recln123        	276
+#define FRAME_recln124        	277
+#define FRAME_recln125        	278
+#define FRAME_recln126        	279
+#define FRAME_recln127        	280
+#define FRAME_recln128        	281
+#define FRAME_recln129        	282
+#define FRAME_recln130        	283
+#define FRAME_recln131        	284
+#define FRAME_recln132        	285
+#define FRAME_recln133        	286
+#define FRAME_recln134        	287
+#define FRAME_recln135        	288
+#define FRAME_recln136        	289
+#define FRAME_recln137        	290
+#define FRAME_recln138        	291
+#define FRAME_recln139        	292
+#define FRAME_recln140        	293
+
+#define MODEL_SCALE		1.000000
--- /dev/null
+++ b/game/p_client.c
@@ -1,0 +1,1805 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+void ClientUserinfoChanged (edict_t *ent, char *userinfo);
+
+void SP_misc_teleporter_dest (edict_t *ent);
+
+//
+// Gross, ugly, disgustuing hack section
+//
+
+// this function is an ugly as hell hack to fix some map flaws
+//
+// the coop spawn spots on some maps are SNAFU.  There are coop spots
+// with the wrong targetname as well as spots with no name at all
+//
+// we use carnal knowledge of the maps to fix the coop spot targetnames to match
+// that of the nearest named single player spot
+
+static void SP_FixCoopSpots (edict_t *self)
+{
+	edict_t	*spot;
+	vec3_t	d;
+
+	spot = NULL;
+
+	while(1)
+	{
+		spot = G_Find(spot, FOFS(classname), "info_player_start");
+		if (!spot)
+			return;
+		if (!spot->targetname)
+			continue;
+		VectorSubtract(self->s.origin, spot->s.origin, d);
+		if (VectorLength(d) < 384)
+		{
+			if ((!self->targetname) || Q_stricmp(self->targetname, spot->targetname) != 0)
+			{
+//				gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
+				self->targetname = spot->targetname;
+			}
+			return;
+		}
+	}
+}
+
+// now if that one wasn't ugly enough for you then try this one on for size
+// some maps don't have any coop spots at all, so we need to create them
+// where they should have been
+
+static void SP_CreateCoopSpots (edict_t *self)
+{
+	edict_t	*spot;
+
+	if(Q_stricmp(level.mapname, "security") == 0)
+	{
+		spot = G_Spawn();
+		spot->classname = "info_player_coop";
+		spot->s.origin[0] = 188 - 64;
+		spot->s.origin[1] = -164;
+		spot->s.origin[2] = 80;
+		spot->targetname = "jail3";
+		spot->s.angles[1] = 90;
+
+		spot = G_Spawn();
+		spot->classname = "info_player_coop";
+		spot->s.origin[0] = 188 + 64;
+		spot->s.origin[1] = -164;
+		spot->s.origin[2] = 80;
+		spot->targetname = "jail3";
+		spot->s.angles[1] = 90;
+
+		spot = G_Spawn();
+		spot->classname = "info_player_coop";
+		spot->s.origin[0] = 188 + 128;
+		spot->s.origin[1] = -164;
+		spot->s.origin[2] = 80;
+		spot->targetname = "jail3";
+		spot->s.angles[1] = 90;
+
+		return;
+	}
+}
+
+
+/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
+The normal starting point for a level.
+*/
+void SP_info_player_start(edict_t *self)
+{
+	if (!coop->value)
+		return;
+	if(Q_stricmp(level.mapname, "security") == 0)
+	{
+		// invoke one of our gross, ugly, disgusting hacks
+		self->think = SP_CreateCoopSpots;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
+potential spawning position for deathmatch games
+*/
+void SP_info_player_deathmatch(edict_t *self)
+{
+	if (!deathmatch->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+	SP_misc_teleporter_dest (self);
+}
+
+/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
+potential spawning position for coop games
+*/
+
+void SP_info_player_coop(edict_t *self)
+{
+	if (!coop->value)
+	{
+		G_FreeEdict (self);
+		return;
+	}
+
+	if((Q_stricmp(level.mapname, "jail2") == 0)   ||
+	   (Q_stricmp(level.mapname, "jail4") == 0)   ||
+	   (Q_stricmp(level.mapname, "mine1") == 0)   ||
+	   (Q_stricmp(level.mapname, "mine2") == 0)   ||
+	   (Q_stricmp(level.mapname, "mine3") == 0)   ||
+	   (Q_stricmp(level.mapname, "mine4") == 0)   ||
+	   (Q_stricmp(level.mapname, "lab") == 0)     ||
+	   (Q_stricmp(level.mapname, "boss1") == 0)   ||
+	   (Q_stricmp(level.mapname, "fact3") == 0)   ||
+	   (Q_stricmp(level.mapname, "biggun") == 0)  ||
+	   (Q_stricmp(level.mapname, "space") == 0)   ||
+	   (Q_stricmp(level.mapname, "command") == 0) ||
+	   (Q_stricmp(level.mapname, "power2") == 0) ||
+	   (Q_stricmp(level.mapname, "strike") == 0))
+	{
+		// invoke one of our gross, ugly, disgusting hacks
+		self->think = SP_FixCoopSpots;
+		self->nextthink = level.time + FRAMETIME;
+	}
+}
+
+
+/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
+The deathmatch intermission point will be at one of these
+Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw.  'pitch yaw roll'
+*/
+void SP_info_player_intermission(void)
+{
+}
+
+
+//=======================================================================
+
+
+void player_pain (edict_t *self, edict_t *other, float kick, int damage)
+{
+	// player pain is handled at the end of the frame in P_DamageFeedback
+}
+
+
+qboolean IsFemale (edict_t *ent)
+{
+	char		*info;
+
+	if (!ent->client)
+		return false;
+
+	info = Info_ValueForKey (ent->client->pers.userinfo, "gender");
+	if (info[0] == 'f' || info[0] == 'F')
+		return true;
+	return false;
+}
+
+qboolean IsNeutral (edict_t *ent)
+{
+	char		*info;
+
+	if (!ent->client)
+		return false;
+
+	info = Info_ValueForKey (ent->client->pers.userinfo, "gender");
+	if (info[0] != 'f' && info[0] != 'F' && info[0] != 'm' && info[0] != 'M')
+		return true;
+	return false;
+}
+
+void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
+{
+	int			mod;
+	char		*message;
+	char		*message2;
+	qboolean	ff;
+
+	if (coop->value && attacker->client)
+		meansOfDeath |= MOD_FRIENDLY_FIRE;
+
+	if (deathmatch->value || coop->value)
+	{
+		ff = meansOfDeath & MOD_FRIENDLY_FIRE;
+		mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
+		message = NULL;
+		message2 = "";
+
+		switch (mod)
+		{
+		case MOD_SUICIDE:
+			message = "suicides";
+			break;
+		case MOD_FALLING:
+			message = "cratered";
+			break;
+		case MOD_CRUSH:
+			message = "was squished";
+			break;
+		case MOD_WATER:
+			message = "sank like a rock";
+			break;
+		case MOD_SLIME:
+			message = "melted";
+			break;
+		case MOD_LAVA:
+			message = "does a back flip into the lava";
+			break;
+		case MOD_EXPLOSIVE:
+		case MOD_BARREL:
+			message = "blew up";
+			break;
+		case MOD_EXIT:
+			message = "found a way out";
+			break;
+		case MOD_TARGET_LASER:
+			message = "saw the light";
+			break;
+		case MOD_TARGET_BLASTER:
+			message = "got blasted";
+			break;
+		case MOD_BOMB:
+		case MOD_SPLASH:
+		case MOD_TRIGGER_HURT:
+			message = "was in the wrong place";
+			break;
+		}
+		if (attacker == self)
+		{
+			switch (mod)
+			{
+			case MOD_HELD_GRENADE:
+				message = "tried to put the pin back in";
+				break;
+			case MOD_HG_SPLASH:
+			case MOD_G_SPLASH:
+				if (IsNeutral(self))
+					message = "tripped on its own grenade";
+				else if (IsFemale(self))
+					message = "tripped on her own grenade";
+				else
+					message = "tripped on his own grenade";
+				break;
+			case MOD_R_SPLASH:
+				if (IsNeutral(self))
+					message = "blew itself up";
+				else if (IsFemale(self))
+					message = "blew herself up";
+				else
+					message = "blew himself up";
+				break;
+			case MOD_BFG_BLAST:
+				message = "should have used a smaller gun";
+				break;
+			default:
+				if (IsNeutral(self))
+					message = "killed itself";
+				else if (IsFemale(self))
+					message = "killed herself";
+				else
+					message = "killed himself";
+				break;
+			}
+		}
+		if (message)
+		{
+			gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message);
+			if (deathmatch->value)
+				self->client->resp.score--;
+			self->enemy = NULL;
+			return;
+		}
+
+		self->enemy = attacker;
+		if (attacker && attacker->client)
+		{
+			switch (mod)
+			{
+			case MOD_BLASTER:
+				message = "was blasted by";
+				break;
+			case MOD_SHOTGUN:
+				message = "was gunned down by";
+				break;
+			case MOD_SSHOTGUN:
+				message = "was blown away by";
+				message2 = "'s super shotgun";
+				break;
+			case MOD_MACHINEGUN:
+				message = "was machinegunned by";
+				break;
+			case MOD_CHAINGUN:
+				message = "was cut in half by";
+				message2 = "'s chaingun";
+				break;
+			case MOD_GRENADE:
+				message = "was popped by";
+				message2 = "'s grenade";
+				break;
+			case MOD_G_SPLASH:
+				message = "was shredded by";
+				message2 = "'s shrapnel";
+				break;
+			case MOD_ROCKET:
+				message = "ate";
+				message2 = "'s rocket";
+				break;
+			case MOD_R_SPLASH:
+				message = "almost dodged";
+				message2 = "'s rocket";
+				break;
+			case MOD_HYPERBLASTER:
+				message = "was melted by";
+				message2 = "'s hyperblaster";
+				break;
+			case MOD_RAILGUN:
+				message = "was railed by";
+				break;
+			case MOD_BFG_LASER:
+				message = "saw the pretty lights from";
+				message2 = "'s BFG";
+				break;
+			case MOD_BFG_BLAST:
+				message = "was disintegrated by";
+				message2 = "'s BFG blast";
+				break;
+			case MOD_BFG_EFFECT:
+				message = "couldn't hide from";
+				message2 = "'s BFG";
+				break;
+			case MOD_HANDGRENADE:
+				message = "caught";
+				message2 = "'s handgrenade";
+				break;
+			case MOD_HG_SPLASH:
+				message = "didn't see";
+				message2 = "'s handgrenade";
+				break;
+			case MOD_HELD_GRENADE:
+				message = "feels";
+				message2 = "'s pain";
+				break;
+			case MOD_TELEFRAG:
+				message = "tried to invade";
+				message2 = "'s personal space";
+				break;
+			}
+			if (message)
+			{
+				gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
+				if (deathmatch->value)
+				{
+					if (ff)
+						attacker->client->resp.score--;
+					else
+						attacker->client->resp.score++;
+				}
+				return;
+			}
+		}
+	}
+
+	gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
+	if (deathmatch->value)
+		self->client->resp.score--;
+}
+
+
+void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
+
+void TossClientWeapon (edict_t *self)
+{
+	gitem_t		*item;
+	edict_t		*drop;
+	qboolean	quad;
+	float		spread;
+
+	if (!deathmatch->value)
+		return;
+
+	item = self->client->pers.weapon;
+	if (! self->client->pers.inventory[self->client->ammo_index] )
+		item = NULL;
+	if (item && (strcmp (item->pickup_name, "Blaster") == 0))
+		item = NULL;
+
+	if (!((int)(dmflags->value) & DF_QUAD_DROP))
+		quad = false;
+	else
+		quad = (self->client->quad_framenum > (level.framenum + 10));
+
+	if (item && quad)
+		spread = 22.5;
+	else
+		spread = 0.0;
+
+	if (item)
+	{
+		self->client->v_angle[YAW] -= spread;
+		drop = Drop_Item (self, item);
+		self->client->v_angle[YAW] += spread;
+		drop->spawnflags = DROPPED_PLAYER_ITEM;
+	}
+
+	if (quad)
+	{
+		self->client->v_angle[YAW] += spread;
+		drop = Drop_Item (self, FindItemByClassname ("item_quad"));
+		self->client->v_angle[YAW] -= spread;
+		drop->spawnflags |= DROPPED_PLAYER_ITEM;
+
+		drop->touch = Touch_Item;
+		drop->nextthink = level.time + (self->client->quad_framenum - level.framenum) * FRAMETIME;
+		drop->think = G_FreeEdict;
+	}
+}
+
+
+/*
+==================
+LookAtKiller
+==================
+*/
+void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
+{
+	vec3_t		dir;
+
+	if (attacker && attacker != world && attacker != self)
+	{
+		VectorSubtract (attacker->s.origin, self->s.origin, dir);
+	}
+	else if (inflictor && inflictor != world && inflictor != self)
+	{
+		VectorSubtract (inflictor->s.origin, self->s.origin, dir);
+	}
+	else
+	{
+		self->client->killer_yaw = self->s.angles[YAW];
+		return;
+	}
+
+	if (dir[0])
+		self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
+	else {
+		self->client->killer_yaw = 0;
+		if (dir[1] > 0)
+			self->client->killer_yaw = 90;
+		else if (dir[1] < 0)
+			self->client->killer_yaw = -90;
+	}
+	if (self->client->killer_yaw < 0)
+		self->client->killer_yaw += 360;
+	
+
+}
+
+/*
+==================
+player_die
+==================
+*/
+void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int		n;
+
+	VectorClear (self->avelocity);
+
+	self->takedamage = DAMAGE_YES;
+	self->movetype = MOVETYPE_TOSS;
+
+	self->s.modelindex2 = 0;	// remove linked weapon model
+
+	self->s.angles[0] = 0;
+	self->s.angles[2] = 0;
+
+	self->s.sound = 0;
+	self->client->weapon_sound = 0;
+
+	self->maxs[2] = -8;
+
+//	self->solid = SOLID_NOT;
+	self->svflags |= SVF_DEADMONSTER;
+
+	if (!self->deadflag)
+	{
+		self->client->respawn_time = level.time + 1.0;
+		LookAtKiller (self, inflictor, attacker);
+		self->client->ps.pmove.pm_type = PM_DEAD;
+		ClientObituary (self, inflictor, attacker);
+		TossClientWeapon (self);
+		if (deathmatch->value)
+			Cmd_Help_f (self);		// show scores
+
+		// clear inventory
+		// this is kind of ugly, but it's how we want to handle keys in coop
+		for (n = 0; n < game.num_items; n++)
+		{
+			if (coop->value && itemlist[n].flags & IT_KEY)
+				self->client->resp.coop_respawn.inventory[n] = self->client->pers.inventory[n];
+			self->client->pers.inventory[n] = 0;
+		}
+	}
+
+	// remove powerups
+	self->client->quad_framenum = 0;
+	self->client->invincible_framenum = 0;
+	self->client->breather_framenum = 0;
+	self->client->enviro_framenum = 0;
+	self->flags &= ~FL_POWER_ARMOR;
+
+	if (self->health < -40)
+	{	// gib
+		gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		ThrowClientHead (self, damage);
+
+		self->takedamage = DAMAGE_NO;
+	}
+	else
+	{	// normal death
+		if (!self->deadflag)
+		{
+			static int i;
+
+			i = (i+1)%3;
+			// start a death animation
+			self->client->anim_priority = ANIM_DEATH;
+			if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				self->s.frame = FRAME_crdeath1-1;
+				self->client->anim_end = FRAME_crdeath5;
+			}
+			else switch (i)
+			{
+			case 0:
+				self->s.frame = FRAME_death101-1;
+				self->client->anim_end = FRAME_death106;
+				break;
+			case 1:
+				self->s.frame = FRAME_death201-1;
+				self->client->anim_end = FRAME_death206;
+				break;
+			case 2:
+				self->s.frame = FRAME_death301-1;
+				self->client->anim_end = FRAME_death308;
+				break;
+			}
+			gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
+		}
+	}
+
+	self->deadflag = DEAD_DEAD;
+
+	gi.linkentity (self);
+}
+
+//=======================================================================
+
+/*
+==============
+InitClientPersistant
+
+This is only called when the game first initializes in single player,
+but is called after each death and level change in deathmatch
+==============
+*/
+void InitClientPersistant (gclient_t *client)
+{
+	gitem_t		*item;
+
+	memset (&client->pers, 0, sizeof(client->pers));
+
+	item = FindItem("Blaster");
+	client->pers.selected_item = ITEM_INDEX(item);
+	client->pers.inventory[client->pers.selected_item] = 1;
+
+	client->pers.weapon = item;
+
+	client->pers.health			= 100;
+	client->pers.max_health		= 100;
+
+	client->pers.max_bullets	= 200;
+	client->pers.max_shells		= 100;
+	client->pers.max_rockets	= 50;
+	client->pers.max_grenades	= 50;
+	client->pers.max_cells		= 200;
+	client->pers.max_slugs		= 50;
+
+	client->pers.connected = true;
+}
+
+
+void InitClientResp (gclient_t *client)
+{
+	memset (&client->resp, 0, sizeof(client->resp));
+	client->resp.enterframe = level.framenum;
+	client->resp.coop_respawn = client->pers;
+}
+
+/*
+==================
+SaveClientData
+
+Some information that should be persistant, like health, 
+is still stored in the edict structure, so it needs to
+be mirrored out to the client structure before all the
+edicts are wiped.
+==================
+*/
+void SaveClientData (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	for (i=0 ; i<game.maxclients ; i++)
+	{
+		ent = &g_edicts[1+i];
+		if (!ent->inuse)
+			continue;
+		game.clients[i].pers.health = ent->health;
+		game.clients[i].pers.max_health = ent->max_health;
+		game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE|FL_NOTARGET|FL_POWER_ARMOR));
+		if (coop->value)
+			game.clients[i].pers.score = ent->client->resp.score;
+	}
+}
+
+void FetchClientEntData (edict_t *ent)
+{
+	ent->health = ent->client->pers.health;
+	ent->max_health = ent->client->pers.max_health;
+	ent->flags |= ent->client->pers.savedFlags;
+	if (coop->value)
+		ent->client->resp.score = ent->client->pers.score;
+}
+
+
+
+/*
+=======================================================================
+
+  SelectSpawnPoint
+
+=======================================================================
+*/
+
+/*
+================
+PlayersRangeFromSpot
+
+Returns the distance to the nearest player from the given spot
+================
+*/
+float	PlayersRangeFromSpot (edict_t *spot)
+{
+	edict_t	*player;
+	float	bestplayerdistance;
+	vec3_t	v;
+	int		n;
+	float	playerdistance;
+
+
+	bestplayerdistance = 9999999;
+
+	for (n = 1; n <= maxclients->value; n++)
+	{
+		player = &g_edicts[n];
+
+		if (!player->inuse)
+			continue;
+
+		if (player->health <= 0)
+			continue;
+
+		VectorSubtract (spot->s.origin, player->s.origin, v);
+		playerdistance = VectorLength (v);
+
+		if (playerdistance < bestplayerdistance)
+			bestplayerdistance = playerdistance;
+	}
+
+	return bestplayerdistance;
+}
+
+/*
+================
+SelectRandomDeathmatchSpawnPoint
+
+go to a random point, but NOT the two points closest
+to other players
+================
+*/
+edict_t *SelectRandomDeathmatchSpawnPoint (void)
+{
+	edict_t	*spot, *spot1, *spot2;
+	int		count = 0;
+	int		selection;
+	float	range, range1, range2;
+
+	spot = NULL;
+	range1 = range2 = 99999;
+	spot1 = spot2 = NULL;
+
+	while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
+	{
+		count++;
+		range = PlayersRangeFromSpot(spot);
+		if (range < range1)
+		{
+			range1 = range;
+			spot1 = spot;
+		}
+		else if (range < range2)
+		{
+			range2 = range;
+			spot2 = spot;
+		}
+	}
+
+	if (!count)
+		return NULL;
+
+	if (count <= 2)
+	{
+		spot1 = spot2 = NULL;
+	}
+	else
+		count -= 2;
+
+	selection = rand() % count;
+
+	spot = NULL;
+	do
+	{
+		spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
+		if (spot == spot1 || spot == spot2)
+			selection++;
+	} while(selection--);
+
+	return spot;
+}
+
+/*
+================
+SelectFarthestDeathmatchSpawnPoint
+
+================
+*/
+edict_t *SelectFarthestDeathmatchSpawnPoint (void)
+{
+	edict_t	*bestspot;
+	float	bestdistance, bestplayerdistance;
+	edict_t	*spot;
+
+
+	spot = NULL;
+	bestspot = NULL;
+	bestdistance = 0;
+	while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
+	{
+		bestplayerdistance = PlayersRangeFromSpot (spot);
+
+		if (bestplayerdistance > bestdistance)
+		{
+			bestspot = spot;
+			bestdistance = bestplayerdistance;
+		}
+	}
+
+	if (bestspot)
+	{
+		return bestspot;
+	}
+
+	// if there is a player just spawned on each and every start spot
+	// we have no choice to turn one into a telefrag meltdown
+	spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
+
+	return spot;
+}
+
+edict_t *SelectDeathmatchSpawnPoint (void)
+{
+	if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
+		return SelectFarthestDeathmatchSpawnPoint ();
+	else
+		return SelectRandomDeathmatchSpawnPoint ();
+}
+
+
+edict_t *SelectCoopSpawnPoint (edict_t *ent)
+{
+	int		index;
+	edict_t	*spot = NULL;
+	char	*target;
+
+	index = ent->client - game.clients;
+
+	// player 0 starts in normal player spawn point
+	if (!index)
+		return NULL;
+
+	spot = NULL;
+
+	// assume there are four coop spots at each spawnpoint
+	while (1)
+	{
+		spot = G_Find (spot, FOFS(classname), "info_player_coop");
+		if (!spot)
+			return NULL;	// we didn't have enough...
+
+		target = spot->targetname;
+		if (!target)
+			target = "";
+		if ( Q_stricmp(game.spawnpoint, target) == 0 )
+		{	// this is a coop spawn point for one of the clients here
+			index--;
+			if (!index)
+				return spot;		// this is it
+		}
+	}
+
+
+	return spot;
+}
+
+
+/*
+===========
+SelectSpawnPoint
+
+Chooses a player start, deathmatch start, coop start, etc
+============
+*/
+void	SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
+{
+	edict_t	*spot = NULL;
+
+	if (deathmatch->value)
+		spot = SelectDeathmatchSpawnPoint ();
+	else if (coop->value)
+		spot = SelectCoopSpawnPoint (ent);
+
+	// find a single player start spot
+	if (!spot)
+	{
+		while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
+		{
+			if (!game.spawnpoint[0] && !spot->targetname)
+				break;
+
+			if (!game.spawnpoint[0] || !spot->targetname)
+				continue;
+
+			if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
+				break;
+		}
+
+		if (!spot)
+		{
+			if (!game.spawnpoint[0])
+			{	// there wasn't a spawnpoint without a target, so use any
+				spot = G_Find (spot, FOFS(classname), "info_player_start");
+			}
+			if (!spot)
+				gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
+		}
+	}
+
+	VectorCopy (spot->s.origin, origin);
+	origin[2] += 9;
+	VectorCopy (spot->s.angles, angles);
+}
+
+//======================================================================
+
+
+void InitBodyQue (void)
+{
+	int		i;
+	edict_t	*ent;
+
+	level.body_que = 0;
+	for (i=0; i<BODY_QUEUE_SIZE ; i++)
+	{
+		ent = G_Spawn();
+		ent->classname = "bodyque";
+	}
+}
+
+void body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
+{
+	int	n;
+
+	if (self->health < -40)
+	{
+		gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
+		for (n= 0; n < 4; n++)
+			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+		self->s.origin[2] -= 48;
+		ThrowClientHead (self, damage);
+		self->takedamage = DAMAGE_NO;
+	}
+}
+
+void CopyToBodyQue (edict_t *ent)
+{
+	edict_t		*body;
+
+	// grab a body que and cycle to the next one
+	body = &g_edicts[(int)maxclients->value + level.body_que + 1];
+	level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
+
+	// FIXME: send an effect on the removed body
+
+	gi.unlinkentity (ent);
+
+	gi.unlinkentity (body);
+	body->s = ent->s;
+	body->s.number = body - g_edicts;
+
+	body->svflags = ent->svflags;
+	VectorCopy (ent->mins, body->mins);
+	VectorCopy (ent->maxs, body->maxs);
+	VectorCopy (ent->absmin, body->absmin);
+	VectorCopy (ent->absmax, body->absmax);
+	VectorCopy (ent->size, body->size);
+	body->solid = ent->solid;
+	body->clipmask = ent->clipmask;
+	body->owner = ent->owner;
+	body->movetype = ent->movetype;
+
+	body->die = body_die;
+	body->takedamage = DAMAGE_YES;
+
+	gi.linkentity (body);
+}
+
+
+void respawn (edict_t *self)
+{
+	if (deathmatch->value || coop->value)
+	{
+		// spectator's don't leave bodies
+		if (self->movetype != MOVETYPE_NOCLIP)
+			CopyToBodyQue (self);
+		self->svflags &= ~SVF_NOCLIENT;
+		PutClientInServer (self);
+
+		// add a teleportation effect
+		self->s.event = EV_PLAYER_TELEPORT;
+
+		// hold in place briefly
+		self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+		self->client->ps.pmove.pm_time = 14;
+
+		self->client->respawn_time = level.time;
+
+		return;
+	}
+
+	// restart the entire server
+	gi.AddCommandString ("menu_loadgame\n");
+}
+
+/* 
+ * only called when pers.spectator changes
+ * note that resp.spectator should be the opposite of pers.spectator here
+ */
+void spectator_respawn (edict_t *ent)
+{
+	int i, numspec;
+
+	// if the user wants to become a spectator, make sure he doesn't
+	// exceed max_spectators
+
+	if (ent->client->pers.spectator) {
+		char *value = Info_ValueForKey (ent->client->pers.userinfo, "spectator");
+		if (*spectator_password->string && 
+			strcmp(spectator_password->string, "none") && 
+			strcmp(spectator_password->string, value)) {
+			gi.cprintf(ent, PRINT_HIGH, "Spectator password incorrect.\n");
+			ent->client->pers.spectator = false;
+			gi.WriteByte (svc_stufftext);
+			gi.WriteString ("spectator 0\n");
+			gi.unicast(ent, true);
+			return;
+		}
+
+		// count spectators
+		for (i = 1, numspec = 0; i <= maxclients->value; i++)
+			if (g_edicts[i].inuse && g_edicts[i].client->pers.spectator)
+				numspec++;
+
+		if (numspec >= maxspectators->value) {
+			gi.cprintf(ent, PRINT_HIGH, "Server spectator limit is full.");
+			ent->client->pers.spectator = false;
+			// reset his spectator var
+			gi.WriteByte (svc_stufftext);
+			gi.WriteString ("spectator 0\n");
+			gi.unicast(ent, true);
+			return;
+		}
+	} else {
+		// he was a spectator and wants to join the game
+		// he must have the right password
+		char *value = Info_ValueForKey (ent->client->pers.userinfo, "password");
+		if (*password->string && strcmp(password->string, "none") && 
+			strcmp(password->string, value)) {
+			gi.cprintf(ent, PRINT_HIGH, "Password incorrect.\n");
+			ent->client->pers.spectator = true;
+			gi.WriteByte (svc_stufftext);
+			gi.WriteString ("spectator 1\n");
+			gi.unicast(ent, true);
+			return;
+		}
+	}
+
+	// clear score on respawn
+	ent->client->pers.score = ent->client->resp.score = 0;
+
+	ent->svflags &= ~SVF_NOCLIENT;
+	PutClientInServer (ent);
+
+	// add a teleportation effect
+	if (!ent->client->pers.spectator)  {
+		// send effect
+		gi.WriteByte (svc_muzzleflash);
+		gi.WriteShort (ent-g_edicts);
+		gi.WriteByte (MZ_LOGIN);
+		gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+		// hold in place briefly
+		ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+		ent->client->ps.pmove.pm_time = 14;
+	}
+
+	ent->client->respawn_time = level.time;
+
+	if (ent->client->pers.spectator) 
+		gi.bprintf (PRINT_HIGH, "%s has moved to the sidelines\n", ent->client->pers.netname);
+	else
+		gi.bprintf (PRINT_HIGH, "%s joined the game\n", ent->client->pers.netname);
+}
+
+//==============================================================
+
+
+/*
+===========
+PutClientInServer
+
+Called when a player connects to a server or respawns in
+a deathmatch.
+============
+*/
+void PutClientInServer (edict_t *ent)
+{
+	vec3_t	mins = {-16, -16, -24};
+	vec3_t	maxs = {16, 16, 32};
+	int		index;
+	vec3_t	spawn_origin, spawn_angles;
+	gclient_t	*client;
+	int		i;
+	client_persistant_t	saved;
+	client_respawn_t	resp;
+
+	// find a spawn point
+	// do it before setting health back up, so farthest
+	// ranging doesn't count this client
+	SelectSpawnPoint (ent, spawn_origin, spawn_angles);
+
+	index = ent-g_edicts-1;
+	client = ent->client;
+
+	// deathmatch wipes most client data every spawn
+	if (deathmatch->value)
+	{
+		char		userinfo[MAX_INFO_STRING];
+
+		resp = client->resp;
+		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
+		InitClientPersistant (client);
+		ClientUserinfoChanged (ent, userinfo);
+	}
+	else if (coop->value)
+	{
+//		int			n;
+		char		userinfo[MAX_INFO_STRING];
+
+		resp = client->resp;
+		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
+		// this is kind of ugly, but it's how we want to handle keys in coop
+//		for (n = 0; n < game.num_items; n++)
+//		{
+//			if (itemlist[n].flags & IT_KEY)
+//				resp.coop_respawn.inventory[n] = client->pers.inventory[n];
+//		}
+		resp.coop_respawn.game_helpchanged = client->pers.game_helpchanged;
+		resp.coop_respawn.helpchanged = client->pers.helpchanged;
+		client->pers = resp.coop_respawn;
+		ClientUserinfoChanged (ent, userinfo);
+		if (resp.score > client->pers.score)
+			client->pers.score = resp.score;
+	}
+	else
+	{
+		memset (&resp, 0, sizeof(resp));
+	}
+
+	// clear everything but the persistant data
+	saved = client->pers;
+	memset (client, 0, sizeof(*client));
+	client->pers = saved;
+	if (client->pers.health <= 0)
+		InitClientPersistant(client);
+	client->resp = resp;
+
+	// copy some data from the client to the entity
+	FetchClientEntData (ent);
+
+	// clear entity values
+	ent->groundentity = NULL;
+	ent->client = &game.clients[index];
+	ent->takedamage = DAMAGE_AIM;
+	ent->movetype = MOVETYPE_WALK;
+	ent->viewheight = 22;
+	ent->inuse = true;
+	ent->classname = "player";
+	ent->mass = 200;
+	ent->solid = SOLID_BBOX;
+	ent->deadflag = DEAD_NO;
+	ent->air_finished = level.time + 12;
+	ent->clipmask = MASK_PLAYERSOLID;
+	ent->model = "players/male/tris.md2";
+	ent->pain = player_pain;
+	ent->die = player_die;
+	ent->waterlevel = 0;
+	ent->watertype = 0;
+	ent->flags &= ~FL_NO_KNOCKBACK;
+	ent->svflags &= ~SVF_DEADMONSTER;
+
+	VectorCopy (mins, ent->mins);
+	VectorCopy (maxs, ent->maxs);
+	VectorClear (ent->velocity);
+
+	// clear playerstate values
+	memset (&ent->client->ps, 0, sizeof(client->ps));
+
+	client->ps.pmove.origin[0] = spawn_origin[0]*8;
+	client->ps.pmove.origin[1] = spawn_origin[1]*8;
+	client->ps.pmove.origin[2] = spawn_origin[2]*8;
+
+	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
+	{
+		client->ps.fov = 90;
+	}
+	else
+	{
+		client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
+		if (client->ps.fov < 1)
+			client->ps.fov = 90;
+		else if (client->ps.fov > 160)
+			client->ps.fov = 160;
+	}
+
+	client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
+
+	// clear entity state values
+	ent->s.effects = 0;
+	ent->s.modelindex = 255;		// will use the skin specified model
+	ent->s.modelindex2 = 255;		// custom gun model
+	// sknum is player num and weapon number
+	// weapon number will be added in changeweapon
+	ent->s.skinnum = ent - g_edicts - 1;
+
+	ent->s.frame = 0;
+	VectorCopy (spawn_origin, ent->s.origin);
+	ent->s.origin[2] += 1;	// make sure off ground
+	VectorCopy (ent->s.origin, ent->s.old_origin);
+
+	// set the delta angle
+	for (i=0 ; i<3 ; i++)
+		client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
+
+	ent->s.angles[PITCH] = 0;
+	ent->s.angles[YAW] = spawn_angles[YAW];
+	ent->s.angles[ROLL] = 0;
+	VectorCopy (ent->s.angles, client->ps.viewangles);
+	VectorCopy (ent->s.angles, client->v_angle);
+
+	// spawn a spectator
+	if (client->pers.spectator) {
+		client->chase_target = NULL;
+
+		client->resp.spectator = true;
+
+		ent->movetype = MOVETYPE_NOCLIP;
+		ent->solid = SOLID_NOT;
+		ent->svflags |= SVF_NOCLIENT;
+		ent->client->ps.gunindex = 0;
+		gi.linkentity (ent);
+		return;
+	} else
+		client->resp.spectator = false;
+
+	if (!KillBox (ent))
+	{	// could't spawn in?
+	}
+
+	gi.linkentity (ent);
+
+	// force the current weapon up
+	client->newweapon = client->pers.weapon;
+	ChangeWeapon (ent);
+}
+
+/*
+=====================
+ClientBeginDeathmatch
+
+A client has just connected to the server in 
+deathmatch mode, so clear everything out before starting them.
+=====================
+*/
+void ClientBeginDeathmatch (edict_t *ent)
+{
+	G_InitEdict (ent);
+
+	InitClientResp (ent->client);
+
+	// locate ent at a spawn point
+	PutClientInServer (ent);
+
+	// send effect
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_LOGIN);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
+
+	// make sure all view stuff is valid
+	ClientEndServerFrame (ent);
+}
+
+
+/*
+===========
+ClientBegin
+
+called when a client has finished connecting, and is ready
+to be placed into the game.  This will happen every level load.
+============
+*/
+void ClientBegin (edict_t *ent)
+{
+	int		i;
+
+	ent->client = game.clients + (ent - g_edicts - 1);
+
+	if (deathmatch->value)
+	{
+		ClientBeginDeathmatch (ent);
+		return;
+	}
+
+	// if there is already a body waiting for us (a loadgame), just
+	// take it, otherwise spawn one from scratch
+	if (ent->inuse == true)
+	{
+		// the client has cleared the client side viewangles upon
+		// connecting to the server, which is different than the
+		// state when the game is saved, so we need to compensate
+		// with deltaangles
+		for (i=0 ; i<3 ; i++)
+			ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
+	}
+	else
+	{
+		// a spawn point will completely reinitialize the entity
+		// except for the persistant data that was initialized at
+		// ClientConnect() time
+		G_InitEdict (ent);
+		ent->classname = "player";
+		InitClientResp (ent->client);
+		PutClientInServer (ent);
+	}
+
+	if (level.intermissiontime)
+	{
+		MoveClientToIntermission (ent);
+	}
+	else
+	{
+		// send effect if in a multiplayer game
+		if (game.maxclients > 1)
+		{
+			gi.WriteByte (svc_muzzleflash);
+			gi.WriteShort (ent-g_edicts);
+			gi.WriteByte (MZ_LOGIN);
+			gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+			gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
+		}
+	}
+
+	// make sure all view stuff is valid
+	ClientEndServerFrame (ent);
+}
+
+/*
+===========
+ClientUserInfoChanged
+
+called whenever the player updates a userinfo variable.
+
+The game can override any of the settings in place
+(forcing skins or names, etc) before copying it off.
+============
+*/
+void ClientUserinfoChanged (edict_t *ent, char *userinfo)
+{
+	char	*s;
+	int		playernum;
+
+	// check for malformed or illegal info strings
+	if (!Info_Validate(userinfo))
+	{
+		strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
+	}
+
+	// set name
+	s = Info_ValueForKey (userinfo, "name");
+	strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
+
+	// set spectator
+	s = Info_ValueForKey (userinfo, "spectator");
+	// spectators are only supported in deathmatch
+	if (deathmatch->value && *s && strcmp(s, "0"))
+		ent->client->pers.spectator = true;
+	else
+		ent->client->pers.spectator = false;
+
+	// set skin
+	s = Info_ValueForKey (userinfo, "skin");
+
+	playernum = ent-g_edicts-1;
+
+	// combine name and skin into a configstring
+	gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );
+
+	// fov
+	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
+	{
+		ent->client->ps.fov = 90;
+	}
+	else
+	{
+		ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov"));
+		if (ent->client->ps.fov < 1)
+			ent->client->ps.fov = 90;
+		else if (ent->client->ps.fov > 160)
+			ent->client->ps.fov = 160;
+	}
+
+	// handedness
+	s = Info_ValueForKey (userinfo, "hand");
+	if (strlen(s))
+	{
+		ent->client->pers.hand = atoi(s);
+	}
+
+	// save off the userinfo in case we want to check something later
+	strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
+}
+
+
+/*
+===========
+ClientConnect
+
+Called when a player begins connecting to the server.
+The game can refuse entrance to a client by returning false.
+If the client is allowed, the connection process will continue
+and eventually get to ClientBegin()
+Changing levels will NOT cause this to be called again, but
+loadgames will.
+============
+*/
+qboolean ClientConnect (edict_t *ent, char *userinfo)
+{
+	char	*value;
+
+	// check to see if they are on the banned IP list
+	value = Info_ValueForKey (userinfo, "ip");
+	if (SV_FilterPacket(value)) {
+		Info_SetValueForKey(userinfo, "rejmsg", "Banned.");
+		return false;
+	}
+
+	// check for a spectator
+	value = Info_ValueForKey (userinfo, "spectator");
+	if (deathmatch->value && *value && strcmp(value, "0")) {
+		int i, numspec;
+
+		if (*spectator_password->string && 
+			strcmp(spectator_password->string, "none") && 
+			strcmp(spectator_password->string, value)) {
+			Info_SetValueForKey(userinfo, "rejmsg", "Spectator password required or incorrect.");
+			return false;
+		}
+
+		// count spectators
+		for (i = numspec = 0; i < maxclients->value; i++)
+			if (g_edicts[i+1].inuse && g_edicts[i+1].client->pers.spectator)
+				numspec++;
+
+		if (numspec >= maxspectators->value) {
+			Info_SetValueForKey(userinfo, "rejmsg", "Server spectator limit is full.");
+			return false;
+		}
+	} else {
+		// check for a password
+		value = Info_ValueForKey (userinfo, "password");
+		if (*password->string && strcmp(password->string, "none") && 
+			strcmp(password->string, value)) {
+			Info_SetValueForKey(userinfo, "rejmsg", "Password required or incorrect.");
+			return false;
+		}
+	}
+
+
+	// they can connect
+	ent->client = game.clients + (ent - g_edicts - 1);
+
+	// if there is already a body waiting for us (a loadgame), just
+	// take it, otherwise spawn one from scratch
+	if (ent->inuse == false)
+	{
+		// clear the respawning variables
+		InitClientResp (ent->client);
+		if (!game.autosaved || !ent->client->pers.weapon)
+			InitClientPersistant (ent->client);
+	}
+
+	ClientUserinfoChanged (ent, userinfo);
+
+	if (game.maxclients > 1)
+		gi.dprintf ("%s connected\n", ent->client->pers.netname);
+
+	ent->client->pers.connected = true;
+	return true;
+}
+
+/*
+===========
+ClientDisconnect
+
+Called when a player drops from the server.
+Will not be called between levels.
+============
+*/
+void ClientDisconnect (edict_t *ent)
+{
+	int		playernum;
+
+	if (!ent->client)
+		return;
+
+	gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
+
+	// send effect
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_LOGOUT);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	gi.unlinkentity (ent);
+	ent->s.modelindex = 0;
+	ent->solid = SOLID_NOT;
+	ent->inuse = false;
+	ent->classname = "disconnected";
+	ent->client->pers.connected = false;
+
+	playernum = ent-g_edicts-1;
+	gi.configstring (CS_PLAYERSKINS+playernum, "");
+}
+
+
+//==============================================================
+
+
+edict_t	*pm_passent;
+
+// pmove doesn't need to know about passent and contentmask
+trace_t	PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+	if (pm_passent->health > 0)
+		return gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
+	else
+		return gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
+}
+
+unsigned CheckBlock (void *b, int c)
+{
+	int	v,i;
+	v = 0;
+	for (i=0 ; i<c ; i++)
+		v+= ((byte *)b)[i];
+	return v;
+}
+void PrintPmove (pmove_t *pm)
+{
+	unsigned	c1, c2;
+
+	c1 = CheckBlock (&pm->s, sizeof(pm->s));
+	c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd));
+	Com_Printf ("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2);
+}
+
+/*
+==============
+ClientThink
+
+This will be called once for each client frame, which will
+usually be a couple times for each server frame.
+==============
+*/
+void ClientThink (edict_t *ent, usercmd_t *ucmd)
+{
+	gclient_t	*client;
+	edict_t	*other;
+	int		i, j;
+	pmove_t	pm;
+
+	level.current_entity = ent;
+	client = ent->client;
+
+	if (level.intermissiontime)
+	{
+		client->ps.pmove.pm_type = PM_FREEZE;
+		// can exit intermission after five seconds
+		if (level.time > level.intermissiontime + 5.0 
+			&& (ucmd->buttons & BUTTON_ANY) )
+			level.exitintermission = true;
+		return;
+	}
+
+	pm_passent = ent;
+
+	if (ent->client->chase_target) {
+
+		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
+		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
+		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
+
+	} else {
+
+		// set up for pmove
+		memset (&pm, 0, sizeof(pm));
+
+		if (ent->movetype == MOVETYPE_NOCLIP)
+			client->ps.pmove.pm_type = PM_SPECTATOR;
+		else if (ent->s.modelindex != 255)
+			client->ps.pmove.pm_type = PM_GIB;
+		else if (ent->deadflag)
+			client->ps.pmove.pm_type = PM_DEAD;
+		else
+			client->ps.pmove.pm_type = PM_NORMAL;
+
+		client->ps.pmove.gravity = sv_gravity->value;
+		pm.s = client->ps.pmove;
+
+		for (i=0 ; i<3 ; i++)
+		{
+			pm.s.origin[i] = ent->s.origin[i]*8;
+			pm.s.velocity[i] = ent->velocity[i]*8;
+		}
+
+		if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
+		{
+			pm.snapinitial = true;
+	//		gi.dprintf ("pmove changed!\n");
+		}
+
+		pm.cmd = *ucmd;
+
+		pm.trace = PM_trace;	// adds default parms
+		pm.pointcontents = gi.pointcontents;
+
+		// perform a pmove
+		gi.Pmove (&pm);
+
+		// save results of pmove
+		client->ps.pmove = pm.s;
+		client->old_pmove = pm.s;
+
+		for (i=0 ; i<3 ; i++)
+		{
+			ent->s.origin[i] = pm.s.origin[i]*0.125;
+			ent->velocity[i] = pm.s.velocity[i]*0.125;
+		}
+
+		VectorCopy (pm.mins, ent->mins);
+		VectorCopy (pm.maxs, ent->maxs);
+
+		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
+		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
+		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
+
+		if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
+		{
+			gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
+			PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
+		}
+
+		ent->viewheight = pm.viewheight;
+		ent->waterlevel = pm.waterlevel;
+		ent->watertype = pm.watertype;
+		ent->groundentity = pm.groundentity;
+		if (pm.groundentity)
+			ent->groundentity_linkcount = pm.groundentity->linkcount;
+
+		if (ent->deadflag)
+		{
+			client->ps.viewangles[ROLL] = 40;
+			client->ps.viewangles[PITCH] = -15;
+			client->ps.viewangles[YAW] = client->killer_yaw;
+		}
+		else
+		{
+			VectorCopy (pm.viewangles, client->v_angle);
+			VectorCopy (pm.viewangles, client->ps.viewangles);
+		}
+
+		gi.linkentity (ent);
+
+		if (ent->movetype != MOVETYPE_NOCLIP)
+			G_TouchTriggers (ent);
+
+		// touch other objects
+		for (i=0 ; i<pm.numtouch ; i++)
+		{
+			other = pm.touchents[i];
+			for (j=0 ; j<i ; j++)
+				if (pm.touchents[j] == other)
+					break;
+			if (j != i)
+				continue;	// duplicated
+			if (!other->touch)
+				continue;
+			other->touch (other, ent, NULL, NULL);
+		}
+
+	}
+
+	client->oldbuttons = client->buttons;
+	client->buttons = ucmd->buttons;
+	client->latched_buttons |= client->buttons & ~client->oldbuttons;
+
+	// save light level the player is standing on for
+	// monster sighting AI
+	ent->light_level = ucmd->lightlevel;
+
+	// fire weapon from final position if needed
+	if (client->latched_buttons & BUTTON_ATTACK)
+	{
+		if (client->resp.spectator) {
+
+			client->latched_buttons = 0;
+
+			if (client->chase_target) {
+				client->chase_target = NULL;
+				client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
+			} else
+				GetChaseTarget(ent);
+
+		} else if (!client->weapon_thunk) {
+			client->weapon_thunk = true;
+			Think_Weapon (ent);
+		}
+	}
+
+	if (client->resp.spectator) {
+		if (ucmd->upmove >= 10) {
+			if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD)) {
+				client->ps.pmove.pm_flags |= PMF_JUMP_HELD;
+				if (client->chase_target)
+					ChaseNext(ent);
+				else
+					GetChaseTarget(ent);
+			}
+		} else
+			client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD;
+	}
+
+	// update chase cam if being followed
+	for (i = 1; i <= maxclients->value; i++) {
+		other = g_edicts + i;
+		if (other->inuse && other->client->chase_target == ent)
+			UpdateChaseCam(other);
+	}
+}
+
+
+/*
+==============
+ClientBeginServerFrame
+
+This will be called once for each server frame, before running
+any other entities in the world.
+==============
+*/
+void ClientBeginServerFrame (edict_t *ent)
+{
+	gclient_t	*client;
+	int			buttonMask;
+
+	if (level.intermissiontime)
+		return;
+
+	client = ent->client;
+
+	if (deathmatch->value &&
+		client->pers.spectator != client->resp.spectator &&
+		(level.time - client->respawn_time) >= 5) {
+		spectator_respawn(ent);
+		return;
+	}
+
+	// run weapon animations if it hasn't been done by a ucmd_t
+	if (!client->weapon_thunk && !client->resp.spectator)
+		Think_Weapon (ent);
+	else
+		client->weapon_thunk = false;
+
+	if (ent->deadflag)
+	{
+		// wait for any button just going down
+		if ( level.time > client->respawn_time)
+		{
+			// in deathmatch, only wait for attack button
+			if (deathmatch->value)
+				buttonMask = BUTTON_ATTACK;
+			else
+				buttonMask = -1;
+
+			if ( ( client->latched_buttons & buttonMask ) ||
+				(deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) )
+			{
+				respawn(ent);
+				client->latched_buttons = 0;
+			}
+		}
+		return;
+	}
+
+	// add player trail so monsters can follow
+	if (!deathmatch->value)
+		if (!visible (ent, PlayerTrail_LastSpot() ) )
+			PlayerTrail_Add (ent->s.old_origin);
+
+	client->latched_buttons = 0;
+}
--- /dev/null
+++ b/game/p_hud.c
@@ -1,0 +1,571 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+
+/*
+======================================================================
+
+INTERMISSION
+
+======================================================================
+*/
+
+void MoveClientToIntermission (edict_t *ent)
+{
+	if (deathmatch->value || coop->value)
+		ent->client->showscores = true;
+	VectorCopy (level.intermission_origin, ent->s.origin);
+	ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8;
+	ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8;
+	ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8;
+	VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
+	ent->client->ps.pmove.pm_type = PM_FREEZE;
+	ent->client->ps.gunindex = 0;
+	ent->client->ps.blend[3] = 0;
+	ent->client->ps.rdflags &= ~RDF_UNDERWATER;
+
+	// clean up powerup info
+	ent->client->quad_framenum = 0;
+	ent->client->invincible_framenum = 0;
+	ent->client->breather_framenum = 0;
+	ent->client->enviro_framenum = 0;
+	ent->client->grenade_blew_up = false;
+	ent->client->grenade_time = 0;
+
+	ent->viewheight = 0;
+	ent->s.modelindex = 0;
+	ent->s.modelindex2 = 0;
+	ent->s.modelindex3 = 0;
+	ent->s.modelindex = 0;
+	ent->s.effects = 0;
+	ent->s.sound = 0;
+	ent->solid = SOLID_NOT;
+
+	// add the layout
+
+	if (deathmatch->value || coop->value)
+	{
+		DeathmatchScoreboardMessage (ent, NULL);
+		gi.unicast (ent, true);
+	}
+
+}
+
+void BeginIntermission (edict_t *targ)
+{
+	int		i, n;
+	edict_t	*ent, *client;
+
+	if (level.intermissiontime)
+		return;		// already activated
+
+	game.autosaved = false;
+
+	// respawn any dead clients
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		client = g_edicts + 1 + i;
+		if (!client->inuse)
+			continue;
+		if (client->health <= 0)
+			respawn(client);
+	}
+
+	level.intermissiontime = level.time;
+	level.changemap = targ->map;
+
+	if (strstr(level.changemap, "*"))
+	{
+		if (coop->value)
+		{
+			for (i=0 ; i<maxclients->value ; i++)
+			{
+				client = g_edicts + 1 + i;
+				if (!client->inuse)
+					continue;
+				// strip players of all keys between units
+				for (n = 0; n < MAX_ITEMS; n++)
+				{
+					if (itemlist[n].flags & IT_KEY)
+						client->client->pers.inventory[n] = 0;
+				}
+			}
+		}
+	}
+	else
+	{
+		if (!deathmatch->value)
+		{
+			level.exitintermission = 1;		// go immediately to the next level
+			return;
+		}
+	}
+
+	level.exitintermission = 0;
+
+	// find an intermission spot
+	ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
+	if (!ent)
+	{	// the map creator forgot to put in an intermission point...
+		ent = G_Find (NULL, FOFS(classname), "info_player_start");
+		if (!ent)
+			ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
+	}
+	else
+	{	// chose one of four spots
+		i = rand() & 3;
+		while (i--)
+		{
+			ent = G_Find (ent, FOFS(classname), "info_player_intermission");
+			if (!ent)	// wrap around the list
+				ent = G_Find (ent, FOFS(classname), "info_player_intermission");
+		}
+	}
+
+	VectorCopy (ent->s.origin, level.intermission_origin);
+	VectorCopy (ent->s.angles, level.intermission_angle);
+
+	// move all clients to the intermission point
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		client = g_edicts + 1 + i;
+		if (!client->inuse)
+			continue;
+		MoveClientToIntermission (client);
+	}
+}
+
+
+/*
+==================
+DeathmatchScoreboardMessage
+
+==================
+*/
+void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer)
+{
+	char	entry[1024];
+	char	string[1400];
+	int		stringlength;
+	int		i, j, k;
+	int		sorted[MAX_CLIENTS];
+	int		sortedscores[MAX_CLIENTS];
+	int		score, total;
+	int		picnum;
+	int		x, y;
+	gclient_t	*cl;
+	edict_t		*cl_ent;
+	char	*tag;
+
+	// sort the clients by score
+	total = 0;
+	for (i=0 ; i<game.maxclients ; i++)
+	{
+		cl_ent = g_edicts + 1 + i;
+		if (!cl_ent->inuse || game.clients[i].resp.spectator)
+			continue;
+		score = game.clients[i].resp.score;
+		for (j=0 ; j<total ; j++)
+		{
+			if (score > sortedscores[j])
+				break;
+		}
+		for (k=total ; k>j ; k--)
+		{
+			sorted[k] = sorted[k-1];
+			sortedscores[k] = sortedscores[k-1];
+		}
+		sorted[j] = i;
+		sortedscores[j] = score;
+		total++;
+	}
+
+	// print level name and exit rules
+	string[0] = 0;
+
+	stringlength = strlen(string);
+
+	// add the clients in sorted order
+	if (total > 12)
+		total = 12;
+
+	for (i=0 ; i<total ; i++)
+	{
+		cl = &game.clients[sorted[i]];
+		cl_ent = g_edicts + 1 + sorted[i];
+
+		picnum = gi.imageindex ("i_fixme");
+		x = (i>=6) ? 160 : 0;
+		y = 32 + 32 * (i%6);
+
+		// add a dogtag
+		if (cl_ent == ent)
+			tag = "tag1";
+		else if (cl_ent == killer)
+			tag = "tag2";
+		else
+			tag = NULL;
+		if (tag)
+		{
+			Com_sprintf (entry, sizeof(entry),
+				"xv %i yv %i picn %s ",x+32, y, tag);
+			j = strlen(entry);
+			if (stringlength + j > 1024)
+				break;
+			strcpy (string + stringlength, entry);
+			stringlength += j;
+		}
+
+		// send the layout
+		Com_sprintf (entry, sizeof(entry),
+			"client %i %i %i %i %i %i ",
+			x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe)/600);
+		j = strlen(entry);
+		if (stringlength + j > 1024)
+			break;
+		strcpy (string + stringlength, entry);
+		stringlength += j;
+	}
+
+	gi.WriteByte (svc_layout);
+	gi.WriteString (string);
+}
+
+
+/*
+==================
+DeathmatchScoreboard
+
+Draw instead of help message.
+Note that it isn't that hard to overflow the 1400 byte message limit!
+==================
+*/
+void DeathmatchScoreboard (edict_t *ent)
+{
+	DeathmatchScoreboardMessage (ent, ent->enemy);
+	gi.unicast (ent, true);
+}
+
+
+/*
+==================
+Cmd_Score_f
+
+Display the scoreboard
+==================
+*/
+void Cmd_Score_f (edict_t *ent)
+{
+	ent->client->showinventory = false;
+	ent->client->showhelp = false;
+
+	if (!deathmatch->value && !coop->value)
+		return;
+
+	if (ent->client->showscores)
+	{
+		ent->client->showscores = false;
+		return;
+	}
+
+	ent->client->showscores = true;
+	DeathmatchScoreboard (ent);
+}
+
+
+/*
+==================
+HelpComputer
+
+Draw help computer.
+==================
+*/
+void HelpComputer (edict_t *ent)
+{
+	char	string[1024];
+	char	*sk;
+
+	if (skill->value == 0)
+		sk = "easy";
+	else if (skill->value == 1)
+		sk = "medium";
+	else if (skill->value == 2)
+		sk = "hard";
+	else
+		sk = "hard+";
+
+	// send the layout
+	Com_sprintf (string, sizeof(string),
+		"xv 32 yv 8 picn help "			// background
+		"xv 202 yv 12 string2 \"%s\" "		// skill
+		"xv 0 yv 24 cstring2 \"%s\" "		// level name
+		"xv 0 yv 54 cstring2 \"%s\" "		// help 1
+		"xv 0 yv 110 cstring2 \"%s\" "		// help 2
+		"xv 50 yv 164 string2 \" kills     goals    secrets\" "
+		"xv 50 yv 172 string2 \"%3i/%3i     %i/%i       %i/%i\" ", 
+		sk,
+		level.level_name,
+		game.helpmessage1,
+		game.helpmessage2,
+		level.killed_monsters, level.total_monsters, 
+		level.found_goals, level.total_goals,
+		level.found_secrets, level.total_secrets);
+
+	gi.WriteByte (svc_layout);
+	gi.WriteString (string);
+	gi.unicast (ent, true);
+}
+
+
+/*
+==================
+Cmd_Help_f
+
+Display the current help message
+==================
+*/
+void Cmd_Help_f (edict_t *ent)
+{
+	// this is for backwards compatability
+	if (deathmatch->value)
+	{
+		Cmd_Score_f (ent);
+		return;
+	}
+
+	ent->client->showinventory = false;
+	ent->client->showscores = false;
+
+	if (ent->client->showhelp && (ent->client->pers.game_helpchanged == game.helpchanged))
+	{
+		ent->client->showhelp = false;
+		return;
+	}
+
+	ent->client->showhelp = true;
+	ent->client->pers.helpchanged = 0;
+	HelpComputer (ent);
+}
+
+
+//=======================================================================
+
+/*
+===============
+G_SetStats
+===============
+*/
+void G_SetStats (edict_t *ent)
+{
+	gitem_t		*item;
+	int			index, cells;
+	int			power_armor_type;
+
+	//
+	// health
+	//
+	ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
+	ent->client->ps.stats[STAT_HEALTH] = ent->health;
+
+	//
+	// ammo
+	//
+	if (!ent->client->ammo_index /* || !ent->client->pers.inventory[ent->client->ammo_index] */)
+	{
+		ent->client->ps.stats[STAT_AMMO_ICON] = 0;
+		ent->client->ps.stats[STAT_AMMO] = 0;
+	}
+	else
+	{
+		item = &itemlist[ent->client->ammo_index];
+		ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex (item->icon);
+		ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index];
+	}
+	
+	//
+	// armor
+	//
+	power_armor_type = PowerArmorType (ent);
+	if (power_armor_type)
+	{
+		cells = ent->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
+		if (cells == 0)
+		{	// ran out of cells for power armor
+			ent->flags &= ~FL_POWER_ARMOR;
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
+			power_armor_type = 0;;
+		}
+	}
+
+	index = ArmorIndex (ent);
+	if (power_armor_type && (!index || (level.framenum & 8) ) )
+	{	// flash between power armor and other armor icon
+		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
+		ent->client->ps.stats[STAT_ARMOR] = cells;
+	}
+	else if (index)
+	{
+		item = GetItemByIndex (index);
+		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex (item->icon);
+		ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index];
+	}
+	else
+	{
+		ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
+		ent->client->ps.stats[STAT_ARMOR] = 0;
+	}
+
+	//
+	// pickup message
+	//
+	if (level.time > ent->client->pickup_msg_time)
+	{
+		ent->client->ps.stats[STAT_PICKUP_ICON] = 0;
+		ent->client->ps.stats[STAT_PICKUP_STRING] = 0;
+	}
+
+	//
+	// timers
+	//
+	if (ent->client->quad_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
+	}
+	else if (ent->client->invincible_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_invulnerability");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum)/10;
+	}
+	else if (ent->client->enviro_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_envirosuit");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum)/10;
+	}
+	else if (ent->client->breather_framenum > level.framenum)
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_rebreather");
+		ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum)/10;
+	}
+	else
+	{
+		ent->client->ps.stats[STAT_TIMER_ICON] = 0;
+		ent->client->ps.stats[STAT_TIMER] = 0;
+	}
+
+	//
+	// selected item
+	//
+	if (ent->client->pers.selected_item == -1)
+		ent->client->ps.stats[STAT_SELECTED_ICON] = 0;
+	else
+		ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex (itemlist[ent->client->pers.selected_item].icon);
+
+	ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item;
+
+	//
+	// layouts
+	//
+	ent->client->ps.stats[STAT_LAYOUTS] = 0;
+
+	if (deathmatch->value)
+	{
+		if (ent->client->pers.health <= 0 || level.intermissiontime
+			|| ent->client->showscores)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
+		if (ent->client->showinventory && ent->client->pers.health > 0)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
+	}
+	else
+	{
+		if (ent->client->showscores || ent->client->showhelp)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
+		if (ent->client->showinventory && ent->client->pers.health > 0)
+			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
+	}
+
+	//
+	// frags
+	//
+	ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score;
+
+	//
+	// help icon / current weapon if not shown
+	//
+	if (ent->client->pers.helpchanged && (level.framenum&8) )
+		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex ("i_help");
+	else if ( (ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91)
+		&& ent->client->pers.weapon)
+		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon);
+	else
+		ent->client->ps.stats[STAT_HELPICON] = 0;
+
+	ent->client->ps.stats[STAT_SPECTATOR] = 0;
+}
+
+/*
+===============
+G_CheckChaseStats
+===============
+*/
+void G_CheckChaseStats (edict_t *ent)
+{
+	int i;
+	gclient_t *cl;
+
+	for (i = 1; i <= maxclients->value; i++) {
+		cl = g_edicts[i].client;
+		if (!g_edicts[i].inuse || cl->chase_target != ent)
+			continue;
+		memcpy(cl->ps.stats, ent->client->ps.stats, sizeof(cl->ps.stats));
+		G_SetSpectatorStats(g_edicts + i);
+	}
+}
+
+/*
+===============
+G_SetSpectatorStats
+===============
+*/
+void G_SetSpectatorStats (edict_t *ent)
+{
+	gclient_t *cl = ent->client;
+
+	if (!cl->chase_target)
+		G_SetStats (ent);
+
+	cl->ps.stats[STAT_SPECTATOR] = 1;
+
+	// layouts are independant in spectator
+	cl->ps.stats[STAT_LAYOUTS] = 0;
+	if (cl->pers.health <= 0 || level.intermissiontime || cl->showscores)
+		cl->ps.stats[STAT_LAYOUTS] |= 1;
+	if (cl->showinventory && cl->pers.health > 0)
+		cl->ps.stats[STAT_LAYOUTS] |= 2;
+
+	if (cl->chase_target && cl->chase_target->inuse)
+		cl->ps.stats[STAT_CHASE] = CS_PLAYERSKINS + 
+			(cl->chase_target - g_edicts) - 1;
+	else
+		cl->ps.stats[STAT_CHASE] = 0;
+}
+
--- /dev/null
+++ b/game/p_trail.c
@@ -1,0 +1,146 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+
+
+/*
+==============================================================================
+
+PLAYER TRAIL
+
+==============================================================================
+
+This is a circular list containing the a list of points of where
+the player has been recently.  It is used by monsters for pursuit.
+
+.origin		the spot
+.owner		forward link
+.aiment		backward link
+*/
+
+
+#define	TRAIL_LENGTH	8
+
+edict_t		*trail[TRAIL_LENGTH];
+int			trail_head;
+qboolean	trail_active = false;
+
+#define NEXT(n)		(((n) + 1) & (TRAIL_LENGTH - 1))
+#define PREV(n)		(((n) - 1) & (TRAIL_LENGTH - 1))
+
+
+void PlayerTrail_Init (void)
+{
+	int		n;
+
+	if (deathmatch->value /* FIXME || coop */)
+		return;
+
+	for (n = 0; n < TRAIL_LENGTH; n++)
+	{
+		trail[n] = G_Spawn();
+		trail[n]->classname = "player_trail";
+	}
+
+	trail_head = 0;
+	trail_active = true;
+}
+
+
+void PlayerTrail_Add (vec3_t spot)
+{
+	vec3_t	temp;
+
+	if (!trail_active)
+		return;
+
+	VectorCopy (spot, trail[trail_head]->s.origin);
+
+	trail[trail_head]->timestamp = level.time;
+
+	VectorSubtract (spot, trail[PREV(trail_head)]->s.origin, temp);
+	trail[trail_head]->s.angles[1] = vectoyaw (temp);
+
+	trail_head = NEXT(trail_head);
+}
+
+
+void PlayerTrail_New (vec3_t spot)
+{
+	if (!trail_active)
+		return;
+
+	PlayerTrail_Init ();
+	PlayerTrail_Add (spot);
+}
+
+
+edict_t *PlayerTrail_PickFirst (edict_t *self)
+{
+	int		marker;
+	int		n;
+
+	if (!trail_active)
+		return NULL;
+
+	for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
+	{
+		if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
+			marker = NEXT(marker);
+		else
+			break;
+	}
+
+	if (visible(self, trail[marker]))
+	{
+		return trail[marker];
+	}
+
+	if (visible(self, trail[PREV(marker)]))
+	{
+		return trail[PREV(marker)];
+	}
+
+	return trail[marker];
+}
+
+edict_t *PlayerTrail_PickNext (edict_t *self)
+{
+	int		marker;
+	int		n;
+
+	if (!trail_active)
+		return NULL;
+
+	for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
+	{
+		if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
+			marker = NEXT(marker);
+		else
+			break;
+	}
+
+	return trail[marker];
+}
+
+edict_t *PlayerTrail_LastSpot (void)
+{
+	return trail[PREV(trail_head)];
+}
--- /dev/null
+++ b/game/p_view.c
@@ -1,0 +1,1087 @@
+/*
+Copyright (C) 1997-2001 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 "g_local.h"
+#include "m_player.h"
+
+
+
+static	edict_t		*current_player;
+static	gclient_t	*current_client;
+
+static	vec3_t	forward, right, up;
+float	xyspeed;
+
+float	bobmove;
+int		bobcycle;		// odd cycles are right foot going forward
+float	bobfracsin;		// sin(bobfrac*M_PI)
+
+/*
+===============
+SV_CalcRoll
+
+===============
+*/
+float SV_CalcRoll (vec3_t angles, vec3_t velocity)
+{
+	float	sign;
+	float	side;
+	float	value;
+	
+	side = DotProduct (velocity, right);
+	sign = side < 0 ? -1 : 1;
+	side = fabs(side);
+	
+	value = sv_rollangle->value;
+
+	if (side < sv_rollspeed->value)
+		side = side * value / sv_rollspeed->value;
+	else
+		side = value;
+	
+	return side*sign;
+	
+}
+
+
+/*
+===============
+P_DamageFeedback
+
+Handles color blends and view kicks
+===============
+*/
+void P_DamageFeedback (edict_t *player)
+{
+	gclient_t	*client;
+	float	side;
+	float	realcount, count, kick;
+	vec3_t	v;
+	int		r, l;
+	static	vec3_t	power_color = {0.0, 1.0, 0.0};
+	static	vec3_t	acolor = {1.0, 1.0, 1.0};
+	static	vec3_t	bcolor = {1.0, 0.0, 0.0};
+
+	client = player->client;
+
+	// flash the backgrounds behind the status numbers
+	client->ps.stats[STAT_FLASHES] = 0;
+	if (client->damage_blood)
+		client->ps.stats[STAT_FLASHES] |= 1;
+	if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
+		client->ps.stats[STAT_FLASHES] |= 2;
+
+	// total points of damage shot at the player this frame
+	count = (client->damage_blood + client->damage_armor + client->damage_parmor);
+	if (count == 0)
+		return;		// didn't take any damage
+
+	// start a pain animation if still in the player model
+	if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255)
+	{
+		static int		i;
+
+		client->anim_priority = ANIM_PAIN;
+		if (client->ps.pmove.pm_flags & PMF_DUCKED)
+		{
+			player->s.frame = FRAME_crpain1-1;
+			client->anim_end = FRAME_crpain4;
+		}
+		else
+		{
+			i = (i+1)%3;
+			switch (i)
+			{
+			case 0:
+				player->s.frame = FRAME_pain101-1;
+				client->anim_end = FRAME_pain104;
+				break;
+			case 1:
+				player->s.frame = FRAME_pain201-1;
+				client->anim_end = FRAME_pain204;
+				break;
+			case 2:
+				player->s.frame = FRAME_pain301-1;
+				client->anim_end = FRAME_pain304;
+				break;
+			}
+		}
+	}
+
+	realcount = count;
+	if (count < 10)
+		count = 10;	// always make a visible effect
+
+	// play an apropriate pain sound
+	if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
+	{
+		r = 1 + (rand()&1);
+		player->pain_debounce_time = level.time + 0.7;
+		if (player->health < 25)
+			l = 25;
+		else if (player->health < 50)
+			l = 50;
+		else if (player->health < 75)
+			l = 75;
+		else
+			l = 100;
+		gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
+	}
+
+	// the total alpha of the blend is always proportional to count
+	if (client->damage_alpha < 0)
+		client->damage_alpha = 0;
+	client->damage_alpha += count*0.01;
+	if (client->damage_alpha < 0.2)
+		client->damage_alpha = 0.2;
+	if (client->damage_alpha > 0.6)
+		client->damage_alpha = 0.6;		// don't go too saturated
+
+	// the color of the blend will vary based on how much was absorbed
+	// by different armors
+	VectorClear (v);
+	if (client->damage_parmor)
+		VectorMA (v, (float)client->damage_parmor/realcount, power_color, v);
+	if (client->damage_armor)
+		VectorMA (v, (float)client->damage_armor/realcount,  acolor, v);
+	if (client->damage_blood)
+		VectorMA (v, (float)client->damage_blood/realcount,  bcolor, v);
+	VectorCopy (v, client->damage_blend);
+
+
+	//
+	// calculate view angle kicks
+	//
+	kick = abs(client->damage_knockback);
+	if (kick && player->health > 0)	// kick of 0 means no view adjust at all
+	{
+		kick = kick * 100 / player->health;
+
+		if (kick < count*0.5)
+			kick = count*0.5;
+		if (kick > 50)
+			kick = 50;
+
+		VectorSubtract (client->damage_from, player->s.origin, v);
+		VectorNormalize (v);
+		
+		side = DotProduct (v, right);
+		client->v_dmg_roll = kick*side*0.3;
+		
+		side = -DotProduct (v, forward);
+		client->v_dmg_pitch = kick*side*0.3;
+
+		client->v_dmg_time = level.time + DAMAGE_TIME;
+	}
+
+	//
+	// clear totals
+	//
+	client->damage_blood = 0;
+	client->damage_armor = 0;
+	client->damage_parmor = 0;
+	client->damage_knockback = 0;
+}
+
+
+
+
+/*
+===============
+SV_CalcViewOffset
+
+Auto pitching on slopes?
+
+  fall from 128: 400 = 160000
+  fall from 256: 580 = 336400
+  fall from 384: 720 = 518400
+  fall from 512: 800 = 640000
+  fall from 640: 960 = 
+
+  damage = deltavelocity*deltavelocity  * 0.0001
+
+===============
+*/
+void SV_CalcViewOffset (edict_t *ent)
+{
+	float		*angles;
+	float		bob;
+	float		ratio;
+	float		delta;
+	vec3_t		v;
+
+
+//===================================
+
+	// base angles
+	angles = ent->client->ps.kick_angles;
+
+	// if dead, fix the angle and don't add any kick
+	if (ent->deadflag)
+	{
+		VectorClear (angles);
+
+		ent->client->ps.viewangles[ROLL] = 40;
+		ent->client->ps.viewangles[PITCH] = -15;
+		ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
+	}
+	else
+	{
+		// add angles based on weapon kick
+
+		VectorCopy (ent->client->kick_angles, angles);
+
+		// add angles based on damage kick
+
+		ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME;
+		if (ratio < 0)
+		{
+			ratio = 0;
+			ent->client->v_dmg_pitch = 0;
+			ent->client->v_dmg_roll = 0;
+		}
+		angles[PITCH] += ratio * ent->client->v_dmg_pitch;
+		angles[ROLL] += ratio * ent->client->v_dmg_roll;
+
+		// add pitch based on fall kick
+
+		ratio = (ent->client->fall_time - level.time) / FALL_TIME;
+		if (ratio < 0)
+			ratio = 0;
+		angles[PITCH] += ratio * ent->client->fall_value;
+
+		// add angles based on velocity
+
+		delta = DotProduct (ent->velocity, forward);
+		angles[PITCH] += delta*run_pitch->value;
+		
+		delta = DotProduct (ent->velocity, right);
+		angles[ROLL] += delta*run_roll->value;
+
+		// add angles based on bob
+
+		delta = bobfracsin * bob_pitch->value * xyspeed;
+		if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			delta *= 6;		// crouching
+		angles[PITCH] += delta;
+		delta = bobfracsin * bob_roll->value * xyspeed;
+		if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			delta *= 6;		// crouching
+		if (bobcycle & 1)
+			delta = -delta;
+		angles[ROLL] += delta;
+	}
+
+//===================================
+
+	// base origin
+
+	VectorClear (v);
+
+	// add view height
+
+	v[2] += ent->viewheight;
+
+	// add fall height
+
+	ratio = (ent->client->fall_time - level.time) / FALL_TIME;
+	if (ratio < 0)
+		ratio = 0;
+	v[2] -= ratio * ent->client->fall_value * 0.4;
+
+	// add bob height
+
+	bob = bobfracsin * xyspeed * bob_up->value;
+	if (bob > 6)
+		bob = 6;
+	//gi.DebugGraph (bob *2, 255);
+	v[2] += bob;
+
+	// add kick offset
+
+	VectorAdd (v, ent->client->kick_origin, v);
+
+	// absolutely bound offsets
+	// so the view can never be outside the player box
+
+	if (v[0] < -14)
+		v[0] = -14;
+	else if (v[0] > 14)
+		v[0] = 14;
+	if (v[1] < -14)
+		v[1] = -14;
+	else if (v[1] > 14)
+		v[1] = 14;
+	if (v[2] < -22)
+		v[2] = -22;
+	else if (v[2] > 30)
+		v[2] = 30;
+
+	VectorCopy (v, ent->client->ps.viewoffset);
+}
+
+/*
+==============
+SV_CalcGunOffset
+==============
+*/
+void SV_CalcGunOffset (edict_t *ent)
+{
+	int		i;
+	float	delta;
+
+	// gun angles from bobbing
+	ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
+	ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
+	if (bobcycle & 1)
+	{
+		ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
+		ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
+	}
+
+	ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
+
+	// gun angles from delta movement
+	for (i=0 ; i<3 ; i++)
+	{
+		delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
+		if (delta > 180)
+			delta -= 360;
+		if (delta < -180)
+			delta += 360;
+		if (delta > 45)
+			delta = 45;
+		if (delta < -45)
+			delta = -45;
+		if (i == YAW)
+			ent->client->ps.gunangles[ROLL] += 0.1*delta;
+		ent->client->ps.gunangles[i] += 0.2 * delta;
+	}
+
+	// gun height
+	VectorClear (ent->client->ps.gunoffset);
+//	ent->ps->gunorigin[2] += bob;
+
+	// gun_x / gun_y / gun_z are development tools
+	for (i=0 ; i<3 ; i++)
+	{
+		ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value);
+		ent->client->ps.gunoffset[i] += right[i]*gun_x->value;
+		ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value);
+	}
+}
+
+
+/*
+=============
+SV_AddBlend
+=============
+*/
+void SV_AddBlend (float r, float g, float b, float a, float *v_blend)
+{
+	float	a2, a3;
+
+	if (a <= 0)
+		return;
+	a2 = v_blend[3] + (1-v_blend[3])*a;	// new total alpha
+	a3 = v_blend[3]/a2;		// fraction of color from old
+
+	v_blend[0] = v_blend[0]*a3 + r*(1-a3);
+	v_blend[1] = v_blend[1]*a3 + g*(1-a3);
+	v_blend[2] = v_blend[2]*a3 + b*(1-a3);
+	v_blend[3] = a2;
+}
+
+
+/*
+=============
+SV_CalcBlend
+=============
+*/
+void SV_CalcBlend (edict_t *ent)
+{
+	int		contents;
+	vec3_t	vieworg;
+	int		remaining;
+
+	ent->client->ps.blend[0] = ent->client->ps.blend[1] = 
+		ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0;
+
+	// add for contents
+	VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg);
+	contents = gi.pointcontents (vieworg);
+	if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
+		ent->client->ps.rdflags |= RDF_UNDERWATER;
+	else
+		ent->client->ps.rdflags &= ~RDF_UNDERWATER;
+
+	if (contents & (CONTENTS_SOLID|CONTENTS_LAVA))
+		SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend);
+	else if (contents & CONTENTS_SLIME)
+		SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend);
+	else if (contents & CONTENTS_WATER)
+		SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend);
+
+	// add for powerups
+	if (ent->client->quad_framenum > level.framenum)
+	{
+		remaining = ent->client->quad_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
+	}
+	else if (ent->client->invincible_framenum > level.framenum)
+	{
+		remaining = ent->client->invincible_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend);
+	}
+	else if (ent->client->enviro_framenum > level.framenum)
+	{
+		remaining = ent->client->enviro_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend);
+	}
+	else if (ent->client->breather_framenum > level.framenum)
+	{
+		remaining = ent->client->breather_framenum - level.framenum;
+		if (remaining == 30)	// beginning to fade
+			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
+		if (remaining > 30 || (remaining & 4) )
+			SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend);
+	}
+
+	// add for damage
+	if (ent->client->damage_alpha > 0)
+		SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1]
+		,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend);
+
+	if (ent->client->bonus_alpha > 0)
+		SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend);
+
+	// drop the damage value
+	ent->client->damage_alpha -= 0.06;
+	if (ent->client->damage_alpha < 0)
+		ent->client->damage_alpha = 0;
+
+	// drop the bonus value
+	ent->client->bonus_alpha -= 0.1;
+	if (ent->client->bonus_alpha < 0)
+		ent->client->bonus_alpha = 0;
+}
+
+
+/*
+=================
+P_FallingDamage
+=================
+*/
+void P_FallingDamage (edict_t *ent)
+{
+	float	delta;
+	int		damage;
+	vec3_t	dir;
+
+	if (ent->s.modelindex != 255)
+		return;		// not in the player model
+
+	if (ent->movetype == MOVETYPE_NOCLIP)
+		return;
+
+	if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity))
+	{
+		delta = ent->client->oldvelocity[2];
+	}
+	else
+	{
+		if (!ent->groundentity)
+			return;
+		delta = ent->velocity[2] - ent->client->oldvelocity[2];
+	}
+	delta = delta*delta * 0.0001;
+
+	// never take falling damage if completely underwater
+	if (ent->waterlevel == 3)
+		return;
+	if (ent->waterlevel == 2)
+		delta *= 0.25;
+	if (ent->waterlevel == 1)
+		delta *= 0.5;
+
+	if (delta < 1)
+		return;
+
+	if (delta < 15)
+	{
+		ent->s.event = EV_FOOTSTEP;
+		return;
+	}
+
+	ent->client->fall_value = delta*0.5;
+	if (ent->client->fall_value > 40)
+		ent->client->fall_value = 40;
+	ent->client->fall_time = level.time + FALL_TIME;
+
+	if (delta > 30)
+	{
+		if (ent->health > 0)
+		{
+			if (delta >= 55)
+				ent->s.event = EV_FALLFAR;
+			else
+				ent->s.event = EV_FALL;
+		}
+		ent->pain_debounce_time = level.time;	// no normal pain sound
+		damage = (delta-30)/2;
+		if (damage < 1)
+			damage = 1;
+		VectorSet (dir, 0, 0, 1);
+
+		if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) )
+			T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
+	}
+	else
+	{
+		ent->s.event = EV_FALLSHORT;
+		return;
+	}
+}
+
+
+
+/*
+=============
+P_WorldEffects
+=============
+*/
+void P_WorldEffects (void)
+{
+	qboolean	breather;
+	qboolean	envirosuit;
+	int			waterlevel, old_waterlevel;
+
+	if (current_player->movetype == MOVETYPE_NOCLIP)
+	{
+		current_player->air_finished = level.time + 12;	// don't need air
+		return;
+	}
+
+	waterlevel = current_player->waterlevel;
+	old_waterlevel = current_client->old_waterlevel;
+	current_client->old_waterlevel = waterlevel;
+
+	breather = current_client->breather_framenum > level.framenum;
+	envirosuit = current_client->enviro_framenum > level.framenum;
+
+	//
+	// if just entered a water volume, play a sound
+	//
+	if (!old_waterlevel && waterlevel)
+	{
+		PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+		if (current_player->watertype & CONTENTS_LAVA)
+			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
+		else if (current_player->watertype & CONTENTS_SLIME)
+			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+		else if (current_player->watertype & CONTENTS_WATER)
+			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+		current_player->flags |= FL_INWATER;
+
+		// clear damage_debounce, so the pain sound will play immediately
+		current_player->damage_debounce_time = level.time - 1;
+	}
+
+	//
+	// if just completely exited a water volume, play a sound
+	//
+	if (old_waterlevel && ! waterlevel)
+	{
+		PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+		gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
+		current_player->flags &= ~FL_INWATER;
+	}
+
+	//
+	// check for head just going under water
+	//
+	if (old_waterlevel != 3 && waterlevel == 3)
+	{
+		gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
+	}
+
+	//
+	// check for head just coming out of water
+	//
+	if (old_waterlevel == 3 && waterlevel != 3)
+	{
+		if (current_player->air_finished < level.time)
+		{	// gasp for air
+			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
+			PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+		}
+		else  if (current_player->air_finished < level.time + 11)
+		{	// just break surface
+			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
+		}
+	}
+
+	//
+	// check for drowning
+	//
+	if (waterlevel == 3)
+	{
+		// breather or envirosuit give air
+		if (breather || envirosuit)
+		{
+			current_player->air_finished = level.time + 10;
+
+			if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
+			{
+				if (!current_client->breather_sound)
+					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
+				current_client->breather_sound ^= 1;
+				PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
+				//FIXME: release a bubble?
+			}
+		}
+
+		// if out of air, start drowning
+		if (current_player->air_finished < level.time)
+		{	// drown!
+			if (current_player->client->next_drown_time < level.time 
+				&& current_player->health > 0)
+			{
+				current_player->client->next_drown_time = level.time + 1;
+
+				// take more damage the longer underwater
+				current_player->dmg += 2;
+				if (current_player->dmg > 15)
+					current_player->dmg = 15;
+
+				// play a gurp sound instead of a normal pain sound
+				if (current_player->health <= current_player->dmg)
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
+				else if (rand()&1)
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
+
+				current_player->pain_debounce_time = level.time;
+
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
+			}
+		}
+	}
+	else
+	{
+		current_player->air_finished = level.time + 12;
+		current_player->dmg = 2;
+	}
+
+	//
+	// check for sizzle damage
+	//
+	if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
+	{
+		if (current_player->watertype & CONTENTS_LAVA)
+		{
+			if (current_player->health > 0
+				&& current_player->pain_debounce_time <= level.time
+				&& current_client->invincible_framenum < level.framenum)
+			{
+				if (rand()&1)
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
+				else
+					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
+				current_player->pain_debounce_time = level.time + 1;
+			}
+
+			if (envirosuit)	// take 1/3 damage with envirosuit
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
+			else
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
+		}
+
+		if (current_player->watertype & CONTENTS_SLIME)
+		{
+			if (!envirosuit)
+			{	// no damage from slime with envirosuit
+				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
+			}
+		}
+	}
+}
+
+
+/*
+===============
+G_SetClientEffects
+===============
+*/
+void G_SetClientEffects (edict_t *ent)
+{
+	int		pa_type;
+	int		remaining;
+
+	ent->s.effects = 0;
+	ent->s.renderfx = 0;
+
+	if (ent->health <= 0 || level.intermissiontime)
+		return;
+
+	if (ent->powerarmor_time > level.time)
+	{
+		pa_type = PowerArmorType (ent);
+		if (pa_type == POWER_ARMOR_SCREEN)
+		{
+			ent->s.effects |= EF_POWERSCREEN;
+		}
+		else if (pa_type == POWER_ARMOR_SHIELD)
+		{
+			ent->s.effects |= EF_COLOR_SHELL;
+			ent->s.renderfx |= RF_SHELL_GREEN;
+		}
+	}
+
+	if (ent->client->quad_framenum > level.framenum)
+	{
+		remaining = ent->client->quad_framenum - level.framenum;
+		if (remaining > 30 || (remaining & 4) )
+			ent->s.effects |= EF_QUAD;
+	}
+
+	if (ent->client->invincible_framenum > level.framenum)
+	{
+		remaining = ent->client->invincible_framenum - level.framenum;
+		if (remaining > 30 || (remaining & 4) )
+			ent->s.effects |= EF_PENT;
+	}
+
+	// show cheaters!!!
+	if (ent->flags & FL_GODMODE)
+	{
+		ent->s.effects |= EF_COLOR_SHELL;
+		ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
+	}
+}
+
+
+/*
+===============
+G_SetClientEvent
+===============
+*/
+void G_SetClientEvent (edict_t *ent)
+{
+	if (ent->s.event)
+		return;
+
+	if ( ent->groundentity && xyspeed > 225)
+	{
+		if ( (int)(current_client->bobtime+bobmove) != bobcycle )
+			ent->s.event = EV_FOOTSTEP;
+	}
+}
+
+/*
+===============
+G_SetClientSound
+===============
+*/
+void G_SetClientSound (edict_t *ent)
+{
+	char	*weap;
+
+	if (ent->client->pers.game_helpchanged != game.helpchanged)
+	{
+		ent->client->pers.game_helpchanged = game.helpchanged;
+		ent->client->pers.helpchanged = 1;
+	}
+
+	// help beep (no more than three times)
+	if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum&63) )
+	{
+		ent->client->pers.helpchanged++;
+		gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
+	}
+
+
+	if (ent->client->pers.weapon)
+		weap = ent->client->pers.weapon->classname;
+	else
+		weap = "";
+
+	if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
+		ent->s.sound = snd_fry;
+	else if (strcmp(weap, "weapon_railgun") == 0)
+		ent->s.sound = gi.soundindex("weapons/rg_hum.wav");
+	else if (strcmp(weap, "weapon_bfg") == 0)
+		ent->s.sound = gi.soundindex("weapons/bfg_hum.wav");
+	else if (ent->client->weapon_sound)
+		ent->s.sound = ent->client->weapon_sound;
+	else
+		ent->s.sound = 0;
+}
+
+/*
+===============
+G_SetClientFrame
+===============
+*/
+void G_SetClientFrame (edict_t *ent)
+{
+	gclient_t	*client;
+	qboolean	duck, run;
+
+	if (ent->s.modelindex != 255)
+		return;		// not in the player model
+
+	client = ent->client;
+
+	if (client->ps.pmove.pm_flags & PMF_DUCKED)
+		duck = true;
+	else
+		duck = false;
+	if (xyspeed)
+		run = true;
+	else
+		run = false;
+
+	// check for stand/duck and stop/go transitions
+	if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH)
+		goto newanim;
+	if (run != client->anim_run && client->anim_priority == ANIM_BASIC)
+		goto newanim;
+	if (!ent->groundentity && client->anim_priority <= ANIM_WAVE)
+		goto newanim;
+
+	if(client->anim_priority == ANIM_REVERSE)
+	{
+		if(ent->s.frame > client->anim_end)
+		{
+			ent->s.frame--;
+			return;
+		}
+	}
+	else if (ent->s.frame < client->anim_end)
+	{	// continue an animation
+		ent->s.frame++;
+		return;
+	}
+
+	if (client->anim_priority == ANIM_DEATH)
+		return;		// stay there
+	if (client->anim_priority == ANIM_JUMP)
+	{
+		if (!ent->groundentity)
+			return;		// stay there
+		ent->client->anim_priority = ANIM_WAVE;
+		ent->s.frame = FRAME_jump3;
+		ent->client->anim_end = FRAME_jump6;
+		return;
+	}
+
+newanim:
+	// return to either a running or standing frame
+	client->anim_priority = ANIM_BASIC;
+	client->anim_duck = duck;
+	client->anim_run = run;
+
+	if (!ent->groundentity)
+	{
+		client->anim_priority = ANIM_JUMP;
+		if (ent->s.frame != FRAME_jump2)
+			ent->s.frame = FRAME_jump1;
+		client->anim_end = FRAME_jump2;
+	}
+	else if (run)
+	{	// running
+		if (duck)
+		{
+			ent->s.frame = FRAME_crwalk1;
+			client->anim_end = FRAME_crwalk6;
+		}
+		else
+		{
+			ent->s.frame = FRAME_run1;
+			client->anim_end = FRAME_run6;
+		}
+	}
+	else
+	{	// standing
+		if (duck)
+		{
+			ent->s.frame = FRAME_crstnd01;
+			client->anim_end = FRAME_crstnd19;
+		}
+		else
+		{
+			ent->s.frame = FRAME_stand01;
+			client->anim_end = FRAME_stand40;
+		}
+	}
+}
+
+
+/*
+=================
+ClientEndServerFrame
+
+Called for each player at the end of the server frame
+and right after spawning
+=================
+*/
+void ClientEndServerFrame (edict_t *ent)
+{
+	float	bobtime;
+	int		i;
+
+	current_player = ent;
+	current_client = ent->client;
+
+	//
+	// If the origin or velocity have changed since ClientThink(),
+	// update the pmove values.  This will happen when the client
+	// is pushed by a bmodel or kicked by an explosion.
+	// 
+	// If it wasn't updated here, the view position would lag a frame
+	// behind the body position when pushed -- "sinking into plats"
+	//
+	for (i=0 ; i<3 ; i++)
+	{
+		current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
+		current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
+	}
+
+	//
+	// If the end of unit layout is displayed, don't give
+	// the player any normal movement attributes
+	//
+	if (level.intermissiontime)
+	{
+		// FIXME: add view drifting here?
+		current_client->ps.blend[3] = 0;
+		current_client->ps.fov = 90;
+		G_SetStats (ent);
+		return;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, up);
+
+	// burn from lava, etc
+	P_WorldEffects ();
+
+	//
+	// set model angles from view angles so other things in
+	// the world can tell which direction you are looking
+	//
+	if (ent->client->v_angle[PITCH] > 180)
+		ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
+	else
+		ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
+	ent->s.angles[YAW] = ent->client->v_angle[YAW];
+	ent->s.angles[ROLL] = 0;
+	ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;
+
+	//
+	// calculate speed and cycle to be used for
+	// all cyclic walking effects
+	//
+	xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);
+
+	if (xyspeed < 5)
+	{
+		bobmove = 0;
+		current_client->bobtime = 0;	// start at beginning of cycle again
+	}
+	else if (ent->groundentity)
+	{	// so bobbing only cycles when on ground
+		if (xyspeed > 210)
+			bobmove = 0.25;
+		else if (xyspeed > 100)
+			bobmove = 0.125;
+		else
+			bobmove = 0.0625;
+	}
+	
+	bobtime = (current_client->bobtime += bobmove);
+
+	if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
+		bobtime *= 4;
+
+	bobcycle = (int)bobtime;
+	bobfracsin = fabs(sin(bobtime*M_PI));
+
+	// detect hitting the floor
+	P_FallingDamage (ent);
+
+	// apply all the damage taken this frame
+	P_DamageFeedback (ent);
+
+	// determine the view offsets
+	SV_CalcViewOffset (ent);
+
+	// determine the gun offsets
+	SV_CalcGunOffset (ent);
+
+	// determine the full screen color blend
+	// must be after viewoffset, so eye contents can be
+	// accurately determined
+	// FIXME: with client prediction, the contents
+	// should be determined by the client
+	SV_CalcBlend (ent);
+
+	// chase cam stuff
+	if (ent->client->resp.spectator)
+		G_SetSpectatorStats(ent);
+	else
+		G_SetStats (ent);
+	G_CheckChaseStats(ent);
+
+	G_SetClientEvent (ent);
+
+	G_SetClientEffects (ent);
+
+	G_SetClientSound (ent);
+
+	G_SetClientFrame (ent);
+
+	VectorCopy (ent->velocity, ent->client->oldvelocity);
+	VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);
+
+	// clear weapon kicks
+	VectorClear (ent->client->kick_origin);
+	VectorClear (ent->client->kick_angles);
+
+	// if the scoreboard is up, update it
+	if (ent->client->showscores && !(level.framenum & 31) )
+	{
+		DeathmatchScoreboardMessage (ent, ent->enemy);
+		gi.unicast (ent, false);
+	}
+}
+
--- /dev/null
+++ b/game/p_weapon.c
@@ -1,0 +1,1434 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// g_weapon.c
+
+#include "g_local.h"
+#include "m_player.h"
+
+
+static qboolean	is_quad;
+static byte		is_silenced;
+
+
+void weapon_grenade_fire (edict_t *ent, qboolean held);
+
+
+static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
+{
+	vec3_t	_distance;
+
+	VectorCopy (distance, _distance);
+	if (client->pers.hand == LEFT_HANDED)
+		_distance[1] *= -1;
+	else if (client->pers.hand == CENTER_HANDED)
+		_distance[1] = 0;
+	G_ProjectSource (point, _distance, forward, right, result);
+}
+
+
+/*
+===============
+PlayerNoise
+
+Each player can have two noise objects associated with it:
+a personal noise (jumping, pain, weapon firing), and a weapon
+target noise (bullet wall impacts)
+
+Monsters that don't directly see the player can move
+to a noise in hopes of seeing the player from there.
+===============
+*/
+void PlayerNoise(edict_t *who, vec3_t where, int type)
+{
+	edict_t		*noise;
+
+	if (type == PNOISE_WEAPON)
+	{
+		if (who->client->silencer_shots)
+		{
+			who->client->silencer_shots--;
+			return;
+		}
+	}
+
+	if (deathmatch->value)
+		return;
+
+	if (who->flags & FL_NOTARGET)
+		return;
+
+
+	if (!who->mynoise)
+	{
+		noise = G_Spawn();
+		noise->classname = "player_noise";
+		VectorSet (noise->mins, -8, -8, -8);
+		VectorSet (noise->maxs, 8, 8, 8);
+		noise->owner = who;
+		noise->svflags = SVF_NOCLIENT;
+		who->mynoise = noise;
+
+		noise = G_Spawn();
+		noise->classname = "player_noise";
+		VectorSet (noise->mins, -8, -8, -8);
+		VectorSet (noise->maxs, 8, 8, 8);
+		noise->owner = who;
+		noise->svflags = SVF_NOCLIENT;
+		who->mynoise2 = noise;
+	}
+
+	if (type == PNOISE_SELF || type == PNOISE_WEAPON)
+	{
+		noise = who->mynoise;
+		level.sound_entity = noise;
+		level.sound_entity_framenum = level.framenum;
+	}
+	else // type == PNOISE_IMPACT
+	{
+		noise = who->mynoise2;
+		level.sound2_entity = noise;
+		level.sound2_entity_framenum = level.framenum;
+	}
+
+	VectorCopy (where, noise->s.origin);
+	VectorSubtract (where, noise->maxs, noise->absmin);
+	VectorAdd (where, noise->maxs, noise->absmax);
+	noise->teleport_time = level.time;
+	gi.linkentity (noise);
+}
+
+
+qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
+{
+	int			index;
+	gitem_t		*ammo;
+
+	index = ITEM_INDEX(ent->item);
+
+	if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) 
+		&& other->client->pers.inventory[index])
+	{
+		if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
+			return false;	// leave the weapon for others to pickup
+	}
+
+	other->client->pers.inventory[index]++;
+
+	if (!(ent->spawnflags & DROPPED_ITEM) )
+	{
+		// give them some ammo with it
+		ammo = FindItem (ent->item->ammo);
+		if ( (int)dmflags->value & DF_INFINITE_AMMO )
+			Add_Ammo (other, ammo, 1000);
+		else
+			Add_Ammo (other, ammo, ammo->quantity);
+
+		if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
+		{
+			if (deathmatch->value)
+			{
+				if ((int)(dmflags->value) & DF_WEAPONS_STAY)
+					ent->flags |= FL_RESPAWN;
+				else
+					SetRespawn (ent, 30);
+			}
+			if (coop->value)
+				ent->flags |= FL_RESPAWN;
+		}
+	}
+
+	if (other->client->pers.weapon != ent->item && 
+		(other->client->pers.inventory[index] == 1) &&
+		( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
+		other->client->newweapon = ent->item;
+
+	return true;
+}
+
+
+/*
+===============
+ChangeWeapon
+
+The old weapon has been dropped all the way, so make the new one
+current
+===============
+*/
+void ChangeWeapon (edict_t *ent)
+{
+	int i;
+
+	if (ent->client->grenade_time)
+	{
+		ent->client->grenade_time = level.time;
+		ent->client->weapon_sound = 0;
+		weapon_grenade_fire (ent, false);
+		ent->client->grenade_time = 0;
+	}
+
+	ent->client->pers.lastweapon = ent->client->pers.weapon;
+	ent->client->pers.weapon = ent->client->newweapon;
+	ent->client->newweapon = NULL;
+	ent->client->machinegun_shots = 0;
+
+	// set visible model
+	if (ent->s.modelindex == 255) {
+		if (ent->client->pers.weapon)
+			i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
+		else
+			i = 0;
+		ent->s.skinnum = (ent - g_edicts - 1) | i;
+	}
+
+	if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
+		ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
+	else
+		ent->client->ammo_index = 0;
+
+	if (!ent->client->pers.weapon)
+	{	// dead
+		ent->client->ps.gunindex = 0;
+		return;
+	}
+
+	ent->client->weaponstate = WEAPON_ACTIVATING;
+	ent->client->ps.gunframe = 0;
+	ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
+
+	ent->client->anim_priority = ANIM_PAIN;
+	if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+			ent->s.frame = FRAME_crpain1;
+			ent->client->anim_end = FRAME_crpain4;
+	}
+	else
+	{
+			ent->s.frame = FRAME_pain301;
+			ent->client->anim_end = FRAME_pain304;
+			
+	}
+}
+
+/*
+=================
+NoAmmoWeaponChange
+=================
+*/
+void NoAmmoWeaponChange (edict_t *ent)
+{
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
+	{
+		ent->client->newweapon = FindItem ("railgun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
+	{
+		ent->client->newweapon = FindItem ("hyperblaster");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
+	{
+		ent->client->newweapon = FindItem ("chaingun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
+	{
+		ent->client->newweapon = FindItem ("machinegun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
+	{
+		ent->client->newweapon = FindItem ("super shotgun");
+		return;
+	}
+	if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
+		&&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
+	{
+		ent->client->newweapon = FindItem ("shotgun");
+		return;
+	}
+	ent->client->newweapon = FindItem ("blaster");
+}
+
+/*
+=================
+Think_Weapon
+
+Called by ClientBeginServerFrame and ClientThink
+=================
+*/
+void Think_Weapon (edict_t *ent)
+{
+	// if just died, put the weapon away
+	if (ent->health < 1)
+	{
+		ent->client->newweapon = NULL;
+		ChangeWeapon (ent);
+	}
+
+	// call active weapon think routine
+	if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
+	{
+		is_quad = (ent->client->quad_framenum > level.framenum);
+		if (ent->client->silencer_shots)
+			is_silenced = MZ_SILENCED;
+		else
+			is_silenced = 0;
+		ent->client->pers.weapon->weaponthink (ent);
+	}
+}
+
+
+/*
+================
+Use_Weapon
+
+Make the weapon ready if there is ammo
+================
+*/
+void Use_Weapon (edict_t *ent, gitem_t *item)
+{
+	int			ammo_index;
+	gitem_t		*ammo_item;
+
+	// see if we're already using it
+	if (item == ent->client->pers.weapon)
+		return;
+
+	if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
+	{
+		ammo_item = FindItem(item->ammo);
+		ammo_index = ITEM_INDEX(ammo_item);
+
+		if (!ent->client->pers.inventory[ammo_index])
+		{
+			gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
+			return;
+		}
+
+		if (ent->client->pers.inventory[ammo_index] < item->quantity)
+		{
+			gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
+			return;
+		}
+	}
+
+	// change to this weapon when down
+	ent->client->newweapon = item;
+}
+
+
+
+/*
+================
+Drop_Weapon
+================
+*/
+void Drop_Weapon (edict_t *ent, gitem_t *item)
+{
+	int		index;
+
+	if ((int)(dmflags->value) & DF_WEAPONS_STAY)
+		return;
+
+	index = ITEM_INDEX(item);
+	// see if we're already using it
+	if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
+	{
+		gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
+		return;
+	}
+
+	Drop_Item (ent, item);
+	ent->client->pers.inventory[index]--;
+}
+
+
+/*
+================
+Weapon_Generic
+
+A generic function to handle the basics of weapon thinking
+================
+*/
+#define FRAME_FIRE_FIRST		(FRAME_ACTIVATE_LAST + 1)
+#define FRAME_IDLE_FIRST		(FRAME_FIRE_LAST + 1)
+#define FRAME_DEACTIVATE_FIRST	(FRAME_IDLE_LAST + 1)
+
+void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
+{
+	int		n;
+
+	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
+	{
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_DROPPING)
+	{
+		if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
+		{
+			ChangeWeapon (ent);
+			return;
+		}
+		else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
+		{
+			ent->client->anim_priority = ANIM_REVERSE;
+			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				ent->s.frame = FRAME_crpain4+1;
+				ent->client->anim_end = FRAME_crpain1;
+			}
+			else
+			{
+				ent->s.frame = FRAME_pain304+1;
+				ent->client->anim_end = FRAME_pain301;
+				
+			}
+		}
+
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_ACTIVATING)
+	{
+		if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
+		{
+			ent->client->weaponstate = WEAPON_READY;
+			ent->client->ps.gunframe = FRAME_IDLE_FIRST;
+			return;
+		}
+
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
+	{
+		ent->client->weaponstate = WEAPON_DROPPING;
+		ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
+
+		if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
+		{
+			ent->client->anim_priority = ANIM_REVERSE;
+			if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				ent->s.frame = FRAME_crpain4+1;
+				ent->client->anim_end = FRAME_crpain1;
+			}
+			else
+			{
+				ent->s.frame = FRAME_pain304+1;
+				ent->client->anim_end = FRAME_pain301;
+				
+			}
+		}
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_READY)
+	{
+		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
+		{
+			ent->client->latched_buttons &= ~BUTTON_ATTACK;
+			if ((!ent->client->ammo_index) || 
+				( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
+			{
+				ent->client->ps.gunframe = FRAME_FIRE_FIRST;
+				ent->client->weaponstate = WEAPON_FIRING;
+
+				// start the animation
+				ent->client->anim_priority = ANIM_ATTACK;
+				if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+				{
+					ent->s.frame = FRAME_crattak1-1;
+					ent->client->anim_end = FRAME_crattak9;
+				}
+				else
+				{
+					ent->s.frame = FRAME_attack1-1;
+					ent->client->anim_end = FRAME_attack8;
+				}
+			}
+			else
+			{
+				if (level.time >= ent->pain_debounce_time)
+				{
+					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+					ent->pain_debounce_time = level.time + 1;
+				}
+				NoAmmoWeaponChange (ent);
+			}
+		}
+		else
+		{
+			if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
+			{
+				ent->client->ps.gunframe = FRAME_IDLE_FIRST;
+				return;
+			}
+
+			if (pause_frames)
+			{
+				for (n = 0; pause_frames[n]; n++)
+				{
+					if (ent->client->ps.gunframe == pause_frames[n])
+					{
+						if (rand()&15)
+							return;
+					}
+				}
+			}
+
+			ent->client->ps.gunframe++;
+			return;
+		}
+	}
+
+	if (ent->client->weaponstate == WEAPON_FIRING)
+	{
+		for (n = 0; fire_frames[n]; n++)
+		{
+			if (ent->client->ps.gunframe == fire_frames[n])
+			{
+				if (ent->client->quad_framenum > level.framenum)
+					gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
+
+				fire (ent);
+				break;
+			}
+		}
+
+		if (!fire_frames[n])
+			ent->client->ps.gunframe++;
+
+		if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
+			ent->client->weaponstate = WEAPON_READY;
+	}
+}
+
+
+/*
+======================================================================
+
+GRENADE
+
+======================================================================
+*/
+
+#define GRENADE_TIMER		3.0
+#define GRENADE_MINSPEED	400
+#define GRENADE_MAXSPEED	800
+
+void weapon_grenade_fire (edict_t *ent, qboolean held)
+{
+	vec3_t	offset;
+	vec3_t	forward, right;
+	vec3_t	start;
+	int		damage = 125;
+	float	timer;
+	int		speed;
+	float	radius;
+
+	radius = damage+40;
+	if (is_quad)
+		damage *= 4;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	timer = ent->client->grenade_time - level.time;
+	speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
+	fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+
+	ent->client->grenade_time = level.time + 1.0;
+
+	if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
+	{
+		return;
+	}
+
+	if (ent->health <= 0)
+		return;
+
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+		ent->client->anim_priority = ANIM_ATTACK;
+		ent->s.frame = FRAME_crattak1-1;
+		ent->client->anim_end = FRAME_crattak3;
+	}
+	else
+	{
+		ent->client->anim_priority = ANIM_REVERSE;
+		ent->s.frame = FRAME_wave08;
+		ent->client->anim_end = FRAME_wave01;
+	}
+}
+
+void Weapon_Grenade (edict_t *ent)
+{
+	if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
+	{
+		ChangeWeapon (ent);
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_ACTIVATING)
+	{
+		ent->client->weaponstate = WEAPON_READY;
+		ent->client->ps.gunframe = 16;
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_READY)
+	{
+		if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
+		{
+			ent->client->latched_buttons &= ~BUTTON_ATTACK;
+			if (ent->client->pers.inventory[ent->client->ammo_index])
+			{
+				ent->client->ps.gunframe = 1;
+				ent->client->weaponstate = WEAPON_FIRING;
+				ent->client->grenade_time = 0;
+			}
+			else
+			{
+				if (level.time >= ent->pain_debounce_time)
+				{
+					gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+					ent->pain_debounce_time = level.time + 1;
+				}
+				NoAmmoWeaponChange (ent);
+			}
+			return;
+		}
+
+		if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
+		{
+			if (rand()&15)
+				return;
+		}
+
+		if (++ent->client->ps.gunframe > 48)
+			ent->client->ps.gunframe = 16;
+		return;
+	}
+
+	if (ent->client->weaponstate == WEAPON_FIRING)
+	{
+		if (ent->client->ps.gunframe == 5)
+			gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
+
+		if (ent->client->ps.gunframe == 11)
+		{
+			if (!ent->client->grenade_time)
+			{
+				ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
+				ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
+			}
+
+			// they waited too long, detonate it in their hand
+			if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
+			{
+				ent->client->weapon_sound = 0;
+				weapon_grenade_fire (ent, true);
+				ent->client->grenade_blew_up = true;
+			}
+
+			if (ent->client->buttons & BUTTON_ATTACK)
+				return;
+
+			if (ent->client->grenade_blew_up)
+			{
+				if (level.time >= ent->client->grenade_time)
+				{
+					ent->client->ps.gunframe = 15;
+					ent->client->grenade_blew_up = false;
+				}
+				else
+				{
+					return;
+				}
+			}
+		}
+
+		if (ent->client->ps.gunframe == 12)
+		{
+			ent->client->weapon_sound = 0;
+			weapon_grenade_fire (ent, false);
+		}
+
+		if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
+			return;
+
+		ent->client->ps.gunframe++;
+
+		if (ent->client->ps.gunframe == 16)
+		{
+			ent->client->grenade_time = 0;
+			ent->client->weaponstate = WEAPON_READY;
+		}
+	}
+}
+
+/*
+======================================================================
+
+GRENADE LAUNCHER
+
+======================================================================
+*/
+
+void weapon_grenadelauncher_fire (edict_t *ent)
+{
+	vec3_t	offset;
+	vec3_t	forward, right;
+	vec3_t	start;
+	int		damage = 120;
+	float	radius;
+
+	radius = damage+40;
+	if (is_quad)
+		damage *= 4;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
+
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_GRENADE | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+void Weapon_GrenadeLauncher (edict_t *ent)
+{
+	static int	pause_frames[]	= {34, 51, 59, 0};
+	static int	fire_frames[]	= {6, 0};
+
+	Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
+}
+
+/*
+======================================================================
+
+ROCKET
+
+======================================================================
+*/
+
+void Weapon_RocketLauncher_Fire (edict_t *ent)
+{
+	vec3_t	offset, start;
+	vec3_t	forward, right;
+	int		damage;
+	float	damage_radius;
+	int		radius_damage;
+
+	damage = 100 + (int)(random() * 20.0);
+	radius_damage = 120;
+	damage_radius = 120;
+	if (is_quad)
+	{
+		damage *= 4;
+		radius_damage *= 4;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_ROCKET | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+void Weapon_RocketLauncher (edict_t *ent)
+{
+	static int	pause_frames[]	= {25, 33, 42, 50, 0};
+	static int	fire_frames[]	= {5, 0};
+
+	Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
+}
+
+
+/*
+======================================================================
+
+BLASTER / HYPERBLASTER
+
+======================================================================
+*/
+
+void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
+{
+	vec3_t	forward, right;
+	vec3_t	start;
+	vec3_t	offset;
+
+	if (is_quad)
+		damage *= 4;
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+	VectorSet(offset, 24, 8, ent->viewheight-8);
+	VectorAdd (offset, g_offset, offset);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -1;
+
+	fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	if (hyper)
+		gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
+	else
+		gi.WriteByte (MZ_BLASTER | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+}
+
+
+void Weapon_Blaster_Fire (edict_t *ent)
+{
+	int		damage;
+
+	if (deathmatch->value)
+		damage = 15;
+	else
+		damage = 10;
+	Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
+	ent->client->ps.gunframe++;
+}
+
+void Weapon_Blaster (edict_t *ent)
+{
+	static int	pause_frames[]	= {19, 32, 0};
+	static int	fire_frames[]	= {5, 0};
+
+	Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
+}
+
+
+void Weapon_HyperBlaster_Fire (edict_t *ent)
+{
+	float	rotation;
+	vec3_t	offset;
+	int		effect;
+	int		damage;
+
+	ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
+
+	if (!(ent->client->buttons & BUTTON_ATTACK))
+	{
+		ent->client->ps.gunframe++;
+	}
+	else
+	{
+		if (! ent->client->pers.inventory[ent->client->ammo_index] )
+		{
+			if (level.time >= ent->pain_debounce_time)
+			{
+				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+				ent->pain_debounce_time = level.time + 1;
+			}
+			NoAmmoWeaponChange (ent);
+		}
+		else
+		{
+			rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
+			offset[0] = -4 * sin(rotation);
+			offset[1] = 0;
+			offset[2] = 4 * cos(rotation);
+
+			if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
+				effect = EF_HYPERBLASTER;
+			else
+				effect = 0;
+			if (deathmatch->value)
+				damage = 15;
+			else
+				damage = 20;
+			Blaster_Fire (ent, offset, damage, true, effect);
+			if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+				ent->client->pers.inventory[ent->client->ammo_index]--;
+
+			ent->client->anim_priority = ANIM_ATTACK;
+			if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+			{
+				ent->s.frame = FRAME_crattak1 - 1;
+				ent->client->anim_end = FRAME_crattak9;
+			}
+			else
+			{
+				ent->s.frame = FRAME_attack1 - 1;
+				ent->client->anim_end = FRAME_attack8;
+			}
+		}
+
+		ent->client->ps.gunframe++;
+		if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
+			ent->client->ps.gunframe = 6;
+	}
+
+	if (ent->client->ps.gunframe == 12)
+	{
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
+		ent->client->weapon_sound = 0;
+	}
+
+}
+
+void Weapon_HyperBlaster (edict_t *ent)
+{
+	static int	pause_frames[]	= {0};
+	static int	fire_frames[]	= {6, 7, 8, 9, 10, 11, 0};
+
+	Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
+}
+
+/*
+======================================================================
+
+MACHINEGUN / CHAINGUN
+
+======================================================================
+*/
+
+void Machinegun_Fire (edict_t *ent)
+{
+	int	i;
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		angles;
+	int			damage = 8;
+	int			kick = 2;
+	vec3_t		offset;
+
+	if (!(ent->client->buttons & BUTTON_ATTACK))
+	{
+		ent->client->machinegun_shots = 0;
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if (ent->client->ps.gunframe == 5)
+		ent->client->ps.gunframe = 4;
+	else
+		ent->client->ps.gunframe = 5;
+
+	if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
+	{
+		ent->client->ps.gunframe = 6;
+		if (level.time >= ent->pain_debounce_time)
+		{
+			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+			ent->pain_debounce_time = level.time + 1;
+		}
+		NoAmmoWeaponChange (ent);
+		return;
+	}
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	for (i=1 ; i<3 ; i++)
+	{
+		ent->client->kick_origin[i] = crandom() * 0.35;
+		ent->client->kick_angles[i] = crandom() * 0.7;
+	}
+	ent->client->kick_origin[0] = crandom() * 0.35;
+	ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
+
+	// raise the gun as it is firing
+	if (!deathmatch->value)
+	{
+		ent->client->machinegun_shots++;
+		if (ent->client->machinegun_shots > 9)
+			ent->client->machinegun_shots = 9;
+	}
+
+	// get start / end positions
+	VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
+	AngleVectors (angles, forward, right, NULL);
+	VectorSet(offset, 0, 8, ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
+
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_MACHINEGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+
+	ent->client->anim_priority = ANIM_ATTACK;
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+		ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
+		ent->client->anim_end = FRAME_crattak9;
+	}
+	else
+	{
+		ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
+		ent->client->anim_end = FRAME_attack8;
+	}
+}
+
+void Weapon_Machinegun (edict_t *ent)
+{
+	static int	pause_frames[]	= {23, 45, 0};
+	static int	fire_frames[]	= {4, 5, 0};
+
+	Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
+}
+
+void Chaingun_Fire (edict_t *ent)
+{
+	int			i;
+	int			shots;
+	vec3_t		start;
+	vec3_t		forward, right, up;
+	float		r, u;
+	vec3_t		offset;
+	int			damage;
+	int			kick = 2;
+
+	if (deathmatch->value)
+		damage = 6;
+	else
+		damage = 8;
+
+	if (ent->client->ps.gunframe == 5)
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
+
+	if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
+	{
+		ent->client->ps.gunframe = 32;
+		ent->client->weapon_sound = 0;
+		return;
+	}
+	else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
+		&& ent->client->pers.inventory[ent->client->ammo_index])
+	{
+		ent->client->ps.gunframe = 15;
+	}
+	else
+	{
+		ent->client->ps.gunframe++;
+	}
+
+	if (ent->client->ps.gunframe == 22)
+	{
+		ent->client->weapon_sound = 0;
+		gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
+	}
+	else
+	{
+		ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
+	}
+
+	ent->client->anim_priority = ANIM_ATTACK;
+	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
+	{
+		ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
+		ent->client->anim_end = FRAME_crattak9;
+	}
+	else
+	{
+		ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
+		ent->client->anim_end = FRAME_attack8;
+	}
+
+	if (ent->client->ps.gunframe <= 9)
+		shots = 1;
+	else if (ent->client->ps.gunframe <= 14)
+	{
+		if (ent->client->buttons & BUTTON_ATTACK)
+			shots = 2;
+		else
+			shots = 1;
+	}
+	else
+		shots = 3;
+
+	if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
+		shots = ent->client->pers.inventory[ent->client->ammo_index];
+
+	if (!shots)
+	{
+		if (level.time >= ent->pain_debounce_time)
+		{
+			gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+			ent->pain_debounce_time = level.time + 1;
+		}
+		NoAmmoWeaponChange (ent);
+		return;
+	}
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		ent->client->kick_origin[i] = crandom() * 0.35;
+		ent->client->kick_angles[i] = crandom() * 0.7;
+	}
+
+	for (i=0 ; i<shots ; i++)
+	{
+		// get start / end positions
+		AngleVectors (ent->client->v_angle, forward, right, up);
+		r = 7 + crandom()*4;
+		u = crandom()*4;
+		VectorSet(offset, 0, r, u + ent->viewheight-8);
+		P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+		fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
+	}
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index] -= shots;
+}
+
+
+void Weapon_Chaingun (edict_t *ent)
+{
+	static int	pause_frames[]	= {38, 43, 51, 61, 0};
+	static int	fire_frames[]	= {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
+
+	Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
+}
+
+
+/*
+======================================================================
+
+SHOTGUN / SUPERSHOTGUN
+
+======================================================================
+*/
+
+void weapon_shotgun_fire (edict_t *ent)
+{
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		offset;
+	int			damage = 4;
+	int			kick = 8;
+
+	if (ent->client->ps.gunframe == 9)
+	{
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -2;
+
+	VectorSet(offset, 0, 8,  ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	if (deathmatch->value)
+		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
+	else
+		fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_SHOTGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+void Weapon_Shotgun (edict_t *ent)
+{
+	static int	pause_frames[]	= {22, 28, 34, 0};
+	static int	fire_frames[]	= {8, 9, 0};
+
+	Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
+}
+
+
+void weapon_supershotgun_fire (edict_t *ent)
+{
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		offset;
+	vec3_t		v;
+	int			damage = 6;
+	int			kick = 12;
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -2;
+
+	VectorSet(offset, 0, 8,  ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	v[PITCH] = ent->client->v_angle[PITCH];
+	v[YAW]   = ent->client->v_angle[YAW] - 5;
+	v[ROLL]  = ent->client->v_angle[ROLL];
+	AngleVectors (v, forward, NULL, NULL);
+	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
+	v[YAW]   = ent->client->v_angle[YAW] + 5;
+	AngleVectors (v, forward, NULL, NULL);
+	fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_SSHOTGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index] -= 2;
+}
+
+void Weapon_SuperShotgun (edict_t *ent)
+{
+	static int	pause_frames[]	= {29, 42, 57, 0};
+	static int	fire_frames[]	= {7, 0};
+
+	Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
+}
+
+
+
+/*
+======================================================================
+
+RAILGUN
+
+======================================================================
+*/
+
+void weapon_railgun_fire (edict_t *ent)
+{
+	vec3_t		start;
+	vec3_t		forward, right;
+	vec3_t		offset;
+	int			damage;
+	int			kick;
+
+	if (deathmatch->value)
+	{	// normal damage is too extreme in dm
+		damage = 100;
+		kick = 200;
+	}
+	else
+	{
+		damage = 150;
+		kick = 250;
+	}
+
+	if (is_quad)
+	{
+		damage *= 4;
+		kick *= 4;
+	}
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -3, ent->client->kick_origin);
+	ent->client->kick_angles[0] = -3;
+
+	VectorSet(offset, 0, 7,  ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_rail (ent, start, forward, damage, kick);
+
+	// send muzzle flash
+	gi.WriteByte (svc_muzzleflash);
+	gi.WriteShort (ent-g_edicts);
+	gi.WriteByte (MZ_RAILGUN | is_silenced);
+	gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+	ent->client->ps.gunframe++;
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index]--;
+}
+
+
+void Weapon_Railgun (edict_t *ent)
+{
+	static int	pause_frames[]	= {56, 0};
+	static int	fire_frames[]	= {4, 0};
+
+	Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
+}
+
+
+/*
+======================================================================
+
+BFG10K
+
+======================================================================
+*/
+
+void weapon_bfg_fire (edict_t *ent)
+{
+	vec3_t	offset, start;
+	vec3_t	forward, right;
+	int		damage;
+	float	damage_radius = 1000;
+
+	if (deathmatch->value)
+		damage = 200;
+	else
+		damage = 500;
+
+	if (ent->client->ps.gunframe == 9)
+	{
+		// send muzzle flash
+		gi.WriteByte (svc_muzzleflash);
+		gi.WriteShort (ent-g_edicts);
+		gi.WriteByte (MZ_BFG | is_silenced);
+		gi.multicast (ent->s.origin, MULTICAST_PVS);
+
+		ent->client->ps.gunframe++;
+
+		PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON);
+		return;
+	}
+
+	// cells can go down during windup (from power armor hits), so
+	// check again and abort firing if we don't have enough now
+	if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
+	{
+		ent->client->ps.gunframe++;
+		return;
+	}
+
+	if (is_quad)
+		damage *= 4;
+
+	AngleVectors (ent->client->v_angle, forward, right, NULL);
+
+	VectorScale (forward, -2, ent->client->kick_origin);
+
+	// make a big pitch kick with an inverse fall
+	ent->client->v_dmg_pitch = -40;
+	ent->client->v_dmg_roll = crandom()*8;
+	ent->client->v_dmg_time = level.time + DAMAGE_TIME;
+
+	VectorSet(offset, 8, 8, ent->viewheight-8);
+	P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
+	fire_bfg (ent, start, forward, damage, 400, damage_radius);
+
+	ent->client->ps.gunframe++;
+
+	PlayerNoise(ent, start, PNOISE_WEAPON);
+
+	if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
+		ent->client->pers.inventory[ent->client->ammo_index] -= 50;
+}
+
+void Weapon_BFG (edict_t *ent)
+{
+	static int	pause_frames[]	= {39, 45, 50, 55, 0};
+	static int	fire_frames[]	= {9, 17, 0};
+
+	Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
+}
+
+
+//======================================================================
--- /dev/null
+++ b/game/q_shared.c
@@ -1,0 +1,1418 @@
+/*
+Copyright (C) 1997-2001 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 "q_shared.h"
+
+#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
+
+vec3_t vec3_origin = {0,0,0};
+
+//============================================================================
+
+#ifdef _WIN32
+#pragma optimize( "", off )
+#endif
+
+void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
+{
+	float	m[3][3];
+	float	im[3][3];
+	float	zrot[3][3];
+	float	tmpmat[3][3];
+	float	rot[3][3];
+	int	i;
+	vec3_t vr, vup, vf;
+
+	vf[0] = dir[0];
+	vf[1] = dir[1];
+	vf[2] = dir[2];
+
+	PerpendicularVector( vr, dir );
+	CrossProduct( vr, vf, vup );
+
+	m[0][0] = vr[0];
+	m[1][0] = vr[1];
+	m[2][0] = vr[2];
+
+	m[0][1] = vup[0];
+	m[1][1] = vup[1];
+	m[2][1] = vup[2];
+
+	m[0][2] = vf[0];
+	m[1][2] = vf[1];
+	m[2][2] = vf[2];
+
+	memcpy( im, m, sizeof( im ) );
+
+	im[0][1] = m[1][0];
+	im[0][2] = m[2][0];
+	im[1][0] = m[0][1];
+	im[1][2] = m[2][1];
+	im[2][0] = m[0][2];
+	im[2][1] = m[1][2];
+
+	memset( zrot, 0, sizeof( zrot ) );
+	zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
+
+	zrot[0][0] = cos( DEG2RAD( degrees ) );
+	zrot[0][1] = sin( DEG2RAD( degrees ) );
+	zrot[1][0] = -sin( DEG2RAD( degrees ) );
+	zrot[1][1] = cos( DEG2RAD( degrees ) );
+
+	R_ConcatRotations( m, zrot, tmpmat );
+	R_ConcatRotations( tmpmat, im, rot );
+
+	for ( i = 0; i < 3; i++ )
+	{
+		dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
+	}
+}
+
+#ifdef _WIN32
+#pragma optimize( "", on )
+#endif
+
+
+
+void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
+{
+	float		angle;
+	static float		sr, sp, sy, cr, cp, cy;
+	// static to help MS compiler fp bugs
+
+	angle = angles[YAW] * (M_PI*2 / 360);
+	sy = sin(angle);
+	cy = cos(angle);
+	angle = angles[PITCH] * (M_PI*2 / 360);
+	sp = sin(angle);
+	cp = cos(angle);
+	angle = angles[ROLL] * (M_PI*2 / 360);
+	sr = sin(angle);
+	cr = cos(angle);
+
+	if (forward)
+	{
+		forward[0] = cp*cy;
+		forward[1] = cp*sy;
+		forward[2] = -sp;
+	}
+	if (right)
+	{
+		right[0] = (-1*sr*sp*cy+-1*cr*-sy);
+		right[1] = (-1*sr*sp*sy+-1*cr*cy);
+		right[2] = -1*sr*cp;
+	}
+	if (up)
+	{
+		up[0] = (cr*sp*cy+-sr*-sy);
+		up[1] = (cr*sp*sy+-sr*cy);
+		up[2] = cr*cp;
+	}
+}
+
+
+void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
+{
+	float d;
+	vec3_t n;
+	float inv_denom;
+
+	inv_denom = 1.0F / DotProduct( normal, normal );
+
+	d = DotProduct( normal, p ) * inv_denom;
+
+	n[0] = normal[0] * inv_denom;
+	n[1] = normal[1] * inv_denom;
+	n[2] = normal[2] * inv_denom;
+
+	dst[0] = p[0] - d * n[0];
+	dst[1] = p[1] - d * n[1];
+	dst[2] = p[2] - d * n[2];
+}
+
+/*
+** assumes "src" is normalized
+*/
+void PerpendicularVector( vec3_t dst, const vec3_t src )
+{
+	int	pos;
+	int i;
+	float minelem = 1.0F;
+	vec3_t tempvec;
+
+	/*
+	** find the smallest magnitude axially aligned vector
+	*/
+	for ( pos = 0, i = 0; i < 3; i++ )
+	{
+		if ( fabs( src[i] ) < minelem )
+		{
+			pos = i;
+			minelem = fabs( src[i] );
+		}
+	}
+	tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
+	tempvec[pos] = 1.0F;
+
+	/*
+	** project the point onto the plane defined by src
+	*/
+	ProjectPointOnPlane( dst, tempvec, src );
+
+	/*
+	** normalize the result
+	*/
+	VectorNormalize( dst );
+}
+
+
+
+/*
+================
+R_ConcatRotations
+================
+*/
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
+{
+	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
+				in1[0][2] * in2[2][0];
+	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
+				in1[0][2] * in2[2][1];
+	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
+				in1[0][2] * in2[2][2];
+	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
+				in1[1][2] * in2[2][0];
+	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
+				in1[1][2] * in2[2][1];
+	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
+				in1[1][2] * in2[2][2];
+	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
+				in1[2][2] * in2[2][0];
+	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
+				in1[2][2] * in2[2][1];
+	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
+				in1[2][2] * in2[2][2];
+}
+
+
+/*
+================
+R_ConcatTransforms
+================
+*/
+void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
+{
+	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
+				in1[0][2] * in2[2][0];
+	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
+				in1[0][2] * in2[2][1];
+	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
+				in1[0][2] * in2[2][2];
+	out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
+				in1[0][2] * in2[2][3] + in1[0][3];
+	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
+				in1[1][2] * in2[2][0];
+	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
+				in1[1][2] * in2[2][1];
+	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
+				in1[1][2] * in2[2][2];
+	out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
+				in1[1][2] * in2[2][3] + in1[1][3];
+	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
+				in1[2][2] * in2[2][0];
+	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
+				in1[2][2] * in2[2][1];
+	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
+				in1[2][2] * in2[2][2];
+	out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
+				in1[2][2] * in2[2][3] + in1[2][3];
+}
+
+
+//============================================================================
+
+
+float Q_fabs (float f)
+{
+#if 0
+	if (f >= 0)
+		return f;
+	return -f;
+#else
+	int tmp = * ( int * ) &f;
+	tmp &= 0x7FFFFFFF;
+	return * ( float * ) &tmp;
+#endif
+}
+
+#if defined _M_IX86 && !defined C_ONLY
+#pragma warning (disable:4035)
+__declspec( naked ) long Q_ftol( float f )
+{
+	static int tmp;
+	__asm fld dword ptr [esp+4]
+	__asm fistp tmp
+	__asm mov eax, tmp
+	__asm ret
+}
+#pragma warning (default:4035)
+#endif
+
+/*
+===============
+LerpAngle
+
+===============
+*/
+float LerpAngle (float a2, float a1, float frac)
+{
+	if (a1 - a2 > 180)
+		a1 -= 360;
+	if (a1 - a2 < -180)
+		a1 += 360;
+	return a2 + frac * (a1 - a2);
+}
+
+
+float	anglemod(float a)
+{
+#if 0
+	if (a >= 0)
+		a -= 360*(int)(a/360);
+	else
+		a += 360*( 1 + (int)(-a/360) );
+#endif
+	a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
+	return a;
+}
+
+	int		i;
+	vec3_t	corners[2];
+
+
+// this is the slow, general version
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+{
+	int		i;
+	float	dist1, dist2;
+	int		sides;
+	vec3_t	corners[2];
+
+	for (i=0 ; i<3 ; i++)
+	{
+		if (p->normal[i] < 0)
+		{
+			corners[0][i] = emins[i];
+			corners[1][i] = emaxs[i];
+		}
+		else
+		{
+			corners[1][i] = emins[i];
+			corners[0][i] = emaxs[i];
+		}
+	}
+	dist1 = DotProduct (p->normal, corners[0]) - p->dist;
+	dist2 = DotProduct (p->normal, corners[1]) - p->dist;
+	sides = 0;
+	if (dist1 >= 0)
+		sides = 1;
+	if (dist2 < 0)
+		sides |= 2;
+
+	return sides;
+}
+
+/*
+==================
+BoxOnPlaneSide
+
+Returns 1, 2, or 1 + 2
+==================
+*/
+#if !id386 || defined __linux__ 
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+{
+	float	dist1, dist2;
+	int		sides;
+
+// fast axial cases
+	if (p->type < 3)
+	{
+		if (p->dist <= emins[p->type])
+			return 1;
+		if (p->dist >= emaxs[p->type])
+			return 2;
+		return 3;
+	}
+	
+// general case
+	switch (p->signbits)
+	{
+	case 0:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+		break;
+	case 1:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+		break;
+	case 2:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+		break;
+	case 3:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+		break;
+	case 4:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+		break;
+	case 5:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+		break;
+	case 6:
+dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+		break;
+	case 7:
+dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+		break;
+	default:
+		dist1 = dist2 = 0;		// shut up compiler
+		assert( 0 );
+		break;
+	}
+
+	sides = 0;
+	if (dist1 >= p->dist)
+		sides = 1;
+	if (dist2 < p->dist)
+		sides |= 2;
+
+	assert( sides != 0 );
+
+	return sides;
+}
+#else
+#pragma warning( disable: 4035 )
+
+__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+{
+	static int bops_initialized;
+	static int Ljmptab[8];
+
+	__asm {
+
+		push ebx
+			
+		cmp bops_initialized, 1
+		je  initialized
+		mov bops_initialized, 1
+		
+		mov Ljmptab[0*4], offset Lcase0
+		mov Ljmptab[1*4], offset Lcase1
+		mov Ljmptab[2*4], offset Lcase2
+		mov Ljmptab[3*4], offset Lcase3
+		mov Ljmptab[4*4], offset Lcase4
+		mov Ljmptab[5*4], offset Lcase5
+		mov Ljmptab[6*4], offset Lcase6
+		mov Ljmptab[7*4], offset Lcase7
+			
+initialized:
+
+		mov edx,ds:dword ptr[4+12+esp]
+		mov ecx,ds:dword ptr[4+4+esp]
+		xor eax,eax
+		mov ebx,ds:dword ptr[4+8+esp]
+		mov al,ds:byte ptr[17+edx]
+		cmp al,8
+		jge Lerror
+		fld ds:dword ptr[0+edx]
+		fld st(0)
+		jmp dword ptr[Ljmptab+eax*4]
+Lcase0:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase1:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase2:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase3:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase4:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase5:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ebx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase6:
+		fmul ds:dword ptr[ebx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ecx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+		jmp LSetSides
+Lcase7:
+		fmul ds:dword ptr[ecx]
+		fld ds:dword ptr[0+4+edx]
+		fxch st(2)
+		fmul ds:dword ptr[ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[4+ecx]
+		fld ds:dword ptr[0+8+edx]
+		fxch st(2)
+		fmul ds:dword ptr[4+ebx]
+		fxch st(2)
+		fld st(0)
+		fmul ds:dword ptr[8+ecx]
+		fxch st(5)
+		faddp st(3),st(0)
+		fmul ds:dword ptr[8+ebx]
+		fxch st(1)
+		faddp st(3),st(0)
+		fxch st(3)
+		faddp st(2),st(0)
+LSetSides:
+		faddp st(2),st(0)
+		fcomp ds:dword ptr[12+edx]
+		xor ecx,ecx
+		fnstsw ax
+		fcomp ds:dword ptr[12+edx]
+		and ah,1
+		xor ah,1
+		add cl,ah
+		fnstsw ax
+		and ah,1
+		add ah,ah
+		add cl,ah
+		pop ebx
+		mov eax,ecx
+		ret
+Lerror:
+		int 3
+	}
+}
+#pragma warning( default: 4035 )
+#endif
+
+void ClearBounds (vec3_t mins, vec3_t maxs)
+{
+	mins[0] = mins[1] = mins[2] = 99999;
+	maxs[0] = maxs[1] = maxs[2] = -99999;
+}
+
+void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
+{
+	int		i;
+	vec_t	val;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		val = v[i];
+		if (val < mins[i])
+			mins[i] = val;
+		if (val > maxs[i])
+			maxs[i] = val;
+	}
+}
+
+
+int VectorCompare (vec3_t v1, vec3_t v2)
+{
+	if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2])
+			return 0;
+			
+	return 1;
+}
+
+
+vec_t VectorNormalize (vec3_t v)
+{
+	float	length, ilength;
+
+	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+	length = sqrt (length);		// FIXME
+
+	if (length)
+	{
+		ilength = 1/length;
+		v[0] *= ilength;
+		v[1] *= ilength;
+		v[2] *= ilength;
+	}
+		
+	return length;
+
+}
+
+vec_t VectorNormalize2 (vec3_t v, vec3_t out)
+{
+	float	length, ilength;
+
+	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+	length = sqrt (length);		// FIXME
+
+	if (length)
+	{
+		ilength = 1/length;
+		out[0] = v[0]*ilength;
+		out[1] = v[1]*ilength;
+		out[2] = v[2]*ilength;
+	}
+		
+	return length;
+
+}
+
+void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
+{
+	vecc[0] = veca[0] + scale*vecb[0];
+	vecc[1] = veca[1] + scale*vecb[1];
+	vecc[2] = veca[2] + scale*vecb[2];
+}
+
+
+vec_t _DotProduct (vec3_t v1, vec3_t v2)
+{
+	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
+{
+	out[0] = veca[0]-vecb[0];
+	out[1] = veca[1]-vecb[1];
+	out[2] = veca[2]-vecb[2];
+}
+
+void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
+{
+	out[0] = veca[0]+vecb[0];
+	out[1] = veca[1]+vecb[1];
+	out[2] = veca[2]+vecb[2];
+}
+
+void _VectorCopy (vec3_t in, vec3_t out)
+{
+	out[0] = in[0];
+	out[1] = in[1];
+	out[2] = in[2];
+}
+
+void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
+{
+	cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
+	cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
+	cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
+}
+
+double sqrt(double x);
+
+vec_t VectorLength(vec3_t v)
+{
+	int		i;
+	float	length;
+	
+	length = 0;
+	for (i=0 ; i< 3 ; i++)
+		length += v[i]*v[i];
+	length = sqrt (length);		// FIXME
+
+	return length;
+}
+
+void VectorInverse (vec3_t v)
+{
+	v[0] = -v[0];
+	v[1] = -v[1];
+	v[2] = -v[2];
+}
+
+void VectorScale (vec3_t in, vec_t scale, vec3_t out)
+{
+	out[0] = in[0]*scale;
+	out[1] = in[1]*scale;
+	out[2] = in[2]*scale;
+}
+
+
+int Q_log2(int val)
+{
+	int answer=0;
+	while (val>>=1)
+		answer++;
+	return answer;
+}
+
+
+
+//====================================================================================
+
+/*
+============
+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 != in && *s2 != '/' ; s2--)
+	;
+	
+	if (s-s2 < 2)
+		out[0] = 0;
+	else
+	{
+		s--;
+		strncpy (out,s2+1, s-s2);
+		out[s-s2] = 0;
+	}
+}
+
+/*
+============
+COM_FilePath
+
+Returns the path up to, but not including the last /
+============
+*/
+void COM_FilePath (char *in, char *out)
+{
+	char *s;
+	
+	s = in + strlen(in) - 1;
+	
+	while (s != in && *s != '/')
+		s--;
+
+	strncpy (out,in, s-in);
+	out[s-in] = 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);
+}
+
+/*
+============================================================================
+
+					BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+qboolean	bigendien;
+
+// can't just use function pointers, or dll linkage can
+// mess up when qcommon is included in multiple places
+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	BigShort(short l){return _BigShort(l);}
+short	LittleShort(short l) {return _LittleShort(l);}
+int		BigLong (int l) {return _BigLong(l);}
+int		LittleLong (int l) {return _LittleLong(l);}
+float	BigFloat (float l) {return _BigFloat(l);}
+float	LittleFloat (float l) {return _LittleFloat(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;
+}
+
+/*
+================
+Swap_Init
+================
+*/
+void Swap_Init (void)
+{
+	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;
+	}
+
+}
+
+
+
+/*
+============
+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;	
+}
+
+
+char	com_token[MAX_TOKEN_CHARS];
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *COM_Parse (char **data_p)
+{
+	int		c;
+	int		len;
+	char	*data;
+
+	data = *data_p;
+	len = 0;
+	com_token[0] = 0;
+	
+	if (!data)
+	{
+		*data_p = NULL;
+		return "";
+	}
+		
+// skip whitespace
+skipwhite:
+	while ( (c = *data) <= ' ')
+	{
+		if (c == 0)
+		{
+			*data_p = NULL;
+			return "";
+		}
+		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;
+				*data_p = data;
+				return com_token;
+			}
+			if (len < MAX_TOKEN_CHARS)
+			{
+				com_token[len] = c;
+				len++;
+			}
+		}
+	}
+
+// parse a regular word
+	do
+	{
+		if (len < MAX_TOKEN_CHARS)
+		{
+			com_token[len] = c;
+			len++;
+		}
+		data++;
+		c = *data;
+	} while (c>32);
+
+	if (len == MAX_TOKEN_CHARS)
+	{
+//		Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
+		len = 0;
+	}
+	com_token[len] = 0;
+
+	*data_p = data;
+	return com_token;
+}
+
+
+/*
+===============
+Com_PageInMemory
+
+===============
+*/
+int	paged_total;
+
+void Com_PageInMemory (byte *buffer, int size)
+{
+	int		i;
+
+	for (i=size-1 ; i>0 ; i-=4096)
+		paged_total += buffer[i];
+}
+
+
+
+/*
+============================================================================
+
+					LIBRARY REPLACEMENT FUNCTIONS
+
+============================================================================
+*/
+
+// FIXME: replace all Q_stricmp with Q_strcasecmp
+int Q_stricmp (char *s1, char *s2)
+{
+#if defined(WIN32)
+	return _stricmp (s1, s2);
+#else
+	return strcasecmp (s1, s2);
+#endif
+}
+
+
+int Q_strncasecmp (char *s1, char *s2, int n)
+{
+	int		c1, c2;
+	
+	do
+	{
+		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
+		}
+	} while (c1);
+	
+	return 0;		// strings are equal
+}
+
+int Q_strcasecmp (char *s1, char *s2)
+{
+	return Q_strncasecmp (s1, s2, 99999);
+}
+
+
+
+void Com_sprintf (char *dest, int size, char *fmt, ...)
+{
+	int		len;
+	va_list		argptr;
+	char	bigbuffer[0x10000];
+
+	va_start (argptr,fmt);
+	len = vsprintf (bigbuffer,fmt,argptr);
+	va_end (argptr);
+	if (len >= size)
+		Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
+	strncpy (dest, bigbuffer, size-1);
+}
+
+/*
+=====================================================================
+
+  INFO STRINGS
+
+=====================================================================
+*/
+
+/*
+===============
+Info_ValueForKey
+
+Searches the string for the given
+key and returns the associated value, or an empty string.
+===============
+*/
+char *Info_ValueForKey (char *s, char *key)
+{
+	char	pkey[512];
+	static	char value[2][512];	// use two buffers so compares
+								// work without stomping on each other
+	static	int	valueindex;
+	char	*o;
+	
+	valueindex ^= 1;
+	if (*s == '\\')
+		s++;
+	while (1)
+	{
+		o = pkey;
+		while (*s != '\\')
+		{
+			if (!*s)
+				return "";
+			*o++ = *s++;
+		}
+		*o = 0;
+		s++;
+
+		o = value[valueindex];
+
+		while (*s != '\\' && *s)
+		{
+			if (!*s)
+				return "";
+			*o++ = *s++;
+		}
+		*o = 0;
+
+		if (!strcmp (key, pkey) )
+			return value[valueindex];
+
+		if (!*s)
+			return "";
+		s++;
+	}
+}
+
+void Info_RemoveKey (char *s, char *key)
+{
+	char	*start;
+	char	pkey[512];
+	char	value[512];
+	char	*o;
+
+	if (strstr (key, "\\"))
+	{
+//		Com_Printf ("Can't use a key with a \\\n");
+		return;
+	}
+
+	while (1)
+	{
+		start = s;
+		if (*s == '\\')
+			s++;
+		o = pkey;
+		while (*s != '\\')
+		{
+			if (!*s)
+				return;
+			*o++ = *s++;
+		}
+		*o = 0;
+		s++;
+
+		o = value;
+		while (*s != '\\' && *s)
+		{
+			if (!*s)
+				return;
+			*o++ = *s++;
+		}
+		*o = 0;
+
+		if (!strcmp (key, pkey) )
+		{
+			strcpy (start, s);	// remove this part
+			return;
+		}
+
+		if (!*s)
+			return;
+	}
+
+}
+
+
+/*
+==================
+Info_Validate
+
+Some characters are illegal in info strings because they
+can mess up the server's parsing
+==================
+*/
+qboolean Info_Validate (char *s)
+{
+	if (strstr (s, "\""))
+		return false;
+	if (strstr (s, ";"))
+		return false;
+	return true;
+}
+
+void Info_SetValueForKey (char *s, char *key, char *value)
+{
+	char	newi[MAX_INFO_STRING], *v;
+	int		c;
+	int		maxsize = MAX_INFO_STRING;
+
+	if (strstr (key, "\\") || strstr (value, "\\") )
+	{
+		Com_Printf ("Can't use keys or values with a \\\n");
+		return;
+	}
+
+	if (strstr (key, ";") )
+	{
+		Com_Printf ("Can't use keys or values with a semicolon\n");
+		return;
+	}
+
+	if (strstr (key, "\"") || strstr (value, "\"") )
+	{
+		Com_Printf ("Can't use keys or values with a \"\n");
+		return;
+	}
+
+	if (strlen(key) > MAX_INFO_KEY-1 || strlen(value) > MAX_INFO_KEY-1)
+	{
+		Com_Printf ("Keys and values must be < 64 characters.\n");
+		return;
+	}
+	Info_RemoveKey (s, key);
+	if (!value || !strlen(value))
+		return;
+
+	Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
+
+	if (strlen(newi) + strlen(s) > maxsize)
+	{
+		Com_Printf ("Info string length exceeded\n");
+		return;
+	}
+
+	// only copy ascii values
+	s += strlen(s);
+	v = newi;
+	while (*v)
+	{
+		c = *v++;
+		c &= 127;		// strip high bits
+		if (c >= 32 && c < 127)
+			*s++ = c;
+	}
+	*s = 0;
+}
+
+//====================================================================
+
+
--- /dev/null
+++ b/game/q_shared.h
@@ -1,0 +1,1200 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+	
+// q_shared.h -- included first by ALL program modules
+
+#ifdef _WIN32
+// unknown pragmas are SUPPOSED to be ignored, but....
+#pragma warning(disable : 4244)     // MIPS
+#pragma warning(disable : 4136)     // X86
+#pragma warning(disable : 4051)     // ALPHA
+
+#pragma warning(disable : 4018)     // signed/unsigned mismatch
+#pragma warning(disable : 4305)		// truncation from const double to float
+
+#endif
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#if (defined _M_IX86 || defined __i386__) && !defined C_ONLY && !defined __sun__
+#define id386	1
+#else
+#define id386	0
+#endif
+
+#if defined _M_ALPHA && !defined C_ONLY
+#define idaxp	1
+#else
+#define idaxp	0
+#endif
+
+typedef unsigned char 		byte;
+typedef enum {false, true}	qboolean;
+
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+
+// angle indexes
+#define	PITCH				0		// up / down
+#define	YAW					1		// left / right
+#define	ROLL				2		// fall over
+
+#define	MAX_STRING_CHARS	1024	// max length of a string passed to Cmd_TokenizeString
+#define	MAX_STRING_TOKENS	80		// max tokens resulting from Cmd_TokenizeString
+#define	MAX_TOKEN_CHARS		128		// max length of an individual token
+
+#define	MAX_QPATH			64		// max length of a quake game pathname
+#define	MAX_OSPATH			128		// max length of a filesystem pathname
+
+//
+// per-level limits
+//
+#define	MAX_CLIENTS			256		// absolute limit
+#define	MAX_EDICTS			1024	// must change protocol to increase more
+#define	MAX_LIGHTSTYLES		256
+#define	MAX_MODELS			256		// these are sent over the net as bytes
+#define	MAX_SOUNDS			256		// so they cannot be blindly increased
+#define	MAX_IMAGES			256
+#define	MAX_ITEMS			256
+#define MAX_GENERAL			(MAX_CLIENTS*2)	// general config strings
+
+
+// game print flags
+#define	PRINT_LOW			0		// pickup messages
+#define	PRINT_MEDIUM		1		// death messages
+#define	PRINT_HIGH			2		// critical messages
+#define	PRINT_CHAT			3		// chat messages
+
+
+
+#define	ERR_FATAL			0		// exit the entire game with a popup window
+#define	ERR_DROP			1		// print to console and disconnect from game
+#define	ERR_DISCONNECT		2		// don't kill server
+
+#define	PRINT_ALL			0
+#define PRINT_DEVELOPER		1		// only print when "developer 1"
+#define PRINT_ALERT			2		
+
+
+// destination class for gi.multicast()
+typedef enum
+{
+MULTICAST_ALL,
+MULTICAST_PHS,
+MULTICAST_PVS,
+MULTICAST_ALL_R,
+MULTICAST_PHS_R,
+MULTICAST_PVS_R
+} multicast_t;
+
+
+/*
+==============================================================
+
+MATHLIB
+
+==============================================================
+*/
+
+typedef float vec_t;
+typedef vec_t vec3_t[3];
+typedef vec_t vec5_t[5];
+
+typedef	int	fixed4_t;
+typedef	int	fixed8_t;
+typedef	int	fixed16_t;
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h
+#endif
+
+struct cplane_s;
+
+extern vec3_t vec3_origin;
+
+#define	nanmask (255<<23)
+
+#define	IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
+
+// microsoft's fabs seems to be ungodly slow...
+//float Q_fabs (float f);
+//#define	fabs(f) Q_fabs(f)
+#if !defined C_ONLY && !defined __linux__ && !defined __sgi
+extern long Q_ftol( float f );
+#else
+#define Q_ftol( f ) ( long ) (f)
+#endif
+
+#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])
+#define VectorAdd(a,b,c)		(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
+#define VectorCopy(a,b)			(b[0]=a[0],b[1]=a[1],b[2]=a[2])
+#define VectorClear(a)			(a[0]=a[1]=a[2]=0)
+#define VectorNegate(a,b)		(b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
+#define VectorSet(v, x, y, z)	(v[0]=(x), v[1]=(y), v[2]=(z))
+
+void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
+
+// just in case you do't want to use the macros
+vec_t _DotProduct (vec3_t v1, vec3_t v2);
+void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
+void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
+void _VectorCopy (vec3_t in, vec3_t out);
+
+void ClearBounds (vec3_t mins, vec3_t maxs);
+void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
+int VectorCompare (vec3_t v1, vec3_t v2);
+vec_t VectorLength (vec3_t v);
+void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
+vec_t VectorNormalize (vec3_t v);		// returns vector length
+vec_t VectorNormalize2 (vec3_t v, vec3_t out);
+void VectorInverse (vec3_t v);
+void VectorScale (vec3_t in, vec_t scale, vec3_t out);
+int Q_log2(int val);
+
+void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
+void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
+
+void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
+float	anglemod(float a);
+float LerpAngle (float a1, float a2, float frac);
+
+#define BOX_ON_PLANE_SIDE(emins, emaxs, p)	\
+	(((p)->type < 3)?						\
+	(										\
+		((p)->dist <= (emins)[(p)->type])?	\
+			1								\
+		:									\
+		(									\
+			((p)->dist >= (emaxs)[(p)->type])?\
+				2							\
+			:								\
+				3							\
+		)									\
+	)										\
+	:										\
+		BoxOnPlaneSide( (emins), (emaxs), (p)))
+
+void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
+void PerpendicularVector( vec3_t dst, const vec3_t src );
+void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
+
+
+//=============================================
+
+char *COM_SkipPath (char *pathname);
+void COM_StripExtension (char *in, char *out);
+void COM_FileBase (char *in, char *out);
+void COM_FilePath (char *in, char *out);
+void COM_DefaultExtension (char *path, char *extension);
+
+char *COM_Parse (char **data_p);
+// data is an in/out parm, returns a parsed out token
+
+void Com_sprintf (char *dest, int size, char *fmt, ...);
+
+void Com_PageInMemory (byte *buffer, int size);
+
+//=============================================
+
+// portable case insensitive compare
+int Q_stricmp (char *s1, char *s2);
+int Q_strcasecmp (char *s1, char *s2);
+int Q_strncasecmp (char *s1, char *s2, int n);
+
+//=============================================
+
+short	BigShort(short l);
+short	LittleShort(short l);
+int		BigLong (int l);
+int		LittleLong (int l);
+float	BigFloat (float l);
+float	LittleFloat (float l);
+
+void	Swap_Init (void);
+char	*va(char *format, ...);
+
+//=============================================
+
+//
+// key / value info strings
+//
+#define	MAX_INFO_KEY		64
+#define	MAX_INFO_VALUE		64
+#define	MAX_INFO_STRING		512
+
+char *Info_ValueForKey (char *s, char *key);
+void Info_RemoveKey (char *s, char *key);
+void Info_SetValueForKey (char *s, char *key, char *value);
+qboolean Info_Validate (char *s);
+
+/*
+==============================================================
+
+SYSTEM SPECIFIC
+
+==============================================================
+*/
+
+extern	int	curtime;		// time returned by last Sys_Milliseconds
+
+int		Sys_Milliseconds (void);
+void	Sys_Mkdir (char *path);
+
+// large block stack allocation routines
+void	*Hunk_Begin (int maxsize);
+void	*Hunk_Alloc (int size);
+void	Hunk_Free (void *buf);
+int		Hunk_End (void);
+
+// directory searching
+#define SFF_ARCH    0x01
+#define SFF_HIDDEN  0x02
+#define SFF_RDONLY  0x04
+#define SFF_SUBDIR  0x08
+#define SFF_SYSTEM  0x10
+
+/*
+** pass in an attribute mask of things you wish to REJECT
+*/
+char	*Sys_FindFirst (char *path, unsigned musthave, unsigned canthave );
+char	*Sys_FindNext ( unsigned musthave, unsigned canthave );
+void	Sys_FindClose (void);
+
+
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...);
+void Com_Printf (char *msg, ...);
+
+
+/*
+==========================================================
+
+CVARS (console variables)
+
+==========================================================
+*/
+
+#ifndef CVAR
+#define	CVAR
+
+#define	CVAR_ARCHIVE	1	// set to cause it to be saved to vars.rc
+#define	CVAR_USERINFO	2	// added to userinfo  when changed
+#define	CVAR_SERVERINFO	4	// added to serverinfo when changed
+#define	CVAR_NOSET		8	// don't allow change from console at all,
+							// but can be set from the command line
+#define	CVAR_LATCH		16	// save changes until server restart
+
+// nothing outside the Cvar_*() functions should modify these fields!
+typedef struct cvar_s
+{
+	char		*name;
+	char		*string;
+	char		*latched_string;	// for CVAR_LATCH vars
+	int			flags;
+	qboolean	modified;	// set each time the cvar is changed
+	float		value;
+	struct cvar_s *next;
+} cvar_t;
+
+#endif		// CVAR
+
+/*
+==============================================================
+
+COLLISION DETECTION
+
+==============================================================
+*/
+
+// lower bits are stronger, and will eat weaker brushes completely
+#define	CONTENTS_SOLID			1		// an eye is never valid in a solid
+#define	CONTENTS_WINDOW			2		// translucent, but not watery
+#define	CONTENTS_AUX			4
+#define	CONTENTS_LAVA			8
+#define	CONTENTS_SLIME			16
+#define	CONTENTS_WATER			32
+#define	CONTENTS_MIST			64
+#define	LAST_VISIBLE_CONTENTS	64
+
+// remaining contents are non-visible, and don't eat brushes
+
+#define	CONTENTS_AREAPORTAL		0x8000
+
+#define	CONTENTS_PLAYERCLIP		0x10000
+#define	CONTENTS_MONSTERCLIP	0x20000
+
+// currents can be added to any other contents, and may be mixed
+#define	CONTENTS_CURRENT_0		0x40000
+#define	CONTENTS_CURRENT_90		0x80000
+#define	CONTENTS_CURRENT_180	0x100000
+#define	CONTENTS_CURRENT_270	0x200000
+#define	CONTENTS_CURRENT_UP		0x400000
+#define	CONTENTS_CURRENT_DOWN	0x800000
+
+#define	CONTENTS_ORIGIN			0x1000000	// removed before bsping an entity
+
+#define	CONTENTS_MONSTER		0x2000000	// should never be on a brush, only in game
+#define	CONTENTS_DEADMONSTER	0x4000000
+#define	CONTENTS_DETAIL			0x8000000	// brushes to be added after vis leafs
+#define	CONTENTS_TRANSLUCENT	0x10000000	// auto set if any surface has trans
+#define	CONTENTS_LADDER			0x20000000
+
+
+
+#define	SURF_LIGHT		0x1		// value will hold the light strength
+
+#define	SURF_SLICK		0x2		// effects game physics
+
+#define	SURF_SKY		0x4		// don't draw, but add to skybox
+#define	SURF_WARP		0x8		// turbulent water warp
+#define	SURF_TRANS33	0x10
+#define	SURF_TRANS66	0x20
+#define	SURF_FLOWING	0x40	// scroll towards angle
+#define	SURF_NODRAW		0x80	// don't bother referencing the texture
+
+
+
+// content masks
+#define	MASK_ALL				(-1)
+#define	MASK_SOLID				(CONTENTS_SOLID|CONTENTS_WINDOW)
+#define	MASK_PLAYERSOLID		(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
+#define	MASK_DEADSOLID			(CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW)
+#define	MASK_MONSTERSOLID		(CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
+#define	MASK_WATER				(CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
+#define	MASK_OPAQUE				(CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
+#define	MASK_SHOT				(CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
+#define MASK_CURRENT			(CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN)
+
+
+// gi.BoxEdicts() can return a list of either solid or trigger entities
+// FIXME: eliminate AREA_ distinction?
+#define	AREA_SOLID		1
+#define	AREA_TRIGGERS	2
+
+
+// plane_t structure
+// !!! if this is changed, it must be changed in asm code too !!!
+typedef struct cplane_s
+{
+	vec3_t	normal;
+	float	dist;
+	byte	type;			// for fast side tests
+	byte	signbits;		// signx + (signy<<1) + (signz<<1)
+	byte	pad[2];
+} cplane_t;
+
+// structure offset for asm code
+#define CPLANE_NORMAL_X			0
+#define CPLANE_NORMAL_Y			4
+#define CPLANE_NORMAL_Z			8
+#define CPLANE_DIST				12
+#define CPLANE_TYPE				16
+#define CPLANE_SIGNBITS			17
+#define CPLANE_PAD0				18
+#define CPLANE_PAD1				19
+
+typedef struct cmodel_s
+{
+	vec3_t		mins, maxs;
+	vec3_t		origin;		// for sounds or lights
+	int			headnode;
+} cmodel_t;
+
+typedef struct csurface_s
+{
+	char		name[16];
+	int			flags;
+	int			value;
+} csurface_t;
+
+typedef struct mapsurface_s  // used internally due to name len probs //ZOID
+{
+	csurface_t	c;
+	char		rname[32];
+} mapsurface_t;
+
+// a trace is returned when a box is swept through the world
+typedef struct
+{
+	qboolean	allsolid;	// if true, plane is not valid
+	qboolean	startsolid;	// if true, the initial point was in a solid area
+	float		fraction;	// time completed, 1.0 = didn't hit anything
+	vec3_t		endpos;		// final position
+	cplane_t	plane;		// surface normal at impact
+	csurface_t	*surface;	// surface hit
+	int			contents;	// contents on other side of surface hit
+	struct edict_s	*ent;		// not set by CM_*() functions
+} trace_t;
+
+
+
+// pmove_state_t is the information necessary for client side movement
+// prediction
+typedef enum 
+{
+	// can accelerate and turn
+	PM_NORMAL,
+	PM_SPECTATOR,
+	// no acceleration or turning
+	PM_DEAD,
+	PM_GIB,		// different bounding box
+	PM_FREEZE
+} pmtype_t;
+
+// pmove->pm_flags
+#define	PMF_DUCKED			1
+#define	PMF_JUMP_HELD		2
+#define	PMF_ON_GROUND		4
+#define	PMF_TIME_WATERJUMP	8	// pm_time is waterjump
+#define	PMF_TIME_LAND		16	// pm_time is time before rejump
+#define	PMF_TIME_TELEPORT	32	// pm_time is non-moving time
+#define PMF_NO_PREDICTION	64	// temporarily disables prediction (used for grappling hook)
+
+// this structure needs to be communicated bit-accurate
+// from the server to the client to guarantee that
+// prediction stays in sync, so no floats are used.
+// if any part of the game code modifies this struct, it
+// will result in a prediction error of some degree.
+typedef struct
+{
+	pmtype_t	pm_type;
+
+	short		origin[3];		// 12.3
+	short		velocity[3];	// 12.3
+	byte		pm_flags;		// ducked, jump_held, etc
+	byte		pm_time;		// each unit = 8 ms
+	short		gravity;
+	short		delta_angles[3];	// add to command angles to get view direction
+									// changed by spawns, rotating objects, and teleporters
+} pmove_state_t;
+
+
+//
+// button bits
+//
+#define	BUTTON_ATTACK		1
+#define	BUTTON_USE			2
+#define	BUTTON_ANY			128			// any key whatsoever
+
+
+// usercmd_t is sent to the server each client frame
+typedef struct usercmd_s
+{
+	byte	msec;
+	byte	buttons;
+	short	angles[3];
+	short	forwardmove, sidemove, upmove;
+	byte	impulse;		// remove?
+	byte	lightlevel;		// light level the player is standing on
+} usercmd_t;
+
+
+#define	MAXTOUCH	32
+typedef struct
+{
+	// state (in / out)
+	pmove_state_t	s;
+
+	// command (in)
+	usercmd_t		cmd;
+	qboolean		snapinitial;	// if s has been changed outside pmove
+
+	// results (out)
+	int			numtouch;
+	struct edict_s	*touchents[MAXTOUCH];
+
+	vec3_t		viewangles;			// clamped
+	float		viewheight;
+
+	vec3_t		mins, maxs;			// bounding box size
+
+	struct edict_s	*groundentity;
+	int			watertype;
+	int			waterlevel;
+
+	// callbacks to test the world
+	trace_t		(*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
+	int			(*pointcontents) (vec3_t point);
+} pmove_t;
+
+
+// entity_state_t->effects
+// Effects are things handled on the client side (lights, particles, frame animations)
+// that happen constantly on the given entity.
+// An entity that has effects will be sent to the client
+// even if it has a zero index model.
+#define	EF_ROTATE			0x00000001		// rotate (bonus items)
+#define	EF_GIB				0x00000002		// leave a trail
+#define	EF_BLASTER			0x00000008		// redlight + trail
+#define	EF_ROCKET			0x00000010		// redlight + trail
+#define	EF_GRENADE			0x00000020
+#define	EF_HYPERBLASTER		0x00000040
+#define	EF_BFG				0x00000080
+#define EF_COLOR_SHELL		0x00000100
+#define EF_POWERSCREEN		0x00000200
+#define	EF_ANIM01			0x00000400		// automatically cycle between frames 0 and 1 at 2 hz
+#define	EF_ANIM23			0x00000800		// automatically cycle between frames 2 and 3 at 2 hz
+#define EF_ANIM_ALL			0x00001000		// automatically cycle through all frames at 2hz
+#define EF_ANIM_ALLFAST		0x00002000		// automatically cycle through all frames at 10hz
+#define	EF_FLIES			0x00004000
+#define	EF_QUAD				0x00008000
+#define	EF_PENT				0x00010000
+#define	EF_TELEPORTER		0x00020000		// particle fountain
+#define EF_FLAG1			0x00040000
+#define EF_FLAG2			0x00080000
+// RAFAEL
+#define EF_IONRIPPER		0x00100000
+#define EF_GREENGIB			0x00200000
+#define	EF_BLUEHYPERBLASTER 0x00400000
+#define EF_SPINNINGLIGHTS	0x00800000
+#define EF_PLASMA			0x01000000
+#define EF_TRAP				0x02000000
+
+//ROGUE
+#define EF_TRACKER			0x04000000
+#define	EF_DOUBLE			0x08000000
+#define	EF_SPHERETRANS		0x10000000
+#define EF_TAGTRAIL			0x20000000
+#define EF_HALF_DAMAGE		0x40000000
+#define EF_TRACKERTRAIL		0x80000000
+//ROGUE
+
+// entity_state_t->renderfx flags
+#define	RF_MINLIGHT			1		// allways have some light (viewmodel)
+#define	RF_VIEWERMODEL		2		// don't draw through eyes, only mirrors
+#define	RF_WEAPONMODEL		4		// only draw through eyes
+#define	RF_FULLBRIGHT		8		// allways draw full intensity
+#define	RF_DEPTHHACK		16		// for view weapon Z crunching
+#define	RF_TRANSLUCENT		32
+#define	RF_FRAMELERP		64
+#define RF_BEAM				128
+#define	RF_CUSTOMSKIN		256		// skin is an index in image_precache
+#define	RF_GLOW				512		// pulse lighting for bonus items
+#define RF_SHELL_RED		1024
+#define	RF_SHELL_GREEN		2048
+#define RF_SHELL_BLUE		4096
+
+//ROGUE
+#define RF_IR_VISIBLE		0x00008000		// 32768
+#define	RF_SHELL_DOUBLE		0x00010000		// 65536
+#define	RF_SHELL_HALF_DAM	0x00020000
+#define RF_USE_DISGUISE		0x00040000
+//ROGUE
+
+// player_state_t->refdef flags
+#define	RDF_UNDERWATER		1		// warp the screen as apropriate
+#define RDF_NOWORLDMODEL	2		// used for player configuration screen
+
+//ROGUE
+#define	RDF_IRGOGGLES		4
+#define RDF_UVGOGGLES		8
+//ROGUE
+
+//
+// muzzle flashes / player effects
+//
+#define	MZ_BLASTER			0
+#define MZ_MACHINEGUN		1
+#define	MZ_SHOTGUN			2
+#define	MZ_CHAINGUN1		3
+#define	MZ_CHAINGUN2		4
+#define	MZ_CHAINGUN3		5
+#define	MZ_RAILGUN			6
+#define	MZ_ROCKET			7
+#define	MZ_GRENADE			8
+#define	MZ_LOGIN			9
+#define	MZ_LOGOUT			10
+#define	MZ_RESPAWN			11
+#define	MZ_BFG				12
+#define	MZ_SSHOTGUN			13
+#define	MZ_HYPERBLASTER		14
+#define	MZ_ITEMRESPAWN		15
+// RAFAEL
+#define MZ_IONRIPPER		16
+#define MZ_BLUEHYPERBLASTER 17
+#define MZ_PHALANX			18
+#define MZ_SILENCED			128		// bit flag ORed with one of the above numbers
+
+//ROGUE
+#define MZ_ETF_RIFLE		30
+#define MZ_UNUSED			31
+#define MZ_SHOTGUN2			32
+#define MZ_HEATBEAM			33
+#define MZ_BLASTER2			34
+#define	MZ_TRACKER			35
+#define	MZ_NUKE1			36
+#define	MZ_NUKE2			37
+#define	MZ_NUKE4			38
+#define	MZ_NUKE8			39
+//ROGUE
+
+//
+// monster muzzle flashes
+//
+#define MZ2_TANK_BLASTER_1				1
+#define MZ2_TANK_BLASTER_2				2
+#define MZ2_TANK_BLASTER_3				3
+#define MZ2_TANK_MACHINEGUN_1			4
+#define MZ2_TANK_MACHINEGUN_2			5
+#define MZ2_TANK_MACHINEGUN_3			6
+#define MZ2_TANK_MACHINEGUN_4			7
+#define MZ2_TANK_MACHINEGUN_5			8
+#define MZ2_TANK_MACHINEGUN_6			9
+#define MZ2_TANK_MACHINEGUN_7			10
+#define MZ2_TANK_MACHINEGUN_8			11
+#define MZ2_TANK_MACHINEGUN_9			12
+#define MZ2_TANK_MACHINEGUN_10			13
+#define MZ2_TANK_MACHINEGUN_11			14
+#define MZ2_TANK_MACHINEGUN_12			15
+#define MZ2_TANK_MACHINEGUN_13			16
+#define MZ2_TANK_MACHINEGUN_14			17
+#define MZ2_TANK_MACHINEGUN_15			18
+#define MZ2_TANK_MACHINEGUN_16			19
+#define MZ2_TANK_MACHINEGUN_17			20
+#define MZ2_TANK_MACHINEGUN_18			21
+#define MZ2_TANK_MACHINEGUN_19			22
+#define MZ2_TANK_ROCKET_1				23
+#define MZ2_TANK_ROCKET_2				24
+#define MZ2_TANK_ROCKET_3				25
+
+#define MZ2_INFANTRY_MACHINEGUN_1		26
+#define MZ2_INFANTRY_MACHINEGUN_2		27
+#define MZ2_INFANTRY_MACHINEGUN_3		28
+#define MZ2_INFANTRY_MACHINEGUN_4		29
+#define MZ2_INFANTRY_MACHINEGUN_5		30
+#define MZ2_INFANTRY_MACHINEGUN_6		31
+#define MZ2_INFANTRY_MACHINEGUN_7		32
+#define MZ2_INFANTRY_MACHINEGUN_8		33
+#define MZ2_INFANTRY_MACHINEGUN_9		34
+#define MZ2_INFANTRY_MACHINEGUN_10		35
+#define MZ2_INFANTRY_MACHINEGUN_11		36
+#define MZ2_INFANTRY_MACHINEGUN_12		37
+#define MZ2_INFANTRY_MACHINEGUN_13		38
+
+#define MZ2_SOLDIER_BLASTER_1			39
+#define MZ2_SOLDIER_BLASTER_2			40
+#define MZ2_SOLDIER_SHOTGUN_1			41
+#define MZ2_SOLDIER_SHOTGUN_2			42
+#define MZ2_SOLDIER_MACHINEGUN_1		43
+#define MZ2_SOLDIER_MACHINEGUN_2		44
+
+#define MZ2_GUNNER_MACHINEGUN_1			45
+#define MZ2_GUNNER_MACHINEGUN_2			46
+#define MZ2_GUNNER_MACHINEGUN_3			47
+#define MZ2_GUNNER_MACHINEGUN_4			48
+#define MZ2_GUNNER_MACHINEGUN_5			49
+#define MZ2_GUNNER_MACHINEGUN_6			50
+#define MZ2_GUNNER_MACHINEGUN_7			51
+#define MZ2_GUNNER_MACHINEGUN_8			52
+#define MZ2_GUNNER_GRENADE_1			53
+#define MZ2_GUNNER_GRENADE_2			54
+#define MZ2_GUNNER_GRENADE_3			55
+#define MZ2_GUNNER_GRENADE_4			56
+
+#define MZ2_CHICK_ROCKET_1				57
+
+#define MZ2_FLYER_BLASTER_1				58
+#define MZ2_FLYER_BLASTER_2				59
+
+#define MZ2_MEDIC_BLASTER_1				60
+
+#define MZ2_GLADIATOR_RAILGUN_1			61
+
+#define MZ2_HOVER_BLASTER_1				62
+
+#define MZ2_ACTOR_MACHINEGUN_1			63
+
+#define MZ2_SUPERTANK_MACHINEGUN_1		64
+#define MZ2_SUPERTANK_MACHINEGUN_2		65
+#define MZ2_SUPERTANK_MACHINEGUN_3		66
+#define MZ2_SUPERTANK_MACHINEGUN_4		67
+#define MZ2_SUPERTANK_MACHINEGUN_5		68
+#define MZ2_SUPERTANK_MACHINEGUN_6		69
+#define MZ2_SUPERTANK_ROCKET_1			70
+#define MZ2_SUPERTANK_ROCKET_2			71
+#define MZ2_SUPERTANK_ROCKET_3			72
+
+#define MZ2_BOSS2_MACHINEGUN_L1			73
+#define MZ2_BOSS2_MACHINEGUN_L2			74
+#define MZ2_BOSS2_MACHINEGUN_L3			75
+#define MZ2_BOSS2_MACHINEGUN_L4			76
+#define MZ2_BOSS2_MACHINEGUN_L5			77
+#define MZ2_BOSS2_ROCKET_1				78
+#define MZ2_BOSS2_ROCKET_2				79
+#define MZ2_BOSS2_ROCKET_3				80
+#define MZ2_BOSS2_ROCKET_4				81
+
+#define MZ2_FLOAT_BLASTER_1				82
+
+#define MZ2_SOLDIER_BLASTER_3			83
+#define MZ2_SOLDIER_SHOTGUN_3			84
+#define MZ2_SOLDIER_MACHINEGUN_3		85
+#define MZ2_SOLDIER_BLASTER_4			86
+#define MZ2_SOLDIER_SHOTGUN_4			87
+#define MZ2_SOLDIER_MACHINEGUN_4		88
+#define MZ2_SOLDIER_BLASTER_5			89
+#define MZ2_SOLDIER_SHOTGUN_5			90
+#define MZ2_SOLDIER_MACHINEGUN_5		91
+#define MZ2_SOLDIER_BLASTER_6			92
+#define MZ2_SOLDIER_SHOTGUN_6			93
+#define MZ2_SOLDIER_MACHINEGUN_6		94
+#define MZ2_SOLDIER_BLASTER_7			95
+#define MZ2_SOLDIER_SHOTGUN_7			96
+#define MZ2_SOLDIER_MACHINEGUN_7		97
+#define MZ2_SOLDIER_BLASTER_8			98
+#define MZ2_SOLDIER_SHOTGUN_8			99
+#define MZ2_SOLDIER_MACHINEGUN_8		100
+
+// --- Xian shit below ---
+#define	MZ2_MAKRON_BFG					101
+#define MZ2_MAKRON_BLASTER_1			102
+#define MZ2_MAKRON_BLASTER_2			103
+#define MZ2_MAKRON_BLASTER_3			104
+#define MZ2_MAKRON_BLASTER_4			105
+#define MZ2_MAKRON_BLASTER_5			106
+#define MZ2_MAKRON_BLASTER_6			107
+#define MZ2_MAKRON_BLASTER_7			108
+#define MZ2_MAKRON_BLASTER_8			109
+#define MZ2_MAKRON_BLASTER_9			110
+#define MZ2_MAKRON_BLASTER_10			111
+#define MZ2_MAKRON_BLASTER_11			112
+#define MZ2_MAKRON_BLASTER_12			113
+#define MZ2_MAKRON_BLASTER_13			114
+#define MZ2_MAKRON_BLASTER_14			115
+#define MZ2_MAKRON_BLASTER_15			116
+#define MZ2_MAKRON_BLASTER_16			117
+#define MZ2_MAKRON_BLASTER_17			118
+#define MZ2_MAKRON_RAILGUN_1			119
+#define	MZ2_JORG_MACHINEGUN_L1			120
+#define	MZ2_JORG_MACHINEGUN_L2			121
+#define	MZ2_JORG_MACHINEGUN_L3			122
+#define	MZ2_JORG_MACHINEGUN_L4			123
+#define	MZ2_JORG_MACHINEGUN_L5			124
+#define	MZ2_JORG_MACHINEGUN_L6			125
+#define	MZ2_JORG_MACHINEGUN_R1			126
+#define	MZ2_JORG_MACHINEGUN_R2			127
+#define	MZ2_JORG_MACHINEGUN_R3			128
+#define	MZ2_JORG_MACHINEGUN_R4			129
+#define MZ2_JORG_MACHINEGUN_R5			130
+#define	MZ2_JORG_MACHINEGUN_R6			131
+#define MZ2_JORG_BFG_1					132
+#define MZ2_BOSS2_MACHINEGUN_R1			133
+#define MZ2_BOSS2_MACHINEGUN_R2			134
+#define MZ2_BOSS2_MACHINEGUN_R3			135
+#define MZ2_BOSS2_MACHINEGUN_R4			136
+#define MZ2_BOSS2_MACHINEGUN_R5			137
+
+//ROGUE
+#define	MZ2_CARRIER_MACHINEGUN_L1		138
+#define	MZ2_CARRIER_MACHINEGUN_R1		139
+#define	MZ2_CARRIER_GRENADE				140
+#define MZ2_TURRET_MACHINEGUN			141
+#define MZ2_TURRET_ROCKET				142
+#define MZ2_TURRET_BLASTER				143
+#define MZ2_STALKER_BLASTER				144
+#define MZ2_DAEDALUS_BLASTER			145
+#define MZ2_MEDIC_BLASTER_2				146
+#define	MZ2_CARRIER_RAILGUN				147
+#define	MZ2_WIDOW_DISRUPTOR				148
+#define	MZ2_WIDOW_BLASTER				149
+#define	MZ2_WIDOW_RAIL					150
+#define	MZ2_WIDOW_PLASMABEAM			151		// PMM - not used
+#define	MZ2_CARRIER_MACHINEGUN_L2		152
+#define	MZ2_CARRIER_MACHINEGUN_R2		153
+#define	MZ2_WIDOW_RAIL_LEFT				154
+#define	MZ2_WIDOW_RAIL_RIGHT			155
+#define	MZ2_WIDOW_BLASTER_SWEEP1		156
+#define	MZ2_WIDOW_BLASTER_SWEEP2		157
+#define	MZ2_WIDOW_BLASTER_SWEEP3		158
+#define	MZ2_WIDOW_BLASTER_SWEEP4		159
+#define	MZ2_WIDOW_BLASTER_SWEEP5		160
+#define	MZ2_WIDOW_BLASTER_SWEEP6		161
+#define	MZ2_WIDOW_BLASTER_SWEEP7		162
+#define	MZ2_WIDOW_BLASTER_SWEEP8		163
+#define	MZ2_WIDOW_BLASTER_SWEEP9		164
+#define	MZ2_WIDOW_BLASTER_100			165
+#define	MZ2_WIDOW_BLASTER_90			166
+#define	MZ2_WIDOW_BLASTER_80			167
+#define	MZ2_WIDOW_BLASTER_70			168
+#define	MZ2_WIDOW_BLASTER_60			169
+#define	MZ2_WIDOW_BLASTER_50			170
+#define	MZ2_WIDOW_BLASTER_40			171
+#define	MZ2_WIDOW_BLASTER_30			172
+#define	MZ2_WIDOW_BLASTER_20			173
+#define	MZ2_WIDOW_BLASTER_10			174
+#define	MZ2_WIDOW_BLASTER_0				175
+#define	MZ2_WIDOW_BLASTER_10L			176
+#define	MZ2_WIDOW_BLASTER_20L			177
+#define	MZ2_WIDOW_BLASTER_30L			178
+#define	MZ2_WIDOW_BLASTER_40L			179
+#define	MZ2_WIDOW_BLASTER_50L			180
+#define	MZ2_WIDOW_BLASTER_60L			181
+#define	MZ2_WIDOW_BLASTER_70L			182
+#define	MZ2_WIDOW_RUN_1					183
+#define	MZ2_WIDOW_RUN_2					184
+#define	MZ2_WIDOW_RUN_3					185
+#define	MZ2_WIDOW_RUN_4					186
+#define	MZ2_WIDOW_RUN_5					187
+#define	MZ2_WIDOW_RUN_6					188
+#define	MZ2_WIDOW_RUN_7					189
+#define	MZ2_WIDOW_RUN_8					190
+#define	MZ2_CARRIER_ROCKET_1			191
+#define	MZ2_CARRIER_ROCKET_2			192
+#define	MZ2_CARRIER_ROCKET_3			193
+#define	MZ2_CARRIER_ROCKET_4			194
+#define	MZ2_WIDOW2_BEAMER_1				195
+#define	MZ2_WIDOW2_BEAMER_2				196
+#define	MZ2_WIDOW2_BEAMER_3				197
+#define	MZ2_WIDOW2_BEAMER_4				198
+#define	MZ2_WIDOW2_BEAMER_5				199
+#define	MZ2_WIDOW2_BEAM_SWEEP_1			200
+#define	MZ2_WIDOW2_BEAM_SWEEP_2			201
+#define	MZ2_WIDOW2_BEAM_SWEEP_3			202
+#define	MZ2_WIDOW2_BEAM_SWEEP_4			203
+#define	MZ2_WIDOW2_BEAM_SWEEP_5			204
+#define	MZ2_WIDOW2_BEAM_SWEEP_6			205
+#define	MZ2_WIDOW2_BEAM_SWEEP_7			206
+#define	MZ2_WIDOW2_BEAM_SWEEP_8			207
+#define	MZ2_WIDOW2_BEAM_SWEEP_9			208
+#define	MZ2_WIDOW2_BEAM_SWEEP_10		209
+#define	MZ2_WIDOW2_BEAM_SWEEP_11		210
+
+// ROGUE
+
+extern	vec3_t monster_flash_offset [];
+
+
+// temp entity events
+//
+// Temp entity events are for things that happen
+// at a location seperate from any existing entity.
+// Temporary entity messages are explicitly constructed
+// and broadcast.
+typedef enum
+{
+	TE_GUNSHOT,
+	TE_BLOOD,
+	TE_BLASTER,
+	TE_RAILTRAIL,
+	TE_SHOTGUN,
+	TE_EXPLOSION1,
+	TE_EXPLOSION2,
+	TE_ROCKET_EXPLOSION,
+	TE_GRENADE_EXPLOSION,
+	TE_SPARKS,
+	TE_SPLASH,
+	TE_BUBBLETRAIL,
+	TE_SCREEN_SPARKS,
+	TE_SHIELD_SPARKS,
+	TE_BULLET_SPARKS,
+	TE_LASER_SPARKS,
+	TE_PARASITE_ATTACK,
+	TE_ROCKET_EXPLOSION_WATER,
+	TE_GRENADE_EXPLOSION_WATER,
+	TE_MEDIC_CABLE_ATTACK,
+	TE_BFG_EXPLOSION,
+	TE_BFG_BIGEXPLOSION,
+	TE_BOSSTPORT,			// used as '22' in a map, so DON'T RENUMBER!!!
+	TE_BFG_LASER,
+	TE_GRAPPLE_CABLE,
+	TE_WELDING_SPARKS,
+	TE_GREENBLOOD,
+	TE_BLUEHYPERBLASTER,
+	TE_PLASMA_EXPLOSION,
+	TE_TUNNEL_SPARKS,
+//ROGUE
+	TE_BLASTER2,
+	TE_RAILTRAIL2,
+	TE_FLAME,
+	TE_LIGHTNING,
+	TE_DEBUGTRAIL,
+	TE_PLAIN_EXPLOSION,
+	TE_FLASHLIGHT,
+	TE_FORCEWALL,
+	TE_HEATBEAM,
+	TE_MONSTER_HEATBEAM,
+	TE_STEAM,
+	TE_BUBBLETRAIL2,
+	TE_MOREBLOOD,
+	TE_HEATBEAM_SPARKS,
+	TE_HEATBEAM_STEAM,
+	TE_CHAINFIST_SMOKE,
+	TE_ELECTRIC_SPARKS,
+	TE_TRACKER_EXPLOSION,
+	TE_TELEPORT_EFFECT,
+	TE_DBALL_GOAL,
+	TE_WIDOWBEAMOUT,
+	TE_NUKEBLAST,
+	TE_WIDOWSPLASH,
+	TE_EXPLOSION1_BIG,
+	TE_EXPLOSION1_NP,
+	TE_FLECHETTE
+//ROGUE
+} temp_event_t;
+
+#define SPLASH_UNKNOWN		0
+#define SPLASH_SPARKS		1
+#define SPLASH_BLUE_WATER	2
+#define SPLASH_BROWN_WATER	3
+#define SPLASH_SLIME		4
+#define	SPLASH_LAVA			5
+#define SPLASH_BLOOD		6
+
+
+// sound channels
+// channel 0 never willingly overrides
+// other channels (1-7) allways override a playing sound on that channel
+#define	CHAN_AUTO               0
+#define	CHAN_WEAPON             1
+#define	CHAN_VOICE              2
+#define	CHAN_ITEM               3
+#define	CHAN_BODY               4
+// modifier flags
+#define	CHAN_NO_PHS_ADD			8	// send to all clients, not just ones in PHS (ATTN 0 will also do this)
+#define	CHAN_RELIABLE			16	// send by reliable message, not datagram
+
+
+// sound attenuation values
+#define	ATTN_NONE               0	// full volume the entire level
+#define	ATTN_NORM               1
+#define	ATTN_IDLE               2
+#define	ATTN_STATIC             3	// diminish very rapidly with distance
+
+
+// player_state->stats[] indexes
+#define STAT_HEALTH_ICON		0
+#define	STAT_HEALTH				1
+#define	STAT_AMMO_ICON			2
+#define	STAT_AMMO				3
+#define	STAT_ARMOR_ICON			4
+#define	STAT_ARMOR				5
+#define	STAT_SELECTED_ICON		6
+#define	STAT_PICKUP_ICON		7
+#define	STAT_PICKUP_STRING		8
+#define	STAT_TIMER_ICON			9
+#define	STAT_TIMER				10
+#define	STAT_HELPICON			11
+#define	STAT_SELECTED_ITEM		12
+#define	STAT_LAYOUTS			13
+#define	STAT_FRAGS				14
+#define	STAT_FLASHES			15		// cleared each frame, 1 = health, 2 = armor
+#define STAT_CHASE				16
+#define STAT_SPECTATOR			17
+
+#define	MAX_STATS				32
+
+
+// dmflags->value flags
+#define	DF_NO_HEALTH		0x00000001	// 1
+#define	DF_NO_ITEMS			0x00000002	// 2
+#define	DF_WEAPONS_STAY		0x00000004	// 4
+#define	DF_NO_FALLING		0x00000008	// 8
+#define	DF_INSTANT_ITEMS	0x00000010	// 16
+#define	DF_SAME_LEVEL		0x00000020	// 32
+#define DF_SKINTEAMS		0x00000040	// 64
+#define DF_MODELTEAMS		0x00000080	// 128
+#define DF_NO_FRIENDLY_FIRE	0x00000100	// 256
+#define	DF_SPAWN_FARTHEST	0x00000200	// 512
+#define DF_FORCE_RESPAWN	0x00000400	// 1024
+#define DF_NO_ARMOR			0x00000800	// 2048
+#define DF_ALLOW_EXIT		0x00001000	// 4096
+#define DF_INFINITE_AMMO	0x00002000	// 8192
+#define DF_QUAD_DROP		0x00004000	// 16384
+#define DF_FIXED_FOV		0x00008000	// 32768
+
+// RAFAEL
+#define	DF_QUADFIRE_DROP	0x00010000	// 65536
+
+//ROGUE
+#define DF_NO_MINES			0x00020000
+#define DF_NO_STACK_DOUBLE	0x00040000
+#define DF_NO_NUKES			0x00080000
+#define DF_NO_SPHERES		0x00100000
+//ROGUE
+
+/*
+ROGUE - VERSIONS
+1234	08/13/1998		Activision
+1235	08/14/1998		Id Software
+1236	08/15/1998		Steve Tietze
+1237	08/15/1998		Phil Dobranski
+1238	08/15/1998		John Sheley
+1239	08/17/1998		Barrett Alexander
+1230	08/17/1998		Brandon Fish
+1245	08/17/1998		Don MacAskill
+1246	08/17/1998		David "Zoid" Kirsch
+1247	08/17/1998		Manu Smith
+1248	08/17/1998		Geoff Scully
+1249	08/17/1998		Andy Van Fossen
+1240	08/20/1998		Activision Build 2
+1256	08/20/1998		Ranger Clan
+1257	08/20/1998		Ensemble Studios
+1258	08/21/1998		Robert Duffy
+1259	08/21/1998		Stephen Seachord
+1250	08/21/1998		Stephen Heaslip
+1267	08/21/1998		Samir Sandesara
+1268	08/21/1998		Oliver Wyman
+1269	08/21/1998		Steven Marchegiano
+1260	08/21/1998		Build #2 for Nihilistic
+1278	08/21/1998		Build #2 for Ensemble
+
+9999	08/20/1998		Internal Use
+*/
+#define ROGUE_VERSION_ID		1278
+
+#define ROGUE_VERSION_STRING	"08/21/1998 Beta 2 for Ensemble"
+
+// ROGUE
+/*
+==========================================================
+
+  ELEMENTS COMMUNICATED ACROSS THE NET
+
+==========================================================
+*/
+
+#define	ANGLE2SHORT(x)	((int)((x)*65536/360) & 65535)
+#define	SHORT2ANGLE(x)	((x)*(360.0/65536))
+
+
+//
+// config strings are a general means of communication from
+// the server to all connected clients.
+// Each config string can be at most MAX_QPATH characters.
+//
+#define	CS_NAME				0
+#define	CS_CDTRACK			1
+#define	CS_SKY				2
+#define	CS_SKYAXIS			3		// %f %f %f format
+#define	CS_SKYROTATE		4
+#define	CS_STATUSBAR		5		// display program string
+
+#define CS_AIRACCEL			29		// air acceleration control
+#define	CS_MAXCLIENTS		30
+#define	CS_MAPCHECKSUM		31		// for catching cheater maps
+
+#define	CS_MODELS			32
+#define	CS_SOUNDS			(CS_MODELS+MAX_MODELS)
+#define	CS_IMAGES			(CS_SOUNDS+MAX_SOUNDS)
+#define	CS_LIGHTS			(CS_IMAGES+MAX_IMAGES)
+#define	CS_ITEMS			(CS_LIGHTS+MAX_LIGHTSTYLES)
+#define	CS_PLAYERSKINS		(CS_ITEMS+MAX_ITEMS)
+#define CS_GENERAL			(CS_PLAYERSKINS+MAX_CLIENTS)
+#define	MAX_CONFIGSTRINGS	(CS_GENERAL+MAX_GENERAL)
+
+
+//==============================================
+
+
+// entity_state_t->event values
+// ertity events are for effects that take place reletive
+// to an existing entities origin.  Very network efficient.
+// All muzzle flashes really should be converted to events...
+typedef enum
+{
+	EV_NONE,
+	EV_ITEM_RESPAWN,
+	EV_FOOTSTEP,
+	EV_FALLSHORT,
+	EV_FALL,
+	EV_FALLFAR,
+	EV_PLAYER_TELEPORT,
+	EV_OTHER_TELEPORT
+} entity_event_t;
+
+
+// entity_state_t is the information conveyed from the server
+// in an update message about entities that the client will
+// need to render in some way
+typedef struct entity_state_s
+{
+	int		number;			// edict index
+
+	vec3_t	origin;
+	vec3_t	angles;
+	vec3_t	old_origin;		// for lerping
+	int		modelindex;
+	int		modelindex2, modelindex3, modelindex4;	// weapons, CTF flags, etc
+	int		frame;
+	int		skinnum;
+	unsigned int		effects;		// PGM - we're filling it, so it needs to be unsigned
+	int		renderfx;
+	int		solid;			// for client side prediction, 8*(bits 0-4) is x/y radius
+							// 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
+							// gi.linkentity sets this properly
+	int		sound;			// for looping sounds, to guarantee shutoff
+	int		event;			// impulse events -- muzzle flashes, footsteps, etc
+							// events only go out for a single frame, they
+							// are automatically cleared each frame
+} entity_state_t;
+
+//==============================================
+
+
+// player_state_t is the information needed in addition to pmove_state_t
+// to rendered a view.  There will only be 10 player_state_t sent each second,
+// but the number of pmove_state_t changes will be reletive to client
+// frame rates
+typedef struct
+{
+	pmove_state_t	pmove;		// for prediction
+
+	// these fields do not need to be communicated bit-precise
+
+	vec3_t		viewangles;		// for fixed views
+	vec3_t		viewoffset;		// add to pmovestate->origin
+	vec3_t		kick_angles;	// add to view direction to get render angles
+								// set by weapon kicks, pain effects, etc
+
+	vec3_t		gunangles;
+	vec3_t		gunoffset;
+	int			gunindex;
+	int			gunframe;
+
+	float		blend[4];		// rgba full screen effect
+	
+	float		fov;			// horizontal field of view
+
+	int			rdflags;		// refdef flags
+
+	short		stats[MAX_STATS];		// fast status bar updates
+} player_state_t;
+
+
+// ==================
+// PGM 
+#define VIDREF_GL		1
+#define VIDREF_SOFT		2
+#define VIDREF_OTHER	3
+
+extern int vidref_val;
+// PGM
+// ==================
--- /dev/null
+++ b/gnu.txt
@@ -1,0 +1,87 @@
+GNU GENERAL PUBLIC LICENSE
+Version 2, June 1991 
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+Preamble
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. 
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. 
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. 
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. 
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. 
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". 
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. 
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: 
+
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. 
+
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. 
+
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) 
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. 
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. 
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: 
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, 
+
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, 
+
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) 
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. 
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. 
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. 
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. 
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. 
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
+
+
+END OF TERMS AND CONDITIONS
--- /dev/null
+++ b/irix/cd_irix.c
@@ -1,0 +1,40 @@
+#include <sys/types.h>
+#include <cdaudio.h>
+
+#include "../client/client.h"
+
+void CDAudio_Play(int track, qboolean looping)
+{
+        Com_Printf("XXX - CDAudio_Play %i (%i)\n", track, looping);
+}
+
+
+void CDAudio_Stop(void)
+{
+        Com_Printf("XXX - CDAudio_Stop\n");
+}
+
+
+void CDAudio_Resume(void)
+{
+        Com_Printf("XXX - CDAudio_Resume\n");
+}
+
+
+void CDAudio_Update(void)
+{
+/*         Com_Printf("XXX - CDAudio_Update\n"); */
+}
+
+
+int CDAudio_Init(void)
+{
+        Com_Printf("XXX - CDAudio_Init\n");
+	return 0;
+}
+
+
+void CDAudio_Shutdown(void)
+{
+        Com_Printf("XXX - CDAudio_Shutdown\n");
+}
--- /dev/null
+++ b/irix/glw_imp.c
@@ -1,0 +1,927 @@
+/*
+** GLW_IMP.C
+**
+** This file contains ALL Linux specific stuff having to do with the
+** OpenGL refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** GLimp_EndFrame
+** GLimp_Init
+** GLimp_Shutdown
+** GLimp_SwitchFullscreen
+**
+*/
+
+#include <signal.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+#include <Xm/MwmUtil.h>
+
+#include <GL/glx.h>
+
+#include "../ref_gl/gl_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+GLXContext				gl_cx;
+
+static qboolean			doShm;
+static Display			*x_disp;
+static Colormap			x_cmap;
+static Window			x_win;
+static GC				x_gc;
+static Visual			*x_vis;
+static XVisualInfo		*x_visinfo;
+
+static int				StudlyRGBattributes[] =
+{
+    GLX_DOUBLEBUFFER,
+    GLX_RGBA,
+    GLX_RED_SIZE, 4,
+    GLX_GREEN_SIZE, 4,
+    GLX_BLUE_SIZE, 4,
+    GLX_DEPTH_SIZE, 1,
+    GLX_SAMPLES_SGIS, 4, /* for better AA */
+    None,
+};
+
+static int				RGBattributes[] =
+{
+    GLX_DOUBLEBUFFER,
+    GLX_RGBA,
+    GLX_RED_SIZE, 4,
+    GLX_GREEN_SIZE, 4,
+    GLX_BLUE_SIZE, 4,
+    GLX_DEPTH_SIZE, 1,
+    None,
+};
+
+#define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \
+	     | KeyReleaseMask | ExposureMask | PointerMotionMask | \
+	     ButtonPressMask | ButtonReleaseMask)
+
+int current_framebuffer;
+static int				x_shmeventtype;
+//static XShmSegmentInfo	x_shminfo;
+
+static qboolean			oktodraw = false;
+static qboolean			X11_active = false;
+
+struct
+{
+	int key;
+	int down;
+} keyq[64];
+int keyq_head=0;
+int keyq_tail=0;
+
+static int		mx, my;
+static int p_mouse_x, p_mouse_y;
+static cvar_t	*_windowed_mouse;
+
+static cvar_t *sensitivity;
+static cvar_t *lookstrafe;
+static cvar_t *m_side;
+static cvar_t *m_yaw;
+static cvar_t *m_pitch;
+static cvar_t *m_forward;
+static cvar_t *freelook;
+
+int config_notify=0;
+int config_notify_width;
+int config_notify_height;
+						      
+typedef unsigned short PIXEL;
+
+// Console variables that we need to access from this module
+
+/*****************************************************************************/
+/* MOUSE                                                                     */
+/*****************************************************************************/
+
+// this is inside the renderer shared lib, so these are called from vid_so
+
+static qboolean        mouse_avail;
+static int     mouse_buttonstate;
+static int     mouse_oldbuttonstate;
+static int   mouse_x, mouse_y;
+static int	old_mouse_x, old_mouse_y;
+static float old_windowed_mouse;
+static int p_mouse_x, p_mouse_y;
+
+static cvar_t	*_windowed_mouse;
+static cvar_t	*m_filter;
+static cvar_t	*in_mouse;
+
+static qboolean	mlooking;
+
+// state struct passed in Init
+static in_state_t	*in_state;
+
+int XShmQueryExtension(Display *);
+int XShmGetEventBase(Display *);
+
+static void signal_handler(int sig)
+{
+	fprintf(stderr, "Received signal %d, exiting...\n", sig);
+	GLimp_Shutdown();
+	_exit(0);
+}
+
+static void InitSig(void)
+{
+        struct sigaction sa;
+	sigaction(SIGINT, 0, &sa);
+	sa.sa_handler = signal_handler;
+	sigaction(SIGINT, &sa, 0);
+	sigaction(SIGTERM, &sa, 0);
+}
+
+/*
+** GLimp_SetMode
+*/
+int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+	int width, height;
+	GLint attribs[32];
+
+	fprintf(stderr, "GLimp_SetMode\n");
+
+	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
+
+	ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
+
+	if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
+	{
+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+		return rserr_invalid_mode;
+	}
+
+	ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
+
+	// destroy the existing window
+	GLimp_Shutdown ();
+
+	*pwidth = width;
+	*pheight = height;
+
+	if ( !GLimp_InitGraphics( fullscreen ) ) {
+		// failed to set a valid mode in windowed mode
+		return rserr_invalid_mode;
+	}
+/* 	gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True ); */
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (width, height);
+
+	return rserr_ok;
+}
+
+/*
+** GLimp_Shutdown
+**
+** This routine does all OS specific shutdown procedures for the OpenGL
+** subsystem.  Under OpenGL this means NULLing out the current DC and
+** HGLRC, deleting the rendering context, and releasing the DC acquired
+** for the window.  The state structure is also nulled out.
+**
+*/
+void GLimp_Shutdown( void )
+{
+	fprintf(stderr, "GLimp_Shutdown\n");
+
+	if (!x_disp)
+	    return;
+
+	XSynchronize( x_disp, True );
+	XAutoRepeatOn(x_disp);
+	XCloseDisplay(x_disp);
+	x_disp = NULL;
+}
+
+/*
+** GLimp_Init
+**
+** This routine is responsible for initializing the OS specific portions
+** of OpenGL.  
+*/
+int GLimp_Init( void *hinstance, void *wndproc )
+{
+// catch signals so i can turn on auto-repeat and stuff
+	InitSig();
+
+	return true;
+}
+
+/*
+** GLimp_BeginFrame
+*/
+void GLimp_BeginFrame( float camera_seperation )
+{
+}
+
+/*
+** GLimp_EndFrame
+** 
+** Responsible for doing a swapbuffers and possibly for other stuff
+** as yet to be determined.  Probably better not to make this a GLimp
+** function and instead do a call to GLimp_SwapBuffers.
+*/
+void GLimp_EndFrame (void)
+{
+	glFlush();
+	glXSwapBuffers( x_disp, x_win );
+}
+
+/*
+** GLimp_AppActivate
+*/
+void GLimp_AppActivate( qboolean active )
+{
+}
+
+// ========================================================================
+// makes a null cursor
+// ========================================================================
+
+static Cursor CreateNullCursor(Display *display, Window root)
+{
+    Pixmap cursormask; 
+    XGCValues xgc;
+    GC gc;
+    XColor dummycolour;
+    Cursor cursor;
+
+    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
+    xgc.function = GXclear;
+    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
+    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
+    dummycolour.pixel = 0;
+    dummycolour.red = 0;
+    dummycolour.flags = 04;
+    cursor = XCreatePixmapCursor(display, cursormask, cursormask,
+          &dummycolour,&dummycolour, 0,0);
+    XFreePixmap(display,cursormask);
+    XFreeGC(display,gc);
+    return cursor;
+}
+
+/*
+** GLimp_InitGraphics
+**
+** This initializes the GL implementation specific
+** graphics subsystem.
+**
+** The necessary width and height parameters are grabbed from
+** vid.width and vid.height.
+*/
+qboolean GLimp_InitGraphics( qboolean fullscreen )
+{
+	int pnum, i;
+	XVisualInfo template;
+	int num_visuals;
+	int template_mask;
+
+	fprintf(stderr, "GLimp_InitGraphics\n");
+
+	srandom(getpid());
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (vid.width, vid.height);
+
+	// open the display
+	x_disp = XOpenDisplay(NULL);
+	if (!x_disp)
+	{
+		if (getenv("DISPLAY"))
+			Sys_Error("VID: Could not open display [%s]\n",
+				getenv("DISPLAY"));
+		else
+			Sys_Error("VID: Could not open local display\n");
+	}
+	else
+	    fprintf(stderr, "VID: Opened display %s\n", getenv("DISPLAY"));
+
+	XAutoRepeatOff(x_disp);
+
+// for debugging only
+	XSynchronize(x_disp, True);
+
+// check for command-line window size
+	template_mask = 0;
+
+#if 0
+// specify a visual id
+	if ((pnum=COM_CheckParm("-visualid")))
+	{
+		if (pnum >= com_argc-1)
+			Sys_Error("VID: -visualid <id#>\n");
+		template.visualid = Q_atoi(com_argv[pnum+1]);
+		template_mask = VisualIDMask;
+	}
+
+// If not specified, use default visual
+	else
+#endif
+	{
+		int screen;
+		screen = XDefaultScreen(x_disp);
+		template.visualid =
+			XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
+		template_mask = VisualIDMask;
+	}
+
+// pick a visual- warn if more than one was available
+
+	x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ),
+				     StudlyRGBattributes );
+	if (!x_visinfo)
+	{
+	    fprintf(stderr, "Using non studly RGB attributes\n");
+		x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ),
+					     RGBattributes );
+		if (!x_visinfo) Sys_Error( "No matching visual available!\n" );
+	}
+
+	ri.Con_Printf(PRINT_ALL, "Using visualid 0x%x:\n",
+		   (int)(x_visinfo->visualid));
+#if 0
+	if (verbose)
+	{
+		printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
+		printf("	screen %d\n", x_visinfo->screen);
+		printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
+		printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
+		printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
+		printf("	colormap_size %d\n", x_visinfo->colormap_size);
+		printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
+	}
+#endif
+
+	x_vis = x_visinfo->visual;
+
+// setup attributes for main window
+	{
+	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
+	   XSetWindowAttributes attribs;
+	   Colormap tmpcmap;
+	   
+	   Window root_win = XRootWindow(x_disp, x_visinfo->screen);
+
+	   tmpcmap = XCreateColormap(x_disp, root_win, x_vis, AllocNone);
+				     
+	   
+	   attribs.event_mask = STD_EVENT_MASK;
+	   attribs.border_pixel = 0;
+	   attribs.colormap = tmpcmap;
+
+// create the main window
+		x_win = XCreateWindow(	x_disp,
+			root_win,		
+			0, 0,	// x, y
+			vid.width, vid.height,
+			0, // borderwidth
+			x_visinfo->depth,
+			InputOutput,
+			x_vis,
+			attribmask,
+			&attribs );
+		XStoreName(x_disp, x_win, "Quake II");
+
+		if (x_visinfo->class != TrueColor)
+			XFreeColormap(x_disp, tmpcmap);
+	}
+
+	if (x_visinfo->depth == 8)
+	{
+	// create and upload the palette
+		if (x_visinfo->class == PseudoColor)
+		{
+			x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
+			XSetWindowColormap(x_disp, x_win, x_cmap);
+		}
+
+	}
+
+// inviso cursor
+	XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
+
+// create the GC
+	{
+		XGCValues xgcvalues;
+		int valuemask = GCGraphicsExposures;
+		xgcvalues.graphics_exposures = False;
+		x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
+	}
+
+// set window properties for full screen
+	if (fullscreen) {
+	    MotifWmHints    wmhints;
+	    Atom aHints;
+	    XSizeHints              sizehints;
+	    XWindowChanges  changes;
+
+	    aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
+	    if (aHints == None)
+	    {
+                ri.Con_Printf( PRINT_ALL, "Could not intern X atom for _MOTIF_WM_HINTS." );
+/*                 return( false ); */
+	    }
+	    else {
+		wmhints.flags = MWM_HINTS_DECORATIONS;
+		wmhints.decorations = 0; // Absolutely no decorations.
+		XChangeProperty(x_disp, x_win, aHints, aHints, 32,
+				PropModeReplace, (unsigned char *)&wmhints,
+				4 );
+
+		sizehints.flags = USPosition | USSize;
+		sizehints.x = 0;
+		sizehints.y = 0;
+		sizehints.width = vid.width;
+		sizehints.height = vid.height;
+		XSetWMNormalHints( x_disp, x_win, &sizehints );
+
+		changes.x = 0;
+		changes.y = 0;
+		changes.width = vid.width;
+		changes.height = vid.height;
+		changes.stack_mode = TopIf;
+		XConfigureWindow(x_disp, x_win,
+				 CWX | CWY | CWWidth | CWHeight | CWStackMode,
+				 &changes);
+	    }
+	}
+
+// map the window
+	XMapWindow(x_disp, x_win);
+
+// wait for first exposure event
+	{
+		XEvent event;
+		do
+		{
+			XNextEvent(x_disp, &event);
+			if (event.type == Expose && !event.xexpose.count)
+				oktodraw = true;
+		} while (!oktodraw);
+	}
+// now safe to draw
+
+    gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True );
+    if (!glXMakeCurrent( x_disp, x_win, gl_cx ))
+		Sys_Error( "Can't make window current to context\n" );
+
+// even if MITSHM is available, make sure it's a local connection
+#if 0
+// This is messing up the DISPLAY environment variable so can't close and
+// reopen the window (it lops off the :0.0)...
+	if (XShmQueryExtension(x_disp))
+	{
+		char *displayname;
+		doShm = true;
+		displayname = (char *) getenv("DISPLAY");
+		if (displayname)
+		{
+			char *d = displayname;
+			while (*d && (*d != ':')) d++;
+			if (*d) *d = 0;
+			if (!(!strcasecmp(displayname, "unix") || !*displayname))
+				doShm = false;
+		}
+	}
+#endif
+
+#if 0
+	if (doShm)
+	{
+		x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
+		ResetSharedFrameBuffers();
+	}
+	else
+		ResetFrameBuffer();
+#endif
+
+	current_framebuffer = 0;
+/* 	vid.rowbytes = x_framebuffer[0]->bytes_per_line; */
+/* 	vid.buffer = x_framebuffer[0]->data; */
+
+//	XSynchronize(x_disp, False);
+
+	X11_active = true;
+
+	return true;
+}
+
+/*****************************************************************************/
+
+int XLateKey(XKeyEvent *ev)
+{
+
+	int key;
+	char buf[64];
+	KeySym keysym;
+
+	key = 0;
+
+	XLookupString(ev, buf, sizeof buf, &keysym, 0);
+
+	switch(keysym)
+	{
+		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;
+		case XK_Page_Up:	 key = K_PGUP; break;
+
+		case XK_KP_Page_Down: key = K_KP_PGDN; break;
+		case XK_Page_Down:	 key = K_PGDN; break;
+
+		case XK_KP_Home: key = K_KP_HOME; break;
+		case XK_Home:	 key = K_HOME; break;
+
+		case XK_KP_End:  key = K_KP_END; break;
+		case XK_End:	 key = K_END; break;
+
+		case XK_KP_Left: key = K_KP_LEFTARROW; break;
+		case XK_Left:	 key = K_LEFTARROW; break;
+
+		case XK_KP_Right: key = K_KP_RIGHTARROW; break;
+		case XK_Right:	key = K_RIGHTARROW;		break;
+
+		case XK_KP_Down: key = K_KP_DOWNARROW; break;
+		case XK_Down:	 key = K_DOWNARROW; break;
+
+		case XK_KP_Up:   key = K_KP_UPARROW; break;
+		case XK_Up:		 key = K_UPARROW;	 break;
+
+		case XK_Escape: key = K_ESCAPE;		break;
+
+		case XK_KP_Enter: key = K_KP_ENTER;	break;
+		case XK_Return: key = K_ENTER;		 break;
+
+		case XK_Tab:		key = K_TAB;			 break;
+
+		case XK_F1:		 key = K_F1;				break;
+
+		case XK_F2:		 key = K_F2;				break;
+
+		case XK_F3:		 key = K_F3;				break;
+
+		case XK_F4:		 key = K_F4;				break;
+
+		case XK_F5:		 key = K_F5;				break;
+
+		case XK_F6:		 key = K_F6;				break;
+
+		case XK_F7:		 key = K_F7;				break;
+
+		case XK_F8:		 key = K_F8;				break;
+
+		case XK_F9:		 key = K_F9;				break;
+
+		case XK_F10:		key = K_F10;			 break;
+
+		case XK_F11:		key = K_F11;			 break;
+
+		case XK_F12:		key = K_F12;			 break;
+
+		case XK_BackSpace: key = K_BACKSPACE; break;
+
+		case XK_KP_Delete: key = K_KP_DEL; break;
+		case XK_Delete: key = K_DEL; break;
+
+		case XK_Pause:	key = K_PAUSE;		 break;
+
+		case XK_Shift_L:
+		case XK_Shift_R:	key = K_SHIFT;		break;
+
+		case XK_Execute: 
+		case XK_Control_L: 
+		case XK_Control_R:	key = K_CTRL;		 break;
+
+		case XK_Alt_L:	
+		case XK_Meta_L: 
+		case XK_Alt_R:	
+		case XK_Meta_R: key = K_ALT;			break;
+
+		case XK_KP_Begin: key = K_KP_5;	break;
+
+		case XK_Insert:key = K_INS; break;
+		case XK_KP_Insert: key = K_KP_INS; break;
+
+		case XK_KP_Multiply: key = '*'; break;
+		case XK_KP_Add:  key = K_KP_PLUS; break;
+		case XK_KP_Subtract: key = K_KP_MINUS; break;
+		case XK_KP_Divide: key = K_KP_SLASH; break;
+
+#if 0
+		case 0x021: key = '1';break;/* [!] */
+		case 0x040: key = '2';break;/* [@] */
+		case 0x023: key = '3';break;/* [#] */
+		case 0x024: key = '4';break;/* [$] */
+		case 0x025: key = '5';break;/* [%] */
+		case 0x05e: key = '6';break;/* [^] */
+		case 0x026: key = '7';break;/* [&] */
+		case 0x02a: key = '8';break;/* [*] */
+		case 0x028: key = '9';;break;/* [(] */
+		case 0x029: key = '0';break;/* [)] */
+		case 0x05f: key = '-';break;/* [_] */
+		case 0x02b: key = '=';break;/* [+] */
+		case 0x07c: key = '\'';break;/* [|] */
+		case 0x07d: key = '[';break;/* [}] */
+		case 0x07b: key = ']';break;/* [{] */
+		case 0x022: key = '\'';break;/* ["] */
+		case 0x03a: key = ';';break;/* [:] */
+		case 0x03f: key = '/';break;/* [?] */
+		case 0x03e: key = '.';break;/* [>] */
+		case 0x03c: key = ',';break;/* [<] */
+#endif
+
+		default:
+			key = *(unsigned char*)buf;
+			if (key >= 'A' && key <= 'Z')
+				key = key - 'A' + 'a';
+			break;
+	} 
+
+	return key;
+}
+
+void GetEvent(void)
+{
+	XEvent x_event;
+	int b;
+   
+	XNextEvent(x_disp, &x_event);
+	switch(x_event.type) {
+	case KeyPress:
+		keyq[keyq_head].key = XLateKey(&x_event.xkey);
+		keyq[keyq_head].down = true;
+		keyq_head = (keyq_head + 1) & 63;
+		break;
+	case KeyRelease:
+		keyq[keyq_head].key = XLateKey(&x_event.xkey);
+		keyq[keyq_head].down = false;
+		keyq_head = (keyq_head + 1) & 63;
+		break;
+
+	case MotionNotify:
+		if (_windowed_mouse->value) {
+			mx += ((int)x_event.xmotion.x - (int)(vid.width/2));
+			my += ((int)x_event.xmotion.y - (int)(vid.height/2));
+
+			/* move the mouse to the window center again */
+			XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
+			XWarpPointer(x_disp,None,x_win,0,0,0,0, 
+				(vid.width/2),(vid.height/2));
+			XSelectInput(x_disp,x_win, STD_EVENT_MASK);
+		} else {
+			mx = ((int)x_event.xmotion.x - (int)p_mouse_x);
+			my = ((int)x_event.xmotion.y - (int)p_mouse_y);
+			p_mouse_x=x_event.xmotion.x;
+			p_mouse_y=x_event.xmotion.y;
+		}
+		break;
+
+	case ButtonPress:
+		b=-1;
+		if (x_event.xbutton.button == 1)
+			b = 0;
+		else if (x_event.xbutton.button == 2)
+			b = 2;
+		else if (x_event.xbutton.button == 3)
+			b = 1;
+		if (b>=0)
+			mouse_buttonstate |= 1<<b;
+		break;
+
+	case ButtonRelease:
+		b=-1;
+		if (x_event.xbutton.button == 1)
+			b = 0;
+		else if (x_event.xbutton.button == 2)
+			b = 2;
+		else if (x_event.xbutton.button == 3)
+			b = 1;
+		if (b>=0)
+			mouse_buttonstate &= ~(1<<b);
+		break;
+	
+	case ConfigureNotify:
+		config_notify_width = x_event.xconfigure.width;
+		config_notify_height = x_event.xconfigure.height;
+		config_notify = 1;
+		break;
+
+	default:
+		if (doShm && x_event.type == x_shmeventtype)
+			oktodraw = true;
+	}
+   
+	if (old_windowed_mouse != _windowed_mouse->value) {
+		old_windowed_mouse = _windowed_mouse->value;
+
+		if (!_windowed_mouse->value) {
+			/* ungrab the pointer */
+			XUngrabPointer(x_disp,CurrentTime);
+		} else {
+			/* grab the pointer */
+			XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
+				GrabModeAsync,x_win,None,CurrentTime);
+		}
+	}
+}
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* KEYBOARD                                                                  */
+/*****************************************************************************/
+
+Key_Event_fp_t Key_Event_fp;
+
+void KBD_Init(Key_Event_fp_t fp)
+{
+	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
+	Key_Event_fp = fp;
+}
+
+void KBD_Update(void)
+{
+// get events from x server
+	if (x_disp)
+	{
+		while (XPending(x_disp)) 
+			GetEvent();
+		while (keyq_head != keyq_tail)
+		{
+			Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down);
+			keyq_tail = (keyq_tail + 1) & 63;
+		}
+	}
+}
+
+void KBD_Close(void)
+{
+}
+
+
+static void Force_CenterView_f (void)
+{
+	in_state->viewangles[PITCH] = 0;
+}
+
+static void RW_IN_MLookDown (void) 
+{ 
+	mlooking = true; 
+}
+
+static void RW_IN_MLookUp (void) 
+{
+	mlooking = false;
+	in_state->IN_CenterView_fp ();
+}
+
+void RW_IN_Init(in_state_t *in_state_p)
+{
+	int mtype;
+	int i;
+
+	fprintf(stderr, "GL RW_IN_Init\n");
+
+	in_state = in_state_p;
+
+	// mouse variables
+	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
+	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
+    in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
+	freelook = ri.Cvar_Get( "freelook", "0", 0 );
+	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
+	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
+	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
+	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
+	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
+	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
+
+	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
+	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
+
+	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
+
+	mouse_x = mouse_y = 0.0;
+	mouse_avail = true;
+}
+
+void RW_IN_Shutdown(void)
+{
+	mouse_avail = false;
+
+	ri.Cmd_RemoveCommand ("force_centerview");
+	ri.Cmd_RemoveCommand ("+mlook");
+	ri.Cmd_RemoveCommand ("-mlook");
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void RW_IN_Commands (void)
+{
+	int i;
+   
+	if (!mouse_avail) 
+		return;
+   
+	for (i=0 ; i<3 ; i++) {
+		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
+			in_state->Key_Event_fp (K_MOUSE1 + i, true);
+
+		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
+			in_state->Key_Event_fp (K_MOUSE1 + i, false);
+	}
+	mouse_oldbuttonstate = mouse_buttonstate;
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void RW_IN_Move (usercmd_t *cmd)
+{
+	if (!mouse_avail)
+		return;
+   
+	if (m_filter->value)
+	{
+		mouse_x = (mx + old_mouse_x) * 0.5;
+		mouse_y = (my + old_mouse_y) * 0.5;
+	} else {
+		mouse_x = mx;
+		mouse_y = my;
+	}
+
+	old_mouse_x = mx;
+	old_mouse_y = my;
+
+	if (!mouse_x && !mouse_y)
+		return;
+
+	mouse_x *= sensitivity->value;
+	mouse_y *= sensitivity->value;
+
+// add mouse X/Y movement to cmd
+	if ( (*in_state->in_strafe_state & 1) || 
+		(lookstrafe->value && mlooking ))
+		cmd->sidemove += m_side->value * mouse_x;
+	else
+		in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
+
+	if ( (mlooking || freelook->value) && 
+		!(*in_state->in_strafe_state & 1))
+	{
+		in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
+	}
+	else
+	{
+		cmd->forwardmove -= m_forward->value * mouse_y;
+	}
+	mx = my = 0;
+}
+
+void RW_IN_Frame (void)
+{
+}
+
+void RW_IN_Activate(void)
+{
+}
+
+
+//===============================================================================
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+	int r;
+	unsigned long addr;
+	int psize = getpagesize();
+
+	addr = (startaddr & ~(psize-1)) - psize;
+
+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+//			addr, startaddr+length, length);
+
+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+	if (r < 0)
+    		Sys_Error("Protection change failed\n");
+
+}
--- /dev/null
+++ b/irix/q_shirix.c
@@ -1,0 +1,200 @@
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "../linux/glob.h"
+
+#include "../qcommon/qcommon.h"
+
+//===============================================================================
+
+byte *membase;
+int maxhunksize;
+int curhunksize;
+
+void *Hunk_Begin (int maxsize)
+{
+	maxhunksize = maxsize + sizeof(int);
+	curhunksize = 0;
+/* 	membase = mmap(0, maxhunksize, PROT_READ|PROT_WRITE,  */
+/* 		MAP_PRIVATE, -1, 0); */
+/* 	if ((membase == NULL) || (membase == MAP_FAILED)) */
+	membase = malloc(maxhunksize);
+	if (membase == NULL)
+		Com_Error(ERR_FATAL, "unable to virtual allocate %d bytes", maxsize);
+
+	*((int *)membase) = curhunksize;
+
+	return membase + sizeof(int);
+}
+
+void *Hunk_Alloc (int size)
+{
+	byte *buf;
+
+	// round to cacheline
+	size = (size+31)&~31;
+	if (curhunksize + size > maxhunksize)
+		Com_Error(ERR_FATAL, "Hunk_Alloc overflow");
+	buf = membase + sizeof(int) + curhunksize;
+	curhunksize += size;
+	return buf;
+}
+
+int Hunk_End (void)
+{
+	return curhunksize;
+}
+
+void Hunk_Free (void *base)
+{
+	byte *m;
+
+	if (base) {
+		m = ((byte *)base) - sizeof(int);
+		free(m);
+	}
+}
+
+//===============================================================================
+
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int curtime;
+int Sys_Milliseconds (void)
+{
+	struct timeval tp;
+	struct timezone tzp;
+	static int		secbase;
+
+	gettimeofday(&tp, &tzp);
+	
+	if (!secbase)
+	{
+		secbase = tp.tv_sec;
+		return tp.tv_usec/1000;
+	}
+
+	curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
+	
+	return curtime;
+}
+
+void Sys_Mkdir (char *path)
+{
+    mkdir (path, 0777);
+}
+
+char *strlwr (char *s)
+{
+        char *origs = s;
+	while (*s) {
+		*s = tolower(*s);
+		s++;
+	}
+	return origs;
+}
+
+//============================================
+
+static	char	findbase[MAX_OSPATH];
+static	char	findpath[MAX_OSPATH];
+static	char	findpattern[MAX_OSPATH];
+static	DIR		*fdir;
+
+static qboolean CompareAttributes(char *path, char *name,
+	unsigned musthave, unsigned canthave )
+{
+	struct stat st;
+	char fn[MAX_OSPATH];
+
+// . and .. never match
+	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+		return false;
+
+	sprintf(fn, "%s/%s", path, name);
+	if (stat(fn, &st) == -1)
+		return false; // shouldn't happen
+
+	if ( ( st.st_mode & S_IFDIR ) && ( canthave & SFF_SUBDIR ) )
+		return false;
+
+	if ( ( musthave & SFF_SUBDIR ) && !( st.st_mode & S_IFDIR ) )
+		return false;
+
+	return true;
+}
+
+char *Sys_FindFirst (char *path, unsigned musthave, unsigned canhave)
+{
+	struct dirent *d;
+	char *p;
+
+	if (fdir)
+		Sys_Error ("Sys_BeginFind without close");
+
+//	COM_FilePath (path, findbase);
+	strcpy(findbase, path);
+
+	if ((p = strrchr(findbase, '/')) != NULL) {
+		*p = 0;
+		strcpy(findpattern, p + 1);
+	} else
+		strcpy(findpattern, "*");
+
+	if (strcmp(findpattern, "*.*") == 0)
+		strcpy(findpattern, "*");
+	
+	if ((fdir = opendir(findbase)) == NULL)
+		return NULL;
+	while ((d = readdir(fdir)) != NULL) {
+		if (!*findpattern || glob_match(findpattern, d->d_name)) {
+//			if (*findpattern)
+//				printf("%s matched %s\n", findpattern, d->d_name);
+			if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+				sprintf (findpath, "%s/%s", findbase, d->d_name);
+				return findpath;
+			}
+		}
+	}
+	return NULL;
+}
+
+char *Sys_FindNext (unsigned musthave, unsigned canhave)
+{
+	struct dirent *d;
+
+	if (fdir == NULL)
+		return NULL;
+	while ((d = readdir(fdir)) != NULL) {
+		if (!*findpattern || glob_match(findpattern, d->d_name)) {
+//			if (*findpattern)
+//				printf("%s matched %s\n", findpattern, d->d_name);
+			if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+				sprintf (findpath, "%s/%s", findbase, d->d_name);
+				return findpath;
+			}
+		}
+	}
+	return NULL;
+}
+
+void Sys_FindClose (void)
+{
+	if (fdir != NULL)
+		closedir(fdir);
+	fdir = NULL;
+}
+
+
+//============================================
+
--- /dev/null
+++ b/irix/qgl_irix.c
@@ -1,0 +1,3997 @@
+/*
+** QGL_WIN.C
+**
+** This file implements the operating system binding of GL to QGL function
+** pointers.  When doing a port of Quake2 you must implement the following
+** two functions:
+**
+** QGL_Init() - loads libraries, assigns function pointers, etc.
+** QGL_Shutdown() - unloads libraries, NULLs function pointers
+*/
+#define QGL
+#include "../ref_gl/gl_local.h"
+
+static FILE *log_fp = NULL;
+
+void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
+void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
+GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+void ( APIENTRY * qglArrayElement )(GLint i);
+void ( APIENTRY * qglBegin )(GLenum mode);
+void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);
+void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);
+void ( APIENTRY * qglCallList )(GLuint list);
+void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+void ( APIENTRY * qglClear )(GLbitfield mask);
+void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void ( APIENTRY * qglClearDepth )(GLclampd depth);
+void ( APIENTRY * qglClearIndex )(GLfloat c);
+void ( APIENTRY * qglClearStencil )(GLint s);
+void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);
+void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+void ( APIENTRY * qglColor3bv )(const GLbyte *v);
+void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+void ( APIENTRY * qglColor3dv )(const GLdouble *v);
+void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+void ( APIENTRY * qglColor3fv )(const GLfloat *v);
+void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue);
+void ( APIENTRY * qglColor3iv )(const GLint *v);
+void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue);
+void ( APIENTRY * qglColor3sv )(const GLshort *v);
+void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+void ( APIENTRY * qglColor3ubv )(const GLubyte *v);
+void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue);
+void ( APIENTRY * qglColor3uiv )(const GLuint *v);
+void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue);
+void ( APIENTRY * qglColor3usv )(const GLushort *v);
+void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+void ( APIENTRY * qglColor4bv )(const GLbyte *v);
+void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+void ( APIENTRY * qglColor4dv )(const GLdouble *v);
+void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void ( APIENTRY * qglColor4fv )(const GLfloat *v);
+void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+void ( APIENTRY * qglColor4iv )(const GLint *v);
+void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+void ( APIENTRY * qglColor4sv )(const GLshort *v);
+void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+void ( APIENTRY * qglColor4ubv )(const GLubyte *v);
+void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+void ( APIENTRY * qglColor4uiv )(const GLuint *v);
+void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+void ( APIENTRY * qglColor4usv )(const GLushort *v);
+void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode);
+void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+void ( APIENTRY * qglCullFace )(GLenum mode);
+void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range);
+void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);
+void ( APIENTRY * qglDepthFunc )(GLenum func);
+void ( APIENTRY * qglDepthMask )(GLboolean flag);
+void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);
+void ( APIENTRY * qglDisable )(GLenum cap);
+void ( APIENTRY * qglDisableClientState )(GLenum array);
+void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count);
+void ( APIENTRY * qglDrawBuffer )(GLenum mode);
+void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglEdgeFlag )(GLboolean flag);
+void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag);
+void ( APIENTRY * qglEnable )(GLenum cap);
+void ( APIENTRY * qglEnableClientState )(GLenum array);
+void ( APIENTRY * qglEnd )(void);
+void ( APIENTRY * qglEndList )(void);
+void ( APIENTRY * qglEvalCoord1d )(GLdouble u);
+void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u);
+void ( APIENTRY * qglEvalCoord1f )(GLfloat u);
+void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u);
+void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v);
+void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u);
+void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v);
+void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u);
+void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+void ( APIENTRY * qglEvalPoint1 )(GLint i);
+void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j);
+void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+void ( APIENTRY * qglFinish )(void);
+void ( APIENTRY * qglFlush )(void);
+void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglFogi )(GLenum pname, GLint param);
+void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params);
+void ( APIENTRY * qglFrontFace )(GLenum mode);
+void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLuint ( APIENTRY * qglGenLists )(GLsizei range);
+void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures);
+void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params);
+void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation);
+void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params);
+GLenum ( APIENTRY * qglGetError )(void);
+void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);
+void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v);
+void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values);
+void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values);
+void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values);
+void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params);
+void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask);
+const GLubyte * ( APIENTRY * qglGetString )(GLenum name);
+void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+void ( APIENTRY * qglHint )(GLenum target, GLenum mode);
+void ( APIENTRY * qglIndexMask )(GLuint mask);
+void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglIndexd )(GLdouble c);
+void ( APIENTRY * qglIndexdv )(const GLdouble *c);
+void ( APIENTRY * qglIndexf )(GLfloat c);
+void ( APIENTRY * qglIndexfv )(const GLfloat *c);
+void ( APIENTRY * qglIndexi )(GLint c);
+void ( APIENTRY * qglIndexiv )(const GLint *c);
+void ( APIENTRY * qglIndexs )(GLshort c);
+void ( APIENTRY * qglIndexsv )(const GLshort *c);
+void ( APIENTRY * qglIndexub )(GLubyte c);
+void ( APIENTRY * qglIndexubv )(const GLubyte *c);
+void ( APIENTRY * qglInitNames )(void);
+void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap);
+GLboolean ( APIENTRY * qglIsList )(GLuint list);
+GLboolean ( APIENTRY * qglIsTexture )(GLuint texture);
+void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param);
+void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params);
+void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param);
+void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param);
+void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params);
+void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern);
+void ( APIENTRY * qglLineWidth )(GLfloat width);
+void ( APIENTRY * qglListBase )(GLuint base);
+void ( APIENTRY * qglLoadIdentity )(void);
+void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m);
+void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);
+void ( APIENTRY * qglLoadName )(GLuint name);
+void ( APIENTRY * qglLogicOp )(GLenum opcode);
+void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param);
+void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param);
+void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+void ( APIENTRY * qglMatrixMode )(GLenum mode);
+void ( APIENTRY * qglMultMatrixd )(const GLdouble *m);
+void ( APIENTRY * qglMultMatrixf )(const GLfloat *m);
+void ( APIENTRY * qglNewList )(GLuint list, GLenum mode);
+void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+void ( APIENTRY * qglNormal3bv )(const GLbyte *v);
+void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+void ( APIENTRY * qglNormal3dv )(const GLdouble *v);
+void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+void ( APIENTRY * qglNormal3fv )(const GLfloat *v);
+void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz);
+void ( APIENTRY * qglNormal3iv )(const GLint *v);
+void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+void ( APIENTRY * qglNormal3sv )(const GLshort *v);
+void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+void ( APIENTRY * qglPassThrough )(GLfloat token);
+void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param);
+void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param);
+void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+void ( APIENTRY * qglPointSize )(GLfloat size);
+void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);
+void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);
+void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask);
+void ( APIENTRY * qglPopAttrib )(void);
+void ( APIENTRY * qglPopClientAttrib )(void);
+void ( APIENTRY * qglPopMatrix )(void);
+void ( APIENTRY * qglPopName )(void);
+void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+void ( APIENTRY * qglPushAttrib )(GLbitfield mask);
+void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask);
+void ( APIENTRY * qglPushMatrix )(void);
+void ( APIENTRY * qglPushName )(GLuint name);
+void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y);
+void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y);
+void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y);
+void ( APIENTRY * qglRasterPos2iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y);
+void ( APIENTRY * qglRasterPos2sv )(const GLshort *v);
+void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z);
+void ( APIENTRY * qglRasterPos3iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z);
+void ( APIENTRY * qglRasterPos3sv )(const GLshort *v);
+void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+void ( APIENTRY * qglRasterPos4iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+void ( APIENTRY * qglRasterPos4sv )(const GLshort *v);
+void ( APIENTRY * qglReadBuffer )(GLenum mode);
+void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2);
+void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2);
+void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2);
+void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2);
+GLint ( APIENTRY * qglRenderMode )(GLenum mode);
+void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer);
+void ( APIENTRY * qglShadeModel )(GLenum mode);
+void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);
+void ( APIENTRY * qglStencilMask )(GLuint mask);
+void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+void ( APIENTRY * qglTexCoord1d )(GLdouble s);
+void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord1f )(GLfloat s);
+void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord1i )(GLint s);
+void ( APIENTRY * qglTexCoord1iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord1s )(GLshort s);
+void ( APIENTRY * qglTexCoord1sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t);
+void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);
+void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t);
+void ( APIENTRY * qglTexCoord2iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t);
+void ( APIENTRY * qglTexCoord2sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r);
+void ( APIENTRY * qglTexCoord3iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r);
+void ( APIENTRY * qglTexCoord3sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+void ( APIENTRY * qglTexCoord4iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+void ( APIENTRY * qglTexCoord4sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param);
+void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param);
+void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param);
+void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param);
+void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y);
+void ( APIENTRY * qglVertex2dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);
+void ( APIENTRY * qglVertex2fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex2i )(GLint x, GLint y);
+void ( APIENTRY * qglVertex2iv )(const GLint *v);
+void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y);
+void ( APIENTRY * qglVertex2sv )(const GLshort *v);
+void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglVertex3dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglVertex3fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z);
+void ( APIENTRY * qglVertex3iv )(const GLint *v);
+void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z);
+void ( APIENTRY * qglVertex3sv )(const GLshort *v);
+void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+void ( APIENTRY * qglVertex4dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void ( APIENTRY * qglVertex4fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w);
+void ( APIENTRY * qglVertex4iv )(const GLint *v);
+void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+void ( APIENTRY * qglVertex4sv )(const GLshort *v);
+void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value );
+void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value );
+void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * );
+void ( APIENTRY * qglSelectTextureSGIS)( GLenum );
+void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat );
+
+static void ( APIENTRY * dllAccum )(GLenum op, GLfloat value);
+static void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref);
+GLboolean ( APIENTRY * dllAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+static void ( APIENTRY * dllArrayElement )(GLint i);
+static void ( APIENTRY * dllBegin )(GLenum mode);
+static void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture);
+static void ( APIENTRY * dllBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+static void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor);
+static void ( APIENTRY * dllCallList )(GLuint list);
+static void ( APIENTRY * dllCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+static void ( APIENTRY * dllClear )(GLbitfield mask);
+static void ( APIENTRY * dllClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+static void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+static void ( APIENTRY * dllClearDepth )(GLclampd depth);
+static void ( APIENTRY * dllClearIndex )(GLfloat c);
+static void ( APIENTRY * dllClearStencil )(GLint s);
+static void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation);
+static void ( APIENTRY * dllColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+static void ( APIENTRY * dllColor3bv )(const GLbyte *v);
+static void ( APIENTRY * dllColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+static void ( APIENTRY * dllColor3dv )(const GLdouble *v);
+static void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+static void ( APIENTRY * dllColor3fv )(const GLfloat *v);
+static void ( APIENTRY * dllColor3i )(GLint red, GLint green, GLint blue);
+static void ( APIENTRY * dllColor3iv )(const GLint *v);
+static void ( APIENTRY * dllColor3s )(GLshort red, GLshort green, GLshort blue);
+static void ( APIENTRY * dllColor3sv )(const GLshort *v);
+static void ( APIENTRY * dllColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+static void ( APIENTRY * dllColor3ubv )(const GLubyte *v);
+static void ( APIENTRY * dllColor3ui )(GLuint red, GLuint green, GLuint blue);
+static void ( APIENTRY * dllColor3uiv )(const GLuint *v);
+static void ( APIENTRY * dllColor3us )(GLushort red, GLushort green, GLushort blue);
+static void ( APIENTRY * dllColor3usv )(const GLushort *v);
+static void ( APIENTRY * dllColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+static void ( APIENTRY * dllColor4bv )(const GLbyte *v);
+static void ( APIENTRY * dllColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+static void ( APIENTRY * dllColor4dv )(const GLdouble *v);
+static void ( APIENTRY * dllColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+static void ( APIENTRY * dllColor4fv )(const GLfloat *v);
+static void ( APIENTRY * dllColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+static void ( APIENTRY * dllColor4iv )(const GLint *v);
+static void ( APIENTRY * dllColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+static void ( APIENTRY * dllColor4sv )(const GLshort *v);
+static void ( APIENTRY * dllColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+static void ( APIENTRY * dllColor4ubv )(const GLubyte *v);
+static void ( APIENTRY * dllColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+static void ( APIENTRY * dllColor4uiv )(const GLuint *v);
+static void ( APIENTRY * dllColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+static void ( APIENTRY * dllColor4usv )(const GLushort *v);
+static void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+static void ( APIENTRY * dllColorMaterial )(GLenum face, GLenum mode);
+static void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+static void ( APIENTRY * dllCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+static void ( APIENTRY * dllCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+static void ( APIENTRY * dllCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+static void ( APIENTRY * dllCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+static void ( APIENTRY * dllCullFace )(GLenum mode);
+static void ( APIENTRY * dllDeleteLists )(GLuint list, GLsizei range);
+static void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures);
+static void ( APIENTRY * dllDepthFunc )(GLenum func);
+static void ( APIENTRY * dllDepthMask )(GLboolean flag);
+static void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar);
+static void ( APIENTRY * dllDisable )(GLenum cap);
+static void ( APIENTRY * dllDisableClientState )(GLenum array);
+static void ( APIENTRY * dllDrawArrays )(GLenum mode, GLint first, GLsizei count);
+static void ( APIENTRY * dllDrawBuffer )(GLenum mode);
+static void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+static void ( APIENTRY * dllDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllEdgeFlag )(GLboolean flag);
+static void ( APIENTRY * dllEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllEdgeFlagv )(const GLboolean *flag);
+static void ( APIENTRY * dllEnable )(GLenum cap);
+static void ( APIENTRY * dllEnableClientState )(GLenum array);
+static void ( APIENTRY * dllEnd )(void);
+static void ( APIENTRY * dllEndList )(void);
+static void ( APIENTRY * dllEvalCoord1d )(GLdouble u);
+static void ( APIENTRY * dllEvalCoord1dv )(const GLdouble *u);
+static void ( APIENTRY * dllEvalCoord1f )(GLfloat u);
+static void ( APIENTRY * dllEvalCoord1fv )(const GLfloat *u);
+static void ( APIENTRY * dllEvalCoord2d )(GLdouble u, GLdouble v);
+static void ( APIENTRY * dllEvalCoord2dv )(const GLdouble *u);
+static void ( APIENTRY * dllEvalCoord2f )(GLfloat u, GLfloat v);
+static void ( APIENTRY * dllEvalCoord2fv )(const GLfloat *u);
+static void ( APIENTRY * dllEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+static void ( APIENTRY * dllEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+static void ( APIENTRY * dllEvalPoint1 )(GLint i);
+static void ( APIENTRY * dllEvalPoint2 )(GLint i, GLint j);
+static void ( APIENTRY * dllFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+static void ( APIENTRY * dllFinish )(void);
+static void ( APIENTRY * dllFlush )(void);
+static void ( APIENTRY * dllFogf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllFogfv )(GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllFogi )(GLenum pname, GLint param);
+static void ( APIENTRY * dllFogiv )(GLenum pname, const GLint *params);
+static void ( APIENTRY * dllFrontFace )(GLenum mode);
+static void ( APIENTRY * dllFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLuint ( APIENTRY * dllGenLists )(GLsizei range);
+static void ( APIENTRY * dllGenTextures )(GLsizei n, GLuint *textures);
+static void ( APIENTRY * dllGetBooleanv )(GLenum pname, GLboolean *params);
+static void ( APIENTRY * dllGetClipPlane )(GLenum plane, GLdouble *equation);
+static void ( APIENTRY * dllGetDoublev )(GLenum pname, GLdouble *params);
+GLenum ( APIENTRY * dllGetError )(void);
+static void ( APIENTRY * dllGetFloatv )(GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetLightiv )(GLenum light, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+static void ( APIENTRY * dllGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+static void ( APIENTRY * dllGetMapiv )(GLenum target, GLenum query, GLint *v);
+static void ( APIENTRY * dllGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetPixelMapfv )(GLenum map, GLfloat *values);
+static void ( APIENTRY * dllGetPixelMapuiv )(GLenum map, GLuint *values);
+static void ( APIENTRY * dllGetPixelMapusv )(GLenum map, GLushort *values);
+static void ( APIENTRY * dllGetPointerv )(GLenum pname, GLvoid* *params);
+static void ( APIENTRY * dllGetPolygonStipple )(GLubyte *mask);
+const GLubyte * ( APIENTRY * dllGetString )(GLenum name);
+static void ( APIENTRY * dllGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+static void ( APIENTRY * dllGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+static void ( APIENTRY * dllGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+static void ( APIENTRY * dllHint )(GLenum target, GLenum mode);
+static void ( APIENTRY * dllIndexMask )(GLuint mask);
+static void ( APIENTRY * dllIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllIndexd )(GLdouble c);
+static void ( APIENTRY * dllIndexdv )(const GLdouble *c);
+static void ( APIENTRY * dllIndexf )(GLfloat c);
+static void ( APIENTRY * dllIndexfv )(const GLfloat *c);
+static void ( APIENTRY * dllIndexi )(GLint c);
+static void ( APIENTRY * dllIndexiv )(const GLint *c);
+static void ( APIENTRY * dllIndexs )(GLshort c);
+static void ( APIENTRY * dllIndexsv )(const GLshort *c);
+static void ( APIENTRY * dllIndexub )(GLubyte c);
+static void ( APIENTRY * dllIndexubv )(const GLubyte *c);
+static void ( APIENTRY * dllInitNames )(void);
+static void ( APIENTRY * dllInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+GLboolean ( APIENTRY * dllIsEnabled )(GLenum cap);
+GLboolean ( APIENTRY * dllIsList )(GLuint list);
+GLboolean ( APIENTRY * dllIsTexture )(GLuint texture);
+static void ( APIENTRY * dllLightModelf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllLightModelfv )(GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllLightModeli )(GLenum pname, GLint param);
+static void ( APIENTRY * dllLightModeliv )(GLenum pname, const GLint *params);
+static void ( APIENTRY * dllLightf )(GLenum light, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllLighti )(GLenum light, GLenum pname, GLint param);
+static void ( APIENTRY * dllLightiv )(GLenum light, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllLineStipple )(GLint factor, GLushort pattern);
+static void ( APIENTRY * dllLineWidth )(GLfloat width);
+static void ( APIENTRY * dllListBase )(GLuint base);
+static void ( APIENTRY * dllLoadIdentity )(void);
+static void ( APIENTRY * dllLoadMatrixd )(const GLdouble *m);
+static void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m);
+static void ( APIENTRY * dllLoadName )(GLuint name);
+static void ( APIENTRY * dllLogicOp )(GLenum opcode);
+static void ( APIENTRY * dllMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+static void ( APIENTRY * dllMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+static void ( APIENTRY * dllMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+static void ( APIENTRY * dllMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+static void ( APIENTRY * dllMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+static void ( APIENTRY * dllMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+static void ( APIENTRY * dllMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+static void ( APIENTRY * dllMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+static void ( APIENTRY * dllMaterialf )(GLenum face, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllMateriali )(GLenum face, GLenum pname, GLint param);
+static void ( APIENTRY * dllMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllMatrixMode )(GLenum mode);
+static void ( APIENTRY * dllMultMatrixd )(const GLdouble *m);
+static void ( APIENTRY * dllMultMatrixf )(const GLfloat *m);
+static void ( APIENTRY * dllNewList )(GLuint list, GLenum mode);
+static void ( APIENTRY * dllNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+static void ( APIENTRY * dllNormal3bv )(const GLbyte *v);
+static void ( APIENTRY * dllNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+static void ( APIENTRY * dllNormal3dv )(const GLdouble *v);
+static void ( APIENTRY * dllNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+static void ( APIENTRY * dllNormal3fv )(const GLfloat *v);
+static void ( APIENTRY * dllNormal3i )(GLint nx, GLint ny, GLint nz);
+static void ( APIENTRY * dllNormal3iv )(const GLint *v);
+static void ( APIENTRY * dllNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+static void ( APIENTRY * dllNormal3sv )(const GLshort *v);
+static void ( APIENTRY * dllNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+static void ( APIENTRY * dllPassThrough )(GLfloat token);
+static void ( APIENTRY * dllPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+static void ( APIENTRY * dllPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+static void ( APIENTRY * dllPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+static void ( APIENTRY * dllPixelStoref )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllPixelStorei )(GLenum pname, GLint param);
+static void ( APIENTRY * dllPixelTransferf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllPixelTransferi )(GLenum pname, GLint param);
+static void ( APIENTRY * dllPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+static void ( APIENTRY * dllPointSize )(GLfloat size);
+static void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode);
+static void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units);
+static void ( APIENTRY * dllPolygonStipple )(const GLubyte *mask);
+static void ( APIENTRY * dllPopAttrib )(void);
+static void ( APIENTRY * dllPopClientAttrib )(void);
+static void ( APIENTRY * dllPopMatrix )(void);
+static void ( APIENTRY * dllPopName )(void);
+static void ( APIENTRY * dllPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+static void ( APIENTRY * dllPushAttrib )(GLbitfield mask);
+static void ( APIENTRY * dllPushClientAttrib )(GLbitfield mask);
+static void ( APIENTRY * dllPushMatrix )(void);
+static void ( APIENTRY * dllPushName )(GLuint name);
+static void ( APIENTRY * dllRasterPos2d )(GLdouble x, GLdouble y);
+static void ( APIENTRY * dllRasterPos2dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos2f )(GLfloat x, GLfloat y);
+static void ( APIENTRY * dllRasterPos2fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos2i )(GLint x, GLint y);
+static void ( APIENTRY * dllRasterPos2iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos2s )(GLshort x, GLshort y);
+static void ( APIENTRY * dllRasterPos2sv )(const GLshort *v);
+static void ( APIENTRY * dllRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllRasterPos3dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllRasterPos3fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos3i )(GLint x, GLint y, GLint z);
+static void ( APIENTRY * dllRasterPos3iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos3s )(GLshort x, GLshort y, GLshort z);
+static void ( APIENTRY * dllRasterPos3sv )(const GLshort *v);
+static void ( APIENTRY * dllRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+static void ( APIENTRY * dllRasterPos4dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+static void ( APIENTRY * dllRasterPos4fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+static void ( APIENTRY * dllRasterPos4iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+static void ( APIENTRY * dllRasterPos4sv )(const GLshort *v);
+static void ( APIENTRY * dllReadBuffer )(GLenum mode);
+static void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+static void ( APIENTRY * dllRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+static void ( APIENTRY * dllRectdv )(const GLdouble *v1, const GLdouble *v2);
+static void ( APIENTRY * dllRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+static void ( APIENTRY * dllRectfv )(const GLfloat *v1, const GLfloat *v2);
+static void ( APIENTRY * dllRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+static void ( APIENTRY * dllRectiv )(const GLint *v1, const GLint *v2);
+static void ( APIENTRY * dllRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+static void ( APIENTRY * dllRectsv )(const GLshort *v1, const GLshort *v2);
+GLint ( APIENTRY * dllRenderMode )(GLenum mode);
+static void ( APIENTRY * dllRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllScaled )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllScalef )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+static void ( APIENTRY * dllSelectBuffer )(GLsizei size, GLuint *buffer);
+static void ( APIENTRY * dllShadeModel )(GLenum mode);
+static void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask);
+static void ( APIENTRY * dllStencilMask )(GLuint mask);
+static void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+static void ( APIENTRY * dllTexCoord1d )(GLdouble s);
+static void ( APIENTRY * dllTexCoord1dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord1f )(GLfloat s);
+static void ( APIENTRY * dllTexCoord1fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord1i )(GLint s);
+static void ( APIENTRY * dllTexCoord1iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord1s )(GLshort s);
+static void ( APIENTRY * dllTexCoord1sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord2d )(GLdouble s, GLdouble t);
+static void ( APIENTRY * dllTexCoord2dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t);
+static void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord2i )(GLint s, GLint t);
+static void ( APIENTRY * dllTexCoord2iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord2s )(GLshort s, GLshort t);
+static void ( APIENTRY * dllTexCoord2sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+static void ( APIENTRY * dllTexCoord3dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+static void ( APIENTRY * dllTexCoord3fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord3i )(GLint s, GLint t, GLint r);
+static void ( APIENTRY * dllTexCoord3iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord3s )(GLshort s, GLshort t, GLshort r);
+static void ( APIENTRY * dllTexCoord3sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+static void ( APIENTRY * dllTexCoord4dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+static void ( APIENTRY * dllTexCoord4fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+static void ( APIENTRY * dllTexCoord4iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+static void ( APIENTRY * dllTexCoord4sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexEnvi )(GLenum target, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexGend )(GLenum coord, GLenum pname, GLdouble param);
+static void ( APIENTRY * dllTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+static void ( APIENTRY * dllTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexGeni )(GLenum coord, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexParameteri )(GLenum target, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTranslated )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllVertex2d )(GLdouble x, GLdouble y);
+static void ( APIENTRY * dllVertex2dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y);
+static void ( APIENTRY * dllVertex2fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex2i )(GLint x, GLint y);
+static void ( APIENTRY * dllVertex2iv )(const GLint *v);
+static void ( APIENTRY * dllVertex2s )(GLshort x, GLshort y);
+static void ( APIENTRY * dllVertex2sv )(const GLshort *v);
+static void ( APIENTRY * dllVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllVertex3dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllVertex3fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex3i )(GLint x, GLint y, GLint z);
+static void ( APIENTRY * dllVertex3iv )(const GLint *v);
+static void ( APIENTRY * dllVertex3s )(GLshort x, GLshort y, GLshort z);
+static void ( APIENTRY * dllVertex3sv )(const GLshort *v);
+static void ( APIENTRY * dllVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+static void ( APIENTRY * dllVertex4dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+static void ( APIENTRY * dllVertex4fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex4i )(GLint x, GLint y, GLint z, GLint w);
+static void ( APIENTRY * dllVertex4iv )(const GLint *v);
+static void ( APIENTRY * dllVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+static void ( APIENTRY * dllVertex4sv )(const GLshort *v);
+static void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+static void APIENTRY logAccum(GLenum op, GLfloat value)
+{
+	fprintf( log_fp, "glAccum\n" );
+	dllAccum( op, value );
+}
+
+static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref)
+{
+	fprintf( log_fp, "glAlphaFunc( 0x%x, %f )\n", func, ref );
+	dllAlphaFunc( func, ref );
+}
+
+static GLboolean APIENTRY logAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences)
+{
+	fprintf( log_fp, "glAreTexturesResident\n" );
+	return dllAreTexturesResident( n, textures, residences );
+}
+
+static void APIENTRY logArrayElement(GLint i)
+{
+	fprintf( log_fp, "glArrayElement\n" );
+	dllArrayElement( i );
+}
+
+static void APIENTRY logBegin(GLenum mode)
+{
+	fprintf( log_fp, "glBegin( 0x%x )\n", mode );
+	dllBegin( mode );
+}
+
+static void APIENTRY logBindTexture(GLenum target, GLuint texture)
+{
+	fprintf( log_fp, "glBindTexture( 0x%x, %u )\n", target, texture );
+	dllBindTexture( target, texture );
+}
+
+static void APIENTRY logBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
+{
+	fprintf( log_fp, "glBitmap\n" );
+	dllBitmap( width, height, xorig, yorig, xmove, ymove, bitmap );
+}
+
+static void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+	fprintf( log_fp, "glBlendFunc( 0x%x, 0x%x )\n", sfactor, dfactor );
+	dllBlendFunc( sfactor, dfactor );
+}
+
+static void APIENTRY logCallList(GLuint list)
+{
+	fprintf( log_fp, "glCallList( %u )\n", list );
+	dllCallList( list );
+}
+
+static void APIENTRY logCallLists(GLsizei n, GLenum type, const void *lists)
+{
+	fprintf( log_fp, "glCallLists\n" );
+	dllCallLists( n, type, lists );
+}
+
+static void APIENTRY logClear(GLbitfield mask)
+{
+	fprintf( log_fp, "glClear\n" );
+	dllClear( mask );
+}
+
+static void APIENTRY logClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+	fprintf( log_fp, "glClearAccum\n" );
+	dllClearAccum( red, green, blue, alpha );
+}
+
+static void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	fprintf( log_fp, "glClearColor\n" );
+	dllClearColor( red, green, blue, alpha );
+}
+
+static void APIENTRY logClearDepth(GLclampd depth)
+{
+	fprintf( log_fp, "glClearDepth\n" );
+	dllClearDepth( depth );
+}
+
+static void APIENTRY logClearIndex(GLfloat c)
+{
+	fprintf( log_fp, "glClearIndex\n" );
+	dllClearIndex( c );
+}
+
+static void APIENTRY logClearStencil(GLint s)
+{
+	fprintf( log_fp, "glClearStencil\n" );
+	dllClearStencil( s );
+}
+
+static void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation)
+{
+	fprintf( log_fp, "glClipPlane\n" );
+	dllClipPlane( plane, equation );
+}
+
+static void APIENTRY logColor3b(GLbyte red, GLbyte green, GLbyte blue)
+{
+	fprintf( log_fp, "glColor3b\n" );
+	dllColor3b( red, green, blue );
+}
+
+static void APIENTRY logColor3bv(const GLbyte *v)
+{
+	fprintf( log_fp, "glColor3bv\n" );
+	dllColor3bv( v );
+}
+
+static void APIENTRY logColor3d(GLdouble red, GLdouble green, GLdouble blue)
+{
+	fprintf( log_fp, "glColor3d\n" );
+	dllColor3d( red, green, blue );
+}
+
+static void APIENTRY logColor3dv(const GLdouble *v)
+{
+	fprintf( log_fp, "glColor3dv\n" );
+	dllColor3dv( v );
+}
+
+static void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue)
+{
+	fprintf( log_fp, "glColor3f\n" );
+	dllColor3f( red, green, blue );
+}
+
+static void APIENTRY logColor3fv(const GLfloat *v)
+{
+	fprintf( log_fp, "glColor3fv\n" );
+	dllColor3fv( v );
+}
+
+static void APIENTRY logColor3i(GLint red, GLint green, GLint blue)
+{
+	fprintf( log_fp, "glColor3i\n" );
+	dllColor3i( red, green, blue );
+}
+
+static void APIENTRY logColor3iv(const GLint *v)
+{
+	fprintf( log_fp, "glColor3iv\n" );
+	dllColor3iv( v );
+}
+
+static void APIENTRY logColor3s(GLshort red, GLshort green, GLshort blue)
+{
+	fprintf( log_fp, "glColor3s\n" );
+	dllColor3s( red, green, blue );
+}
+
+static void APIENTRY logColor3sv(const GLshort *v)
+{
+	fprintf( log_fp, "glColor3sv\n" );
+	dllColor3sv( v );
+}
+
+static void APIENTRY logColor3ub(GLubyte red, GLubyte green, GLubyte blue)
+{
+	fprintf( log_fp, "glColor3ub\n" );
+	dllColor3ub( red, green, blue );
+}
+
+static void APIENTRY logColor3ubv(const GLubyte *v)
+{
+	fprintf( log_fp, "glColor3ubv\n" );
+	dllColor3ubv( v );
+}
+
+#define SIG( x ) fprintf( log_fp, x "\n" )
+
+static void APIENTRY logColor3ui(GLuint red, GLuint green, GLuint blue)
+{
+	SIG( "glColor3ui" );
+	dllColor3ui( red, green, blue );
+}
+
+static void APIENTRY logColor3uiv(const GLuint *v)
+{
+	SIG( "glColor3uiv" );
+	dllColor3uiv( v );
+}
+
+static void APIENTRY logColor3us(GLushort red, GLushort green, GLushort blue)
+{
+	SIG( "glColor3us" );
+	dllColor3us( red, green, blue );
+}
+
+static void APIENTRY logColor3usv(const GLushort *v)
+{
+	SIG( "glColor3usv" );
+	dllColor3usv( v );
+}
+
+static void APIENTRY logColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha)
+{
+	SIG( "glColor4b" );
+	dllColor4b( red, green, blue, alpha );
+}
+
+static void APIENTRY logColor4bv(const GLbyte *v)
+{
+	SIG( "glColor4bv" );
+	dllColor4bv( v );
+}
+
+static void APIENTRY logColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
+{
+	SIG( "glColor4d" );
+	dllColor4d( red, green, blue, alpha );
+}
+static void APIENTRY logColor4dv(const GLdouble *v)
+{
+	SIG( "glColor4dv" );
+	dllColor4dv( v );
+}
+static void APIENTRY logColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+	SIG( "glColor4f" );
+	dllColor4f( red, green, blue, alpha );
+}
+static void APIENTRY logColor4fv(const GLfloat *v)
+{
+	SIG( "glColor4fv" );
+	dllColor4fv( v );
+}
+static void APIENTRY logColor4i(GLint red, GLint green, GLint blue, GLint alpha)
+{
+	SIG( "glColor4i" );
+	dllColor4i( red, green, blue, alpha );
+}
+static void APIENTRY logColor4iv(const GLint *v)
+{
+	SIG( "glColor4iv" );
+	dllColor4iv( v );
+}
+static void APIENTRY logColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha)
+{
+	SIG( "glColor4s" );
+	dllColor4s( red, green, blue, alpha );
+}
+static void APIENTRY logColor4sv(const GLshort *v)
+{
+	SIG( "glColor4sv" );
+	dllColor4sv( v );
+}
+static void APIENTRY logColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+{
+	SIG( "glColor4b" );
+	dllColor4b( red, green, blue, alpha );
+}
+static void APIENTRY logColor4ubv(const GLubyte *v)
+{
+	SIG( "glColor4ubv" );
+	dllColor4ubv( v );
+}
+static void APIENTRY logColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha)
+{
+	SIG( "glColor4ui" );
+	dllColor4ui( red, green, blue, alpha );
+}
+static void APIENTRY logColor4uiv(const GLuint *v)
+{
+	SIG( "glColor4uiv" );
+	dllColor4uiv( v );
+}
+static void APIENTRY logColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha)
+{
+	SIG( "glColor4us" );
+	dllColor4us( red, green, blue, alpha );
+}
+static void APIENTRY logColor4usv(const GLushort *v)
+{
+	SIG( "glColor4usv" );
+	dllColor4usv( v );
+}
+static void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+	SIG( "glColorMask" );
+	dllColorMask( red, green, blue, alpha );
+}
+static void APIENTRY logColorMaterial(GLenum face, GLenum mode)
+{
+	SIG( "glColorMaterial" );
+	dllColorMaterial( face, mode );
+}
+
+static void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glColorPointer" );
+	dllColorPointer( size, type, stride, pointer );
+}
+
+static void APIENTRY logCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)
+{
+	SIG( "glCopyPixels" );
+	dllCopyPixels( x, y, width, height, type );
+}
+
+static void APIENTRY logCopyTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border)
+{
+	SIG( "glCopyTexImage1D" );
+	dllCopyTexImage1D( target, level, internalFormat, x, y, width, border );
+}
+
+static void APIENTRY logCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+	SIG( "glCopyTexImage2D" );
+	dllCopyTexImage2D( target, level, internalFormat, x, y, width, height, border );
+}
+
+static void APIENTRY logCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+	SIG( "glCopyTexSubImage1D" );
+	dllCopyTexSubImage1D( target, level, xoffset, x, y, width );
+}
+
+static void APIENTRY logCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glCopyTexSubImage2D" );
+	dllCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height );
+}
+
+static void APIENTRY logCullFace(GLenum mode)
+{
+	SIG( "glCullFace" );
+	dllCullFace( mode );
+}
+
+static void APIENTRY logDeleteLists(GLuint list, GLsizei range)
+{
+	SIG( "glDeleteLists" );
+	dllDeleteLists( list, range );
+}
+
+static void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures)
+{
+	SIG( "glDeleteTextures" );
+	dllDeleteTextures( n, textures );
+}
+
+static void APIENTRY logDepthFunc(GLenum func)
+{
+	SIG( "glDepthFunc" );
+	dllDepthFunc( func );
+}
+
+static void APIENTRY logDepthMask(GLboolean flag)
+{
+	SIG( "glDepthMask" );
+	dllDepthMask( flag );
+}
+
+static void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar)
+{
+	SIG( "glDepthRange" );
+	dllDepthRange( zNear, zFar );
+}
+
+static void APIENTRY logDisable(GLenum cap)
+{
+	fprintf( log_fp, "glDisable( 0x%x )\n", cap );
+	dllDisable( cap );
+}
+
+static void APIENTRY logDisableClientState(GLenum array)
+{
+	SIG( "glDisableClientState" );
+	dllDisableClientState( array );
+}
+
+static void APIENTRY logDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+	SIG( "glDrawArrays" );
+	dllDrawArrays( mode, first, count );
+}
+
+static void APIENTRY logDrawBuffer(GLenum mode)
+{
+	SIG( "glDrawBuffer" );
+	dllDrawBuffer( mode );
+}
+
+static void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+	SIG( "glDrawElements" );
+	dllDrawElements( mode, count, type, indices );
+}
+
+static void APIENTRY logDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glDrawPixels" );
+	dllDrawPixels( width, height, format, type, pixels );
+}
+
+static void APIENTRY logEdgeFlag(GLboolean flag)
+{
+	SIG( "glEdgeFlag" );
+	dllEdgeFlag( flag );
+}
+
+static void APIENTRY logEdgeFlagPointer(GLsizei stride, const void *pointer)
+{
+	SIG( "glEdgeFlagPointer" );
+	dllEdgeFlagPointer( stride, pointer );
+}
+
+static void APIENTRY logEdgeFlagv(const GLboolean *flag)
+{
+	SIG( "glEdgeFlagv" );
+	dllEdgeFlagv( flag );
+}
+
+static void APIENTRY logEnable(GLenum cap)
+{
+	fprintf( log_fp, "glEnable( 0x%x )\n", cap );
+	dllEnable( cap );
+}
+
+static void APIENTRY logEnableClientState(GLenum array)
+{
+	SIG( "glEnableClientState" );
+	dllEnableClientState( array );
+}
+
+static void APIENTRY logEnd(void)
+{
+	SIG( "glEnd" );
+	dllEnd();
+}
+
+static void APIENTRY logEndList(void)
+{
+	SIG( "glEndList" );
+	dllEndList();
+}
+
+static void APIENTRY logEvalCoord1d(GLdouble u)
+{
+	SIG( "glEvalCoord1d" );
+	dllEvalCoord1d( u );
+}
+
+static void APIENTRY logEvalCoord1dv(const GLdouble *u)
+{
+	SIG( "glEvalCoord1dv" );
+	dllEvalCoord1dv( u );
+}
+
+static void APIENTRY logEvalCoord1f(GLfloat u)
+{
+	SIG( "glEvalCoord1f" );
+	dllEvalCoord1f( u );
+}
+
+static void APIENTRY logEvalCoord1fv(const GLfloat *u)
+{
+	SIG( "glEvalCoord1fv" );
+	dllEvalCoord1fv( u );
+}
+static void APIENTRY logEvalCoord2d(GLdouble u, GLdouble v)
+{
+	SIG( "glEvalCoord2d" );
+	dllEvalCoord2d( u, v );
+}
+static void APIENTRY logEvalCoord2dv(const GLdouble *u)
+{
+	SIG( "glEvalCoord2dv" );
+	dllEvalCoord2dv( u );
+}
+static void APIENTRY logEvalCoord2f(GLfloat u, GLfloat v)
+{
+	SIG( "glEvalCoord2f" );
+	dllEvalCoord2f( u, v );
+}
+static void APIENTRY logEvalCoord2fv(const GLfloat *u)
+{
+	SIG( "glEvalCoord2fv" );
+	dllEvalCoord2fv( u );
+}
+
+static void APIENTRY logEvalMesh1(GLenum mode, GLint i1, GLint i2)
+{
+	SIG( "glEvalMesh1" );
+	dllEvalMesh1( mode, i1, i2 );
+}
+static void APIENTRY logEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
+{
+	SIG( "glEvalMesh2" );
+	dllEvalMesh2( mode, i1, i2, j1, j2 );
+}
+static void APIENTRY logEvalPoint1(GLint i)
+{
+	SIG( "glEvalPoint1" );
+	dllEvalPoint1( i );
+}
+static void APIENTRY logEvalPoint2(GLint i, GLint j)
+{
+	SIG( "glEvalPoint2" );
+	dllEvalPoint2( i, j );
+}
+
+static void APIENTRY logFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer)
+{
+	SIG( "glFeedbackBuffer" );
+	dllFeedbackBuffer( size, type, buffer );
+}
+
+static void APIENTRY logFinish(void)
+{
+	SIG( "glFinish" );
+	dllFinish();
+}
+
+static void APIENTRY logFlush(void)
+{
+	SIG( "glFlush" );
+	dllFlush();
+}
+
+static void APIENTRY logFogf(GLenum pname, GLfloat param)
+{
+	SIG( "glFogf" );
+	dllFogf( pname, param );
+}
+
+static void APIENTRY logFogfv(GLenum pname, const GLfloat *params)
+{
+	SIG( "glFogfv" );
+	dllFogfv( pname, params );
+}
+
+static void APIENTRY logFogi(GLenum pname, GLint param)
+{
+	SIG( "glFogi" );
+	dllFogi( pname, param );
+}
+
+static void APIENTRY logFogiv(GLenum pname, const GLint *params)
+{
+	SIG( "glFogiv" );
+	dllFogiv( pname, params );
+}
+
+static void APIENTRY logFrontFace(GLenum mode)
+{
+	SIG( "glFrontFace" );
+	dllFrontFace( mode );
+}
+
+static void APIENTRY logFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+{
+	SIG( "glFrustum" );
+	dllFrustum( left, right, bottom, top, zNear, zFar );
+}
+
+static GLuint APIENTRY logGenLists(GLsizei range)
+{
+	SIG( "glGenLists" );
+	return dllGenLists( range );
+}
+
+static void APIENTRY logGenTextures(GLsizei n, GLuint *textures)
+{
+	SIG( "glGenTextures" );
+	dllGenTextures( n, textures );
+}
+
+static void APIENTRY logGetBooleanv(GLenum pname, GLboolean *params)
+{
+	SIG( "glGetBooleanv" );
+	dllGetBooleanv( pname, params );
+}
+
+static void APIENTRY logGetClipPlane(GLenum plane, GLdouble *equation)
+{
+	SIG( "glGetClipPlane" );
+	dllGetClipPlane( plane, equation );
+}
+
+static void APIENTRY logGetDoublev(GLenum pname, GLdouble *params)
+{
+	SIG( "glGetDoublev" );
+	dllGetDoublev( pname, params );
+}
+
+static GLenum APIENTRY logGetError(void)
+{
+	SIG( "glGetError" );
+	return dllGetError();
+}
+
+static void APIENTRY logGetFloatv(GLenum pname, GLfloat *params)
+{
+	SIG( "glGetFloatv" );
+	dllGetFloatv( pname, params );
+}
+
+static void APIENTRY logGetIntegerv(GLenum pname, GLint *params)
+{
+	SIG( "glGetIntegerv" );
+	dllGetIntegerv( pname, params );
+}
+
+static void APIENTRY logGetLightfv(GLenum light, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetLightfv" );
+	dllGetLightfv( light, pname, params );
+}
+
+static void APIENTRY logGetLightiv(GLenum light, GLenum pname, GLint *params)
+{
+	SIG( "glGetLightiv" );
+	dllGetLightiv( light, pname, params );
+}
+
+static void APIENTRY logGetMapdv(GLenum target, GLenum query, GLdouble *v)
+{
+	SIG( "glGetMapdv" );
+	dllGetMapdv( target, query, v );
+}
+
+static void APIENTRY logGetMapfv(GLenum target, GLenum query, GLfloat *v)
+{
+	SIG( "glGetMapfv" );
+	dllGetMapfv( target, query, v );
+}
+
+static void APIENTRY logGetMapiv(GLenum target, GLenum query, GLint *v)
+{
+	SIG( "glGetMapiv" );
+	dllGetMapiv( target, query, v );
+}
+
+static void APIENTRY logGetMaterialfv(GLenum face, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetMaterialfv" );
+	dllGetMaterialfv( face, pname, params );
+}
+
+static void APIENTRY logGetMaterialiv(GLenum face, GLenum pname, GLint *params)
+{
+	SIG( "glGetMaterialiv" );
+	dllGetMaterialiv( face, pname, params );
+}
+
+static void APIENTRY logGetPixelMapfv(GLenum map, GLfloat *values)
+{
+	SIG( "glGetPixelMapfv" );
+	dllGetPixelMapfv( map, values );
+}
+
+static void APIENTRY logGetPixelMapuiv(GLenum map, GLuint *values)
+{
+	SIG( "glGetPixelMapuiv" );
+	dllGetPixelMapuiv( map, values );
+}
+
+static void APIENTRY logGetPixelMapusv(GLenum map, GLushort *values)
+{
+	SIG( "glGetPixelMapusv" );
+	dllGetPixelMapusv( map, values );
+}
+
+static void APIENTRY logGetPointerv(GLenum pname, GLvoid* *params)
+{
+	SIG( "glGetPointerv" );
+	dllGetPointerv( pname, params );
+}
+
+static void APIENTRY logGetPolygonStipple(GLubyte *mask)
+{
+	SIG( "glGetPolygonStipple" );
+	dllGetPolygonStipple( mask );
+}
+
+static const GLubyte * APIENTRY logGetString(GLenum name)
+{
+	SIG( "glGetString" );
+	return dllGetString( name );
+}
+
+static void APIENTRY logGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexEnvfv" );
+	dllGetTexEnvfv( target, pname, params );
+}
+
+static void APIENTRY logGetTexEnviv(GLenum target, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexEnviv" );
+	dllGetTexEnviv( target, pname, params );
+}
+
+static void APIENTRY logGetTexGendv(GLenum coord, GLenum pname, GLdouble *params)
+{
+	SIG( "glGetTexGendv" );
+	dllGetTexGendv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexGenfv" );
+	dllGetTexGenfv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexGeniv(GLenum coord, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexGeniv" );
+	dllGetTexGeniv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels)
+{
+	SIG( "glGetTexImage" );
+	dllGetTexImage( target, level, format, type, pixels );
+}
+static void APIENTRY logGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params )
+{
+	SIG( "glGetTexLevelParameterfv" );
+	dllGetTexLevelParameterfv( target, level, pname, params );
+}
+
+static void APIENTRY logGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexLevelParameteriv" );
+	dllGetTexLevelParameteriv( target, level, pname, params );
+}
+
+static void APIENTRY logGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexParameterfv" );
+	dllGetTexParameterfv( target, pname, params );
+}
+
+static void APIENTRY logGetTexParameteriv(GLenum target, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexParameteriv" );
+	dllGetTexParameteriv( target, pname, params );
+}
+
+static void APIENTRY logHint(GLenum target, GLenum mode)
+{
+	fprintf( log_fp, "glHint( 0x%x, 0x%x )\n", target, mode );
+	dllHint( target, mode );
+}
+
+static void APIENTRY logIndexMask(GLuint mask)
+{
+	SIG( "glIndexMask" );
+	dllIndexMask( mask );
+}
+
+static void APIENTRY logIndexPointer(GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glIndexPointer" );
+	dllIndexPointer( type, stride, pointer );
+}
+
+static void APIENTRY logIndexd(GLdouble c)
+{
+	SIG( "glIndexd" );
+	dllIndexd( c );
+}
+
+static void APIENTRY logIndexdv(const GLdouble *c)
+{
+	SIG( "glIndexdv" );
+	dllIndexdv( c );
+}
+
+static void APIENTRY logIndexf(GLfloat c)
+{
+	SIG( "glIndexf" );
+	dllIndexf( c );
+}
+
+static void APIENTRY logIndexfv(const GLfloat *c)
+{
+	SIG( "glIndexfv" );
+	dllIndexfv( c );
+}
+
+static void APIENTRY logIndexi(GLint c)
+{
+	SIG( "glIndexi" );
+	dllIndexi( c );
+}
+
+static void APIENTRY logIndexiv(const GLint *c)
+{
+	SIG( "glIndexiv" );
+	dllIndexiv( c );
+}
+
+static void APIENTRY logIndexs(GLshort c)
+{
+	SIG( "glIndexs" );
+	dllIndexs( c );
+}
+
+static void APIENTRY logIndexsv(const GLshort *c)
+{
+	SIG( "glIndexsv" );
+	dllIndexsv( c );
+}
+
+static void APIENTRY logIndexub(GLubyte c)
+{
+	SIG( "glIndexub" );
+	dllIndexub( c );
+}
+
+static void APIENTRY logIndexubv(const GLubyte *c)
+{
+	SIG( "glIndexubv" );
+	dllIndexubv( c );
+}
+
+static void APIENTRY logInitNames(void)
+{
+	SIG( "glInitNames" );
+	dllInitNames();
+}
+
+static void APIENTRY logInterleavedArrays(GLenum format, GLsizei stride, const void *pointer)
+{
+	SIG( "glInterleavedArrays" );
+	dllInterleavedArrays( format, stride, pointer );
+}
+
+static GLboolean APIENTRY logIsEnabled(GLenum cap)
+{
+	SIG( "glIsEnabled" );
+	return dllIsEnabled( cap );
+}
+static GLboolean APIENTRY logIsList(GLuint list)
+{
+	SIG( "glIsList" );
+	return dllIsList( list );
+}
+static GLboolean APIENTRY logIsTexture(GLuint texture)
+{
+	SIG( "glIsTexture" );
+	return dllIsTexture( texture );
+}
+
+static void APIENTRY logLightModelf(GLenum pname, GLfloat param)
+{
+	SIG( "glLightModelf" );
+	dllLightModelf( pname, param );
+}
+
+static void APIENTRY logLightModelfv(GLenum pname, const GLfloat *params)
+{
+	SIG( "glLightModelfv" );
+	dllLightModelfv( pname, params );
+}
+
+static void APIENTRY logLightModeli(GLenum pname, GLint param)
+{
+	SIG( "glLightModeli" );
+	dllLightModeli( pname, param );
+
+}
+
+static void APIENTRY logLightModeliv(GLenum pname, const GLint *params)
+{
+	SIG( "glLightModeliv" );
+	dllLightModeliv( pname, params );
+}
+
+static void APIENTRY logLightf(GLenum light, GLenum pname, GLfloat param)
+{
+	SIG( "glLightf" );
+	dllLightf( light, pname, param );
+}
+
+static void APIENTRY logLightfv(GLenum light, GLenum pname, const GLfloat *params)
+{
+	SIG( "glLightfv" );
+	dllLightfv( light, pname, params );
+}
+
+static void APIENTRY logLighti(GLenum light, GLenum pname, GLint param)
+{
+	SIG( "glLighti" );
+	dllLighti( light, pname, param );
+}
+
+static void APIENTRY logLightiv(GLenum light, GLenum pname, const GLint *params)
+{
+	SIG( "glLightiv" );
+	dllLightiv( light, pname, params );
+}
+
+static void APIENTRY logLineStipple(GLint factor, GLushort pattern)
+{
+	SIG( "glLineStipple" );
+	dllLineStipple( factor, pattern );
+}
+
+static void APIENTRY logLineWidth(GLfloat width)
+{
+	SIG( "glLineWidth" );
+	dllLineWidth( width );
+}
+
+static void APIENTRY logListBase(GLuint base)
+{
+	SIG( "glListBase" );
+	dllListBase( base );
+}
+
+static void APIENTRY logLoadIdentity(void)
+{
+	SIG( "glLoadIdentity" );
+	dllLoadIdentity();
+}
+
+static void APIENTRY logLoadMatrixd(const GLdouble *m)
+{
+	SIG( "glLoadMatrixd" );
+	dllLoadMatrixd( m );
+}
+
+static void APIENTRY logLoadMatrixf(const GLfloat *m)
+{
+	SIG( "glLoadMatrixf" );
+	dllLoadMatrixf( m );
+}
+
+static void APIENTRY logLoadName(GLuint name)
+{
+	SIG( "glLoadName" );
+	dllLoadName( name );
+}
+
+static void APIENTRY logLogicOp(GLenum opcode)
+{
+	SIG( "glLogicOp" );
+	dllLogicOp( opcode );
+}
+
+static void APIENTRY logMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points)
+{
+	SIG( "glMap1d" );
+	dllMap1d( target, u1, u2, stride, order, points );
+}
+
+static void APIENTRY logMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points)
+{
+	SIG( "glMap1f" );
+	dllMap1f( target, u1, u2, stride, order, points );
+}
+
+static void APIENTRY logMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points)
+{
+	SIG( "glMap2d" );
+	dllMap2d( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points );
+}
+
+static void APIENTRY logMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points)
+{
+	SIG( "glMap2f" );
+	dllMap2f( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points );
+}
+
+static void APIENTRY logMapGrid1d(GLint un, GLdouble u1, GLdouble u2)
+{
+	SIG( "glMapGrid1d" );
+	dllMapGrid1d( un, u1, u2 );
+}
+
+static void APIENTRY logMapGrid1f(GLint un, GLfloat u1, GLfloat u2)
+{
+	SIG( "glMapGrid1f" );
+	dllMapGrid1f( un, u1, u2 );
+}
+
+static void APIENTRY logMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2)
+{
+	SIG( "glMapGrid2d" );
+	dllMapGrid2d( un, u1, u2, vn, v1, v2 );
+}
+static void APIENTRY logMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2)
+{
+	SIG( "glMapGrid2f" );
+	dllMapGrid2f( un, u1, u2, vn, v1, v2 );
+}
+static void APIENTRY logMaterialf(GLenum face, GLenum pname, GLfloat param)
+{
+	SIG( "glMaterialf" );
+	dllMaterialf( face, pname, param );
+}
+static void APIENTRY logMaterialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+	SIG( "glMaterialfv" );
+	dllMaterialfv( face, pname, params );
+}
+
+static void APIENTRY logMateriali(GLenum face, GLenum pname, GLint param)
+{
+	SIG( "glMateriali" );
+	dllMateriali( face, pname, param );
+}
+
+static void APIENTRY logMaterialiv(GLenum face, GLenum pname, const GLint *params)
+{
+	SIG( "glMaterialiv" );
+	dllMaterialiv( face, pname, params );
+}
+
+static void APIENTRY logMatrixMode(GLenum mode)
+{
+	SIG( "glMatrixMode" );
+	dllMatrixMode( mode );
+}
+
+static void APIENTRY logMultMatrixd(const GLdouble *m)
+{
+	SIG( "glMultMatrixd" );
+	dllMultMatrixd( m );
+}
+
+static void APIENTRY logMultMatrixf(const GLfloat *m)
+{
+	SIG( "glMultMatrixf" );
+	dllMultMatrixf( m );
+}
+
+static void APIENTRY logNewList(GLuint list, GLenum mode)
+{
+	SIG( "glNewList" );
+	dllNewList( list, mode );
+}
+
+static void APIENTRY logNormal3b(GLbyte nx, GLbyte ny, GLbyte nz)
+{
+	SIG ("glNormal3b" );
+	dllNormal3b( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3bv(const GLbyte *v)
+{
+	SIG( "glNormal3bv" );
+	dllNormal3bv( v );
+}
+
+static void APIENTRY logNormal3d(GLdouble nx, GLdouble ny, GLdouble nz)
+{
+	SIG( "glNormal3d" );
+	dllNormal3d( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3dv(const GLdouble *v)
+{
+	SIG( "glNormal3dv" );
+	dllNormal3dv( v );
+}
+
+static void APIENTRY logNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
+{
+	SIG( "glNormal3f" );
+	dllNormal3f( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3fv(const GLfloat *v)
+{
+	SIG( "glNormal3fv" );
+	dllNormal3fv( v );
+}
+static void APIENTRY logNormal3i(GLint nx, GLint ny, GLint nz)
+{
+	SIG( "glNormal3i" );
+	dllNormal3i( nx, ny, nz );
+}
+static void APIENTRY logNormal3iv(const GLint *v)
+{
+	SIG( "glNormal3iv" );
+	dllNormal3iv( v );
+}
+static void APIENTRY logNormal3s(GLshort nx, GLshort ny, GLshort nz)
+{
+	SIG( "glNormal3s" );
+	dllNormal3s( nx, ny, nz );
+}
+static void APIENTRY logNormal3sv(const GLshort *v)
+{
+	SIG( "glNormal3sv" );
+	dllNormal3sv( v );
+}
+static void APIENTRY logNormalPointer(GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glNormalPointer" );
+	dllNormalPointer( type, stride, pointer );
+}
+static void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+{
+	SIG( "glOrtho" );
+	dllOrtho( left, right, bottom, top, zNear, zFar );
+}
+
+static void APIENTRY logPassThrough(GLfloat token)
+{
+	SIG( "glPassThrough" );
+	dllPassThrough( token );
+}
+
+static void APIENTRY logPixelMapfv(GLenum map, GLsizei mapsize, const GLfloat *values)
+{
+	SIG( "glPixelMapfv" );
+	dllPixelMapfv( map, mapsize, values );
+}
+
+static void APIENTRY logPixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values)
+{
+	SIG( "glPixelMapuiv" );
+	dllPixelMapuiv( map, mapsize, values );
+}
+
+static void APIENTRY logPixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values)
+{
+	SIG( "glPixelMapusv" );
+	dllPixelMapusv( map, mapsize, values );
+}
+static void APIENTRY logPixelStoref(GLenum pname, GLfloat param)
+{
+	SIG( "glPixelStoref" );
+	dllPixelStoref( pname, param );
+}
+static void APIENTRY logPixelStorei(GLenum pname, GLint param)
+{
+	SIG( "glPixelStorei" );
+	dllPixelStorei( pname, param );
+}
+static void APIENTRY logPixelTransferf(GLenum pname, GLfloat param)
+{
+	SIG( "glPixelTransferf" );
+	dllPixelTransferf( pname, param );
+}
+
+static void APIENTRY logPixelTransferi(GLenum pname, GLint param)
+{
+	SIG( "glPixelTransferi" );
+	dllPixelTransferi( pname, param );
+}
+
+static void APIENTRY logPixelZoom(GLfloat xfactor, GLfloat yfactor)
+{
+	SIG( "glPixelZoom" );
+	dllPixelZoom( xfactor, yfactor );
+}
+
+static void APIENTRY logPointSize(GLfloat size)
+{
+	SIG( "glPointSize" );
+	dllPointSize( size );
+}
+
+static void APIENTRY logPolygonMode(GLenum face, GLenum mode)
+{
+	fprintf( log_fp, "glPolygonMode( 0x%x, 0x%x )\n", face, mode );
+	dllPolygonMode( face, mode );
+}
+
+static void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units)
+{
+	SIG( "glPolygonOffset" );
+	dllPolygonOffset( factor, units );
+}
+static void APIENTRY logPolygonStipple(const GLubyte *mask )
+{
+	SIG( "glPolygonStipple" );
+	dllPolygonStipple( mask );
+}
+static void APIENTRY logPopAttrib(void)
+{
+	SIG( "glPopAttrib" );
+	dllPopAttrib();
+}
+
+static void APIENTRY logPopClientAttrib(void)
+{
+	SIG( "glPopClientAttrib" );
+	dllPopClientAttrib();
+}
+
+static void APIENTRY logPopMatrix(void)
+{
+	SIG( "glPopMatrix" );
+	dllPopMatrix();
+}
+
+static void APIENTRY logPopName(void)
+{
+	SIG( "glPopName" );
+	dllPopName();
+}
+
+static void APIENTRY logPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities)
+{
+	SIG( "glPrioritizeTextures" );
+	dllPrioritizeTextures( n, textures, priorities );
+}
+
+static void APIENTRY logPushAttrib(GLbitfield mask)
+{
+	SIG( "glPushAttrib" );
+	dllPushAttrib( mask );
+}
+
+static void APIENTRY logPushClientAttrib(GLbitfield mask)
+{
+	SIG( "glPushClientAttrib" );
+	dllPushClientAttrib( mask );
+}
+
+static void APIENTRY logPushMatrix(void)
+{
+	SIG( "glPushMatrix" );
+	dllPushMatrix();
+}
+
+static void APIENTRY logPushName(GLuint name)
+{
+	SIG( "glPushName" );
+	dllPushName( name );
+}
+
+static void APIENTRY logRasterPos2d(GLdouble x, GLdouble y)
+{
+	SIG ("glRasterPot2d" );
+	dllRasterPos2d( x, y );
+}
+
+static void APIENTRY logRasterPos2dv(const GLdouble *v)
+{
+	SIG( "glRasterPos2dv" );
+	dllRasterPos2dv( v );
+}
+
+static void APIENTRY logRasterPos2f(GLfloat x, GLfloat y)
+{
+	SIG( "glRasterPos2f" );
+	dllRasterPos2f( x, y );
+}
+static void APIENTRY logRasterPos2fv(const GLfloat *v)
+{
+	SIG( "glRasterPos2dv" );
+	dllRasterPos2fv( v );
+}
+static void APIENTRY logRasterPos2i(GLint x, GLint y)
+{
+	SIG( "glRasterPos2if" );
+	dllRasterPos2i( x, y );
+}
+static void APIENTRY logRasterPos2iv(const GLint *v)
+{
+	SIG( "glRasterPos2iv" );
+	dllRasterPos2iv( v );
+}
+static void APIENTRY logRasterPos2s(GLshort x, GLshort y)
+{
+	SIG( "glRasterPos2s" );
+	dllRasterPos2s( x, y );
+}
+static void APIENTRY logRasterPos2sv(const GLshort *v)
+{
+	SIG( "glRasterPos2sv" );
+	dllRasterPos2sv( v );
+}
+static void APIENTRY logRasterPos3d(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glRasterPos3d" );
+	dllRasterPos3d( x, y, z );
+}
+static void APIENTRY logRasterPos3dv(const GLdouble *v)
+{
+	SIG( "glRasterPos3dv" );
+	dllRasterPos3dv( v );
+}
+static void APIENTRY logRasterPos3f(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glRasterPos3f" );
+	dllRasterPos3f( x, y, z );
+}
+static void APIENTRY logRasterPos3fv(const GLfloat *v)
+{
+	SIG( "glRasterPos3fv" );
+	dllRasterPos3fv( v );
+}
+static void APIENTRY logRasterPos3i(GLint x, GLint y, GLint z)
+{
+	SIG( "glRasterPos3i" );
+	dllRasterPos3i( x, y, z );
+}
+static void APIENTRY logRasterPos3iv(const GLint *v)
+{
+	SIG( "glRasterPos3iv" );
+	dllRasterPos3iv( v );
+}
+static void APIENTRY logRasterPos3s(GLshort x, GLshort y, GLshort z)
+{
+	SIG( "glRasterPos3s" );
+	dllRasterPos3s( x, y, z );
+}
+static void APIENTRY logRasterPos3sv(const GLshort *v)
+{
+	SIG( "glRasterPos3sv" );
+	dllRasterPos3sv( v );
+}
+static void APIENTRY logRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+	SIG( "glRasterPos4d" );
+	dllRasterPos4d( x, y, z, w );
+}
+static void APIENTRY logRasterPos4dv(const GLdouble *v)
+{
+	SIG( "glRasterPos4dv" );
+	dllRasterPos4dv( v );
+}
+static void APIENTRY logRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	SIG( "glRasterPos4f" );
+	dllRasterPos4f( x, y, z, w );
+}
+static void APIENTRY logRasterPos4fv(const GLfloat *v)
+{
+	SIG( "glRasterPos4fv" );
+	dllRasterPos4fv( v );
+}
+static void APIENTRY logRasterPos4i(GLint x, GLint y, GLint z, GLint w)
+{
+	SIG( "glRasterPos4i" );
+	dllRasterPos4i( x, y, z, w );
+}
+static void APIENTRY logRasterPos4iv(const GLint *v)
+{
+	SIG( "glRasterPos4iv" );
+	dllRasterPos4iv( v );
+}
+static void APIENTRY logRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w)
+{
+	SIG( "glRasterPos4s" );
+	dllRasterPos4s( x, y, z, w );
+}
+static void APIENTRY logRasterPos4sv(const GLshort *v)
+{
+	SIG( "glRasterPos4sv" );
+	dllRasterPos4sv( v );
+}
+static void APIENTRY logReadBuffer(GLenum mode)
+{
+	SIG( "glReadBuffer" );
+	dllReadBuffer( mode );
+}
+static void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)
+{
+	SIG( "glReadPixels" );
+	dllReadPixels( x, y, width, height, format, type, pixels );
+}
+
+static void APIENTRY logRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
+{
+	SIG( "glRectd" );
+	dllRectd( x1, y1, x2, y2 );
+}
+
+static void APIENTRY logRectdv(const GLdouble *v1, const GLdouble *v2)
+{
+	SIG( "glRectdv" );
+	dllRectdv( v1, v2 );
+}
+
+static void APIENTRY logRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+	SIG( "glRectf" );
+	dllRectf( x1, y1, x2, y2 );
+}
+
+static void APIENTRY logRectfv(const GLfloat *v1, const GLfloat *v2)
+{
+	SIG( "glRectfv" );
+	dllRectfv( v1, v2 );
+}
+static void APIENTRY logRecti(GLint x1, GLint y1, GLint x2, GLint y2)
+{
+	SIG( "glRecti" );
+	dllRecti( x1, y1, x2, y2 );
+}
+static void APIENTRY logRectiv(const GLint *v1, const GLint *v2)
+{
+	SIG( "glRectiv" );
+	dllRectiv( v1, v2 );
+}
+static void APIENTRY logRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
+{
+	SIG( "glRects" );
+	dllRects( x1, y1, x2, y2 );
+}
+static void APIENTRY logRectsv(const GLshort *v1, const GLshort *v2)
+{
+	SIG( "glRectsv" );
+	dllRectsv( v1, v2 );
+}
+static GLint APIENTRY logRenderMode(GLenum mode)
+{
+	SIG( "glRenderMode" );
+	return dllRenderMode( mode );
+}
+static void APIENTRY logRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glRotated" );
+	dllRotated( angle, x, y, z );
+}
+
+static void APIENTRY logRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glRotatef" );
+	dllRotatef( angle, x, y, z );
+}
+
+static void APIENTRY logScaled(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glScaled" );
+	dllScaled( x, y, z );
+}
+
+static void APIENTRY logScalef(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glScalef" );
+	dllScalef( x, y, z );
+}
+
+static void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glScissor" );
+	dllScissor( x, y, width, height );
+}
+
+static void APIENTRY logSelectBuffer(GLsizei size, GLuint *buffer)
+{
+	SIG( "glSelectBuffer" );
+	dllSelectBuffer( size, buffer );
+}
+
+static void APIENTRY logShadeModel(GLenum mode)
+{
+	SIG( "glShadeModel" );
+	dllShadeModel( mode );
+}
+
+static void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+	SIG( "glStencilFunc" );
+	dllStencilFunc( func, ref, mask );
+}
+
+static void APIENTRY logStencilMask(GLuint mask)
+{
+	SIG( "glStencilMask" );
+	dllStencilMask( mask );
+}
+
+static void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+	SIG( "glStencilOp" );
+	dllStencilOp( fail, zfail, zpass );
+}
+
+static void APIENTRY logTexCoord1d(GLdouble s)
+{
+	SIG( "glTexCoord1d" );
+	dllTexCoord1d( s );
+}
+
+static void APIENTRY logTexCoord1dv(const GLdouble *v)
+{
+	SIG( "glTexCoord1dv" );
+	dllTexCoord1dv( v );
+}
+
+static void APIENTRY logTexCoord1f(GLfloat s)
+{
+	SIG( "glTexCoord1f" );
+	dllTexCoord1f( s );
+}
+static void APIENTRY logTexCoord1fv(const GLfloat *v)
+{
+	SIG( "glTexCoord1fv" );
+	dllTexCoord1fv( v );
+}
+static void APIENTRY logTexCoord1i(GLint s)
+{
+	SIG( "glTexCoord1i" );
+	dllTexCoord1i( s );
+}
+static void APIENTRY logTexCoord1iv(const GLint *v)
+{
+	SIG( "glTexCoord1iv" );
+	dllTexCoord1iv( v );
+}
+static void APIENTRY logTexCoord1s(GLshort s)
+{
+	SIG( "glTexCoord1s" );
+	dllTexCoord1s( s );
+}
+static void APIENTRY logTexCoord1sv(const GLshort *v)
+{
+	SIG( "glTexCoord1sv" );
+	dllTexCoord1sv( v );
+}
+static void APIENTRY logTexCoord2d(GLdouble s, GLdouble t)
+{
+	SIG( "glTexCoord2d" );
+	dllTexCoord2d( s, t );
+}
+
+static void APIENTRY logTexCoord2dv(const GLdouble *v)
+{
+	SIG( "glTexCoord2dv" );
+	dllTexCoord2dv( v );
+}
+static void APIENTRY logTexCoord2f(GLfloat s, GLfloat t)
+{
+	SIG( "glTexCoord2f" );
+	dllTexCoord2f( s, t );
+}
+static void APIENTRY logTexCoord2fv(const GLfloat *v)
+{
+	SIG( "glTexCoord2fv" );
+	dllTexCoord2fv( v );
+}
+static void APIENTRY logTexCoord2i(GLint s, GLint t)
+{
+	SIG( "glTexCoord2i" );
+	dllTexCoord2i( s, t );
+}
+static void APIENTRY logTexCoord2iv(const GLint *v)
+{
+	SIG( "glTexCoord2iv" );
+	dllTexCoord2iv( v );
+}
+static void APIENTRY logTexCoord2s(GLshort s, GLshort t)
+{
+	SIG( "glTexCoord2s" );
+	dllTexCoord2s( s, t );
+}
+static void APIENTRY logTexCoord2sv(const GLshort *v)
+{
+	SIG( "glTexCoord2sv" );
+	dllTexCoord2sv( v );
+}
+static void APIENTRY logTexCoord3d(GLdouble s, GLdouble t, GLdouble r)
+{
+	SIG( "glTexCoord3d" );
+	dllTexCoord3d( s, t, r );
+}
+static void APIENTRY logTexCoord3dv(const GLdouble *v)
+{
+	SIG( "glTexCoord3dv" );
+	dllTexCoord3dv( v );
+}
+static void APIENTRY logTexCoord3f(GLfloat s, GLfloat t, GLfloat r)
+{
+	SIG( "glTexCoord3f" );
+	dllTexCoord3f( s, t, r );
+}
+static void APIENTRY logTexCoord3fv(const GLfloat *v)
+{
+	SIG( "glTexCoord3fv" );
+	dllTexCoord3fv( v );
+}
+static void APIENTRY logTexCoord3i(GLint s, GLint t, GLint r)
+{
+	SIG( "glTexCoord3i" );
+	dllTexCoord3i( s, t, r );
+}
+static void APIENTRY logTexCoord3iv(const GLint *v)
+{
+	SIG( "glTexCoord3iv" );
+	dllTexCoord3iv( v );
+}
+static void APIENTRY logTexCoord3s(GLshort s, GLshort t, GLshort r)
+{
+	SIG( "glTexCoord3s" );
+	dllTexCoord3s( s, t, r );
+}
+static void APIENTRY logTexCoord3sv(const GLshort *v)
+{
+	SIG( "glTexCoord3sv" );
+	dllTexCoord3sv( v );
+}
+static void APIENTRY logTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q)
+{
+	SIG( "glTexCoord4d" );
+	dllTexCoord4d( s, t, r, q );
+}
+static void APIENTRY logTexCoord4dv(const GLdouble *v)
+{
+	SIG( "glTexCoord4dv" );
+	dllTexCoord4dv( v );
+}
+static void APIENTRY logTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+	SIG( "glTexCoord4f" );
+	dllTexCoord4f( s, t, r, q );
+}
+static void APIENTRY logTexCoord4fv(const GLfloat *v)
+{
+	SIG( "glTexCoord4fv" );
+	dllTexCoord4fv( v );
+}
+static void APIENTRY logTexCoord4i(GLint s, GLint t, GLint r, GLint q)
+{
+	SIG( "glTexCoord4i" );
+	dllTexCoord4i( s, t, r, q );
+}
+static void APIENTRY logTexCoord4iv(const GLint *v)
+{
+	SIG( "glTexCoord4iv" );
+	dllTexCoord4iv( v );
+}
+static void APIENTRY logTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q)
+{
+	SIG( "glTexCoord4s" );
+	dllTexCoord4s( s, t, r, q );
+}
+static void APIENTRY logTexCoord4sv(const GLshort *v)
+{
+	SIG( "glTexCoord4sv" );
+	dllTexCoord4sv( v );
+}
+static void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glTexCoordPointer" );
+	dllTexCoordPointer( size, type, stride, pointer );
+}
+
+static void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param)
+{
+	fprintf( log_fp, "glTexEnvf( 0x%x, 0x%x, %f )\n", target, pname, param );
+	dllTexEnvf( target, pname, param );
+}
+
+static void APIENTRY logTexEnvfv(GLenum target, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexEnvfv" );
+	dllTexEnvfv( target, pname, params );
+}
+
+static void APIENTRY logTexEnvi(GLenum target, GLenum pname, GLint param)
+{
+	fprintf( log_fp, "glTexEnvi( 0x%x, 0x%x, 0x%x )\n", target, pname, param );
+	dllTexEnvi( target, pname, param );
+}
+static void APIENTRY logTexEnviv(GLenum target, GLenum pname, const GLint *params)
+{
+	SIG( "glTexEnviv" );
+	dllTexEnviv( target, pname, params );
+}
+
+static void APIENTRY logTexGend(GLenum coord, GLenum pname, GLdouble param)
+{
+	SIG( "glTexGend" );
+	dllTexGend( coord, pname, param );
+}
+
+static void APIENTRY logTexGendv(GLenum coord, GLenum pname, const GLdouble *params)
+{
+	SIG( "glTexGendv" );
+	dllTexGendv( coord, pname, params );
+}
+
+static void APIENTRY logTexGenf(GLenum coord, GLenum pname, GLfloat param)
+{
+	SIG( "glTexGenf" );
+	dllTexGenf( coord, pname, param );
+}
+static void APIENTRY logTexGenfv(GLenum coord, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexGenfv" );
+	dllTexGenfv( coord, pname, params );
+}
+static void APIENTRY logTexGeni(GLenum coord, GLenum pname, GLint param)
+{
+	SIG( "glTexGeni" );
+	dllTexGeni( coord, pname, param );
+}
+static void APIENTRY logTexGeniv(GLenum coord, GLenum pname, const GLint *params)
+{
+	SIG( "glTexGeniv" );
+	dllTexGeniv( coord, pname, params );
+}
+static void APIENTRY logTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexImage1D" );
+	dllTexImage1D( target, level, internalformat, width, border, format, type, pixels );
+}
+static void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexImage2D" );
+	dllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels );
+}
+
+static void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+	fprintf( log_fp, "glTexParameterf( 0x%x, 0x%x, %f )\n", target, pname, param );
+	dllTexParameterf( target, pname, param );
+}
+
+static void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexParameterfv" );
+	dllTexParameterfv( target, pname, params );
+}
+static void APIENTRY logTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+	fprintf( log_fp, "glTexParameteri( 0x%x, 0x%x, 0x%x )\n", target, pname, param );
+	dllTexParameteri( target, pname, param );
+}
+static void APIENTRY logTexParameteriv(GLenum target, GLenum pname, const GLint *params)
+{
+	SIG( "glTexParameteriv" );
+	dllTexParameteriv( target, pname, params );
+}
+static void APIENTRY logTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexSubImage1D" );
+	dllTexSubImage1D( target, level, xoffset, width, format, type, pixels );
+}
+static void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexSubImage2D" );
+	dllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels );
+}
+static void APIENTRY logTranslated(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glTranslated" );
+	dllTranslated( x, y, z );
+}
+
+static void APIENTRY logTranslatef(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glTranslatef" );
+	dllTranslatef( x, y, z );
+}
+
+static void APIENTRY logVertex2d(GLdouble x, GLdouble y)
+{
+	SIG( "glVertex2d" );
+	dllVertex2d( x, y );
+}
+
+static void APIENTRY logVertex2dv(const GLdouble *v)
+{
+	SIG( "glVertex2dv" );
+	dllVertex2dv( v );
+}
+static void APIENTRY logVertex2f(GLfloat x, GLfloat y)
+{
+	SIG( "glVertex2f" );
+	dllVertex2f( x, y );
+}
+static void APIENTRY logVertex2fv(const GLfloat *v)
+{
+	SIG( "glVertex2fv" );
+	dllVertex2fv( v );
+}
+static void APIENTRY logVertex2i(GLint x, GLint y)
+{
+	SIG( "glVertex2i" );
+	dllVertex2i( x, y );
+}
+static void APIENTRY logVertex2iv(const GLint *v)
+{
+	SIG( "glVertex2iv" );
+	dllVertex2iv( v );
+}
+static void APIENTRY logVertex2s(GLshort x, GLshort y)
+{
+	SIG( "glVertex2s" );
+	dllVertex2s( x, y );
+}
+static void APIENTRY logVertex2sv(const GLshort *v)
+{
+	SIG( "glVertex2sv" );
+	dllVertex2sv( v );
+}
+static void APIENTRY logVertex3d(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glVertex3d" );
+	dllVertex3d( x, y, z );
+}
+static void APIENTRY logVertex3dv(const GLdouble *v)
+{
+	SIG( "glVertex3dv" );
+	dllVertex3dv( v );
+}
+static void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glVertex3f" );
+	dllVertex3f( x, y, z );
+}
+static void APIENTRY logVertex3fv(const GLfloat *v)
+{
+	SIG( "glVertex3fv" );
+	dllVertex3fv( v );
+}
+static void APIENTRY logVertex3i(GLint x, GLint y, GLint z)
+{
+	SIG( "glVertex3i" );
+	dllVertex3i( x, y, z );
+}
+static void APIENTRY logVertex3iv(const GLint *v)
+{
+	SIG( "glVertex3iv" );
+	dllVertex3iv( v );
+}
+static void APIENTRY logVertex3s(GLshort x, GLshort y, GLshort z)
+{
+	SIG( "glVertex3s" );
+	dllVertex3s( x, y, z );
+}
+static void APIENTRY logVertex3sv(const GLshort *v)
+{
+	SIG( "glVertex3sv" );
+	dllVertex3sv( v );
+}
+static void APIENTRY logVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+	SIG( "glVertex4d" );
+	dllVertex4d( x, y, z, w );
+}
+static void APIENTRY logVertex4dv(const GLdouble *v)
+{
+	SIG( "glVertex4dv" );
+	dllVertex4dv( v );
+}
+static void APIENTRY logVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	SIG( "glVertex4f" );
+	dllVertex4f( x, y, z, w );
+}
+static void APIENTRY logVertex4fv(const GLfloat *v)
+{
+	SIG( "glVertex4fv" );
+	dllVertex4fv( v );
+}
+static void APIENTRY logVertex4i(GLint x, GLint y, GLint z, GLint w)
+{
+	SIG( "glVertex4i" );
+	dllVertex4i( x, y, z, w );
+}
+static void APIENTRY logVertex4iv(const GLint *v)
+{
+	SIG( "glVertex4iv" );
+	dllVertex4iv( v );
+}
+static void APIENTRY logVertex4s(GLshort x, GLshort y, GLshort z, GLshort w)
+{
+	SIG( "glVertex4s" );
+	dllVertex4s( x, y, z, w );
+}
+static void APIENTRY logVertex4sv(const GLshort *v)
+{
+	SIG( "glVertex4sv" );
+	dllVertex4sv( v );
+}
+static void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glVertexPointer" );
+	dllVertexPointer( size, type, stride, pointer );
+}
+static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glViewport" );
+	dllViewport( x, y, width, height );
+}
+
+/*
+** QGL_Shutdown
+**
+** Unloads the specified DLL then nulls out all the proc pointers.
+*/
+void QGL_Shutdown( void )
+{
+	qglAccum                     = NULL;
+	qglAlphaFunc                 = NULL;
+	qglAreTexturesResident       = NULL;
+	qglArrayElement              = NULL;
+	qglBegin                     = NULL;
+	qglBindTexture               = NULL;
+	qglBitmap                    = NULL;
+	qglBlendFunc                 = NULL;
+	qglCallList                  = NULL;
+	qglCallLists                 = NULL;
+	qglClear                     = NULL;
+	qglClearAccum                = NULL;
+	qglClearColor                = NULL;
+	qglClearDepth                = NULL;
+	qglClearIndex                = NULL;
+	qglClearStencil              = NULL;
+	qglClipPlane                 = NULL;
+	qglColor3b                   = NULL;
+	qglColor3bv                  = NULL;
+	qglColor3d                   = NULL;
+	qglColor3dv                  = NULL;
+	qglColor3f                   = NULL;
+	qglColor3fv                  = NULL;
+	qglColor3i                   = NULL;
+	qglColor3iv                  = NULL;
+	qglColor3s                   = NULL;
+	qglColor3sv                  = NULL;
+	qglColor3ub                  = NULL;
+	qglColor3ubv                 = NULL;
+	qglColor3ui                  = NULL;
+	qglColor3uiv                 = NULL;
+	qglColor3us                  = NULL;
+	qglColor3usv                 = NULL;
+	qglColor4b                   = NULL;
+	qglColor4bv                  = NULL;
+	qglColor4d                   = NULL;
+	qglColor4dv                  = NULL;
+	qglColor4f                   = NULL;
+	qglColor4fv                  = NULL;
+	qglColor4i                   = NULL;
+	qglColor4iv                  = NULL;
+	qglColor4s                   = NULL;
+	qglColor4sv                  = NULL;
+	qglColor4ub                  = NULL;
+	qglColor4ubv                 = NULL;
+	qglColor4ui                  = NULL;
+	qglColor4uiv                 = NULL;
+	qglColor4us                  = NULL;
+	qglColor4usv                 = NULL;
+	qglColorMask                 = NULL;
+	qglColorMaterial             = NULL;
+	qglColorPointer              = NULL;
+	qglCopyPixels                = NULL;
+	qglCopyTexImage1D            = NULL;
+	qglCopyTexImage2D            = NULL;
+	qglCopyTexSubImage1D         = NULL;
+	qglCopyTexSubImage2D         = NULL;
+	qglCullFace                  = NULL;
+	qglDeleteLists               = NULL;
+	qglDeleteTextures            = NULL;
+	qglDepthFunc                 = NULL;
+	qglDepthMask                 = NULL;
+	qglDepthRange                = NULL;
+	qglDisable                   = NULL;
+	qglDisableClientState        = NULL;
+	qglDrawArrays                = NULL;
+	qglDrawBuffer                = NULL;
+	qglDrawElements              = NULL;
+	qglDrawPixels                = NULL;
+	qglEdgeFlag                  = NULL;
+	qglEdgeFlagPointer           = NULL;
+	qglEdgeFlagv                 = NULL;
+	qglEnable                    = NULL;
+	qglEnableClientState         = NULL;
+	qglEnd                       = NULL;
+	qglEndList                   = NULL;
+	qglEvalCoord1d               = NULL;
+	qglEvalCoord1dv              = NULL;
+	qglEvalCoord1f               = NULL;
+	qglEvalCoord1fv              = NULL;
+	qglEvalCoord2d               = NULL;
+	qglEvalCoord2dv              = NULL;
+	qglEvalCoord2f               = NULL;
+	qglEvalCoord2fv              = NULL;
+	qglEvalMesh1                 = NULL;
+	qglEvalMesh2                 = NULL;
+	qglEvalPoint1                = NULL;
+	qglEvalPoint2                = NULL;
+	qglFeedbackBuffer            = NULL;
+	qglFinish                    = NULL;
+	qglFlush                     = NULL;
+	qglFogf                      = NULL;
+	qglFogfv                     = NULL;
+	qglFogi                      = NULL;
+	qglFogiv                     = NULL;
+	qglFrontFace                 = NULL;
+	qglFrustum                   = NULL;
+	qglGenLists                  = NULL;
+	qglGenTextures               = NULL;
+	qglGetBooleanv               = NULL;
+	qglGetClipPlane              = NULL;
+	qglGetDoublev                = NULL;
+	qglGetError                  = NULL;
+	qglGetFloatv                 = NULL;
+	qglGetIntegerv               = NULL;
+	qglGetLightfv                = NULL;
+	qglGetLightiv                = NULL;
+	qglGetMapdv                  = NULL;
+	qglGetMapfv                  = NULL;
+	qglGetMapiv                  = NULL;
+	qglGetMaterialfv             = NULL;
+	qglGetMaterialiv             = NULL;
+	qglGetPixelMapfv             = NULL;
+	qglGetPixelMapuiv            = NULL;
+	qglGetPixelMapusv            = NULL;
+	qglGetPointerv               = NULL;
+	qglGetPolygonStipple         = NULL;
+	qglGetString                 = NULL;
+	qglGetTexEnvfv               = NULL;
+	qglGetTexEnviv               = NULL;
+	qglGetTexGendv               = NULL;
+	qglGetTexGenfv               = NULL;
+	qglGetTexGeniv               = NULL;
+	qglGetTexImage               = NULL;
+	qglGetTexLevelParameterfv    = NULL;
+	qglGetTexLevelParameteriv    = NULL;
+	qglGetTexParameterfv         = NULL;
+	qglGetTexParameteriv         = NULL;
+	qglHint                      = NULL;
+	qglIndexMask                 = NULL;
+	qglIndexPointer              = NULL;
+	qglIndexd                    = NULL;
+	qglIndexdv                   = NULL;
+	qglIndexf                    = NULL;
+	qglIndexfv                   = NULL;
+	qglIndexi                    = NULL;
+	qglIndexiv                   = NULL;
+	qglIndexs                    = NULL;
+	qglIndexsv                   = NULL;
+	qglIndexub                   = NULL;
+	qglIndexubv                  = NULL;
+	qglInitNames                 = NULL;
+	qglInterleavedArrays         = NULL;
+	qglIsEnabled                 = NULL;
+	qglIsList                    = NULL;
+	qglIsTexture                 = NULL;
+	qglLightModelf               = NULL;
+	qglLightModelfv              = NULL;
+	qglLightModeli               = NULL;
+	qglLightModeliv              = NULL;
+	qglLightf                    = NULL;
+	qglLightfv                   = NULL;
+	qglLighti                    = NULL;
+	qglLightiv                   = NULL;
+	qglLineStipple               = NULL;
+	qglLineWidth                 = NULL;
+	qglListBase                  = NULL;
+	qglLoadIdentity              = NULL;
+	qglLoadMatrixd               = NULL;
+	qglLoadMatrixf               = NULL;
+	qglLoadName                  = NULL;
+	qglLogicOp                   = NULL;
+	qglMap1d                     = NULL;
+	qglMap1f                     = NULL;
+	qglMap2d                     = NULL;
+	qglMap2f                     = NULL;
+	qglMapGrid1d                 = NULL;
+	qglMapGrid1f                 = NULL;
+	qglMapGrid2d                 = NULL;
+	qglMapGrid2f                 = NULL;
+	qglMaterialf                 = NULL;
+	qglMaterialfv                = NULL;
+	qglMateriali                 = NULL;
+	qglMaterialiv                = NULL;
+	qglMatrixMode                = NULL;
+	qglMultMatrixd               = NULL;
+	qglMultMatrixf               = NULL;
+	qglNewList                   = NULL;
+	qglNormal3b                  = NULL;
+	qglNormal3bv                 = NULL;
+	qglNormal3d                  = NULL;
+	qglNormal3dv                 = NULL;
+	qglNormal3f                  = NULL;
+	qglNormal3fv                 = NULL;
+	qglNormal3i                  = NULL;
+	qglNormal3iv                 = NULL;
+	qglNormal3s                  = NULL;
+	qglNormal3sv                 = NULL;
+	qglNormalPointer             = NULL;
+	qglOrtho                     = NULL;
+	qglPassThrough               = NULL;
+	qglPixelMapfv                = NULL;
+	qglPixelMapuiv               = NULL;
+	qglPixelMapusv               = NULL;
+	qglPixelStoref               = NULL;
+	qglPixelStorei               = NULL;
+	qglPixelTransferf            = NULL;
+	qglPixelTransferi            = NULL;
+	qglPixelZoom                 = NULL;
+	qglPointSize                 = NULL;
+	qglPolygonMode               = NULL;
+	qglPolygonOffset             = NULL;
+	qglPolygonStipple            = NULL;
+	qglPopAttrib                 = NULL;
+	qglPopClientAttrib           = NULL;
+	qglPopMatrix                 = NULL;
+	qglPopName                   = NULL;
+	qglPrioritizeTextures        = NULL;
+	qglPushAttrib                = NULL;
+	qglPushClientAttrib          = NULL;
+	qglPushMatrix                = NULL;
+	qglPushName                  = NULL;
+	qglRasterPos2d               = NULL;
+	qglRasterPos2dv              = NULL;
+	qglRasterPos2f               = NULL;
+	qglRasterPos2fv              = NULL;
+	qglRasterPos2i               = NULL;
+	qglRasterPos2iv              = NULL;
+	qglRasterPos2s               = NULL;
+	qglRasterPos2sv              = NULL;
+	qglRasterPos3d               = NULL;
+	qglRasterPos3dv              = NULL;
+	qglRasterPos3f               = NULL;
+	qglRasterPos3fv              = NULL;
+	qglRasterPos3i               = NULL;
+	qglRasterPos3iv              = NULL;
+	qglRasterPos3s               = NULL;
+	qglRasterPos3sv              = NULL;
+	qglRasterPos4d               = NULL;
+	qglRasterPos4dv              = NULL;
+	qglRasterPos4f               = NULL;
+	qglRasterPos4fv              = NULL;
+	qglRasterPos4i               = NULL;
+	qglRasterPos4iv              = NULL;
+	qglRasterPos4s               = NULL;
+	qglRasterPos4sv              = NULL;
+	qglReadBuffer                = NULL;
+	qglReadPixels                = NULL;
+	qglRectd                     = NULL;
+	qglRectdv                    = NULL;
+	qglRectf                     = NULL;
+	qglRectfv                    = NULL;
+	qglRecti                     = NULL;
+	qglRectiv                    = NULL;
+	qglRects                     = NULL;
+	qglRectsv                    = NULL;
+	qglRenderMode                = NULL;
+	qglRotated                   = NULL;
+	qglRotatef                   = NULL;
+	qglScaled                    = NULL;
+	qglScalef                    = NULL;
+	qglScissor                   = NULL;
+	qglSelectBuffer              = NULL;
+	qglShadeModel                = NULL;
+	qglStencilFunc               = NULL;
+	qglStencilMask               = NULL;
+	qglStencilOp                 = NULL;
+	qglTexCoord1d                = NULL;
+	qglTexCoord1dv               = NULL;
+	qglTexCoord1f                = NULL;
+	qglTexCoord1fv               = NULL;
+	qglTexCoord1i                = NULL;
+	qglTexCoord1iv               = NULL;
+	qglTexCoord1s                = NULL;
+	qglTexCoord1sv               = NULL;
+	qglTexCoord2d                = NULL;
+	qglTexCoord2dv               = NULL;
+	qglTexCoord2f                = NULL;
+	qglTexCoord2fv               = NULL;
+	qglTexCoord2i                = NULL;
+	qglTexCoord2iv               = NULL;
+	qglTexCoord2s                = NULL;
+	qglTexCoord2sv               = NULL;
+	qglTexCoord3d                = NULL;
+	qglTexCoord3dv               = NULL;
+	qglTexCoord3f                = NULL;
+	qglTexCoord3fv               = NULL;
+	qglTexCoord3i                = NULL;
+	qglTexCoord3iv               = NULL;
+	qglTexCoord3s                = NULL;
+	qglTexCoord3sv               = NULL;
+	qglTexCoord4d                = NULL;
+	qglTexCoord4dv               = NULL;
+	qglTexCoord4f                = NULL;
+	qglTexCoord4fv               = NULL;
+	qglTexCoord4i                = NULL;
+	qglTexCoord4iv               = NULL;
+	qglTexCoord4s                = NULL;
+	qglTexCoord4sv               = NULL;
+	qglTexCoordPointer           = NULL;
+	qglTexEnvf                   = NULL;
+	qglTexEnvfv                  = NULL;
+	qglTexEnvi                   = NULL;
+	qglTexEnviv                  = NULL;
+	qglTexGend                   = NULL;
+	qglTexGendv                  = NULL;
+	qglTexGenf                   = NULL;
+	qglTexGenfv                  = NULL;
+	qglTexGeni                   = NULL;
+	qglTexGeniv                  = NULL;
+	qglTexImage1D                = NULL;
+	qglTexImage2D                = NULL;
+	qglTexParameterf             = NULL;
+	qglTexParameterfv            = NULL;
+	qglTexParameteri             = NULL;
+	qglTexParameteriv            = NULL;
+	qglTexSubImage1D             = NULL;
+	qglTexSubImage2D             = NULL;
+	qglTranslated                = NULL;
+	qglTranslatef                = NULL;
+	qglVertex2d                  = NULL;
+	qglVertex2dv                 = NULL;
+	qglVertex2f                  = NULL;
+	qglVertex2fv                 = NULL;
+	qglVertex2i                  = NULL;
+	qglVertex2iv                 = NULL;
+	qglVertex2s                  = NULL;
+	qglVertex2sv                 = NULL;
+	qglVertex3d                  = NULL;
+	qglVertex3dv                 = NULL;
+	qglVertex3f                  = NULL;
+	qglVertex3fv                 = NULL;
+	qglVertex3i                  = NULL;
+	qglVertex3iv                 = NULL;
+	qglVertex3s                  = NULL;
+	qglVertex3sv                 = NULL;
+	qglVertex4d                  = NULL;
+	qglVertex4dv                 = NULL;
+	qglVertex4f                  = NULL;
+	qglVertex4fv                 = NULL;
+	qglVertex4i                  = NULL;
+	qglVertex4iv                 = NULL;
+	qglVertex4s                  = NULL;
+	qglVertex4sv                 = NULL;
+	qglVertexPointer             = NULL;
+	qglViewport                  = NULL;
+
+	qglColorTableEXT             = NULL;
+
+}
+
+/*
+** QGL_Init
+**
+** This is responsible for binding our qgl function pointers to 
+** the appropriate GL stuff.  In Windows this means doing a 
+** LoadLibrary and a bunch of calls to GetProcAddress.  On other
+** operating systems we need to do the right thing, whatever that
+** might be.
+** 
+*/
+qboolean QGL_Init( const char *dllname )
+{
+	gl_config.allow_cds = true;
+
+	qglAccum                     = dllAccum = glAccum;
+	qglAlphaFunc                 = dllAlphaFunc = glAlphaFunc;
+	qglAreTexturesResident       = dllAreTexturesResident = glAreTexturesResident;
+	qglArrayElement              = dllArrayElement = glArrayElement;
+	qglBegin                     = dllBegin = glBegin;
+	qglBindTexture               = dllBindTexture = glBindTexture;
+	qglBitmap                    = dllBitmap = glBitmap;
+	qglBlendFunc                 = dllBlendFunc = glBlendFunc;
+	qglCallList                  = dllCallList = glCallList;
+	qglCallLists                 = dllCallLists = glCallLists;
+	qglClear                     = dllClear = glClear;
+	qglClearAccum                = dllClearAccum = glClearAccum;
+	qglClearColor                = dllClearColor = glClearColor;
+	qglClearDepth                = dllClearDepth = glClearDepth;
+	qglClearIndex                = dllClearIndex = glClearIndex;
+	qglClearStencil              = dllClearStencil = glClearStencil;
+	qglClipPlane                 = dllClipPlane = glClipPlane;
+	qglColor3b                   = dllColor3b = glColor3b;
+	qglColor3bv                  = dllColor3bv = glColor3bv;
+	qglColor3d                   = dllColor3d = glColor3d;
+	qglColor3dv                  = dllColor3dv = glColor3dv;
+	qglColor3f                   = dllColor3f = glColor3f;
+	qglColor3fv                  = dllColor3fv = glColor3fv;
+	qglColor3i                   = dllColor3i = glColor3i;
+	qglColor3iv                  = dllColor3iv = glColor3iv;
+	qglColor3s                   = dllColor3s = glColor3s;
+	qglColor3sv                  = dllColor3sv = glColor3sv;
+	qglColor3ub                  = dllColor3ub = glColor3ub;
+	qglColor3ubv                 = dllColor3ubv = glColor3ubv;
+	qglColor3ui                  = dllColor3ui = glColor3ui;
+	qglColor3uiv                 = dllColor3uiv = glColor3uiv;
+	qglColor3us                  = dllColor3us = glColor3us;
+	qglColor3usv                 = dllColor3usv = glColor3usv;
+	qglColor4b                   = dllColor4b = glColor4b;
+	qglColor4bv                  = dllColor4bv = glColor4bv;
+	qglColor4d                   = dllColor4d = glColor4d;
+	qglColor4dv                  = dllColor4dv = glColor4dv;
+	qglColor4f                   = dllColor4f = glColor4f;
+	qglColor4fv                  = dllColor4fv = glColor4fv;
+	qglColor4i                   = dllColor4i = glColor4i;
+	qglColor4iv                  = dllColor4iv = glColor4iv;
+	qglColor4s                   = dllColor4s = glColor4s;
+	qglColor4sv                  = dllColor4sv = glColor4sv;
+	qglColor4ub                  = dllColor4ub = glColor4ub;
+	qglColor4ubv                 = dllColor4ubv = glColor4ubv;
+	qglColor4ui                  = dllColor4ui = glColor4ui;
+	qglColor4uiv                 = dllColor4uiv = glColor4uiv;
+	qglColor4us                  = dllColor4us = glColor4us;
+	qglColor4usv                 = dllColor4usv = glColor4usv;
+	qglColorMask                 = dllColorMask = glColorMask;
+	qglColorMaterial             = dllColorMaterial = glColorMaterial;
+	qglColorPointer              = dllColorPointer = glColorPointer;
+	qglCopyPixels                = dllCopyPixels = glCopyPixels;
+	qglCopyTexImage1D            = dllCopyTexImage1D = glCopyTexImage1D;
+	qglCopyTexImage2D            = dllCopyTexImage2D = glCopyTexImage2D;
+	qglCopyTexSubImage1D         = dllCopyTexSubImage1D = glCopyTexSubImage1D;
+	qglCopyTexSubImage2D         = dllCopyTexSubImage2D = glCopyTexSubImage2D;
+	qglCullFace                  = dllCullFace = glCullFace;
+	qglDeleteLists               = dllDeleteLists = glDeleteLists;
+	qglDeleteTextures            = dllDeleteTextures = glDeleteTextures;
+	qglDepthFunc                 = dllDepthFunc = glDepthFunc;
+	qglDepthMask                 = dllDepthMask = glDepthMask;
+	qglDepthRange                = dllDepthRange = glDepthRange;
+	qglDisable                   = dllDisable = glDisable;
+	qglDisableClientState        = dllDisableClientState = glDisableClientState;
+	qglDrawArrays                = dllDrawArrays = glDrawArrays;
+	qglDrawBuffer                = dllDrawBuffer = glDrawBuffer;
+	qglDrawElements              = dllDrawElements = glDrawElements;
+	qglDrawPixels                = dllDrawPixels = glDrawPixels;
+	qglEdgeFlag                  = dllEdgeFlag = glEdgeFlag;
+	qglEdgeFlagPointer           = dllEdgeFlagPointer = glEdgeFlagPointer;
+	qglEdgeFlagv                 = dllEdgeFlagv = glEdgeFlagv;
+	qglEnable                    = 	dllEnable                    = glEnable;
+	qglEnableClientState         = 	dllEnableClientState         = glEnableClientState;
+	qglEnd                       = 	dllEnd                       = glEnd;
+	qglEndList                   = 	dllEndList                   = glEndList;
+	qglEvalCoord1d				 = 	dllEvalCoord1d				 = glEvalCoord1d;
+	qglEvalCoord1dv              = 	dllEvalCoord1dv              = glEvalCoord1dv;
+	qglEvalCoord1f               = 	dllEvalCoord1f               = glEvalCoord1f;
+	qglEvalCoord1fv              = 	dllEvalCoord1fv              = glEvalCoord1fv;
+	qglEvalCoord2d               = 	dllEvalCoord2d               = glEvalCoord2d;
+	qglEvalCoord2dv              = 	dllEvalCoord2dv              = glEvalCoord2dv;
+	qglEvalCoord2f               = 	dllEvalCoord2f               = glEvalCoord2f;
+	qglEvalCoord2fv              = 	dllEvalCoord2fv              = glEvalCoord2fv;
+	qglEvalMesh1                 = 	dllEvalMesh1                 = glEvalMesh1;
+	qglEvalMesh2                 = 	dllEvalMesh2                 = glEvalMesh2;
+	qglEvalPoint1                = 	dllEvalPoint1                = glEvalPoint1;
+	qglEvalPoint2                = 	dllEvalPoint2                = glEvalPoint2;
+	qglFeedbackBuffer            = 	dllFeedbackBuffer            = glFeedbackBuffer;
+	qglFinish                    = 	dllFinish                    = glFinish;
+	qglFlush                     = 	dllFlush                     = glFlush;
+	qglFogf                      = 	dllFogf                      = glFogf;
+	qglFogfv                     = 	dllFogfv                     = glFogfv;
+	qglFogi                      = 	dllFogi                      = glFogi;
+	qglFogiv                     = 	dllFogiv                     = glFogiv;
+	qglFrontFace                 = 	dllFrontFace                 = glFrontFace;
+	qglFrustum                   = 	dllFrustum                   = glFrustum;
+	qglGenLists                  = 	dllGenLists                  = glGenLists;
+	qglGenTextures               = 	dllGenTextures               = glGenTextures;
+	qglGetBooleanv               = 	dllGetBooleanv               = glGetBooleanv;
+	qglGetClipPlane              = 	dllGetClipPlane              = glGetClipPlane;
+	qglGetDoublev                = 	dllGetDoublev                = glGetDoublev;
+	qglGetError                  = 	dllGetError                  = glGetError;
+	qglGetFloatv                 = 	dllGetFloatv                 = glGetFloatv;
+	qglGetIntegerv               = 	dllGetIntegerv               = glGetIntegerv;
+	qglGetLightfv                = 	dllGetLightfv                = glGetLightfv;
+	qglGetLightiv                = 	dllGetLightiv                = glGetLightiv;
+	qglGetMapdv                  = 	dllGetMapdv                  = glGetMapdv;
+	qglGetMapfv                  = 	dllGetMapfv                  = glGetMapfv;
+	qglGetMapiv                  = 	dllGetMapiv                  = glGetMapiv;
+	qglGetMaterialfv             = 	dllGetMaterialfv             = glGetMaterialfv;
+	qglGetMaterialiv             = 	dllGetMaterialiv             = glGetMaterialiv;
+	qglGetPixelMapfv             = 	dllGetPixelMapfv             = glGetPixelMapfv;
+	qglGetPixelMapuiv            = 	dllGetPixelMapuiv            = glGetPixelMapuiv;
+	qglGetPixelMapusv            = 	dllGetPixelMapusv            = glGetPixelMapusv;
+	qglGetPointerv               = 	dllGetPointerv               = glGetPointerv;
+	qglGetPolygonStipple         = 	dllGetPolygonStipple         = glGetPolygonStipple;
+	qglGetString                 = 	dllGetString                 = glGetString;
+	qglGetTexEnvfv               = 	dllGetTexEnvfv               = glGetTexEnvfv;
+	qglGetTexEnviv               = 	dllGetTexEnviv               = glGetTexEnviv;
+	qglGetTexGendv               = 	dllGetTexGendv               = glGetTexGendv;
+	qglGetTexGenfv               = 	dllGetTexGenfv               = glGetTexGenfv;
+	qglGetTexGeniv               = 	dllGetTexGeniv               = glGetTexGeniv;
+	qglGetTexImage               = 	dllGetTexImage               = glGetTexImage;
+//	qglGetTexLevelParameterfv    = 	dllGetTexLevelParameterfv    = glGetLevelParameterfv;
+//	qglGetTexLevelParameteriv    = 	dllGetTexLevelParameteriv    = glGetLevelParameteriv;
+	qglGetTexParameterfv         = 	dllGetTexParameterfv         = glGetTexParameterfv;
+	qglGetTexParameteriv         = 	dllGetTexParameteriv         = glGetTexParameteriv;
+	qglHint                      = 	dllHint                      = glHint;
+	qglIndexMask                 = 	dllIndexMask                 = glIndexMask;
+	qglIndexPointer              = 	dllIndexPointer              = glIndexPointer;
+	qglIndexd                    = 	dllIndexd                    = glIndexd;
+	qglIndexdv                   = 	dllIndexdv                   = glIndexdv;
+	qglIndexf                    = 	dllIndexf                    = glIndexf;
+	qglIndexfv                   = 	dllIndexfv                   = glIndexfv;
+	qglIndexi                    = 	dllIndexi                    = glIndexi;
+	qglIndexiv                   = 	dllIndexiv                   = glIndexiv;
+	qglIndexs                    = 	dllIndexs                    = glIndexs;
+	qglIndexsv                   = 	dllIndexsv                   = glIndexsv;
+	qglIndexub                   = 	dllIndexub                   = glIndexub;
+	qglIndexubv                  = 	dllIndexubv                  = glIndexubv;
+	qglInitNames                 = 	dllInitNames                 = glInitNames;
+	qglInterleavedArrays         = 	dllInterleavedArrays         = glInterleavedArrays;
+	qglIsEnabled                 = 	dllIsEnabled                 = glIsEnabled;
+	qglIsList                    = 	dllIsList                    = glIsList;
+	qglIsTexture                 = 	dllIsTexture                 = glIsTexture;
+	qglLightModelf               = 	dllLightModelf               = glLightModelf;
+	qglLightModelfv              = 	dllLightModelfv              = glLightModelfv;
+	qglLightModeli               = 	dllLightModeli               = glLightModeli;
+	qglLightModeliv              = 	dllLightModeliv              = glLightModeliv;
+	qglLightf                    = 	dllLightf                    = glLightf;
+	qglLightfv                   = 	dllLightfv                   = glLightfv;
+	qglLighti                    = 	dllLighti                    = glLighti;
+	qglLightiv                   = 	dllLightiv                   = glLightiv;
+	qglLineStipple               = 	dllLineStipple               = glLineStipple;
+	qglLineWidth                 = 	dllLineWidth                 = glLineWidth;
+	qglListBase                  = 	dllListBase                  = glListBase;
+	qglLoadIdentity              = 	dllLoadIdentity              = glLoadIdentity;
+	qglLoadMatrixd               = 	dllLoadMatrixd               = glLoadMatrixd;
+	qglLoadMatrixf               = 	dllLoadMatrixf               = glLoadMatrixf;
+	qglLoadName                  = 	dllLoadName                  = glLoadName;
+	qglLogicOp                   = 	dllLogicOp                   = glLogicOp;
+	qglMap1d                     = 	dllMap1d                     = glMap1d;
+	qglMap1f                     = 	dllMap1f                     = glMap1f;
+	qglMap2d                     = 	dllMap2d                     = glMap2d;
+	qglMap2f                     = 	dllMap2f                     = glMap2f;
+	qglMapGrid1d                 = 	dllMapGrid1d                 = glMapGrid1d;
+	qglMapGrid1f                 = 	dllMapGrid1f                 = glMapGrid1f;
+	qglMapGrid2d                 = 	dllMapGrid2d                 = glMapGrid2d;
+	qglMapGrid2f                 = 	dllMapGrid2f                 = glMapGrid2f;
+	qglMaterialf                 = 	dllMaterialf                 = glMaterialf;
+	qglMaterialfv                = 	dllMaterialfv                = glMaterialfv;
+	qglMateriali                 = 	dllMateriali                 = glMateriali;
+	qglMaterialiv                = 	dllMaterialiv                = glMaterialiv;
+	qglMatrixMode                = 	dllMatrixMode                = glMatrixMode;
+	qglMultMatrixd               = 	dllMultMatrixd               = glMultMatrixd;
+	qglMultMatrixf               = 	dllMultMatrixf               = glMultMatrixf;
+	qglNewList                   = 	dllNewList                   = glNewList;
+	qglNormal3b                  = 	dllNormal3b                  = glNormal3b;
+	qglNormal3bv                 = 	dllNormal3bv                 = glNormal3bv;
+	qglNormal3d                  = 	dllNormal3d                  = glNormal3d;
+	qglNormal3dv                 = 	dllNormal3dv                 = glNormal3dv;
+	qglNormal3f                  = 	dllNormal3f                  = glNormal3f;
+	qglNormal3fv                 = 	dllNormal3fv                 = glNormal3fv;
+	qglNormal3i                  = 	dllNormal3i                  = glNormal3i;
+	qglNormal3iv                 = 	dllNormal3iv                 = glNormal3iv;
+	qglNormal3s                  = 	dllNormal3s                  = glNormal3s;
+	qglNormal3sv                 = 	dllNormal3sv                 = glNormal3sv;
+	qglNormalPointer             = 	dllNormalPointer             = glNormalPointer;
+	qglOrtho                     = 	dllOrtho                     = glOrtho;
+	qglPassThrough               = 	dllPassThrough               = glPassThrough;
+	qglPixelMapfv                = 	dllPixelMapfv                = glPixelMapfv;
+	qglPixelMapuiv               = 	dllPixelMapuiv               = glPixelMapuiv;
+	qglPixelMapusv               = 	dllPixelMapusv               = glPixelMapusv;
+	qglPixelStoref               = 	dllPixelStoref               = glPixelStoref;
+	qglPixelStorei               = 	dllPixelStorei               = glPixelStorei;
+	qglPixelTransferf            = 	dllPixelTransferf            = glPixelTransferf;
+	qglPixelTransferi            = 	dllPixelTransferi            = glPixelTransferi;
+	qglPixelZoom                 = 	dllPixelZoom                 = glPixelZoom;
+	qglPointSize                 = 	dllPointSize                 = glPointSize;
+	qglPolygonMode               = 	dllPolygonMode               = glPolygonMode;
+	qglPolygonOffset             = 	dllPolygonOffset             = glPolygonOffset;
+	qglPolygonStipple            = 	dllPolygonStipple            = glPolygonStipple;
+	qglPopAttrib                 = 	dllPopAttrib                 = glPopAttrib;
+	qglPopClientAttrib           = 	dllPopClientAttrib           = glPopClientAttrib;
+	qglPopMatrix                 = 	dllPopMatrix                 = glPopMatrix;
+	qglPopName                   = 	dllPopName                   = glPopName;
+	qglPrioritizeTextures        = 	dllPrioritizeTextures        = glPrioritizeTextures;
+	qglPushAttrib                = 	dllPushAttrib                = glPushAttrib;
+	qglPushClientAttrib          = 	dllPushClientAttrib          = glPushClientAttrib;
+	qglPushMatrix                = 	dllPushMatrix                = glPushMatrix;
+	qglPushName                  = 	dllPushName                  = glPushName;
+	qglRasterPos2d               = 	dllRasterPos2d               = glRasterPos2d;
+	qglRasterPos2dv              = 	dllRasterPos2dv              = glRasterPos2dv;
+	qglRasterPos2f               = 	dllRasterPos2f               = glRasterPos2f;
+	qglRasterPos2fv              = 	dllRasterPos2fv              = glRasterPos2fv;
+	qglRasterPos2i               = 	dllRasterPos2i               = glRasterPos2i;
+	qglRasterPos2iv              = 	dllRasterPos2iv              = glRasterPos2iv;
+	qglRasterPos2s               = 	dllRasterPos2s               = glRasterPos2s;
+	qglRasterPos2sv              = 	dllRasterPos2sv              = glRasterPos2sv;
+	qglRasterPos3d               = 	dllRasterPos3d               = glRasterPos3d;
+	qglRasterPos3dv              = 	dllRasterPos3dv              = glRasterPos3dv;
+	qglRasterPos3f               = 	dllRasterPos3f               = glRasterPos3f;
+	qglRasterPos3fv              = 	dllRasterPos3fv              = glRasterPos3fv;
+	qglRasterPos3i               = 	dllRasterPos3i               = glRasterPos3i;
+	qglRasterPos3iv              = 	dllRasterPos3iv              = glRasterPos3iv;
+	qglRasterPos3s               = 	dllRasterPos3s               = glRasterPos3s;
+	qglRasterPos3sv              = 	dllRasterPos3sv              = glRasterPos3sv;
+	qglRasterPos4d               = 	dllRasterPos4d               = glRasterPos4d;
+	qglRasterPos4dv              = 	dllRasterPos4dv              = glRasterPos4dv;
+	qglRasterPos4f               = 	dllRasterPos4f               = glRasterPos4f;
+	qglRasterPos4fv              = 	dllRasterPos4fv              = glRasterPos4fv;
+	qglRasterPos4i               = 	dllRasterPos4i               = glRasterPos4i;
+	qglRasterPos4iv              = 	dllRasterPos4iv              = glRasterPos4iv;
+	qglRasterPos4s               = 	dllRasterPos4s               = glRasterPos4s;
+	qglRasterPos4sv              = 	dllRasterPos4sv              = glRasterPos4sv;
+	qglReadBuffer                = 	dllReadBuffer                = glReadBuffer;
+	qglReadPixels                = 	dllReadPixels                = glReadPixels;
+	qglRectd                     = 	dllRectd                     = glRectd;
+	qglRectdv                    = 	dllRectdv                    = glRectdv;
+	qglRectf                     = 	dllRectf                     = glRectf;
+	qglRectfv                    = 	dllRectfv                    = glRectfv;
+	qglRecti                     = 	dllRecti                     = glRecti;
+	qglRectiv                    = 	dllRectiv                    = glRectiv;
+	qglRects                     = 	dllRects                     = glRects;
+	qglRectsv                    = 	dllRectsv                    = glRectsv;
+	qglRenderMode                = 	dllRenderMode                = glRenderMode;
+	qglRotated                   = 	dllRotated                   = glRotated;
+	qglRotatef                   = 	dllRotatef                   = glRotatef;
+	qglScaled                    = 	dllScaled                    = glScaled;
+	qglScalef                    = 	dllScalef                    = glScalef;
+	qglScissor                   = 	dllScissor                   = glScissor;
+	qglSelectBuffer              = 	dllSelectBuffer              = glSelectBuffer;
+	qglShadeModel                = 	dllShadeModel                = glShadeModel;
+	qglStencilFunc               = 	dllStencilFunc               = glStencilFunc;
+	qglStencilMask               = 	dllStencilMask               = glStencilMask;
+	qglStencilOp                 = 	dllStencilOp                 = glStencilOp;
+	qglTexCoord1d                = 	dllTexCoord1d                = glTexCoord1d;
+	qglTexCoord1dv               = 	dllTexCoord1dv               = glTexCoord1dv;
+	qglTexCoord1f                = 	dllTexCoord1f                = glTexCoord1f;
+	qglTexCoord1fv               = 	dllTexCoord1fv               = glTexCoord1fv;
+	qglTexCoord1i                = 	dllTexCoord1i                = glTexCoord1i;
+	qglTexCoord1iv               = 	dllTexCoord1iv               = glTexCoord1iv;
+	qglTexCoord1s                = 	dllTexCoord1s                = glTexCoord1s;
+	qglTexCoord1sv               = 	dllTexCoord1sv               = glTexCoord1sv;
+	qglTexCoord2d                = 	dllTexCoord2d                = glTexCoord2d;
+	qglTexCoord2dv               = 	dllTexCoord2dv               = glTexCoord2dv;
+	qglTexCoord2f                = 	dllTexCoord2f                = glTexCoord2f;
+	qglTexCoord2fv               = 	dllTexCoord2fv               = glTexCoord2fv;
+	qglTexCoord2i                = 	dllTexCoord2i                = glTexCoord2i;
+	qglTexCoord2iv               = 	dllTexCoord2iv               = glTexCoord2iv;
+	qglTexCoord2s                = 	dllTexCoord2s                = glTexCoord2s;
+	qglTexCoord2sv               = 	dllTexCoord2sv               = glTexCoord2sv;
+	qglTexCoord3d                = 	dllTexCoord3d                = glTexCoord3d;
+	qglTexCoord3dv               = 	dllTexCoord3dv               = glTexCoord3dv;
+	qglTexCoord3f                = 	dllTexCoord3f                = glTexCoord3f;
+	qglTexCoord3fv               = 	dllTexCoord3fv               = glTexCoord3fv;
+	qglTexCoord3i                = 	dllTexCoord3i                = glTexCoord3i;
+	qglTexCoord3iv               = 	dllTexCoord3iv               = glTexCoord3iv;
+	qglTexCoord3s                = 	dllTexCoord3s                = glTexCoord3s;
+	qglTexCoord3sv               = 	dllTexCoord3sv               = glTexCoord3sv;
+	qglTexCoord4d                = 	dllTexCoord4d                = glTexCoord4d;
+	qglTexCoord4dv               = 	dllTexCoord4dv               = glTexCoord4dv;
+	qglTexCoord4f                = 	dllTexCoord4f                = glTexCoord4f;
+	qglTexCoord4fv               = 	dllTexCoord4fv               = glTexCoord4fv;
+	qglTexCoord4i                = 	dllTexCoord4i                = glTexCoord4i;
+	qglTexCoord4iv               = 	dllTexCoord4iv               = glTexCoord4iv;
+	qglTexCoord4s                = 	dllTexCoord4s                = glTexCoord4s;
+	qglTexCoord4sv               = 	dllTexCoord4sv               = glTexCoord4sv;
+	qglTexCoordPointer           = 	dllTexCoordPointer           = glTexCoordPointer;
+	qglTexEnvf                   = 	dllTexEnvf                   = glTexEnvf;
+	qglTexEnvfv                  = 	dllTexEnvfv                  = glTexEnvfv;
+	qglTexEnvi                   = 	dllTexEnvi                   = glTexEnvi;
+	qglTexEnviv                  = 	dllTexEnviv                  = glTexEnviv;
+	qglTexGend                   = 	dllTexGend                   = glTexGend;
+	qglTexGendv                  = 	dllTexGendv                  = glTexGendv;
+	qglTexGenf                   = 	dllTexGenf                   = glTexGenf;
+	qglTexGenfv                  = 	dllTexGenfv                  = glTexGenfv;
+	qglTexGeni                   = 	dllTexGeni                   = glTexGeni;
+	qglTexGeniv                  = 	dllTexGeniv                  = glTexGeniv;
+	qglTexImage1D                = 	dllTexImage1D                = glTexImage1D;
+	qglTexImage2D                = 	dllTexImage2D                = glTexImage2D;
+	qglTexParameterf             = 	dllTexParameterf             = glTexParameterf;
+	qglTexParameterfv            = 	dllTexParameterfv            = glTexParameterfv;
+	qglTexParameteri             = 	dllTexParameteri             = glTexParameteri;
+	qglTexParameteriv            = 	dllTexParameteriv            = glTexParameteriv;
+	qglTexSubImage1D             = 	dllTexSubImage1D             = glTexSubImage1D;
+	qglTexSubImage2D             = 	dllTexSubImage2D             = glTexSubImage2D;
+	qglTranslated                = 	dllTranslated                = glTranslated;
+	qglTranslatef                = 	dllTranslatef                = glTranslatef;
+	qglVertex2d                  = 	dllVertex2d                  = glVertex2d;
+	qglVertex2dv                 = 	dllVertex2dv                 = glVertex2dv;
+	qglVertex2f                  = 	dllVertex2f                  = glVertex2f;
+	qglVertex2fv                 = 	dllVertex2fv                 = glVertex2fv;
+	qglVertex2i                  = 	dllVertex2i                  = glVertex2i;
+	qglVertex2iv                 = 	dllVertex2iv                 = glVertex2iv;
+	qglVertex2s                  = 	dllVertex2s                  = glVertex2s;
+	qglVertex2sv                 = 	dllVertex2sv                 = glVertex2sv;
+	qglVertex3d                  = 	dllVertex3d                  = glVertex3d;
+	qglVertex3dv                 = 	dllVertex3dv                 = glVertex3dv;
+	qglVertex3f                  = 	dllVertex3f                  = glVertex3f;
+	qglVertex3fv                 = 	dllVertex3fv                 = glVertex3fv;
+	qglVertex3i                  = 	dllVertex3i                  = glVertex3i;
+	qglVertex3iv                 = 	dllVertex3iv                 = glVertex3iv;
+	qglVertex3s                  = 	dllVertex3s                  = glVertex3s;
+	qglVertex3sv                 = 	dllVertex3sv                 = glVertex3sv;
+	qglVertex4d                  = 	dllVertex4d                  = glVertex4d;
+	qglVertex4dv                 = 	dllVertex4dv                 = glVertex4dv;
+	qglVertex4f                  = 	dllVertex4f                  = glVertex4f;
+	qglVertex4fv                 = 	dllVertex4fv                 = glVertex4fv;
+	qglVertex4i                  = 	dllVertex4i                  = glVertex4i;
+	qglVertex4iv                 = 	dllVertex4iv                 = glVertex4iv;
+	qglVertex4s                  = 	dllVertex4s                  = glVertex4s;
+	qglVertex4sv                 = 	dllVertex4sv                 = glVertex4sv;
+	qglVertexPointer             = 	dllVertexPointer             = glVertexPointer;
+	qglViewport                  = 	dllViewport                  = glViewport;
+
+	qglPointParameterfEXT = 0;
+	qglPointParameterfvEXT = 0;
+	qglColorTableEXT = glColorTableSGI;
+	qglColorTableEXT = 0;
+	qglSelectTextureSGIS = 0;
+	qglMTexCoord2fSGIS = 0;
+
+	return true;
+}
+
+void GLimp_EnableLogging( qboolean enable )
+{
+	if ( enable )
+	{
+		if ( !log_fp )
+		{
+			struct tm *newtime;
+			time_t aclock;
+			char buffer[1024];
+
+			time( &aclock );
+			newtime = localtime( &aclock );
+
+			asctime( newtime );
+
+			sprintf( buffer, "%s/gl.log", ri.FS_Gamedir() ); 
+			log_fp = fopen( buffer, "wt");
+
+			fprintf( log_fp, "%s\n", asctime( newtime ) );
+		}
+
+		qglAccum                     = logAccum;
+		qglAlphaFunc                 = logAlphaFunc;
+		qglAreTexturesResident       = logAreTexturesResident;
+		qglArrayElement              = logArrayElement;
+		qglBegin                     = logBegin;
+		qglBindTexture               = logBindTexture;
+		qglBitmap                    = logBitmap;
+		qglBlendFunc                 = logBlendFunc;
+		qglCallList                  = logCallList;
+		qglCallLists                 = logCallLists;
+		qglClear                     = logClear;
+		qglClearAccum                = logClearAccum;
+		qglClearColor                = logClearColor;
+		qglClearDepth                = logClearDepth;
+		qglClearIndex                = logClearIndex;
+		qglClearStencil              = logClearStencil;
+		qglClipPlane                 = logClipPlane;
+		qglColor3b                   = logColor3b;
+		qglColor3bv                  = logColor3bv;
+		qglColor3d                   = logColor3d;
+		qglColor3dv                  = logColor3dv;
+		qglColor3f                   = logColor3f;
+		qglColor3fv                  = logColor3fv;
+		qglColor3i                   = logColor3i;
+		qglColor3iv                  = logColor3iv;
+		qglColor3s                   = logColor3s;
+		qglColor3sv                  = logColor3sv;
+		qglColor3ub                  = logColor3ub;
+		qglColor3ubv                 = logColor3ubv;
+		qglColor3ui                  = logColor3ui;
+		qglColor3uiv                 = logColor3uiv;
+		qglColor3us                  = logColor3us;
+		qglColor3usv                 = logColor3usv;
+		qglColor4b                   = logColor4b;
+		qglColor4bv                  = logColor4bv;
+		qglColor4d                   = logColor4d;
+		qglColor4dv                  = logColor4dv;
+		qglColor4f                   = logColor4f;
+		qglColor4fv                  = logColor4fv;
+		qglColor4i                   = logColor4i;
+		qglColor4iv                  = logColor4iv;
+		qglColor4s                   = logColor4s;
+		qglColor4sv                  = logColor4sv;
+		qglColor4ub                  = logColor4ub;
+		qglColor4ubv                 = logColor4ubv;
+		qglColor4ui                  = logColor4ui;
+		qglColor4uiv                 = logColor4uiv;
+		qglColor4us                  = logColor4us;
+		qglColor4usv                 = logColor4usv;
+		qglColorMask                 = logColorMask;
+		qglColorMaterial             = logColorMaterial;
+		qglColorPointer              = logColorPointer;
+		qglCopyPixels                = logCopyPixels;
+		qglCopyTexImage1D            = logCopyTexImage1D;
+		qglCopyTexImage2D            = logCopyTexImage2D;
+		qglCopyTexSubImage1D         = logCopyTexSubImage1D;
+		qglCopyTexSubImage2D         = logCopyTexSubImage2D;
+		qglCullFace                  = logCullFace;
+		qglDeleteLists               = logDeleteLists ;
+		qglDeleteTextures            = logDeleteTextures ;
+		qglDepthFunc                 = logDepthFunc ;
+		qglDepthMask                 = logDepthMask ;
+		qglDepthRange                = logDepthRange ;
+		qglDisable                   = logDisable ;
+		qglDisableClientState        = logDisableClientState ;
+		qglDrawArrays                = logDrawArrays ;
+		qglDrawBuffer                = logDrawBuffer ;
+		qglDrawElements              = logDrawElements ;
+		qglDrawPixels                = logDrawPixels ;
+		qglEdgeFlag                  = logEdgeFlag ;
+		qglEdgeFlagPointer           = logEdgeFlagPointer ;
+		qglEdgeFlagv                 = logEdgeFlagv ;
+		qglEnable                    = 	logEnable                    ;
+		qglEnableClientState         = 	logEnableClientState         ;
+		qglEnd                       = 	logEnd                       ;
+		qglEndList                   = 	logEndList                   ;
+		qglEvalCoord1d				 = 	logEvalCoord1d				 ;
+		qglEvalCoord1dv              = 	logEvalCoord1dv              ;
+		qglEvalCoord1f               = 	logEvalCoord1f               ;
+		qglEvalCoord1fv              = 	logEvalCoord1fv              ;
+		qglEvalCoord2d               = 	logEvalCoord2d               ;
+		qglEvalCoord2dv              = 	logEvalCoord2dv              ;
+		qglEvalCoord2f               = 	logEvalCoord2f               ;
+		qglEvalCoord2fv              = 	logEvalCoord2fv              ;
+		qglEvalMesh1                 = 	logEvalMesh1                 ;
+		qglEvalMesh2                 = 	logEvalMesh2                 ;
+		qglEvalPoint1                = 	logEvalPoint1                ;
+		qglEvalPoint2                = 	logEvalPoint2                ;
+		qglFeedbackBuffer            = 	logFeedbackBuffer            ;
+		qglFinish                    = 	logFinish                    ;
+		qglFlush                     = 	logFlush                     ;
+		qglFogf                      = 	logFogf                      ;
+		qglFogfv                     = 	logFogfv                     ;
+		qglFogi                      = 	logFogi                      ;
+		qglFogiv                     = 	logFogiv                     ;
+		qglFrontFace                 = 	logFrontFace                 ;
+		qglFrustum                   = 	logFrustum                   ;
+		qglGenLists                  = 	logGenLists                  ;
+		qglGenTextures               = 	logGenTextures               ;
+		qglGetBooleanv               = 	logGetBooleanv               ;
+		qglGetClipPlane              = 	logGetClipPlane              ;
+		qglGetDoublev                = 	logGetDoublev                ;
+		qglGetError                  = 	logGetError                  ;
+		qglGetFloatv                 = 	logGetFloatv                 ;
+		qglGetIntegerv               = 	logGetIntegerv               ;
+		qglGetLightfv                = 	logGetLightfv                ;
+		qglGetLightiv                = 	logGetLightiv                ;
+		qglGetMapdv                  = 	logGetMapdv                  ;
+		qglGetMapfv                  = 	logGetMapfv                  ;
+		qglGetMapiv                  = 	logGetMapiv                  ;
+		qglGetMaterialfv             = 	logGetMaterialfv             ;
+		qglGetMaterialiv             = 	logGetMaterialiv             ;
+		qglGetPixelMapfv             = 	logGetPixelMapfv             ;
+		qglGetPixelMapuiv            = 	logGetPixelMapuiv            ;
+		qglGetPixelMapusv            = 	logGetPixelMapusv            ;
+		qglGetPointerv               = 	logGetPointerv               ;
+		qglGetPolygonStipple         = 	logGetPolygonStipple         ;
+		qglGetString                 = 	logGetString                 ;
+		qglGetTexEnvfv               = 	logGetTexEnvfv               ;
+		qglGetTexEnviv               = 	logGetTexEnviv               ;
+		qglGetTexGendv               = 	logGetTexGendv               ;
+		qglGetTexGenfv               = 	logGetTexGenfv               ;
+		qglGetTexGeniv               = 	logGetTexGeniv               ;
+		qglGetTexImage               = 	logGetTexImage               ;
+//		qglGetTexLevelParameterfv    = 	logGetTexLevelParameterfv    ;
+//		qglGetTexLevelParameteriv    = 	logGetTexLevelParameteriv    ;
+		qglGetTexParameterfv         = 	logGetTexParameterfv         ;
+		qglGetTexParameteriv         = 	logGetTexParameteriv         ;
+		qglHint                      = 	logHint                      ;
+		qglIndexMask                 = 	logIndexMask                 ;
+		qglIndexPointer              = 	logIndexPointer              ;
+		qglIndexd                    = 	logIndexd                    ;
+		qglIndexdv                   = 	logIndexdv                   ;
+		qglIndexf                    = 	logIndexf                    ;
+		qglIndexfv                   = 	logIndexfv                   ;
+		qglIndexi                    = 	logIndexi                    ;
+		qglIndexiv                   = 	logIndexiv                   ;
+		qglIndexs                    = 	logIndexs                    ;
+		qglIndexsv                   = 	logIndexsv                   ;
+		qglIndexub                   = 	logIndexub                   ;
+		qglIndexubv                  = 	logIndexubv                  ;
+		qglInitNames                 = 	logInitNames                 ;
+		qglInterleavedArrays         = 	logInterleavedArrays         ;
+		qglIsEnabled                 = 	logIsEnabled                 ;
+		qglIsList                    = 	logIsList                    ;
+		qglIsTexture                 = 	logIsTexture                 ;
+		qglLightModelf               = 	logLightModelf               ;
+		qglLightModelfv              = 	logLightModelfv              ;
+		qglLightModeli               = 	logLightModeli               ;
+		qglLightModeliv              = 	logLightModeliv              ;
+		qglLightf                    = 	logLightf                    ;
+		qglLightfv                   = 	logLightfv                   ;
+		qglLighti                    = 	logLighti                    ;
+		qglLightiv                   = 	logLightiv                   ;
+		qglLineStipple               = 	logLineStipple               ;
+		qglLineWidth                 = 	logLineWidth                 ;
+		qglListBase                  = 	logListBase                  ;
+		qglLoadIdentity              = 	logLoadIdentity              ;
+		qglLoadMatrixd               = 	logLoadMatrixd               ;
+		qglLoadMatrixf               = 	logLoadMatrixf               ;
+		qglLoadName                  = 	logLoadName                  ;
+		qglLogicOp                   = 	logLogicOp                   ;
+		qglMap1d                     = 	logMap1d                     ;
+		qglMap1f                     = 	logMap1f                     ;
+		qglMap2d                     = 	logMap2d                     ;
+		qglMap2f                     = 	logMap2f                     ;
+		qglMapGrid1d                 = 	logMapGrid1d                 ;
+		qglMapGrid1f                 = 	logMapGrid1f                 ;
+		qglMapGrid2d                 = 	logMapGrid2d                 ;
+		qglMapGrid2f                 = 	logMapGrid2f                 ;
+		qglMaterialf                 = 	logMaterialf                 ;
+		qglMaterialfv                = 	logMaterialfv                ;
+		qglMateriali                 = 	logMateriali                 ;
+		qglMaterialiv                = 	logMaterialiv                ;
+		qglMatrixMode                = 	logMatrixMode                ;
+		qglMultMatrixd               = 	logMultMatrixd               ;
+		qglMultMatrixf               = 	logMultMatrixf               ;
+		qglNewList                   = 	logNewList                   ;
+		qglNormal3b                  = 	logNormal3b                  ;
+		qglNormal3bv                 = 	logNormal3bv                 ;
+		qglNormal3d                  = 	logNormal3d                  ;
+		qglNormal3dv                 = 	logNormal3dv                 ;
+		qglNormal3f                  = 	logNormal3f                  ;
+		qglNormal3fv                 = 	logNormal3fv                 ;
+		qglNormal3i                  = 	logNormal3i                  ;
+		qglNormal3iv                 = 	logNormal3iv                 ;
+		qglNormal3s                  = 	logNormal3s                  ;
+		qglNormal3sv                 = 	logNormal3sv                 ;
+		qglNormalPointer             = 	logNormalPointer             ;
+		qglOrtho                     = 	logOrtho                     ;
+		qglPassThrough               = 	logPassThrough               ;
+		qglPixelMapfv                = 	logPixelMapfv                ;
+		qglPixelMapuiv               = 	logPixelMapuiv               ;
+		qglPixelMapusv               = 	logPixelMapusv               ;
+		qglPixelStoref               = 	logPixelStoref               ;
+		qglPixelStorei               = 	logPixelStorei               ;
+		qglPixelTransferf            = 	logPixelTransferf            ;
+		qglPixelTransferi            = 	logPixelTransferi            ;
+		qglPixelZoom                 = 	logPixelZoom                 ;
+		qglPointSize                 = 	logPointSize                 ;
+		qglPolygonMode               = 	logPolygonMode               ;
+		qglPolygonOffset             = 	logPolygonOffset             ;
+		qglPolygonStipple            = 	logPolygonStipple            ;
+		qglPopAttrib                 = 	logPopAttrib                 ;
+		qglPopClientAttrib           = 	logPopClientAttrib           ;
+		qglPopMatrix                 = 	logPopMatrix                 ;
+		qglPopName                   = 	logPopName                   ;
+		qglPrioritizeTextures        = 	logPrioritizeTextures        ;
+		qglPushAttrib                = 	logPushAttrib                ;
+		qglPushClientAttrib          = 	logPushClientAttrib          ;
+		qglPushMatrix                = 	logPushMatrix                ;
+		qglPushName                  = 	logPushName                  ;
+		qglRasterPos2d               = 	logRasterPos2d               ;
+		qglRasterPos2dv              = 	logRasterPos2dv              ;
+		qglRasterPos2f               = 	logRasterPos2f               ;
+		qglRasterPos2fv              = 	logRasterPos2fv              ;
+		qglRasterPos2i               = 	logRasterPos2i               ;
+		qglRasterPos2iv              = 	logRasterPos2iv              ;
+		qglRasterPos2s               = 	logRasterPos2s               ;
+		qglRasterPos2sv              = 	logRasterPos2sv              ;
+		qglRasterPos3d               = 	logRasterPos3d               ;
+		qglRasterPos3dv              = 	logRasterPos3dv              ;
+		qglRasterPos3f               = 	logRasterPos3f               ;
+		qglRasterPos3fv              = 	logRasterPos3fv              ;
+		qglRasterPos3i               = 	logRasterPos3i               ;
+		qglRasterPos3iv              = 	logRasterPos3iv              ;
+		qglRasterPos3s               = 	logRasterPos3s               ;
+		qglRasterPos3sv              = 	logRasterPos3sv              ;
+		qglRasterPos4d               = 	logRasterPos4d               ;
+		qglRasterPos4dv              = 	logRasterPos4dv              ;
+		qglRasterPos4f               = 	logRasterPos4f               ;
+		qglRasterPos4fv              = 	logRasterPos4fv              ;
+		qglRasterPos4i               = 	logRasterPos4i               ;
+		qglRasterPos4iv              = 	logRasterPos4iv              ;
+		qglRasterPos4s               = 	logRasterPos4s               ;
+		qglRasterPos4sv              = 	logRasterPos4sv              ;
+		qglReadBuffer                = 	logReadBuffer                ;
+		qglReadPixels                = 	logReadPixels                ;
+		qglRectd                     = 	logRectd                     ;
+		qglRectdv                    = 	logRectdv                    ;
+		qglRectf                     = 	logRectf                     ;
+		qglRectfv                    = 	logRectfv                    ;
+		qglRecti                     = 	logRecti                     ;
+		qglRectiv                    = 	logRectiv                    ;
+		qglRects                     = 	logRects                     ;
+		qglRectsv                    = 	logRectsv                    ;
+		qglRenderMode                = 	logRenderMode                ;
+		qglRotated                   = 	logRotated                   ;
+		qglRotatef                   = 	logRotatef                   ;
+		qglScaled                    = 	logScaled                    ;
+		qglScalef                    = 	logScalef                    ;
+		qglScissor                   = 	logScissor                   ;
+		qglSelectBuffer              = 	logSelectBuffer              ;
+		qglShadeModel                = 	logShadeModel                ;
+		qglStencilFunc               = 	logStencilFunc               ;
+		qglStencilMask               = 	logStencilMask               ;
+		qglStencilOp                 = 	logStencilOp                 ;
+		qglTexCoord1d                = 	logTexCoord1d                ;
+		qglTexCoord1dv               = 	logTexCoord1dv               ;
+		qglTexCoord1f                = 	logTexCoord1f                ;
+		qglTexCoord1fv               = 	logTexCoord1fv               ;
+		qglTexCoord1i                = 	logTexCoord1i                ;
+		qglTexCoord1iv               = 	logTexCoord1iv               ;
+		qglTexCoord1s                = 	logTexCoord1s                ;
+		qglTexCoord1sv               = 	logTexCoord1sv               ;
+		qglTexCoord2d                = 	logTexCoord2d                ;
+		qglTexCoord2dv               = 	logTexCoord2dv               ;
+		qglTexCoord2f                = 	logTexCoord2f                ;
+		qglTexCoord2fv               = 	logTexCoord2fv               ;
+		qglTexCoord2i                = 	logTexCoord2i                ;
+		qglTexCoord2iv               = 	logTexCoord2iv               ;
+		qglTexCoord2s                = 	logTexCoord2s                ;
+		qglTexCoord2sv               = 	logTexCoord2sv               ;
+		qglTexCoord3d                = 	logTexCoord3d                ;
+		qglTexCoord3dv               = 	logTexCoord3dv               ;
+		qglTexCoord3f                = 	logTexCoord3f                ;
+		qglTexCoord3fv               = 	logTexCoord3fv               ;
+		qglTexCoord3i                = 	logTexCoord3i                ;
+		qglTexCoord3iv               = 	logTexCoord3iv               ;
+		qglTexCoord3s                = 	logTexCoord3s                ;
+		qglTexCoord3sv               = 	logTexCoord3sv               ;
+		qglTexCoord4d                = 	logTexCoord4d                ;
+		qglTexCoord4dv               = 	logTexCoord4dv               ;
+		qglTexCoord4f                = 	logTexCoord4f                ;
+		qglTexCoord4fv               = 	logTexCoord4fv               ;
+		qglTexCoord4i                = 	logTexCoord4i                ;
+		qglTexCoord4iv               = 	logTexCoord4iv               ;
+		qglTexCoord4s                = 	logTexCoord4s                ;
+		qglTexCoord4sv               = 	logTexCoord4sv               ;
+		qglTexCoordPointer           = 	logTexCoordPointer           ;
+		qglTexEnvf                   = 	logTexEnvf                   ;
+		qglTexEnvfv                  = 	logTexEnvfv                  ;
+		qglTexEnvi                   = 	logTexEnvi                   ;
+		qglTexEnviv                  = 	logTexEnviv                  ;
+		qglTexGend                   = 	logTexGend                   ;
+		qglTexGendv                  = 	logTexGendv                  ;
+		qglTexGenf                   = 	logTexGenf                   ;
+		qglTexGenfv                  = 	logTexGenfv                  ;
+		qglTexGeni                   = 	logTexGeni                   ;
+		qglTexGeniv                  = 	logTexGeniv                  ;
+		qglTexImage1D                = 	logTexImage1D                ;
+		qglTexImage2D                = 	logTexImage2D                ;
+		qglTexParameterf             = 	logTexParameterf             ;
+		qglTexParameterfv            = 	logTexParameterfv            ;
+		qglTexParameteri             = 	logTexParameteri             ;
+		qglTexParameteriv            = 	logTexParameteriv            ;
+		qglTexSubImage1D             = 	logTexSubImage1D             ;
+		qglTexSubImage2D             = 	logTexSubImage2D             ;
+		qglTranslated                = 	logTranslated                ;
+		qglTranslatef                = 	logTranslatef                ;
+		qglVertex2d                  = 	logVertex2d                  ;
+		qglVertex2dv                 = 	logVertex2dv                 ;
+		qglVertex2f                  = 	logVertex2f                  ;
+		qglVertex2fv                 = 	logVertex2fv                 ;
+		qglVertex2i                  = 	logVertex2i                  ;
+		qglVertex2iv                 = 	logVertex2iv                 ;
+		qglVertex2s                  = 	logVertex2s                  ;
+		qglVertex2sv                 = 	logVertex2sv                 ;
+		qglVertex3d                  = 	logVertex3d                  ;
+		qglVertex3dv                 = 	logVertex3dv                 ;
+		qglVertex3f                  = 	logVertex3f                  ;
+		qglVertex3fv                 = 	logVertex3fv                 ;
+		qglVertex3i                  = 	logVertex3i                  ;
+		qglVertex3iv                 = 	logVertex3iv                 ;
+		qglVertex3s                  = 	logVertex3s                  ;
+		qglVertex3sv                 = 	logVertex3sv                 ;
+		qglVertex4d                  = 	logVertex4d                  ;
+		qglVertex4dv                 = 	logVertex4dv                 ;
+		qglVertex4f                  = 	logVertex4f                  ;
+		qglVertex4fv                 = 	logVertex4fv                 ;
+		qglVertex4i                  = 	logVertex4i                  ;
+		qglVertex4iv                 = 	logVertex4iv                 ;
+		qglVertex4s                  = 	logVertex4s                  ;
+		qglVertex4sv                 = 	logVertex4sv                 ;
+		qglVertexPointer             = 	logVertexPointer             ;
+		qglViewport                  = 	logViewport                  ;
+	}
+	else
+	{
+		qglAccum                     = dllAccum;
+		qglAlphaFunc                 = dllAlphaFunc;
+		qglAreTexturesResident       = dllAreTexturesResident;
+		qglArrayElement              = dllArrayElement;
+		qglBegin                     = dllBegin;
+		qglBindTexture               = dllBindTexture;
+		qglBitmap                    = dllBitmap;
+		qglBlendFunc                 = dllBlendFunc;
+		qglCallList                  = dllCallList;
+		qglCallLists                 = dllCallLists;
+		qglClear                     = dllClear;
+		qglClearAccum                = dllClearAccum;
+		qglClearColor                = dllClearColor;
+		qglClearDepth                = dllClearDepth;
+		qglClearIndex                = dllClearIndex;
+		qglClearStencil              = dllClearStencil;
+		qglClipPlane                 = dllClipPlane;
+		qglColor3b                   = dllColor3b;
+		qglColor3bv                  = dllColor3bv;
+		qglColor3d                   = dllColor3d;
+		qglColor3dv                  = dllColor3dv;
+		qglColor3f                   = dllColor3f;
+		qglColor3fv                  = dllColor3fv;
+		qglColor3i                   = dllColor3i;
+		qglColor3iv                  = dllColor3iv;
+		qglColor3s                   = dllColor3s;
+		qglColor3sv                  = dllColor3sv;
+		qglColor3ub                  = dllColor3ub;
+		qglColor3ubv                 = dllColor3ubv;
+		qglColor3ui                  = dllColor3ui;
+		qglColor3uiv                 = dllColor3uiv;
+		qglColor3us                  = dllColor3us;
+		qglColor3usv                 = dllColor3usv;
+		qglColor4b                   = dllColor4b;
+		qglColor4bv                  = dllColor4bv;
+		qglColor4d                   = dllColor4d;
+		qglColor4dv                  = dllColor4dv;
+		qglColor4f                   = dllColor4f;
+		qglColor4fv                  = dllColor4fv;
+		qglColor4i                   = dllColor4i;
+		qglColor4iv                  = dllColor4iv;
+		qglColor4s                   = dllColor4s;
+		qglColor4sv                  = dllColor4sv;
+		qglColor4ub                  = dllColor4ub;
+		qglColor4ubv                 = dllColor4ubv;
+		qglColor4ui                  = dllColor4ui;
+		qglColor4uiv                 = dllColor4uiv;
+		qglColor4us                  = dllColor4us;
+		qglColor4usv                 = dllColor4usv;
+		qglColorMask                 = dllColorMask;
+		qglColorMaterial             = dllColorMaterial;
+		qglColorPointer              = dllColorPointer;
+		qglCopyPixels                = dllCopyPixels;
+		qglCopyTexImage1D            = dllCopyTexImage1D;
+		qglCopyTexImage2D            = dllCopyTexImage2D;
+		qglCopyTexSubImage1D         = dllCopyTexSubImage1D;
+		qglCopyTexSubImage2D         = dllCopyTexSubImage2D;
+		qglCullFace                  = dllCullFace;
+		qglDeleteLists               = dllDeleteLists ;
+		qglDeleteTextures            = dllDeleteTextures ;
+		qglDepthFunc                 = dllDepthFunc ;
+		qglDepthMask                 = dllDepthMask ;
+		qglDepthRange                = dllDepthRange ;
+		qglDisable                   = dllDisable ;
+		qglDisableClientState        = dllDisableClientState ;
+		qglDrawArrays                = dllDrawArrays ;
+		qglDrawBuffer                = dllDrawBuffer ;
+		qglDrawElements              = dllDrawElements ;
+		qglDrawPixels                = dllDrawPixels ;
+		qglEdgeFlag                  = dllEdgeFlag ;
+		qglEdgeFlagPointer           = dllEdgeFlagPointer ;
+		qglEdgeFlagv                 = dllEdgeFlagv ;
+		qglEnable                    = 	dllEnable                    ;
+		qglEnableClientState         = 	dllEnableClientState         ;
+		qglEnd                       = 	dllEnd                       ;
+		qglEndList                   = 	dllEndList                   ;
+		qglEvalCoord1d				 = 	dllEvalCoord1d				 ;
+		qglEvalCoord1dv              = 	dllEvalCoord1dv              ;
+		qglEvalCoord1f               = 	dllEvalCoord1f               ;
+		qglEvalCoord1fv              = 	dllEvalCoord1fv              ;
+		qglEvalCoord2d               = 	dllEvalCoord2d               ;
+		qglEvalCoord2dv              = 	dllEvalCoord2dv              ;
+		qglEvalCoord2f               = 	dllEvalCoord2f               ;
+		qglEvalCoord2fv              = 	dllEvalCoord2fv              ;
+		qglEvalMesh1                 = 	dllEvalMesh1                 ;
+		qglEvalMesh2                 = 	dllEvalMesh2                 ;
+		qglEvalPoint1                = 	dllEvalPoint1                ;
+		qglEvalPoint2                = 	dllEvalPoint2                ;
+		qglFeedbackBuffer            = 	dllFeedbackBuffer            ;
+		qglFinish                    = 	dllFinish                    ;
+		qglFlush                     = 	dllFlush                     ;
+		qglFogf                      = 	dllFogf                      ;
+		qglFogfv                     = 	dllFogfv                     ;
+		qglFogi                      = 	dllFogi                      ;
+		qglFogiv                     = 	dllFogiv                     ;
+		qglFrontFace                 = 	dllFrontFace                 ;
+		qglFrustum                   = 	dllFrustum                   ;
+		qglGenLists                  = 	dllGenLists                  ;
+		qglGenTextures               = 	dllGenTextures               ;
+		qglGetBooleanv               = 	dllGetBooleanv               ;
+		qglGetClipPlane              = 	dllGetClipPlane              ;
+		qglGetDoublev                = 	dllGetDoublev                ;
+		qglGetError                  = 	dllGetError                  ;
+		qglGetFloatv                 = 	dllGetFloatv                 ;
+		qglGetIntegerv               = 	dllGetIntegerv               ;
+		qglGetLightfv                = 	dllGetLightfv                ;
+		qglGetLightiv                = 	dllGetLightiv                ;
+		qglGetMapdv                  = 	dllGetMapdv                  ;
+		qglGetMapfv                  = 	dllGetMapfv                  ;
+		qglGetMapiv                  = 	dllGetMapiv                  ;
+		qglGetMaterialfv             = 	dllGetMaterialfv             ;
+		qglGetMaterialiv             = 	dllGetMaterialiv             ;
+		qglGetPixelMapfv             = 	dllGetPixelMapfv             ;
+		qglGetPixelMapuiv            = 	dllGetPixelMapuiv            ;
+		qglGetPixelMapusv            = 	dllGetPixelMapusv            ;
+		qglGetPointerv               = 	dllGetPointerv               ;
+		qglGetPolygonStipple         = 	dllGetPolygonStipple         ;
+		qglGetString                 = 	dllGetString                 ;
+		qglGetTexEnvfv               = 	dllGetTexEnvfv               ;
+		qglGetTexEnviv               = 	dllGetTexEnviv               ;
+		qglGetTexGendv               = 	dllGetTexGendv               ;
+		qglGetTexGenfv               = 	dllGetTexGenfv               ;
+		qglGetTexGeniv               = 	dllGetTexGeniv               ;
+		qglGetTexImage               = 	dllGetTexImage               ;
+		qglGetTexLevelParameterfv    = 	dllGetTexLevelParameterfv    ;
+		qglGetTexLevelParameteriv    = 	dllGetTexLevelParameteriv    ;
+		qglGetTexParameterfv         = 	dllGetTexParameterfv         ;
+		qglGetTexParameteriv         = 	dllGetTexParameteriv         ;
+		qglHint                      = 	dllHint                      ;
+		qglIndexMask                 = 	dllIndexMask                 ;
+		qglIndexPointer              = 	dllIndexPointer              ;
+		qglIndexd                    = 	dllIndexd                    ;
+		qglIndexdv                   = 	dllIndexdv                   ;
+		qglIndexf                    = 	dllIndexf                    ;
+		qglIndexfv                   = 	dllIndexfv                   ;
+		qglIndexi                    = 	dllIndexi                    ;
+		qglIndexiv                   = 	dllIndexiv                   ;
+		qglIndexs                    = 	dllIndexs                    ;
+		qglIndexsv                   = 	dllIndexsv                   ;
+		qglIndexub                   = 	dllIndexub                   ;
+		qglIndexubv                  = 	dllIndexubv                  ;
+		qglInitNames                 = 	dllInitNames                 ;
+		qglInterleavedArrays         = 	dllInterleavedArrays         ;
+		qglIsEnabled                 = 	dllIsEnabled                 ;
+		qglIsList                    = 	dllIsList                    ;
+		qglIsTexture                 = 	dllIsTexture                 ;
+		qglLightModelf               = 	dllLightModelf               ;
+		qglLightModelfv              = 	dllLightModelfv              ;
+		qglLightModeli               = 	dllLightModeli               ;
+		qglLightModeliv              = 	dllLightModeliv              ;
+		qglLightf                    = 	dllLightf                    ;
+		qglLightfv                   = 	dllLightfv                   ;
+		qglLighti                    = 	dllLighti                    ;
+		qglLightiv                   = 	dllLightiv                   ;
+		qglLineStipple               = 	dllLineStipple               ;
+		qglLineWidth                 = 	dllLineWidth                 ;
+		qglListBase                  = 	dllListBase                  ;
+		qglLoadIdentity              = 	dllLoadIdentity              ;
+		qglLoadMatrixd               = 	dllLoadMatrixd               ;
+		qglLoadMatrixf               = 	dllLoadMatrixf               ;
+		qglLoadName                  = 	dllLoadName                  ;
+		qglLogicOp                   = 	dllLogicOp                   ;
+		qglMap1d                     = 	dllMap1d                     ;
+		qglMap1f                     = 	dllMap1f                     ;
+		qglMap2d                     = 	dllMap2d                     ;
+		qglMap2f                     = 	dllMap2f                     ;
+		qglMapGrid1d                 = 	dllMapGrid1d                 ;
+		qglMapGrid1f                 = 	dllMapGrid1f                 ;
+		qglMapGrid2d                 = 	dllMapGrid2d                 ;
+		qglMapGrid2f                 = 	dllMapGrid2f                 ;
+		qglMaterialf                 = 	dllMaterialf                 ;
+		qglMaterialfv                = 	dllMaterialfv                ;
+		qglMateriali                 = 	dllMateriali                 ;
+		qglMaterialiv                = 	dllMaterialiv                ;
+		qglMatrixMode                = 	dllMatrixMode                ;
+		qglMultMatrixd               = 	dllMultMatrixd               ;
+		qglMultMatrixf               = 	dllMultMatrixf               ;
+		qglNewList                   = 	dllNewList                   ;
+		qglNormal3b                  = 	dllNormal3b                  ;
+		qglNormal3bv                 = 	dllNormal3bv                 ;
+		qglNormal3d                  = 	dllNormal3d                  ;
+		qglNormal3dv                 = 	dllNormal3dv                 ;
+		qglNormal3f                  = 	dllNormal3f                  ;
+		qglNormal3fv                 = 	dllNormal3fv                 ;
+		qglNormal3i                  = 	dllNormal3i                  ;
+		qglNormal3iv                 = 	dllNormal3iv                 ;
+		qglNormal3s                  = 	dllNormal3s                  ;
+		qglNormal3sv                 = 	dllNormal3sv                 ;
+		qglNormalPointer             = 	dllNormalPointer             ;
+		qglOrtho                     = 	dllOrtho                     ;
+		qglPassThrough               = 	dllPassThrough               ;
+		qglPixelMapfv                = 	dllPixelMapfv                ;
+		qglPixelMapuiv               = 	dllPixelMapuiv               ;
+		qglPixelMapusv               = 	dllPixelMapusv               ;
+		qglPixelStoref               = 	dllPixelStoref               ;
+		qglPixelStorei               = 	dllPixelStorei               ;
+		qglPixelTransferf            = 	dllPixelTransferf            ;
+		qglPixelTransferi            = 	dllPixelTransferi            ;
+		qglPixelZoom                 = 	dllPixelZoom                 ;
+		qglPointSize                 = 	dllPointSize                 ;
+		qglPolygonMode               = 	dllPolygonMode               ;
+		qglPolygonOffset             = 	dllPolygonOffset             ;
+		qglPolygonStipple            = 	dllPolygonStipple            ;
+		qglPopAttrib                 = 	dllPopAttrib                 ;
+		qglPopClientAttrib           = 	dllPopClientAttrib           ;
+		qglPopMatrix                 = 	dllPopMatrix                 ;
+		qglPopName                   = 	dllPopName                   ;
+		qglPrioritizeTextures        = 	dllPrioritizeTextures        ;
+		qglPushAttrib                = 	dllPushAttrib                ;
+		qglPushClientAttrib          = 	dllPushClientAttrib          ;
+		qglPushMatrix                = 	dllPushMatrix                ;
+		qglPushName                  = 	dllPushName                  ;
+		qglRasterPos2d               = 	dllRasterPos2d               ;
+		qglRasterPos2dv              = 	dllRasterPos2dv              ;
+		qglRasterPos2f               = 	dllRasterPos2f               ;
+		qglRasterPos2fv              = 	dllRasterPos2fv              ;
+		qglRasterPos2i               = 	dllRasterPos2i               ;
+		qglRasterPos2iv              = 	dllRasterPos2iv              ;
+		qglRasterPos2s               = 	dllRasterPos2s               ;
+		qglRasterPos2sv              = 	dllRasterPos2sv              ;
+		qglRasterPos3d               = 	dllRasterPos3d               ;
+		qglRasterPos3dv              = 	dllRasterPos3dv              ;
+		qglRasterPos3f               = 	dllRasterPos3f               ;
+		qglRasterPos3fv              = 	dllRasterPos3fv              ;
+		qglRasterPos3i               = 	dllRasterPos3i               ;
+		qglRasterPos3iv              = 	dllRasterPos3iv              ;
+		qglRasterPos3s               = 	dllRasterPos3s               ;
+		qglRasterPos3sv              = 	dllRasterPos3sv              ;
+		qglRasterPos4d               = 	dllRasterPos4d               ;
+		qglRasterPos4dv              = 	dllRasterPos4dv              ;
+		qglRasterPos4f               = 	dllRasterPos4f               ;
+		qglRasterPos4fv              = 	dllRasterPos4fv              ;
+		qglRasterPos4i               = 	dllRasterPos4i               ;
+		qglRasterPos4iv              = 	dllRasterPos4iv              ;
+		qglRasterPos4s               = 	dllRasterPos4s               ;
+		qglRasterPos4sv              = 	dllRasterPos4sv              ;
+		qglReadBuffer                = 	dllReadBuffer                ;
+		qglReadPixels                = 	dllReadPixels                ;
+		qglRectd                     = 	dllRectd                     ;
+		qglRectdv                    = 	dllRectdv                    ;
+		qglRectf                     = 	dllRectf                     ;
+		qglRectfv                    = 	dllRectfv                    ;
+		qglRecti                     = 	dllRecti                     ;
+		qglRectiv                    = 	dllRectiv                    ;
+		qglRects                     = 	dllRects                     ;
+		qglRectsv                    = 	dllRectsv                    ;
+		qglRenderMode                = 	dllRenderMode                ;
+		qglRotated                   = 	dllRotated                   ;
+		qglRotatef                   = 	dllRotatef                   ;
+		qglScaled                    = 	dllScaled                    ;
+		qglScalef                    = 	dllScalef                    ;
+		qglScissor                   = 	dllScissor                   ;
+		qglSelectBuffer              = 	dllSelectBuffer              ;
+		qglShadeModel                = 	dllShadeModel                ;
+		qglStencilFunc               = 	dllStencilFunc               ;
+		qglStencilMask               = 	dllStencilMask               ;
+		qglStencilOp                 = 	dllStencilOp                 ;
+		qglTexCoord1d                = 	dllTexCoord1d                ;
+		qglTexCoord1dv               = 	dllTexCoord1dv               ;
+		qglTexCoord1f                = 	dllTexCoord1f                ;
+		qglTexCoord1fv               = 	dllTexCoord1fv               ;
+		qglTexCoord1i                = 	dllTexCoord1i                ;
+		qglTexCoord1iv               = 	dllTexCoord1iv               ;
+		qglTexCoord1s                = 	dllTexCoord1s                ;
+		qglTexCoord1sv               = 	dllTexCoord1sv               ;
+		qglTexCoord2d                = 	dllTexCoord2d                ;
+		qglTexCoord2dv               = 	dllTexCoord2dv               ;
+		qglTexCoord2f                = 	dllTexCoord2f                ;
+		qglTexCoord2fv               = 	dllTexCoord2fv               ;
+		qglTexCoord2i                = 	dllTexCoord2i                ;
+		qglTexCoord2iv               = 	dllTexCoord2iv               ;
+		qglTexCoord2s                = 	dllTexCoord2s                ;
+		qglTexCoord2sv               = 	dllTexCoord2sv               ;
+		qglTexCoord3d                = 	dllTexCoord3d                ;
+		qglTexCoord3dv               = 	dllTexCoord3dv               ;
+		qglTexCoord3f                = 	dllTexCoord3f                ;
+		qglTexCoord3fv               = 	dllTexCoord3fv               ;
+		qglTexCoord3i                = 	dllTexCoord3i                ;
+		qglTexCoord3iv               = 	dllTexCoord3iv               ;
+		qglTexCoord3s                = 	dllTexCoord3s                ;
+		qglTexCoord3sv               = 	dllTexCoord3sv               ;
+		qglTexCoord4d                = 	dllTexCoord4d                ;
+		qglTexCoord4dv               = 	dllTexCoord4dv               ;
+		qglTexCoord4f                = 	dllTexCoord4f                ;
+		qglTexCoord4fv               = 	dllTexCoord4fv               ;
+		qglTexCoord4i                = 	dllTexCoord4i                ;
+		qglTexCoord4iv               = 	dllTexCoord4iv               ;
+		qglTexCoord4s                = 	dllTexCoord4s                ;
+		qglTexCoord4sv               = 	dllTexCoord4sv               ;
+		qglTexCoordPointer           = 	dllTexCoordPointer           ;
+		qglTexEnvf                   = 	dllTexEnvf                   ;
+		qglTexEnvfv                  = 	dllTexEnvfv                  ;
+		qglTexEnvi                   = 	dllTexEnvi                   ;
+		qglTexEnviv                  = 	dllTexEnviv                  ;
+		qglTexGend                   = 	dllTexGend                   ;
+		qglTexGendv                  = 	dllTexGendv                  ;
+		qglTexGenf                   = 	dllTexGenf                   ;
+		qglTexGenfv                  = 	dllTexGenfv                  ;
+		qglTexGeni                   = 	dllTexGeni                   ;
+		qglTexGeniv                  = 	dllTexGeniv                  ;
+		qglTexImage1D                = 	dllTexImage1D                ;
+		qglTexImage2D                = 	dllTexImage2D                ;
+		qglTexParameterf             = 	dllTexParameterf             ;
+		qglTexParameterfv            = 	dllTexParameterfv            ;
+		qglTexParameteri             = 	dllTexParameteri             ;
+		qglTexParameteriv            = 	dllTexParameteriv            ;
+		qglTexSubImage1D             = 	dllTexSubImage1D             ;
+		qglTexSubImage2D             = 	dllTexSubImage2D             ;
+		qglTranslated                = 	dllTranslated                ;
+		qglTranslatef                = 	dllTranslatef                ;
+		qglVertex2d                  = 	dllVertex2d                  ;
+		qglVertex2dv                 = 	dllVertex2dv                 ;
+		qglVertex2f                  = 	dllVertex2f                  ;
+		qglVertex2fv                 = 	dllVertex2fv                 ;
+		qglVertex2i                  = 	dllVertex2i                  ;
+		qglVertex2iv                 = 	dllVertex2iv                 ;
+		qglVertex2s                  = 	dllVertex2s                  ;
+		qglVertex2sv                 = 	dllVertex2sv                 ;
+		qglVertex3d                  = 	dllVertex3d                  ;
+		qglVertex3dv                 = 	dllVertex3dv                 ;
+		qglVertex3f                  = 	dllVertex3f                  ;
+		qglVertex3fv                 = 	dllVertex3fv                 ;
+		qglVertex3i                  = 	dllVertex3i                  ;
+		qglVertex3iv                 = 	dllVertex3iv                 ;
+		qglVertex3s                  = 	dllVertex3s                  ;
+		qglVertex3sv                 = 	dllVertex3sv                 ;
+		qglVertex4d                  = 	dllVertex4d                  ;
+		qglVertex4dv                 = 	dllVertex4dv                 ;
+		qglVertex4f                  = 	dllVertex4f                  ;
+		qglVertex4fv                 = 	dllVertex4fv                 ;
+		qglVertex4i                  = 	dllVertex4i                  ;
+		qglVertex4iv                 = 	dllVertex4iv                 ;
+		qglVertex4s                  = 	dllVertex4s                  ;
+		qglVertex4sv                 = 	dllVertex4sv                 ;
+		qglVertexPointer             = 	dllVertexPointer             ;
+		qglViewport                  = 	dllViewport                  ;
+	}
+}
+
+
+void GLimp_LogNewFrame( void )
+{
+	fprintf( log_fp, "*** R_BeginFrame ***\n");
+}
+
+
--- /dev/null
+++ b/irix/snd_irix.c
@@ -1,0 +1,222 @@
+#include <dmedia/dmedia.h>
+#include <dmedia/audio.h>
+
+#include "../client/client.h"
+#include "../client/snd_loc.h"
+
+/*
+==================
+SNDDM_Init
+
+Try to find a sound device to mix for.
+Returns false if nothing is found.
+Returns true and fills in the "dma" structure with information for the mixer.
+==================
+*/
+
+// must be power of two!
+#define QSND_SKID	    2
+#define QSND_BUFFER_FRAMES  8192
+#define QSND_BUFFER_SIZE    (QSND_BUFFER_FRAMES*2)
+
+#define UST_TO_BUFFPOS(ust) ((int)((ust) & (QSND_BUFFER_FRAMES - 1)) << 1)
+
+cvar_t *s_loadas8bit;
+cvar_t *s_khz;
+cvar_t *sndchannels;
+
+short int dma_buffer[QSND_BUFFER_SIZE];
+ALport sgisnd_aport = NULL;
+long long sgisnd_startframe;
+double sgisnd_frames_per_ns;
+long long sgisnd_lastframewritten = 0;
+
+qboolean SNDDMA_Init(void)
+{
+    ALconfig	ac = NULL;
+    ALpv	pvbuf[2];
+
+    s_loadas8bit = Cvar_Get("s_loadas8bit", "16", CVAR_ARCHIVE);
+    if ((int)s_loadas8bit->value)
+	dma.samplebits = 8;
+    else
+	dma.samplebits = 16;
+
+    if (dma.samplebits != 16) {
+	Com_Printf("Don't currently support %i-bit data.  Forcing 16-bit.\n",
+		   dma.samplebits);
+	dma.samplebits = 16;
+	Cvar_SetValue( "s_loadas8bit", false );
+    }
+
+    s_khz = Cvar_Get("s_khz", "0", CVAR_ARCHIVE);
+    switch ((int)s_khz->value) {
+    case 48:
+	dma.speed = AL_RATE_48000;
+	break;
+    case 44:
+	dma.speed = AL_RATE_44100;
+	break;
+    case 32:
+	dma.speed = AL_RATE_32000;
+	break;
+    case 22:
+	dma.speed = AL_RATE_22050;
+	break;
+    case 16:
+	dma.speed = AL_RATE_16000;
+	break;
+    case 11:
+	dma.speed = AL_RATE_11025;
+	break;
+    case 8:
+	dma.speed = AL_RATE_8000;
+	break;
+    default:
+	dma.speed = AL_RATE_22050;
+	Com_Printf("Don't currently support %i kHz sample rate.  Using %i.\n",
+		   (int)s_khz->value, (int)(dma.speed/1000));
+    }
+    
+    sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
+    dma.channels = (int)sndchannels->value;
+    if (dma.channels != 2)
+	Com_Printf("Don't currently support %i sound channels.  Try 2.\n",
+		   sndchannels);
+
+    /***********************/
+
+    ac = alNewConfig();
+    alSetChannels( ac, AL_STEREO );
+    alSetSampFmt( ac, AL_SAMPFMT_TWOSCOMP );
+    alSetQueueSize( ac, QSND_BUFFER_FRAMES );
+    if (dma.samplebits == 8)
+	alSetWidth( ac, AL_SAMPLE_8 );
+    else
+	alSetWidth( ac, AL_SAMPLE_16 );
+
+    sgisnd_aport = alOpenPort( "Quake", "w", ac );
+    if (!sgisnd_aport)
+    {
+	printf( "failed to open audio port!\n" );
+    }
+
+    // set desired sample rate
+    pvbuf[0].param = AL_MASTER_CLOCK;
+    pvbuf[0].value.i = AL_CRYSTAL_MCLK_TYPE;
+    pvbuf[1].param = AL_RATE;
+    pvbuf[1].value.ll = alIntToFixed( dma.speed );
+    alSetParams( alGetResource( sgisnd_aport ), pvbuf, 2 );
+    if (pvbuf[1].sizeOut < 0)
+	printf( "illegal sample rate %d\n", dma.speed );
+
+    sgisnd_frames_per_ns = dma.speed * 1.0e-9;
+
+    dma.samples = sizeof(dma_buffer)/(dma.samplebits/8);
+    dma.submission_chunk = 1;
+
+    dma.buffer = (unsigned char *)dma_buffer;
+
+    dma.samplepos = 0;
+
+    alFreeConfig( ac );
+    return true;
+}
+
+
+/*
+==============
+SNDDMA_GetDMAPos
+
+return the current sample position (in mono samples, not stereo)
+inside the recirculating dma buffer, so the mixing code will know
+how many sample are required to fill it up.
+===============
+*/
+int SNDDMA_GetDMAPos(void)
+{
+    long long ustFuture, ustNow;
+    if (!sgisnd_aport) return( 0 );
+    alGetFrameTime( sgisnd_aport, &sgisnd_startframe, &ustFuture );
+    dmGetUST( (unsigned long long *)&ustNow );
+    sgisnd_startframe -= (long long)((ustFuture - ustNow) * sgisnd_frames_per_ns);
+    sgisnd_startframe += 100;
+//printf( "frame %ld pos %d\n", frame, UST_TO_BUFFPOS( sgisnd_startframe ) );
+    return( UST_TO_BUFFPOS( sgisnd_startframe ) );
+}
+
+/*
+==============
+SNDDMA_Shutdown
+
+Reset the sound device for exiting
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+    if (sgisnd_aport) alClosePort( sgisnd_aport ), sgisnd_aport = NULL;
+    return;
+}
+
+/*
+==============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+===============
+*/
+
+extern int soundtime;
+
+void SNDDMA_Submit(void)
+{
+    int nFillable, nFilled, nPos;
+    int nFrames, nFramesLeft;
+    unsigned endtime;
+
+    if (!sgisnd_aport) return;
+
+    nFillable = alGetFillable( sgisnd_aport );
+    nFilled = QSND_BUFFER_FRAMES - nFillable;
+
+    nFrames = dma.samples >> (dma.channels - 1);
+
+    if (paintedtime - soundtime < nFrames)
+	nFrames = paintedtime - soundtime;
+
+    if (nFrames <= QSND_SKID) return;
+
+    nPos = UST_TO_BUFFPOS( sgisnd_startframe );
+
+    // dump re-written contents of the buffer
+    if (sgisnd_lastframewritten > sgisnd_startframe)
+    {
+	alDiscardFrames( sgisnd_aport, sgisnd_lastframewritten - sgisnd_startframe );
+    }
+    else if ((int)(sgisnd_startframe - sgisnd_lastframewritten) >= QSND_BUFFER_FRAMES)
+    {
+	// blow away everything if we've underflowed
+	alDiscardFrames( sgisnd_aport, QSND_BUFFER_FRAMES );
+    }
+
+    // don't block
+    if (nFrames > nFillable) nFrames = nFillable;
+
+    // account for stereo
+    nFramesLeft = nFrames;
+    if (nPos + nFrames * dma.channels > QSND_BUFFER_SIZE)
+    {
+	int nFramesAtEnd = (QSND_BUFFER_SIZE - nPos) >> (dma.channels - 1);
+	
+	alWriteFrames( sgisnd_aport, &dma_buffer[nPos], nFramesAtEnd );
+	nPos = 0;
+	nFramesLeft -= nFramesAtEnd;
+    }
+    alWriteFrames( sgisnd_aport, &dma_buffer[nPos], nFramesLeft );
+
+    sgisnd_lastframewritten = sgisnd_startframe + nFrames;
+}
+
+void SNDDMA_BeginPainting (void)
+{
+}
--- /dev/null
+++ b/irix/sys_irix.c
@@ -1,0 +1,383 @@
+#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 <mntent.h>
+
+#include <dlfcn.h>
+
+#include "../qcommon/qcommon.h"
+
+#include "../linux/rw_linux.h"
+
+cvar_t *nostdout;
+
+unsigned	sys_frame_time;
+
+uid_t saved_euid;
+qboolean stdin_active = true;
+
+// =======================================================================
+// General routines
+// =======================================================================
+
+void Sys_ConsoleOutput (char *string)
+{
+	if (nostdout && nostdout->value)
+		return;
+
+	fputs(string, stdout);
+}
+
+void Sys_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+	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 && nostdout->value)
+        return;
+
+	for (p = (unsigned char *)text; *p; p++) {
+		*p &= 0x7f;
+		if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
+			printf("[%02x]", *p);
+		else
+			putc(*p, stdout);
+	}
+}
+
+void Sys_Quit (void)
+{
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+    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);
+
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+	_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 floating_point_exception_handler(int whatever)
+{
+//	Sys_Warn("floating point exception\n");
+	signal(SIGFPE, floating_point_exception_handler);
+}
+
+char *Sys_ConsoleInput(void)
+{
+    static char text[256];
+    int     len;
+	fd_set	fdset;
+    struct timeval timeout;
+
+	if (!dedicated || !dedicated->value)
+		return NULL;
+
+	if (!stdin_active)
+		return NULL;
+
+	FD_ZERO(&fdset);
+	FD_SET(0, &fdset); // stdin
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+	if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
+		return NULL;
+
+	len = read (0, text, sizeof(text));
+	if (len == 0) { // eof!
+		stdin_active = false;
+		return NULL;
+	}
+
+	if (len < 1)
+		return NULL;
+	text[len-1] = 0;    // rip off the /n and terminate
+
+	return text;
+}
+
+/*****************************************************************************/
+
+static void *game_library;
+
+/*
+=================
+Sys_UnloadGame
+=================
+*/
+void Sys_UnloadGame (void)
+{
+	if (game_library) 
+		dlclose (game_library);
+	game_library = NULL;
+}
+
+/*
+=================
+Sys_GetGameAPI
+
+Loads the game dll
+=================
+*/
+void *Sys_GetGameAPI (void *parms)
+{
+#ifndef REF_HARD_LINKED
+	void	*(*GetGameAPI) (void *);
+
+	char	name[MAX_OSPATH];
+	char	curpath[MAX_OSPATH];
+	char	*path;
+#ifdef __sgi
+	const char *gamename = "gamemips.so";
+#else
+#error Unknown arch
+#endif
+
+	setreuid(getuid(), getuid());
+	setegid(getgid());
+
+	if (game_library)
+		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
+
+	getcwd(curpath, sizeof(curpath));
+
+	Com_Printf("------- Loading %s -------", gamename);
+
+	// now run through the search paths
+	path = NULL;
+	while (1)
+	{
+		path = FS_NextPath (path);
+		if (!path)
+			return NULL;		// couldn't find one anywhere
+		sprintf (name, "%s/%s/%s", curpath, path, gamename);
+		Com_Printf ("Trying to load library (%s)\n",name);
+		game_library = dlopen (name, RTLD_NOW );
+		if (game_library)
+		{
+			Com_DPrintf ("LoadLibrary (%s)\n",name);
+			break;
+		}
+	}
+
+	GetGameAPI = (void *)dlsym (game_library, "GetGameAPI");
+	if (!GetGameAPI)
+	{
+		Sys_UnloadGame ();		
+		return NULL;
+	}
+
+	return GetGameAPI (parms);
+#else
+	return (void *)GetGameAPI (parms);
+#endif
+}
+
+/*****************************************************************************/
+
+void Sys_AppActivate (void)
+{
+}
+
+void Sys_SendKeyEvents (void)
+{
+	if (KBD_Update_fp)
+		KBD_Update_fp();
+
+	// grab frame time 
+	sys_frame_time = Sys_Milliseconds();
+}
+
+/*****************************************************************************/
+
+char *Sys_GetClipboardData(void)
+{
+	return NULL;
+}
+
+int main (int argc, char **argv)
+{
+	int 	time, oldtime, newtime;
+
+	// go back to real user for config loads
+	saved_euid = geteuid();
+	seteuid(getuid());
+
+	Qcommon_Init(argc, argv);
+
+/* 	fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); */
+
+	nostdout = Cvar_Get("nostdout", "0", 0);
+	if (!nostdout->value) {
+/* 		fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); */
+//		printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
+	}
+
+    oldtime = Sys_Milliseconds ();
+    while (1)
+    {
+// find time spent rendering last frame
+		do {
+			newtime = Sys_Milliseconds ();
+			time = newtime - oldtime;
+		} while (time < 1);
+		Qcommon_Frame (time);
+		oldtime = newtime;
+    }
+
+}
+
+void Sys_CopyProtect(void)
+{
+	FILE *mnt;
+	struct mntent *ent;
+	char path[MAX_OSPATH];
+	struct stat st;
+	qboolean found_cd = false;
+
+	static qboolean checked = false;
+
+	if (checked)
+		return;
+
+        Com_Printf("XXX - Sys_CopyProtect disabled\n");
+	checked = true;
+	return;
+
+	if ((mnt = setmntent("/etc/mtab", "r")) == NULL)
+		Com_Error(ERR_FATAL, "Can't read mount table to determine mounted cd location.");
+
+	while ((ent = getmntent(mnt)) != NULL) {
+		if (strcmp(ent->mnt_type, "iso9660") == 0) {
+			// found a cd file system
+			found_cd = true;
+			sprintf(path, "%s/%s", ent->mnt_dir, "install/data/quake2.exe");
+			if (stat(path, &st) == 0) {
+				// found it
+				checked = true;
+				endmntent(mnt);
+				return;
+			}
+			sprintf(path, "%s/%s", ent->mnt_dir, "Install/Data/quake2.exe");
+			if (stat(path, &st) == 0) {
+				// found it
+				checked = true;
+				endmntent(mnt);
+				return;
+			}
+			sprintf(path, "%s/%s", ent->mnt_dir, "quake2.exe");
+			if (stat(path, &st) == 0) {
+				// found it
+				checked = true;
+				endmntent(mnt);
+				return;
+			}
+		}
+	}
+	endmntent(mnt);
+
+	if (found_cd)
+		Com_Error (ERR_FATAL, "Could not find a Quake2 CD in your CD drive.");
+	Com_Error (ERR_FATAL, "Unable to find a mounted iso9660 file system.\n"
+		"You must mount the Quake2 CD in a cdrom drive in order to play.");
+}
+
+#if 0
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+	int r;
+	unsigned long addr;
+	int psize = getpagesize();
+
+	addr = (startaddr & ~(psize-1)) - psize;
+
+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+//			addr, startaddr+length, length);
+
+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+	if (r < 0)
+    		Sys_Error("Protection change failed\n");
+
+}
+
+#endif
--- /dev/null
+++ b/irix/vid_menu.c
@@ -1,0 +1,426 @@
+#include "../client/client.h"
+#include "../client/qmenu.h"
+
+#define REF_SOFT	0
+#define REF_OPENGL	1
+
+extern cvar_t *vid_ref;
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+
+static cvar_t *gl_mode;
+static cvar_t *gl_driver;
+static cvar_t *gl_picmip;
+static cvar_t *gl_ext_palettedtexture;
+
+static cvar_t *sw_mode;
+static cvar_t *sw_stipplealpha;
+
+static cvar_t *_windowed_mouse;
+
+extern void M_ForceMenuOff( void );
+
+/*
+====================================================================
+
+MENU INTERACTION
+
+====================================================================
+*/
+#define SOFTWARE_MENU 0
+#define OPENGL_MENU   1
+
+static menuframework_s  s_software_menu;
+static menuframework_s	s_opengl_menu;
+static menuframework_s *s_current_menu;
+static int				s_current_menu_index;
+
+static menulist_s		s_mode_list[2];
+static menulist_s		s_ref_list[2];
+static menuslider_s		s_tq_slider;
+static menuslider_s		s_screensize_slider[2];
+static menuslider_s		s_brightness_slider[2];
+static menulist_s  		s_fs_box[2];
+static menulist_s  		s_stipple_box;
+static menulist_s  		s_paletted_texture_box;
+static menulist_s  		s_windowed_mouse;
+static menuaction_s		s_apply_action[2];
+static menuaction_s		s_defaults_action[2];
+
+static void DriverCallback( void *unused )
+{
+	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+	if ( s_ref_list[s_current_menu_index].curvalue < 1 )
+	{
+		s_current_menu = &s_software_menu;
+		s_current_menu_index = 0;
+	}
+	else
+	{
+		s_current_menu = &s_opengl_menu;
+		s_current_menu_index = 1;
+	}
+
+}
+
+static void ScreenSizeCallback( void *s )
+{
+	menuslider_s *slider = ( menuslider_s * ) s;
+
+	Cvar_SetValue( "viewsize", slider->curvalue * 10 );
+}
+
+static void BrightnessCallback( void *s )
+{
+	menuslider_s *slider = ( menuslider_s * ) s;
+
+	if ( s_current_menu_index == 0)
+		s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
+	else
+		s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
+
+	if ( Q_stricmp( vid_ref->string, "soft" ) == 0 )
+	{
+		float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5;
+
+		Cvar_SetValue( "vid_gamma", gamma );
+	}
+}
+
+static void ResetDefaults( void *unused )
+{
+	VID_MenuInit();
+}
+
+static void ApplyChanges( void *unused )
+{
+	float gamma;
+
+	/*
+	** make values consistent
+	*/
+	s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
+	s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
+	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+	/*
+	** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+	*/
+	gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5;
+
+	Cvar_SetValue( "vid_gamma", gamma );
+	Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
+	Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
+	Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
+	Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
+	Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
+	Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
+	Cvar_SetValue( "_windowed_mouse", s_windowed_mouse.curvalue);
+
+	switch ( s_ref_list[s_current_menu_index].curvalue )
+	{
+	case REF_SOFT:
+		Cvar_Set( "vid_ref", "soft" );
+		break;
+	case REF_OPENGL:
+		Cvar_Set( "vid_ref", "gl" );
+		Cvar_Set( "gl_driver", "opengl32" );
+		break;
+	}
+
+#if 0
+	/*
+	** update appropriate stuff if we're running OpenGL and gamma
+	** has been modified
+	*/
+	if ( Q_stricmp( vid_ref->string, "gl" ) == 0 )
+	{
+		if ( vid_gamma->modified )
+		{
+			vid_ref->modified = true;
+			if ( Q_stricmp( gl_driver->string, "3dfxgl" ) == 0 )
+			{
+				char envbuffer[1024];
+				float g;
+
+				vid_ref->modified = true;
+
+				g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
+				Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
+				putenv( envbuffer );
+
+				vid_gamma->modified = false;
+			}
+		}
+	}
+#endif
+
+	M_ForceMenuOff();
+}
+
+/*
+** VID_MenuInit
+*/
+void VID_MenuInit( void )
+{
+	static const char *resolutions[] = 
+	{
+		"[320 240  ]",
+		"[400 300  ]",
+		"[512 384  ]",
+		"[640 480  ]",
+		"[800 600  ]",
+		"[960 720  ]",
+		"[1024 768 ]",
+		"[1152 864 ]",
+		"[1280 1024]",
+		"[1600 1200]",
+		0
+	};
+	static const char *refs[] =
+	{
+		"[software      ]",
+		"[default OpenGL]",
+		0
+	};
+	static const char *yesno_names[] =
+	{
+		"no",
+		"yes",
+		0
+	};
+	int i;
+
+	if ( !gl_driver )
+		gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
+	if ( !gl_picmip )
+		gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
+	if ( !gl_mode )
+		gl_mode = Cvar_Get( "gl_mode", "3", 0 );
+	if ( !sw_mode )
+		sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+	if ( !gl_ext_palettedtexture )
+		gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
+
+	if ( !sw_stipplealpha )
+		sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+
+	if ( !_windowed_mouse)
+        _windowed_mouse = Cvar_Get( "_windowed_mouse", "0", CVAR_ARCHIVE );
+
+	s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value;
+	s_mode_list[OPENGL_MENU].curvalue = gl_mode->value;
+
+	if ( !scr_viewsize )
+		scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+
+	s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10;
+	s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10;
+
+	if (strcmp( vid_ref->string, "soft" ) == 0 ) 
+	{
+		s_current_menu_index = SOFTWARE_MENU;
+		s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
+	}
+	else if ( strcmp( vid_ref->string, "gl" ) == 0 )
+	{
+		s_current_menu_index = OPENGL_MENU;
+		s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+#if 0
+		if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_3DFX;
+		else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_POWERVR;
+		else if ( strcmp( gl_driver->string, "opengl32" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+		else
+			s_ref_list[s_current_menu_index].curvalue = REF_VERITE;
+#endif
+	}
+
+	s_software_menu.x = viddef.width * 0.50;
+	s_software_menu.nitems = 0;
+	s_opengl_menu.x = viddef.width * 0.50;
+	s_opengl_menu.nitems = 0;
+
+	for ( i = 0; i < 2; i++ )
+	{
+		s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
+		s_ref_list[i].generic.name = "driver";
+		s_ref_list[i].generic.x = 0;
+		s_ref_list[i].generic.y = 0;
+		s_ref_list[i].generic.callback = DriverCallback;
+		s_ref_list[i].itemnames = refs;
+
+		s_mode_list[i].generic.type = MTYPE_SPINCONTROL;
+		s_mode_list[i].generic.name = "video mode";
+		s_mode_list[i].generic.x = 0;
+		s_mode_list[i].generic.y = 10;
+		s_mode_list[i].itemnames = resolutions;
+
+		s_screensize_slider[i].generic.type	= MTYPE_SLIDER;
+		s_screensize_slider[i].generic.x		= 0;
+		s_screensize_slider[i].generic.y		= 20;
+		s_screensize_slider[i].generic.name	= "screen size";
+		s_screensize_slider[i].minvalue = 3;
+		s_screensize_slider[i].maxvalue = 12;
+		s_screensize_slider[i].generic.callback = ScreenSizeCallback;
+
+		s_brightness_slider[i].generic.type	= MTYPE_SLIDER;
+		s_brightness_slider[i].generic.x	= 0;
+		s_brightness_slider[i].generic.y	= 30;
+		s_brightness_slider[i].generic.name	= "brightness";
+		s_brightness_slider[i].generic.callback = BrightnessCallback;
+		s_brightness_slider[i].minvalue = 5;
+		s_brightness_slider[i].maxvalue = 13;
+		s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10;
+
+		s_fs_box[i].generic.type = MTYPE_SPINCONTROL;
+		s_fs_box[i].generic.x	= 0;
+		s_fs_box[i].generic.y	= 40;
+		s_fs_box[i].generic.name	= "fullscreen";
+		s_fs_box[i].itemnames = yesno_names;
+		s_fs_box[i].curvalue = vid_fullscreen->value;
+
+		s_defaults_action[i].generic.type = MTYPE_ACTION;
+		s_defaults_action[i].generic.name = "reset to default";
+		s_defaults_action[i].generic.x    = 0;
+		s_defaults_action[i].generic.y    = 90;
+		s_defaults_action[i].generic.callback = ResetDefaults;
+
+		s_apply_action[i].generic.type = MTYPE_ACTION;
+		s_apply_action[i].generic.name = "apply";
+		s_apply_action[i].generic.x    = 0;
+		s_apply_action[i].generic.y    = 100;
+		s_apply_action[i].generic.callback = ApplyChanges;
+	}
+
+	s_stipple_box.generic.type = MTYPE_SPINCONTROL;
+	s_stipple_box.generic.x	= 0;
+	s_stipple_box.generic.y	= 60;
+	s_stipple_box.generic.name	= "stipple alpha";
+	s_stipple_box.curvalue = sw_stipplealpha->value;
+	s_stipple_box.itemnames = yesno_names;
+
+	s_windowed_mouse.generic.type = MTYPE_SPINCONTROL;
+	s_windowed_mouse.generic.x  = 0;
+	s_windowed_mouse.generic.y  = 72;
+	s_windowed_mouse.generic.name   = "windowed mouse";
+	s_windowed_mouse.curvalue = _windowed_mouse->value;
+	s_windowed_mouse.itemnames = yesno_names;
+
+	s_tq_slider.generic.type	= MTYPE_SLIDER;
+	s_tq_slider.generic.x		= 0;
+	s_tq_slider.generic.y		= 60;
+	s_tq_slider.generic.name	= "texture quality";
+	s_tq_slider.minvalue = 0;
+	s_tq_slider.maxvalue = 3;
+	s_tq_slider.curvalue = 3-gl_picmip->value;
+
+	s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL;
+	s_paletted_texture_box.generic.x	= 0;
+	s_paletted_texture_box.generic.y	= 70;
+	s_paletted_texture_box.generic.name	= "8-bit textures";
+	s_paletted_texture_box.itemnames = yesno_names;
+	s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value;
+
+	Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_windowed_mouse );
+
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box );
+
+	Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_apply_action[SOFTWARE_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_apply_action[OPENGL_MENU] );
+
+	Menu_Center( &s_software_menu );
+	Menu_Center( &s_opengl_menu );
+	s_opengl_menu.x -= 8;
+	s_software_menu.x -= 8;
+}
+
+/*
+================
+VID_MenuDraw
+================
+*/
+void VID_MenuDraw (void)
+{
+	int w, h;
+
+	if ( s_current_menu_index == 0 )
+		s_current_menu = &s_software_menu;
+	else
+		s_current_menu = &s_opengl_menu;
+
+	/*
+	** draw the banner
+	*/
+	re.DrawGetPicSize( &w, &h, "m_banner_video" );
+	re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
+
+	/*
+	** move cursor to a reasonable starting position
+	*/
+	Menu_AdjustCursor( s_current_menu, 1 );
+
+	/*
+	** draw the menu
+	*/
+	Menu_Draw( s_current_menu );
+}
+
+/*
+================
+VID_MenuKey
+================
+*/
+const char *VID_MenuKey( int key )
+{
+	extern void M_PopMenu( void );
+
+	menuframework_s *m = s_current_menu;
+	static const char *sound = "misc/menu1.wav";
+
+	switch ( key )
+	{
+	case K_ESCAPE:
+		M_PopMenu();
+		return NULL;
+	case K_UPARROW:
+		m->cursor--;
+		Menu_AdjustCursor( m, -1 );
+		break;
+	case K_DOWNARROW:
+		m->cursor++;
+		Menu_AdjustCursor( m, 1 );
+		break;
+	case K_LEFTARROW:
+		Menu_SlideItem( m, -1 );
+		break;
+	case K_RIGHTARROW:
+		Menu_SlideItem( m, 1 );
+		break;
+	case K_ENTER:
+		Menu_SelectItem( m );
+		break;
+	}
+
+	return sound;
+}
+
+
--- /dev/null
+++ b/irix/vid_so.c
@@ -1,0 +1,492 @@
+// Main windowed and fullscreen graphics interface module. This module
+// is used for both the software and OpenGL rendering versions of the
+// Quake refresh engine.
+
+#define SO_FILE "/etc/quake2.conf"
+
+#include <errno.h>
+#include <assert.h>
+#include <dlfcn.h> // ELF dl loader
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "../client/client.h"
+
+#include "../linux/rw_linux.h"
+
+// Structure containing functions exported from refresh DLL
+refexport_t	re;
+
+#ifdef REF_HARD_LINKED
+refexport_t GetRefAPI (refimport_t rimp);
+#endif
+
+// Console variables that we need to access from this module
+cvar_t		*vid_gamma;
+cvar_t		*vid_ref;			// Name of Refresh DLL loaded
+cvar_t		*vid_xpos;			// X coordinate of window position
+cvar_t		*vid_ypos;			// Y coordinate of window position
+cvar_t		*vid_fullscreen;
+
+// Global variables used internally by this module
+viddef_t	viddef;				// global video state; used by other modules
+void		*reflib_library;		// Handle to refresh DLL 
+qboolean	reflib_active = 0;
+
+#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
+
+/** KEYBOARD **************************************************************/
+
+void Do_Key_Event(int key, qboolean down);
+
+void (*KBD_Update_fp)(void);
+void (*KBD_Init_fp)(Key_Event_fp_t fp);
+void (*KBD_Close_fp)(void);
+
+/** MOUSE *****************************************************************/
+
+in_state_t in_state;
+
+void (*RW_IN_Init_fp)(in_state_t *in_state_p);
+void (*RW_IN_Shutdown_fp)(void);
+void (*RW_IN_Activate_fp)(qboolean active);
+void (*RW_IN_Commands_fp)(void);
+void (*RW_IN_Move_fp)(usercmd_t *cmd);
+void (*RW_IN_Frame_fp)(void);
+
+void Real_IN_Init (void);
+
+/*
+==========================================================================
+
+DLL GLUE
+
+==========================================================================
+*/
+
+#define	MAXPRINTMSG	4096
+void VID_Printf (int print_level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	if (print_level == PRINT_ALL)
+		Com_Printf ("%s", msg);
+	else
+		Com_DPrintf ("%s", msg);
+}
+
+void VID_Error (int err_level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	Com_Error (err_level,"%s", msg);
+}
+
+//==========================================================================
+
+/*
+============
+VID_Restart_f
+
+Console command to re-start the video mode and refresh DLL. We do this
+simply by setting the modified flag for the vid_ref variable, which will
+cause the entire video mode and refresh DLL to be reset on the next frame.
+============
+*/
+void VID_Restart_f (void)
+{
+	vid_ref->modified = true;
+}
+
+/*
+** VID_GetModeInfo
+*/
+typedef struct vidmode_s
+{
+	const char *description;
+	int         width, height;
+	int         mode;
+} vidmode_t;
+
+vidmode_t vid_modes[] =
+{
+	{ "Mode 0: 320x240",   320, 240,   0 },
+	{ "Mode 1: 400x300",   400, 300,   1 },
+	{ "Mode 2: 512x384",   512, 384,   2 },
+	{ "Mode 3: 640x480",   640, 480,   3 },
+	{ "Mode 4: 800x600",   800, 600,   4 },
+	{ "Mode 5: 960x720",   960, 720,   5 },
+	{ "Mode 6: 1024x768",  1024, 768,  6 },
+	{ "Mode 7: 1152x864",  1152, 864,  7 },
+	{ "Mode 8: 1280x1024",  1280, 1024, 8 },
+	{ "Mode 9: 1600x1200", 1600, 1200, 9 }
+};
+
+qboolean VID_GetModeInfo( int *width, int *height, int mode )
+{
+	if ( mode < 0 || mode >= VID_NUM_MODES )
+		return false;
+
+	*width  = vid_modes[mode].width;
+	*height = vid_modes[mode].height;
+
+	return true;
+}
+
+/*
+** VID_NewWindow
+*/
+void VID_NewWindow ( int width, int height)
+{
+	viddef.width  = width;
+	viddef.height = height;
+}
+
+void VID_FreeReflib (void)
+{
+	if (reflib_library) {
+		if (KBD_Close_fp)
+			KBD_Close_fp();
+		if (RW_IN_Shutdown_fp)
+			RW_IN_Shutdown_fp();
+#ifndef REF_HARD_LINKED
+		dlclose(reflib_library);
+#endif
+	}
+
+	KBD_Init_fp = NULL;
+	KBD_Update_fp = NULL;
+	KBD_Close_fp = NULL;
+	RW_IN_Init_fp = NULL;
+	RW_IN_Shutdown_fp = NULL;
+	RW_IN_Activate_fp = NULL;
+	RW_IN_Commands_fp = NULL;
+	RW_IN_Move_fp = NULL;
+	RW_IN_Frame_fp = NULL;
+
+	memset (&re, 0, sizeof(re));
+	reflib_library = NULL;
+	reflib_active  = false;
+}
+
+/*
+==============
+VID_LoadRefresh
+==============
+*/
+qboolean VID_LoadRefresh( char *name )
+{
+	refimport_t	ri;
+#ifndef REF_HARD_LINKED
+	GetRefAPI_t	GetRefAPI;
+#endif
+	char	fn[MAX_OSPATH];
+	struct stat st;
+	extern uid_t saved_euid;
+	FILE *fp;
+	char	*path;
+	char	curpath[MAX_OSPATH];
+
+	if ( reflib_active )
+	{
+		if (KBD_Close_fp)
+			KBD_Close_fp();
+		if (RW_IN_Shutdown_fp)
+			RW_IN_Shutdown_fp();
+		KBD_Close_fp = NULL;
+		RW_IN_Shutdown_fp = NULL;
+		re.Shutdown();
+		VID_FreeReflib ();
+	}
+
+#ifndef REF_HARD_LINKED
+	getcwd(curpath, sizeof(curpath));
+	
+	Com_Printf( "------- Loading %s -------\n", name );
+
+	// now run through the search paths
+	path = NULL;
+	while (1)
+	{
+		path = FS_NextPath (path);
+		if (!path)
+			return NULL;		// couldn't find one anywhere
+		sprintf (fn, "%s/%s/%s", curpath, path, name);
+		Com_Printf ("Trying to load library (%s)\n", fn);
+
+		reflib_library = dlopen( fn, RTLD_NOW );
+		if (reflib_library)
+		{
+			Com_DPrintf ("LoadLibrary (%s)\n",name);
+			break;
+		}
+	}
+
+#endif
+
+	ri.Cmd_AddCommand = Cmd_AddCommand;
+	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+	ri.Cmd_Argc = Cmd_Argc;
+	ri.Cmd_Argv = Cmd_Argv;
+	ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+	ri.Con_Printf = VID_Printf;
+	ri.Sys_Error = VID_Error;
+	ri.FS_LoadFile = FS_LoadFile;
+	ri.FS_FreeFile = FS_FreeFile;
+	ri.FS_Gamedir = FS_Gamedir;
+	ri.Cvar_Get = Cvar_Get;
+	ri.Cvar_Set = Cvar_Set;
+	ri.Cvar_SetValue = Cvar_SetValue;
+	ri.Vid_GetModeInfo = VID_GetModeInfo;
+	ri.Vid_MenuInit = VID_MenuInit;
+	ri.Vid_NewWindow = VID_NewWindow;
+
+#ifndef REF_HARD_LINKED
+	if ( ( GetRefAPI = (void *) dlsym( reflib_library, "GetRefAPI" ) ) == 0 )
+		Com_Error( ERR_FATAL, "dlsym failed on %s", name );
+#endif
+	re = GetRefAPI( ri );
+
+	if (re.api_version != API_VERSION)
+	{
+		VID_FreeReflib ();
+		Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
+	}
+
+	/* Init IN (Mouse) */
+	in_state.IN_CenterView_fp = IN_CenterView;
+	in_state.Key_Event_fp = Do_Key_Event;
+	in_state.viewangles = cl.viewangles;
+	in_state.in_strafe_state = &in_strafe.state;
+
+#ifndef REF_HARD_LINKED
+	if ((RW_IN_Init_fp = dlsym(reflib_library, "RW_IN_Init")) == NULL ||
+		(RW_IN_Shutdown_fp = dlsym(reflib_library, "RW_IN_Shutdown")) == NULL ||
+		(RW_IN_Activate_fp = dlsym(reflib_library, "RW_IN_Activate")) == NULL ||
+		(RW_IN_Commands_fp = dlsym(reflib_library, "RW_IN_Commands")) == NULL ||
+		(RW_IN_Move_fp = dlsym(reflib_library, "RW_IN_Move")) == NULL ||
+		(RW_IN_Frame_fp = dlsym(reflib_library, "RW_IN_Frame")) == NULL)
+		Sys_Error("No RW_IN functions in REF.\n");
+#else
+	{
+	    void RW_IN_Init(in_state_t *in_state_p);
+	    void RW_IN_Shutdown(void);
+	    void RW_IN_Commands (void);
+	    void RW_IN_Move (usercmd_t *cmd);
+	    void RW_IN_Frame (void);
+	    void RW_IN_Activate(void);
+
+	    RW_IN_Init_fp = RW_IN_Init;
+	    RW_IN_Shutdown_fp = RW_IN_Shutdown;
+	    RW_IN_Activate_fp = RW_IN_Activate;
+	    RW_IN_Commands_fp = RW_IN_Commands;
+	    RW_IN_Move_fp = RW_IN_Move;
+	    RW_IN_Frame_fp = RW_IN_Frame;
+	}
+#endif
+
+	if ( re.Init( 0, 0 ) == -1 )
+	{
+		re.Shutdown();
+		VID_FreeReflib ();
+		return false;
+	}
+
+	// give up root now
+	setreuid(getuid(), getuid());
+	setegid(getgid());
+
+	/* Init KBD */
+#ifndef REF_HARD_LINKED
+	if ((KBD_Init_fp = dlsym(reflib_library, "KBD_Init")) == NULL ||
+		(KBD_Update_fp = dlsym(reflib_library, "KBD_Update")) == NULL ||
+		(KBD_Close_fp = dlsym(reflib_library, "KBD_Close")) == NULL)
+		Sys_Error("No KBD functions in REF.\n");
+#else
+	{
+		void KBD_Init(void);
+		void KBD_Update(void);
+		void KBD_Close(void);
+
+		KBD_Init_fp = KBD_Init;
+		KBD_Update_fp = KBD_Update;
+		KBD_Close_fp = KBD_Close;
+	}
+#endif
+	KBD_Init_fp(Do_Key_Event);
+	Real_IN_Init();
+
+	Com_Printf( "------------------------------------\n");
+	reflib_active = true;
+	return true;
+}
+
+/*
+============
+VID_CheckChanges
+
+This function gets called once just before drawing each frame, and it's sole purpose in life
+is to check to see if any of the video mode parameters have changed, and if they have to 
+update the rendering DLL and/or video mode to match.
+============
+*/
+void VID_CheckChanges (void)
+{
+	char name[100];
+	cvar_t *sw_mode;
+
+	if ( vid_ref->modified )
+	{
+		S_StopAllSounds();
+	}
+
+	while (vid_ref->modified)
+	{
+		/*
+		** refresh has changed
+		*/
+		vid_ref->modified = false;
+		vid_fullscreen->modified = true;
+		cl.refresh_prepped = false;
+		cls.disable_screen = true;
+
+		sprintf( name, "ref_%s.so", vid_ref->string );
+		if ( !VID_LoadRefresh( name ) )
+		{
+		        if ( strcmp (vid_ref->string, "soft") == 0 ) {
+			        Com_Printf("Refresh failed\n");
+				sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+				if (sw_mode->value != 0) {
+				        Com_Printf("Trying mode 0\n");
+					Cvar_SetValue("sw_mode", 0);
+					if ( !VID_LoadRefresh( name ) )
+						Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+				} else
+					Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+			}
+
+			Cvar_Set( "vid_ref", "soft" );
+
+			/*
+			** drop the console if we fail to load a refresh
+			*/
+			if ( cls.key_dest != key_console )
+			{
+				Con_ToggleConsole_f();
+			}
+		}
+		cls.disable_screen = false;
+	}
+
+}
+
+/*
+============
+VID_Init
+============
+*/
+void VID_Init (void)
+{
+	/* Create the video variables so we know how to start the graphics drivers */
+        vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
+	vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
+	vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
+	vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
+	vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
+
+	/* Add some console commands that we want to handle */
+	Cmd_AddCommand ("vid_restart", VID_Restart_f);
+
+	/* Disable the 3Dfx splash screen */
+	putenv("FX_GLIDE_NO_SPLASH=0");
+		
+	/* Start the graphics mode and load refresh DLL */
+	VID_CheckChanges();
+}
+
+/*
+============
+VID_Shutdown
+============
+*/
+void VID_Shutdown (void)
+{
+	if ( reflib_active )
+	{
+		if (KBD_Close_fp)
+			KBD_Close_fp();
+		if (RW_IN_Shutdown_fp)
+			RW_IN_Shutdown_fp();
+		KBD_Close_fp = NULL;
+		RW_IN_Shutdown_fp = NULL;
+		re.Shutdown ();
+		VID_FreeReflib ();
+	}
+}
+
+
+/*****************************************************************************/
+/* INPUT                                                                     */
+/*****************************************************************************/
+
+cvar_t	*in_joystick;
+
+// This if fake, it's acutally done by the Refresh load
+void IN_Init (void)
+{
+	in_joystick	= Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
+}
+
+void Real_IN_Init (void)
+{
+	if (RW_IN_Init_fp)
+		RW_IN_Init_fp(&in_state);
+}
+
+void IN_Shutdown (void)
+{
+	if (RW_IN_Shutdown_fp)
+		RW_IN_Shutdown_fp();
+}
+
+void IN_Commands (void)
+{
+	if (RW_IN_Commands_fp)
+		RW_IN_Commands_fp();
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+	if (RW_IN_Move_fp)
+		RW_IN_Move_fp(cmd);
+}
+
+void IN_Frame (void)
+{
+	if (RW_IN_Frame_fp)
+		RW_IN_Frame_fp();
+}
+
+void IN_Activate (qboolean active)
+{
+	if (RW_IN_Activate_fp)
+		RW_IN_Activate_fp(active);
+}
+
+void Do_Key_Event(int key, qboolean down)
+{
+	Key_Event(key, down, Sys_Milliseconds());
+}
+
--- /dev/null
+++ b/joystick.txt
@@ -1,0 +1,226 @@
+Title: Description of Windows 95 Quake 2 support for DirectInput devices such as:
+	standard joysticks
+	FPgaming Assassin 3D		www.fpgaming.com
+	Logitech WingMan Warrior	www.logitech.com
+        Mad Catz Panther                www.madcatz.com
+	Mad Catz Panther XL		www.madcatz.com
+	SpaceTec IMC SpaceOrb 360	www.spacetec.com
+File: JOYSTICK.TXT
+Revision History:
+	02/21/97  JCB  Quake 1:  Created by FPgaming, Inc. (www.fpgaming.com) -- Creators of the Assassin 3D.
+        03/12/97  id   Quake 1:  Joysticks are disabled by default now.
+        10/28/97  JCB  Quake 2:  Added up/down axis control for SpaceOrb 360 users, changed names to joy_* and changed 'joystick to 'in_joystick'.
+Overview:
+The input device support in Quake 2 is designed to take full advantage of your DirectInput device.  Standard joysticks, digital joysticks and new advanced controllers are all supported.
+
+
+Standard Joystick Directions:
+1.  Verify your joystick or game controller is selected in the Joystick (or Game Controllers) control panel applet.
+2.  Verify your device has been calibrated and tested.
+3.  Launch Quake 2 (quake2.exe).
+4.  Type 'in_joystick 1' at the console to enable your joystick (only needs to by typed in one time).
+From then on, just launch Quake 2.
+
+
+Advanced Controller Directions:
+1.  Verify your joystick or game controller is selected in the Joystick (or Game Controllers) control panel applet.
+2.  Verify your device has been calibrated and tested.
+3.  Get the configuration file for your controller from your manufacturer's website or copy from the selections below.
+4.  Place the configuration file in your quake2\baseq2 directory.
+6.  Launch Quake 2 (quake2.exe).
+7.  Type 'exec <configuration file name here>' at the console to enable your advanced controller each time you launch Quake 2.
+Optionally you can:
+Create or modify quake2\baseq2\autoexec.cfg to include an exec to your configuration file (i.e. 'exec adva3d.cfg').  This will automatically load your configuration file each time you launch Quake 2.
+From then on, just launch Quake 2.
+  
+
+Details:
+(This may be more information than you ever wanted to know.)
+Standard Joystick Support
+The standard joystick support has been enhanced to provide the following:
+1. proportional movement (the farther you move the stick, the faster you move) 
+2. support for up to 32 buttons (JOY1-JOY4 and AUX5-AUX32)
+3. sensitivity setting for each control (allows tuning and inverting the control direction)
+4. dead-zone setting for each control
+
+The default joystick setting is for joystick left/right movement to control turning and for joystick forward/backward movement to control moving forward/backward.  For optional strafing, add the 'sidestep' feature to one of your buttons (via the Customize menu).  For optional looking, add the 'mouse look' feature to one of your buttons (also via the Customize menu).  
+
+Additionally, there are several features that you can set from the Options menu.  'Always Run' allows you change your maximum speed from walking to running.  'Invert Mouse' allows you to change the direction the joystick has to move to when looking up and down.  'Lookspring' enables automatic look-forward-when-moving.  And, 'Lookstrafe' automatically enables strafing when the 'mouse look' button is pressed.
+
+The following variables control your sensititivity settings:
+	joy_forwardsensitivity - controls the ramp-up speed for moving forward and backward
+	joy_sidesensitivity - controls the ramp-up speed for moving side to side
+	joy_upsensitivity - controls the ramp-up speed for moving up and down
+	joy_pitchsensitivity - controls the speed that you look up and down
+	joy_yawsensitivity - controls the speed that you look left to right
+You can set the sensitivity settings to negative numbers.  This inverts the direction of movement for the control.  The default sensitivity settings are 1 (or -1).  There is no limit on the range; whatever feels good.
+
+The following variables control your threshold settings:
+	joy_forwardthreshold - controls the dead-zone for moving forward and backward
+	joy_sidethreshold - controls the dead-zone for moving side to side
+	joy_upthreshold - controls the dead-zone for moving up and down
+	joy_pitchthreshold - controls the dead-zone for looking up and down
+	joy_yawthreshold - controls the dead-zone for looking left and right
+The threshold settings allow you to control your dead-zone (or no-movement zone).  The default threshold settings are .15 (meaning 15% of the full-range).  The range of the threshold settings is from 0 to 1.  Troublesome analog joysticks may need a larger number (like .2).  Premium joysticks can use a smaller number (like .1).
+
+The joystick sensitivity settings and the threshold settings are not saved after you quit your game as inadvertent settings can really hose your control.  If you want to keep any changes, add them into your autoexec.cfg file or add an 'exec' call to your configuration file.
+
+If your joystick has a POV hat, the buttons are mapped to AUX29-AUX32.  So, you get 8 buttons with the Logitech WingMan Extreme and 12 buttons with the Microsoft SideWinder 3D Pro, etc.
+
+
+Advanced Controller Support
+The following features have been added:
+1. support for all 6 axes (X, Y, Z, R, U, V)
+2. mapping of any axis to any control (Forward, Look, Side, Turn, Up)
+3. proportional movement for all controls
+4. sensitivity setting for any control (allows tuning and inverting the control direction)
+5. threshold setting for any control (allows dead-zone setting)
+6. support for absolute controls (like joysticks) and relative controls (like trackballs)
+7. support for up to 32 buttons (JOY1-JOY4 and AUX5-AUX32)
+
+******************************************************************************
+NOTE:  The information below is for game controller companies to integrate their device and for anyone wanting to create a custom setup.
+
+In addition to the above new variables, there are six more for axis mapping.  These are:
+	joy_advaxisx - controls mapping of DirectInput axis X (typically joystick left and right)
+	joy_advaxisy - controls mapping of DirectInput axis Y (typically joystick forward and backward)
+	joy_advaxisz - controls mapping of DirectInput axis Z (typically joystick throttle)
+	joy_advaxisr - controls mapping of DirectInput axis R (typically joystick rudder)
+        joy_advaxisu - controls mapping of DirectInput axis U (custom axis - Assassin 3D trackball left and right and SpaceOrb roll)
+	joy_advaxisv - controls mapping of DirectInput axis V (custom axis - Assassin 3D trackball forward and backward and SpaceOrb yaw)
+Each joy_advaxis variable can be set to the following controls:
+	0 = Axis not used
+	1 = Axis is for forward and backward movement
+	2 = Axis is for looking up and down (pitch)
+	3 = Axis is for side to side movement
+	4 = Axis is for turning left and right (yaw)
+	5 = Axis is for up and down movement
+Additionally, each axis can be designated as an absolute axis (like a joystick) or a relative axis (like the FPgaming trackball).  Absolute axes are defined as having a stopping position whereas relative axes don't have a stopping position and just go around and around.  To designate an axis as a relative axis, add 16 to the above control number.  For example, to set the Assassin 3D's axis U to be looking left and right, type 'joyadvaxisu 20'.  As another example, to make your rudder pedals contol turning left and right, type 'joyadvaxisr 4'.  It's a bit complicated, but only needs to be done once.
+
+The advanced axes variables will not have any effect until joyadvanced is set to 1.  Additionally, any changes to the to the axes will not take effect until the joyadvancedupdate command is executed.  So, the procedure for creating an advanced mapping is:
+1.  set 'joy_advanced 1'
+2.  make any desired mapping changes
+3.  make any desired sensitivity changes
+4.  make any desired threshold changes
+3.  call 'joy_advancedupdate'
+
+Here is the config file for the FPgaming Assassin 3D:
+// ADVA3D.CFG
+// Revision 2.0 -- refer to www.fpgaming.com for updates
+joy_name "FPgaming Assassin 3D"
++mlook
+in_joystick 1
+joy_advanced 1
+joy_advaxisx 3
+joy_advaxisy 1
+joy_advaxisz 0
+joy_advaxisr 0
+joy_advaxisu 20
+joy_advaxisv 18
+joy_forwardsensitivity -1.0
+joy_sidesensitivity 1.0
+joy_upsensitivity 1.0
+joy_pitchsensitivity -0.25
+joy_yawsensitivity -0.5
+joy_forwardthreshold 0.15
+joy_sidethreshold 0.15
+joy_upthreshold 0.15
+joy_yawthreshold 0.0
+joy_pitchthreshold 0.0
+joy_advancedupdate
+
+Here is a config file for the Mad Catz Panther and Mad Catz Panther XL:
+// ADVPNTHR.CFG
+// Revision 2.0 -- refer to www.madcatz.com for updates
+joy_name "Mad Catz Panther/Panther XL"
++mlook
+in_joystick 1
+joy_advanced 1
+joy_advaxisx 3
+joy_advaxisy 1
+joy_advaxisz 0
+joy_advaxisr 0
+joy_advaxisu 20
+joy_advaxisv 18
+joy_forwardsensitivity -1.0
+joy_sidesensitivity 1.0
+joy_upsensitivity 1.0
+joy_pitchsensitivity -0.25
+joy_yawsensitivity -0.5
+joy_forwardthreshold 0.15
+joy_sidethreshold 0.15
+joy_upthreshold 0.15
+joy_yawthreshold 0.0
+joy_pitchthreshold 0.0
+joy_advancedupdate
+
+Here is a config file for the Logitech WingMan Warrior:
+// ADVWW.CFG
+// Revision 0.2 -- refer to www.logitech.com for updates
+joy_name "Logitech WingMan Warrior"
+in_joystick 1
+joy_advanced 1
+joy_advaxisx 3
+joy_advaxisy 1
+joy_advaxisz 0
+joy_advaxisr 4
+joy_advaxisu 0
+joy_advaxisv 0
+joy_forwardsensitivity -1.0
+joy_sidesensitivity 1.0
+joy_upsensitivity 1.0
+joy_pitchsensitivity 0.0
+joy_yawsensitivity -3.0
+joy_forwardthreshold 0.15
+joy_sidethreshold 0.15
+joy_upthreshold 0.15
+joy_pitchthreshold 0.0
+joy_yawthreshold 0.0
+joy_advancedupdate
+
+Here is a config file for the SpaceTec IMC SpaceOrb 360:
+// ADVSPORB.CFG
+// Revision 0.2 -- refer to www.spacetec.com for updates
+joy_name "SpaceTec IMC SpaceOrb 360"
++mlook
+in_joystick 1
+joy_advanced 1
+joy_advaxisx 3
+joy_advaxisy 0
+joy_advaxisz 1
+joy_advaxisr 2
+joy_advaxisu 4
+joy_advaxisv 5
+joy_forwardsensitivity 2.5
+joy_sidesensitivity 2.0
+joy_upsensitivity -2.0
+joy_pitchsensitivity 2.0
+joy_yawsensitivity 5.0
+joy_forwardthreshold 0.0
+joy_sidethreshold 0.0
+joy_upthreshold 0.15
+joy_pitchthreshold 0.1
+joy_yawthreshold 0.0
+joy_advancedupdate
+
+Here is a config file for making your joystick operate looking around and strafing, your rudder pedals control turning left and right and throttle control moving forward and backward:
+joy_name "Joystick, Rudder & Throttle"
+in_joystick 1
+joy_advanced 1
+joy_advaxisx 3
+joy_advaxisy 2
+joy_advaxisz 1
+joy_advaxisr 4
+joy_advaxisu 0
+joy_advaxisv 0
+joy_forwardsensitivity -1.0
+joy_sidesensitivity -1.0
+joy_upsensitivity 1.0
+joy_pitchsensitivity 1.0
+joy_yawsensitivity -1.0
+joy_forwardthreshold 0.15
+joy_sidethreshold 0.15
+joy_upthreshold 0.15
+joy_pitchthreshold 0.15
+joy_yawthreshold 0.15
+joy_advancedupdate
--- /dev/null
+++ b/linux/Makefile.AXP
@@ -1,0 +1,716 @@
+#
+# Quake2 Makefile for Solaris
+#
+# Nov '97 by Zoid <[email protected]>
+#
+# ELF only
+#
+
+ARCH=axp
+
+MOUNT_DIR=/chest/Quake2/code
+
+BUILD_DEBUG_DIR=debug$(ARCH)
+BUILD_RELEASE_DIR=release$(ARCH)
+CLIENT_DIR=$(MOUNT_DIR)/client
+SERVER_DIR=$(MOUNT_DIR)/server
+COMMON_DIR=$(MOUNT_DIR)/qcommon
+LINUX_DIR=$(MOUNT_DIR)/linux
+GAME_DIR=$(MOUNT_DIR)/game
+CTF_DIR=$(MOUNT_DIR)/ctf
+XATRIX_DIR=$(MOUNT_DIR)/xatrix
+NULL_DIR=$(MOUNT_DIR)/null
+
+CC=gcc
+BASE_CFLAGS=-Dstricmp=strcasecmp -DC_ONLY -DDEDICATED_ONLY
+RELEASE_CFLAGS=$(BASE_CFLAGS) -ffast-math -funroll-loops \
+	-fomit-frame-pointer -fexpensive-optimizations
+DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+LDFLAGS=-ldl -lm
+XCFLAGS=
+
+SHLIBEXT=so
+
+SHLIBCFLAGS=-fPIC
+SHLIBLDFLAGS=-shared
+
+DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
+DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+
+#############################################################################
+# SETUP AND BUILD
+#############################################################################
+
+TARGETS=$(BUILDDIR)/q2ded \
+	$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT)
+
+build_debug:
+	@-mkdir $(BUILD_DEBUG_DIR) \
+		$(BUILD_DEBUG_DIR)/client \
+		$(BUILD_DEBUG_DIR)/game \
+		$(BUILD_DEBUG_DIR)/ctf \
+		$(BUILD_DEBUG_DIR)/xatrix
+	$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+build_release:
+	@-mkdir $(BUILD_RELEASE_DIR) \
+		$(BUILD_RELEASE_DIR)/client \
+		$(BUILD_RELEASE_DIR)/game \
+		$(BUILD_RELEASE_DIR)/ctf \
+		$(BUILD_RELEASE_DIR)/xatrix
+	$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
+
+all: build_debug build_release
+
+targets: $(TARGETS)
+
+#############################################################################
+# CLIENT/SERVER
+#############################################################################
+
+QUAKE2_OBJS = \
+	\
+	$(BUILDDIR)/client/cmd.o \
+	$(BUILDDIR)/client/cmodel.o \
+	$(BUILDDIR)/client/common.o \
+	$(BUILDDIR)/client/crc.o \
+	$(BUILDDIR)/client/cvar.o \
+	$(BUILDDIR)/client/files.o \
+	$(BUILDDIR)/client/md4.o \
+	$(BUILDDIR)/client/net_chan.o \
+	\
+	$(BUILDDIR)/client/sv_ccmds.o \
+	$(BUILDDIR)/client/sv_ents.o \
+	$(BUILDDIR)/client/sv_game.o \
+	$(BUILDDIR)/client/sv_init.o \
+	$(BUILDDIR)/client/sv_main.o \
+	$(BUILDDIR)/client/sv_send.o \
+	$(BUILDDIR)/client/sv_user.o \
+	$(BUILDDIR)/client/sv_world.o \
+	\
+	$(BUILDDIR)/client/q_shlinux.o \
+	$(BUILDDIR)/client/sys_linux.o \
+	$(BUILDDIR)/client/glob.o \
+	$(BUILDDIR)/client/net_udp.o \
+	\
+	$(BUILDDIR)/client/q_shared.o \
+	$(BUILDDIR)/client/pmove.o \
+	\
+	$(BUILDDIR)/client/cl_null.o \
+	$(BUILDDIR)/client/cd_null.o
+
+$(BUILDDIR)/q2ded : $(QUAKE2_OBJS)
+	$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(LDFLAGS)
+
+$(BUILDDIR)/client/cmd.o :        $(COMMON_DIR)/cmd.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cmodel.o :     $(COMMON_DIR)/cmodel.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/common.o :     $(COMMON_DIR)/common.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/crc.o :        $(COMMON_DIR)/crc.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cvar.o :       $(COMMON_DIR)/cvar.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/files.o :      $(COMMON_DIR)/files.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/md4.o :        $(COMMON_DIR)/md4.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_chan.o :   $(COMMON_DIR)/net_chan.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shared.o :   $(GAME_DIR)/q_shared.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/pmove.o :      $(COMMON_DIR)/pmove.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ccmds.o :   $(SERVER_DIR)/sv_ccmds.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ents.o :    $(SERVER_DIR)/sv_ents.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_game.o :    $(SERVER_DIR)/sv_game.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_init.o :    $(SERVER_DIR)/sv_init.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_main.o :    $(SERVER_DIR)/sv_main.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_send.o :    $(SERVER_DIR)/sv_send.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_user.o :    $(SERVER_DIR)/sv_user.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_world.o :   $(SERVER_DIR)/sv_world.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shlinux.o :  $(LINUX_DIR)/q_shlinux.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sys_linux.o :  $(LINUX_DIR)/sys_linux.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/glob.o :       $(LINUX_DIR)/glob.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_udp.o :    $(LINUX_DIR)/net_udp.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cd_null.o     : $(NULL_DIR)/cd_null.c    
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_null.o     : $(NULL_DIR)/cl_null.c    
+	$(DO_CC)
+
+#############################################################################
+# GAME
+#############################################################################
+
+GAME_OBJS = \
+	$(BUILDDIR)/game/g_ai.o \
+	$(BUILDDIR)/game/p_client.o \
+	$(BUILDDIR)/game/g_cmds.o \
+	$(BUILDDIR)/game/g_svcmds.o \
+	$(BUILDDIR)/game/g_combat.o \
+	$(BUILDDIR)/game/g_func.o \
+	$(BUILDDIR)/game/g_items.o \
+	$(BUILDDIR)/game/g_main.o \
+	$(BUILDDIR)/game/g_misc.o \
+	$(BUILDDIR)/game/g_monster.o \
+	$(BUILDDIR)/game/g_phys.o \
+	$(BUILDDIR)/game/g_save.o \
+	$(BUILDDIR)/game/g_spawn.o \
+	$(BUILDDIR)/game/g_target.o \
+	$(BUILDDIR)/game/g_trigger.o \
+	$(BUILDDIR)/game/g_turret.o \
+	$(BUILDDIR)/game/g_utils.o \
+	$(BUILDDIR)/game/g_weapon.o \
+	$(BUILDDIR)/game/m_actor.o \
+	$(BUILDDIR)/game/m_berserk.o \
+	$(BUILDDIR)/game/m_boss2.o \
+	$(BUILDDIR)/game/m_boss3.o \
+	$(BUILDDIR)/game/m_boss31.o \
+	$(BUILDDIR)/game/m_boss32.o \
+	$(BUILDDIR)/game/m_brain.o \
+	$(BUILDDIR)/game/m_chick.o \
+	$(BUILDDIR)/game/m_flipper.o \
+	$(BUILDDIR)/game/m_float.o \
+	$(BUILDDIR)/game/m_flyer.o \
+	$(BUILDDIR)/game/m_gladiator.o \
+	$(BUILDDIR)/game/m_gunner.o \
+	$(BUILDDIR)/game/m_hover.o \
+	$(BUILDDIR)/game/m_infantry.o \
+	$(BUILDDIR)/game/m_insane.o \
+	$(BUILDDIR)/game/m_medic.o \
+	$(BUILDDIR)/game/m_move.o \
+	$(BUILDDIR)/game/m_mutant.o \
+	$(BUILDDIR)/game/m_parasite.o \
+	$(BUILDDIR)/game/m_soldier.o \
+	$(BUILDDIR)/game/m_supertank.o \
+	$(BUILDDIR)/game/m_tank.o \
+	$(BUILDDIR)/game/p_hud.o \
+	$(BUILDDIR)/game/p_trail.o \
+	$(BUILDDIR)/game/p_view.o \
+	$(BUILDDIR)/game/p_weapon.o \
+	$(BUILDDIR)/game/q_shared.o \
+	$(BUILDDIR)/game/m_flash.o
+
+$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
+
+$(BUILDDIR)/game/g_ai.o :        $(GAME_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_client.o :    $(GAME_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_cmds.o :      $(GAME_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_svcmds.o :    $(GAME_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_combat.o :    $(GAME_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_func.o :      $(GAME_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_items.o :     $(GAME_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_main.o :      $(GAME_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_misc.o :      $(GAME_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_monster.o :   $(GAME_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_phys.o :      $(GAME_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_save.o :      $(GAME_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_spawn.o :     $(GAME_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_target.o :    $(GAME_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_trigger.o :   $(GAME_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_turret.o :    $(GAME_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_utils.o :     $(GAME_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_weapon.o :    $(GAME_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_actor.o :     $(GAME_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_berserk.o :   $(GAME_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss2.o :     $(GAME_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss3.o :     $(GAME_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss31.o :     $(GAME_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss32.o :     $(GAME_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_brain.o :     $(GAME_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_chick.o :     $(GAME_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flipper.o :   $(GAME_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_float.o :     $(GAME_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flyer.o :     $(GAME_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gladiator.o : $(GAME_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gunner.o :    $(GAME_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_hover.o :     $(GAME_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_infantry.o :  $(GAME_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_insane.o :    $(GAME_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_medic.o :     $(GAME_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_move.o :      $(GAME_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_mutant.o :    $(GAME_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_parasite.o :  $(GAME_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_soldier.o :   $(GAME_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_supertank.o : $(GAME_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_tank.o :      $(GAME_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_hud.o :       $(GAME_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_trail.o :     $(GAME_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_view.o :      $(GAME_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_weapon.o :    $(GAME_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/q_shared.o :    $(GAME_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flash.o :     $(GAME_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# CTF
+#############################################################################
+
+CTF_OBJS = \
+	$(BUILDDIR)/ctf/g_ai.o \
+	$(BUILDDIR)/ctf/g_chase.o \
+	$(BUILDDIR)/ctf/g_cmds.o \
+	$(BUILDDIR)/ctf/g_combat.o \
+	$(BUILDDIR)/ctf/g_ctf.o \
+	$(BUILDDIR)/ctf/g_func.o \
+	$(BUILDDIR)/ctf/g_items.o \
+	$(BUILDDIR)/ctf/g_main.o \
+	$(BUILDDIR)/ctf/g_misc.o \
+	$(BUILDDIR)/ctf/g_monster.o \
+	$(BUILDDIR)/ctf/g_phys.o \
+	$(BUILDDIR)/ctf/g_save.o \
+	$(BUILDDIR)/ctf/g_spawn.o \
+	$(BUILDDIR)/ctf/g_svcmds.o \
+	$(BUILDDIR)/ctf/g_target.o \
+	$(BUILDDIR)/ctf/g_trigger.o \
+	$(BUILDDIR)/ctf/g_utils.o \
+	$(BUILDDIR)/ctf/g_weapon.o \
+	$(BUILDDIR)/ctf/m_move.o \
+	$(BUILDDIR)/ctf/p_client.o \
+	$(BUILDDIR)/ctf/p_hud.o \
+	$(BUILDDIR)/ctf/p_menu.o \
+	$(BUILDDIR)/ctf/p_trail.o \
+	$(BUILDDIR)/ctf/p_view.o \
+	$(BUILDDIR)/ctf/p_weapon.o \
+	$(BUILDDIR)/ctf/q_shared.o
+
+$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) : $(CTF_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CTF_OBJS)
+
+$(BUILDDIR)/ctf/g_ai.o :       $(CTF_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_chase.o :    $(CTF_DIR)/g_chase.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_cmds.o :     $(CTF_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_combat.o :   $(CTF_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_ctf.o :      $(CTF_DIR)/g_ctf.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_func.o :     $(CTF_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_items.o :    $(CTF_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_main.o :     $(CTF_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_misc.o :     $(CTF_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_monster.o :  $(CTF_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_phys.o :     $(CTF_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_save.o :     $(CTF_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_spawn.o :    $(CTF_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_svcmds.o :   $(CTF_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_target.o :   $(CTF_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_trigger.o :  $(CTF_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_utils.o :    $(CTF_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_weapon.o :   $(CTF_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/m_move.o :     $(CTF_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_client.o :   $(CTF_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_hud.o :      $(CTF_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_menu.o :     $(CTF_DIR)/p_menu.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_trail.o :    $(CTF_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_view.o :     $(CTF_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_weapon.o :   $(CTF_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/q_shared.o :   $(CTF_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# XATRIX
+#############################################################################
+
+XATRIX_OBJS = \
+	$(BUILDDIR)/xatrix/g_ai.o \
+	$(BUILDDIR)/xatrix/g_cmds.o \
+	$(BUILDDIR)/xatrix/g_combat.o \
+	$(BUILDDIR)/xatrix/g_func.o \
+	$(BUILDDIR)/xatrix/g_items.o \
+	$(BUILDDIR)/xatrix/g_main.o \
+	$(BUILDDIR)/xatrix/g_misc.o \
+	$(BUILDDIR)/xatrix/g_monster.o \
+	$(BUILDDIR)/xatrix/g_phys.o \
+	$(BUILDDIR)/xatrix/g_save.o \
+	$(BUILDDIR)/xatrix/g_spawn.o \
+	$(BUILDDIR)/xatrix/g_svcmds.o \
+	$(BUILDDIR)/xatrix/g_target.o \
+	$(BUILDDIR)/xatrix/g_trigger.o \
+	$(BUILDDIR)/xatrix/g_turret.o \
+	$(BUILDDIR)/xatrix/g_utils.o \
+	$(BUILDDIR)/xatrix/g_weapon.o \
+	$(BUILDDIR)/xatrix/m_actor.o \
+	$(BUILDDIR)/xatrix/m_berserk.o \
+	$(BUILDDIR)/xatrix/m_boss2.o \
+	$(BUILDDIR)/xatrix/m_boss3.o \
+	$(BUILDDIR)/xatrix/m_boss31.o \
+	$(BUILDDIR)/xatrix/m_boss32.o \
+	$(BUILDDIR)/xatrix/m_boss5.o \
+	$(BUILDDIR)/xatrix/m_brain.o \
+	$(BUILDDIR)/xatrix/m_chick.o \
+	$(BUILDDIR)/xatrix/m_fixbot.o \
+	$(BUILDDIR)/xatrix/m_flash.o \
+	$(BUILDDIR)/xatrix/m_flipper.o \
+	$(BUILDDIR)/xatrix/m_float.o \
+	$(BUILDDIR)/xatrix/m_flyer.o \
+	$(BUILDDIR)/xatrix/m_gekk.o \
+	$(BUILDDIR)/xatrix/m_gladb.o \
+	$(BUILDDIR)/xatrix/m_gladiator.o \
+	$(BUILDDIR)/xatrix/m_gunner.o \
+	$(BUILDDIR)/xatrix/m_hover.o \
+	$(BUILDDIR)/xatrix/m_infantry.o \
+	$(BUILDDIR)/xatrix/m_insane.o \
+	$(BUILDDIR)/xatrix/m_medic.o \
+	$(BUILDDIR)/xatrix/m_move.o \
+	$(BUILDDIR)/xatrix/m_mutant.o \
+	$(BUILDDIR)/xatrix/m_parasite.o \
+	$(BUILDDIR)/xatrix/m_soldier.o \
+	$(BUILDDIR)/xatrix/m_supertank.o \
+	$(BUILDDIR)/xatrix/m_tank.o \
+	$(BUILDDIR)/xatrix/p_client.o \
+	$(BUILDDIR)/xatrix/p_hud.o \
+	$(BUILDDIR)/xatrix/p_trail.o \
+	$(BUILDDIR)/xatrix/p_view.o \
+	$(BUILDDIR)/xatrix/p_weapon.o \
+	$(BUILDDIR)/xatrix/q_shared.o
+
+$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT) : $(XATRIX_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(XATRIX_OBJS)
+
+$(BUILDDIR)/xatrix/g_ai.o :        $(XATRIX_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_cmds.o :      $(XATRIX_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_combat.o :    $(XATRIX_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_func.o :      $(XATRIX_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_items.o :     $(XATRIX_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_main.o :      $(XATRIX_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_misc.o :      $(XATRIX_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_monster.o :   $(XATRIX_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_phys.o :      $(XATRIX_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_save.o :      $(XATRIX_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_spawn.o :     $(XATRIX_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_svcmds.o :    $(XATRIX_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_target.o :    $(XATRIX_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_trigger.o :   $(XATRIX_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_turret.o :    $(XATRIX_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_utils.o :     $(XATRIX_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_weapon.o :    $(XATRIX_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_actor.o :     $(XATRIX_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_berserk.o :   $(XATRIX_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss2.o :     $(XATRIX_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss3.o :     $(XATRIX_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss31.o :    $(XATRIX_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss32.o :    $(XATRIX_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss5.o :     $(XATRIX_DIR)/m_boss5.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_brain.o :     $(XATRIX_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_chick.o :     $(XATRIX_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_fixbot.o :    $(XATRIX_DIR)/m_fixbot.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flash.o :     $(XATRIX_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flipper.o :   $(XATRIX_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_float.o :     $(XATRIX_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flyer.o :     $(XATRIX_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gekk.o :      $(XATRIX_DIR)/m_gekk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gladb.o :     $(XATRIX_DIR)/m_gladb.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gladiator.o : $(XATRIX_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gunner.o :    $(XATRIX_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_hover.o :     $(XATRIX_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_infantry.o :  $(XATRIX_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_insane.o :    $(XATRIX_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_medic.o :     $(XATRIX_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_move.o :      $(XATRIX_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_mutant.o :    $(XATRIX_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_parasite.o :  $(XATRIX_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_soldier.o :   $(XATRIX_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_supertank.o : $(XATRIX_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_tank.o :      $(XATRIX_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_client.o :    $(XATRIX_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_hud.o :       $(XATRIX_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_trail.o :     $(XATRIX_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_view.o :      $(XATRIX_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_weapon.o :    $(XATRIX_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/q_shared.o :    $(XATRIX_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean: clean-debug clean-release
+
+clean-debug:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean-release:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean2:
+	-rm -f $(QUAKE2_OBJS) $(GAME_OBJS) $(CTF_OBJS) $(XATRIX_OBJS)
+
--- /dev/null
+++ b/linux/Makefile.i386
@@ -1,0 +1,1085 @@
+#
+# Quake2 Makefile for Linux 2.0
+#
+# Nov '97 by Zoid <[email protected]>
+#
+# ELF only
+#
+
+ifneq (,$(findstring alpha,$(shell uname -m)))
+ARCH=axp
+else
+ARCH=i386
+endif
+
+MOUNT_DIR=/grog/NewWork/Quake2/code
+
+BUILD_DEBUG_DIR=debug$(ARCH)
+BUILD_RELEASE_DIR=release$(ARCH)
+CLIENT_DIR=$(MOUNT_DIR)/client
+SERVER_DIR=$(MOUNT_DIR)/server
+REF_SOFT_DIR=$(MOUNT_DIR)/ref_soft
+REF_GL_DIR=$(MOUNT_DIR)/ref_gl
+COMMON_DIR=$(MOUNT_DIR)/qcommon
+LINUX_DIR=$(MOUNT_DIR)/linux
+GAME_DIR=$(MOUNT_DIR)/game
+CTF_DIR=$(MOUNT_DIR)/ctf
+XATRIX_DIR=$(MOUNT_DIR)/xatrix
+
+CC=gcc
+BASE_CFLAGS=-Dstricmp=strcasecmp
+
+ifeq ($(ARCH),axp)
+RELEASE_CFLAGS=$(BASE_CFLAGS) -ffast-math -funroll-loops \
+	-fomit-frame-pointer -fexpensive-optimizations
+else
+RELEASE_CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \
+	-fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
+	-malign-jumps=2 -malign-functions=2
+endif
+
+DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+LDFLAGS=-ldl -lm
+SVGALDFLAGS=-lvga
+XLDFLAGS=-L/usr/X11R6/lib -lX11 -lXext
+XCFLAGS=
+
+GLLDFLAGS=-L/usr/local/glide/lib -L/usr/X11/lib -L/usr/local/lib \
+	-L/usr/local/src/Mesa-2.6/lib -lMesaGL -lglide2x -lX11 -lXext -lvga
+GLCFLAGS=-I/usr/local/src/Mesa-2.6/include -I/usr/local/glide/include
+
+SHLIBEXT=so
+
+SHLIBCFLAGS=-fPIC
+SHLIBLDFLAGS=-shared
+
+DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
+DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+DO_GL_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) -o $@ -c $<
+DO_AS=$(CC) $(CFLAGS) -DELF -x assembler-with-cpp -o $@ -c $<
+DO_SHLIB_AS=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -DELF -x assembler-with-cpp -o $@ -c $<
+
+#############################################################################
+# SETUP AND BUILD
+#############################################################################
+
+ifeq ($(ARCH),axp)
+TARGETS=$(BUILDDIR)/quake2 \
+	$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT)
+else
+TARGETS=$(BUILDDIR)/quake2 \
+	$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/ref_soft.$(SHLIBEXT) \
+	$(BUILDDIR)/ref_softx.$(SHLIBEXT) \
+	$(BUILDDIR)/ref_gl.$(SHLIBEXT) \
+	$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT)
+endif
+
+build_debug:
+	@-mkdir $(BUILD_DEBUG_DIR) \
+		$(BUILD_DEBUG_DIR)/client \
+		$(BUILD_DEBUG_DIR)/ref_soft \
+		$(BUILD_DEBUG_DIR)/ref_gl \
+		$(BUILD_DEBUG_DIR)/game \
+		$(BUILD_DEBUG_DIR)/ctf \
+		$(BUILD_DEBUG_DIR)/xatrix
+	$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+build_release:
+	@-mkdir $(BUILD_RELEASE_DIR) \
+		$(BUILD_RELEASE_DIR)/client \
+		$(BUILD_RELEASE_DIR)/ref_soft \
+		$(BUILD_RELEASE_DIR)/ref_gl \
+		$(BUILD_RELEASE_DIR)/game \
+		$(BUILD_RELEASE_DIR)/ctf \
+		$(BUILD_RELEASE_DIR)/xatrix
+	$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
+
+all: build_debug build_release
+
+targets: $(TARGETS)
+
+#############################################################################
+# CLIENT/SERVER
+#############################################################################
+
+QUAKE2_OBJS = \
+	$(BUILDDIR)/client/cl_cin.o \
+	$(BUILDDIR)/client/cl_ents.o \
+	$(BUILDDIR)/client/cl_fx.o \
+	$(BUILDDIR)/client/cl_input.o \
+	$(BUILDDIR)/client/cl_inv.o \
+	$(BUILDDIR)/client/cl_main.o \
+	$(BUILDDIR)/client/cl_parse.o \
+	$(BUILDDIR)/client/cl_pred.o \
+	$(BUILDDIR)/client/cl_tent.o \
+	$(BUILDDIR)/client/cl_scrn.o \
+	$(BUILDDIR)/client/cl_view.o \
+	$(BUILDDIR)/client/console.o \
+	$(BUILDDIR)/client/keys.o \
+	$(BUILDDIR)/client/menu.o \
+	$(BUILDDIR)/client/snd_dma.o \
+	$(BUILDDIR)/client/snd_mem.o \
+	$(BUILDDIR)/client/snd_mix.o \
+	$(BUILDDIR)/client/qmenu.o \
+	$(BUILDDIR)/client/m_flash.o \
+	\
+	$(BUILDDIR)/client/cmd.o \
+	$(BUILDDIR)/client/cmodel.o \
+	$(BUILDDIR)/client/common.o \
+	$(BUILDDIR)/client/crc.o \
+	$(BUILDDIR)/client/cvar.o \
+	$(BUILDDIR)/client/files.o \
+	$(BUILDDIR)/client/md4.o \
+	$(BUILDDIR)/client/net_chan.o \
+	\
+	$(BUILDDIR)/client/sv_ccmds.o \
+	$(BUILDDIR)/client/sv_ents.o \
+	$(BUILDDIR)/client/sv_game.o \
+	$(BUILDDIR)/client/sv_init.o \
+	$(BUILDDIR)/client/sv_main.o \
+	$(BUILDDIR)/client/sv_send.o \
+	$(BUILDDIR)/client/sv_user.o \
+	$(BUILDDIR)/client/sv_world.o \
+	\
+	$(BUILDDIR)/client/cd_linux.o \
+	$(BUILDDIR)/client/q_shlinux.o \
+	$(BUILDDIR)/client/vid_menu.o \
+	$(BUILDDIR)/client/vid_so.o \
+	$(BUILDDIR)/client/snd_linux.o \
+	$(BUILDDIR)/client/sys_linux.o \
+	$(BUILDDIR)/client/glob.o \
+	$(BUILDDIR)/client/net_udp.o \
+	\
+	$(BUILDDIR)/client/q_shared.o \
+	$(BUILDDIR)/client/pmove.o
+
+ifeq ($(ARCH),axp)
+QUAKE2_AS_OBJS =  #blank
+else
+QUAKE2_AS_OBJS = \
+	$(BUILDDIR)/client/snd_mixa.o
+endif
+
+$(BUILDDIR)/quake2 : $(QUAKE2_OBJS) $(QUAKE2_AS_OBJS)
+	$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(QUAKE2_AS_OBJS) $(LDFLAGS)
+
+$(BUILDDIR)/client/cl_cin.o :     $(CLIENT_DIR)/cl_cin.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_ents.o :    $(CLIENT_DIR)/cl_ents.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_fx.o :      $(CLIENT_DIR)/cl_fx.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_input.o :   $(CLIENT_DIR)/cl_input.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_inv.o :     $(CLIENT_DIR)/cl_inv.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_main.o :    $(CLIENT_DIR)/cl_main.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_parse.o :   $(CLIENT_DIR)/cl_parse.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_pred.o :    $(CLIENT_DIR)/cl_pred.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_tent.o :    $(CLIENT_DIR)/cl_tent.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_scrn.o :    $(CLIENT_DIR)/cl_scrn.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_view.o :    $(CLIENT_DIR)/cl_view.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/console.o :    $(CLIENT_DIR)/console.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/keys.o :       $(CLIENT_DIR)/keys.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/menu.o :       $(CLIENT_DIR)/menu.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_dma.o :    $(CLIENT_DIR)/snd_dma.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_mem.o :    $(CLIENT_DIR)/snd_mem.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_mix.o :    $(CLIENT_DIR)/snd_mix.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/qmenu.o :      $(CLIENT_DIR)/qmenu.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/m_flash.o :    $(GAME_DIR)/m_flash.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cmd.o :        $(COMMON_DIR)/cmd.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cmodel.o :     $(COMMON_DIR)/cmodel.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/common.o :     $(COMMON_DIR)/common.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/crc.o :        $(COMMON_DIR)/crc.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cvar.o :       $(COMMON_DIR)/cvar.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/files.o :      $(COMMON_DIR)/files.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/md4.o :        $(COMMON_DIR)/md4.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_chan.o :   $(COMMON_DIR)/net_chan.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shared.o :   $(GAME_DIR)/q_shared.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/pmove.o :      $(COMMON_DIR)/pmove.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ccmds.o :   $(SERVER_DIR)/sv_ccmds.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ents.o :    $(SERVER_DIR)/sv_ents.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_game.o :    $(SERVER_DIR)/sv_game.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_init.o :    $(SERVER_DIR)/sv_init.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_main.o :    $(SERVER_DIR)/sv_main.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_send.o :    $(SERVER_DIR)/sv_send.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_user.o :    $(SERVER_DIR)/sv_user.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_world.o :   $(SERVER_DIR)/sv_world.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cd_linux.o :   $(LINUX_DIR)/cd_linux.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shlinux.o :  $(LINUX_DIR)/q_shlinux.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/vid_menu.o :   $(LINUX_DIR)/vid_menu.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/vid_so.o :     $(LINUX_DIR)/vid_so.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_linux.o :  $(LINUX_DIR)/snd_linux.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_mixa.o :   $(LINUX_DIR)/snd_mixa.s
+	$(DO_AS)
+
+$(BUILDDIR)/client/sys_linux.o :  $(LINUX_DIR)/sys_linux.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/glob.o :       $(LINUX_DIR)/glob.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_udp.o :    $(LINUX_DIR)/net_udp.c
+	$(DO_CC)
+
+#############################################################################
+# GAME
+#############################################################################
+
+GAME_OBJS = \
+	$(BUILDDIR)/game/g_ai.o \
+	$(BUILDDIR)/game/p_client.o \
+	$(BUILDDIR)/game/g_cmds.o \
+	$(BUILDDIR)/game/g_svcmds.o \
+	$(BUILDDIR)/game/g_combat.o \
+	$(BUILDDIR)/game/g_func.o \
+	$(BUILDDIR)/game/g_items.o \
+	$(BUILDDIR)/game/g_main.o \
+	$(BUILDDIR)/game/g_misc.o \
+	$(BUILDDIR)/game/g_monster.o \
+	$(BUILDDIR)/game/g_phys.o \
+	$(BUILDDIR)/game/g_save.o \
+	$(BUILDDIR)/game/g_spawn.o \
+	$(BUILDDIR)/game/g_target.o \
+	$(BUILDDIR)/game/g_trigger.o \
+	$(BUILDDIR)/game/g_turret.o \
+	$(BUILDDIR)/game/g_utils.o \
+	$(BUILDDIR)/game/g_weapon.o \
+	$(BUILDDIR)/game/m_actor.o \
+	$(BUILDDIR)/game/m_berserk.o \
+	$(BUILDDIR)/game/m_boss2.o \
+	$(BUILDDIR)/game/m_boss3.o \
+	$(BUILDDIR)/game/m_boss31.o \
+	$(BUILDDIR)/game/m_boss32.o \
+	$(BUILDDIR)/game/m_brain.o \
+	$(BUILDDIR)/game/m_chick.o \
+	$(BUILDDIR)/game/m_flipper.o \
+	$(BUILDDIR)/game/m_float.o \
+	$(BUILDDIR)/game/m_flyer.o \
+	$(BUILDDIR)/game/m_gladiator.o \
+	$(BUILDDIR)/game/m_gunner.o \
+	$(BUILDDIR)/game/m_hover.o \
+	$(BUILDDIR)/game/m_infantry.o \
+	$(BUILDDIR)/game/m_insane.o \
+	$(BUILDDIR)/game/m_medic.o \
+	$(BUILDDIR)/game/m_move.o \
+	$(BUILDDIR)/game/m_mutant.o \
+	$(BUILDDIR)/game/m_parasite.o \
+	$(BUILDDIR)/game/m_soldier.o \
+	$(BUILDDIR)/game/m_supertank.o \
+	$(BUILDDIR)/game/m_tank.o \
+	$(BUILDDIR)/game/p_hud.o \
+	$(BUILDDIR)/game/p_trail.o \
+	$(BUILDDIR)/game/p_view.o \
+	$(BUILDDIR)/game/p_weapon.o \
+	$(BUILDDIR)/game/q_shared.o \
+	$(BUILDDIR)/game/m_flash.o
+
+$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
+
+$(BUILDDIR)/game/g_ai.o :        $(GAME_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_client.o :    $(GAME_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_cmds.o :      $(GAME_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_svcmds.o :    $(GAME_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_combat.o :    $(GAME_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_func.o :      $(GAME_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_items.o :     $(GAME_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_main.o :      $(GAME_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_misc.o :      $(GAME_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_monster.o :   $(GAME_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_phys.o :      $(GAME_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_save.o :      $(GAME_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_spawn.o :     $(GAME_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_target.o :    $(GAME_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_trigger.o :   $(GAME_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_turret.o :    $(GAME_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_utils.o :     $(GAME_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_weapon.o :    $(GAME_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_actor.o :     $(GAME_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_berserk.o :   $(GAME_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss2.o :     $(GAME_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss3.o :     $(GAME_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss31.o :     $(GAME_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss32.o :     $(GAME_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_brain.o :     $(GAME_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_chick.o :     $(GAME_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flipper.o :   $(GAME_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_float.o :     $(GAME_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flyer.o :     $(GAME_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gladiator.o : $(GAME_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gunner.o :    $(GAME_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_hover.o :     $(GAME_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_infantry.o :  $(GAME_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_insane.o :    $(GAME_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_medic.o :     $(GAME_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_move.o :      $(GAME_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_mutant.o :    $(GAME_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_parasite.o :  $(GAME_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_soldier.o :   $(GAME_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_supertank.o : $(GAME_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_tank.o :      $(GAME_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_hud.o :       $(GAME_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_trail.o :     $(GAME_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_view.o :      $(GAME_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_weapon.o :    $(GAME_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/q_shared.o :    $(GAME_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flash.o :     $(GAME_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# CTF
+#############################################################################
+
+CTF_OBJS = \
+	$(BUILDDIR)/ctf/g_ai.o \
+	$(BUILDDIR)/ctf/g_chase.o \
+	$(BUILDDIR)/ctf/g_cmds.o \
+	$(BUILDDIR)/ctf/g_combat.o \
+	$(BUILDDIR)/ctf/g_ctf.o \
+	$(BUILDDIR)/ctf/g_func.o \
+	$(BUILDDIR)/ctf/g_items.o \
+	$(BUILDDIR)/ctf/g_main.o \
+	$(BUILDDIR)/ctf/g_misc.o \
+	$(BUILDDIR)/ctf/g_monster.o \
+	$(BUILDDIR)/ctf/g_phys.o \
+	$(BUILDDIR)/ctf/g_save.o \
+	$(BUILDDIR)/ctf/g_spawn.o \
+	$(BUILDDIR)/ctf/g_svcmds.o \
+	$(BUILDDIR)/ctf/g_target.o \
+	$(BUILDDIR)/ctf/g_trigger.o \
+	$(BUILDDIR)/ctf/g_utils.o \
+	$(BUILDDIR)/ctf/g_weapon.o \
+	$(BUILDDIR)/ctf/m_move.o \
+	$(BUILDDIR)/ctf/p_client.o \
+	$(BUILDDIR)/ctf/p_hud.o \
+	$(BUILDDIR)/ctf/p_menu.o \
+	$(BUILDDIR)/ctf/p_trail.o \
+	$(BUILDDIR)/ctf/p_view.o \
+	$(BUILDDIR)/ctf/p_weapon.o \
+	$(BUILDDIR)/ctf/q_shared.o
+
+$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) : $(CTF_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CTF_OBJS)
+
+$(BUILDDIR)/ctf/g_ai.o :       $(CTF_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_chase.o :    $(CTF_DIR)/g_chase.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_cmds.o :     $(CTF_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_combat.o :   $(CTF_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_ctf.o :      $(CTF_DIR)/g_ctf.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_func.o :     $(CTF_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_items.o :    $(CTF_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_main.o :     $(CTF_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_misc.o :     $(CTF_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_monster.o :  $(CTF_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_phys.o :     $(CTF_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_save.o :     $(CTF_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_spawn.o :    $(CTF_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_svcmds.o :   $(CTF_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_target.o :   $(CTF_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_trigger.o :  $(CTF_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_utils.o :    $(CTF_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_weapon.o :   $(CTF_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/m_move.o :     $(CTF_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_client.o :   $(CTF_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_hud.o :      $(CTF_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_menu.o :     $(CTF_DIR)/p_menu.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_trail.o :    $(CTF_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_view.o :     $(CTF_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_weapon.o :   $(CTF_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/q_shared.o :   $(CTF_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# XATRIX
+#############################################################################
+
+XATRIX_OBJS = \
+	$(BUILDDIR)/xatrix/g_ai.o \
+	$(BUILDDIR)/xatrix/g_cmds.o \
+	$(BUILDDIR)/xatrix/g_combat.o \
+	$(BUILDDIR)/xatrix/g_func.o \
+	$(BUILDDIR)/xatrix/g_items.o \
+	$(BUILDDIR)/xatrix/g_main.o \
+	$(BUILDDIR)/xatrix/g_misc.o \
+	$(BUILDDIR)/xatrix/g_monster.o \
+	$(BUILDDIR)/xatrix/g_phys.o \
+	$(BUILDDIR)/xatrix/g_save.o \
+	$(BUILDDIR)/xatrix/g_spawn.o \
+	$(BUILDDIR)/xatrix/g_svcmds.o \
+	$(BUILDDIR)/xatrix/g_target.o \
+	$(BUILDDIR)/xatrix/g_trigger.o \
+	$(BUILDDIR)/xatrix/g_turret.o \
+	$(BUILDDIR)/xatrix/g_utils.o \
+	$(BUILDDIR)/xatrix/g_weapon.o \
+	$(BUILDDIR)/xatrix/m_actor.o \
+	$(BUILDDIR)/xatrix/m_berserk.o \
+	$(BUILDDIR)/xatrix/m_boss2.o \
+	$(BUILDDIR)/xatrix/m_boss3.o \
+	$(BUILDDIR)/xatrix/m_boss31.o \
+	$(BUILDDIR)/xatrix/m_boss32.o \
+	$(BUILDDIR)/xatrix/m_boss5.o \
+	$(BUILDDIR)/xatrix/m_brain.o \
+	$(BUILDDIR)/xatrix/m_chick.o \
+	$(BUILDDIR)/xatrix/m_fixbot.o \
+	$(BUILDDIR)/xatrix/m_flash.o \
+	$(BUILDDIR)/xatrix/m_flipper.o \
+	$(BUILDDIR)/xatrix/m_float.o \
+	$(BUILDDIR)/xatrix/m_flyer.o \
+	$(BUILDDIR)/xatrix/m_gekk.o \
+	$(BUILDDIR)/xatrix/m_gladb.o \
+	$(BUILDDIR)/xatrix/m_gladiator.o \
+	$(BUILDDIR)/xatrix/m_gunner.o \
+	$(BUILDDIR)/xatrix/m_hover.o \
+	$(BUILDDIR)/xatrix/m_infantry.o \
+	$(BUILDDIR)/xatrix/m_insane.o \
+	$(BUILDDIR)/xatrix/m_medic.o \
+	$(BUILDDIR)/xatrix/m_move.o \
+	$(BUILDDIR)/xatrix/m_mutant.o \
+	$(BUILDDIR)/xatrix/m_parasite.o \
+	$(BUILDDIR)/xatrix/m_soldier.o \
+	$(BUILDDIR)/xatrix/m_supertank.o \
+	$(BUILDDIR)/xatrix/m_tank.o \
+	$(BUILDDIR)/xatrix/p_client.o \
+	$(BUILDDIR)/xatrix/p_hud.o \
+	$(BUILDDIR)/xatrix/p_trail.o \
+	$(BUILDDIR)/xatrix/p_view.o \
+	$(BUILDDIR)/xatrix/p_weapon.o \
+	$(BUILDDIR)/xatrix/q_shared.o
+
+$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT) : $(XATRIX_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(XATRIX_OBJS)
+
+$(BUILDDIR)/xatrix/g_ai.o :        $(XATRIX_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_cmds.o :      $(XATRIX_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_combat.o :    $(XATRIX_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_func.o :      $(XATRIX_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_items.o :     $(XATRIX_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_main.o :      $(XATRIX_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_misc.o :      $(XATRIX_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_monster.o :   $(XATRIX_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_phys.o :      $(XATRIX_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_save.o :      $(XATRIX_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_spawn.o :     $(XATRIX_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_svcmds.o :    $(XATRIX_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_target.o :    $(XATRIX_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_trigger.o :   $(XATRIX_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_turret.o :    $(XATRIX_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_utils.o :     $(XATRIX_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_weapon.o :    $(XATRIX_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_actor.o :     $(XATRIX_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_berserk.o :   $(XATRIX_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss2.o :     $(XATRIX_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss3.o :     $(XATRIX_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss31.o :    $(XATRIX_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss32.o :    $(XATRIX_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss5.o :     $(XATRIX_DIR)/m_boss5.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_brain.o :     $(XATRIX_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_chick.o :     $(XATRIX_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_fixbot.o :    $(XATRIX_DIR)/m_fixbot.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flash.o :     $(XATRIX_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flipper.o :   $(XATRIX_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_float.o :     $(XATRIX_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flyer.o :     $(XATRIX_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gekk.o :      $(XATRIX_DIR)/m_gekk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gladb.o :     $(XATRIX_DIR)/m_gladb.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gladiator.o : $(XATRIX_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gunner.o :    $(XATRIX_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_hover.o :     $(XATRIX_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_infantry.o :  $(XATRIX_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_insane.o :    $(XATRIX_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_medic.o :     $(XATRIX_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_move.o :      $(XATRIX_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_mutant.o :    $(XATRIX_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_parasite.o :  $(XATRIX_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_soldier.o :   $(XATRIX_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_supertank.o : $(XATRIX_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_tank.o :      $(XATRIX_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_client.o :    $(XATRIX_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_hud.o :       $(XATRIX_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_trail.o :     $(XATRIX_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_view.o :      $(XATRIX_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_weapon.o :    $(XATRIX_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/q_shared.o :    $(XATRIX_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+
+#############################################################################
+# REF_SOFT
+#############################################################################
+
+REF_SOFT_OBJS = \
+	$(BUILDDIR)/ref_soft/r_aclip.o \
+	$(BUILDDIR)/ref_soft/r_alias.o \
+	$(BUILDDIR)/ref_soft/r_bsp.o \
+	$(BUILDDIR)/ref_soft/r_draw.o \
+	$(BUILDDIR)/ref_soft/r_edge.o \
+	$(BUILDDIR)/ref_soft/r_image.o \
+	$(BUILDDIR)/ref_soft/r_light.o \
+	$(BUILDDIR)/ref_soft/r_main.o \
+	$(BUILDDIR)/ref_soft/r_misc.o \
+	$(BUILDDIR)/ref_soft/r_model.o \
+	$(BUILDDIR)/ref_soft/r_part.o \
+	$(BUILDDIR)/ref_soft/r_poly.o \
+	$(BUILDDIR)/ref_soft/r_polyse.o \
+	$(BUILDDIR)/ref_soft/r_rast.o \
+	$(BUILDDIR)/ref_soft/r_scan.o \
+	$(BUILDDIR)/ref_soft/r_sprite.o \
+	$(BUILDDIR)/ref_soft/r_surf.o \
+	\
+	$(BUILDDIR)/ref_soft/r_aclipa.o \
+	$(BUILDDIR)/ref_soft/r_draw16.o \
+	$(BUILDDIR)/ref_soft/r_drawa.o \
+	$(BUILDDIR)/ref_soft/r_edgea.o \
+	$(BUILDDIR)/ref_soft/r_scana.o \
+	$(BUILDDIR)/ref_soft/r_spr8.o \
+	$(BUILDDIR)/ref_soft/r_surf8.o \
+	$(BUILDDIR)/ref_soft/math.o \
+	$(BUILDDIR)/ref_soft/d_polysa.o \
+	$(BUILDDIR)/ref_soft/r_varsa.o \
+	$(BUILDDIR)/ref_soft/sys_dosa.o \
+	\
+	$(BUILDDIR)/ref_soft/q_shared.o \
+	$(BUILDDIR)/ref_soft/q_shlinux.o \
+	$(BUILDDIR)/ref_soft/glob.o
+
+REF_SOFT_SVGA_OBJS = \
+	$(BUILDDIR)/ref_soft/rw_svgalib.o \
+	$(BUILDDIR)/ref_soft/d_copy.o \
+	$(BUILDDIR)/ref_soft/rw_in_svgalib.o
+
+REF_SOFT_X11_OBJS = \
+	$(BUILDDIR)/ref_soft/rw_x11.o
+
+$(BUILDDIR)/ref_soft.$(SHLIBEXT) : $(REF_SOFT_OBJS) $(REF_SOFT_SVGA_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(REF_SOFT_OBJS) \
+		$(REF_SOFT_SVGA_OBJS) $(SVGALDFLAGS)
+
+$(BUILDDIR)/ref_softx.$(SHLIBEXT) : $(REF_SOFT_OBJS) $(REF_SOFT_X11_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(REF_SOFT_OBJS) \
+		$(REF_SOFT_X11_OBJS) $(XLDFLAGS)
+
+$(BUILDDIR)/ref_soft/r_aclip.o :      $(REF_SOFT_DIR)/r_aclip.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_alias.o :      $(REF_SOFT_DIR)/r_alias.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_bsp.o :        $(REF_SOFT_DIR)/r_bsp.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_draw.o :       $(REF_SOFT_DIR)/r_draw.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_edge.o :       $(REF_SOFT_DIR)/r_edge.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_image.o :      $(REF_SOFT_DIR)/r_image.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_light.o :      $(REF_SOFT_DIR)/r_light.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_main.o :       $(REF_SOFT_DIR)/r_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_misc.o :       $(REF_SOFT_DIR)/r_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_model.o :      $(REF_SOFT_DIR)/r_model.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_part.o :       $(REF_SOFT_DIR)/r_part.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_poly.o :       $(REF_SOFT_DIR)/r_poly.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_polyse.o :     $(REF_SOFT_DIR)/r_polyse.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_rast.o :       $(REF_SOFT_DIR)/r_rast.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_scan.o :       $(REF_SOFT_DIR)/r_scan.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_sprite.o :     $(REF_SOFT_DIR)/r_sprite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_surf.o :       $(REF_SOFT_DIR)/r_surf.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/r_aclipa.o :     $(LINUX_DIR)/r_aclipa.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_draw16.o :     $(LINUX_DIR)/r_draw16.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_drawa.o :      $(LINUX_DIR)/r_drawa.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_edgea.o :      $(LINUX_DIR)/r_edgea.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_scana.o :      $(LINUX_DIR)/r_scana.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_spr8.o :       $(LINUX_DIR)/r_spr8.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_surf8.o :      $(LINUX_DIR)/r_surf8.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/math.o :         $(LINUX_DIR)/math.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/d_polysa.o :     $(LINUX_DIR)/d_polysa.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/r_varsa.o :      $(LINUX_DIR)/r_varsa.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/sys_dosa.o :     $(LINUX_DIR)/sys_dosa.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/q_shared.o :     $(GAME_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/q_shlinux.o :    $(LINUX_DIR)/q_shlinux.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/glob.o :         $(LINUX_DIR)/glob.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/rw_svgalib.o :   $(LINUX_DIR)/rw_svgalib.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/d_copy.o :       $(LINUX_DIR)/d_copy.s
+	$(DO_SHLIB_AS)
+
+$(BUILDDIR)/ref_soft/rw_in_svgalib.o : $(LINUX_DIR)/rw_in_svgalib.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ref_soft/rw_x11.o :       $(LINUX_DIR)/rw_x11.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# REF_GL
+#############################################################################
+
+REF_GL_OBJS = \
+	$(BUILDDIR)/ref_gl/gl_draw.o \
+	$(BUILDDIR)/ref_gl/gl_image.o \
+	$(BUILDDIR)/ref_gl/gl_light.o \
+	$(BUILDDIR)/ref_gl/gl_mesh.o \
+	$(BUILDDIR)/ref_gl/gl_model.o \
+	$(BUILDDIR)/ref_gl/gl_rmain.o \
+	$(BUILDDIR)/ref_gl/gl_rmisc.o \
+	$(BUILDDIR)/ref_gl/gl_rsurf.o \
+	$(BUILDDIR)/ref_gl/gl_warp.o \
+	\
+	$(BUILDDIR)/ref_gl/qgl_linux.o \
+	$(BUILDDIR)/ref_gl/gl_fxmesa.o \
+	$(BUILDDIR)/ref_gl/rw_in_svgalib.o \
+	$(BUILDDIR)/ref_gl/q_shared.o \
+	$(BUILDDIR)/ref_gl/q_shlinux.o \
+	$(BUILDDIR)/ref_gl/glob.o
+
+$(BUILDDIR)/ref_gl.$(SHLIBEXT) : $(REF_GL_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(REF_GL_OBJS) $(GLLDFLAGS)
+
+$(BUILDDIR)/ref_gl/gl_draw.o :        $(REF_GL_DIR)/gl_draw.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_image.o :       $(REF_GL_DIR)/gl_image.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_light.o :       $(REF_GL_DIR)/gl_light.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_mesh.o :        $(REF_GL_DIR)/gl_mesh.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_model.o :       $(REF_GL_DIR)/gl_model.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_rmain.o :       $(REF_GL_DIR)/gl_rmain.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_rmisc.o :       $(REF_GL_DIR)/gl_rmisc.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_rsurf.o :       $(REF_GL_DIR)/gl_rsurf.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_warp.o :        $(REF_GL_DIR)/gl_warp.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/qgl_linux.o :      $(LINUX_DIR)/qgl_linux.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/gl_fxmesa.o :      $(LINUX_DIR)/gl_fxmesa.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/rw_in_svgalib.o :  $(LINUX_DIR)/rw_in_svgalib.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/q_shared.o :       $(GAME_DIR)/q_shared.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/q_shlinux.o :      $(LINUX_DIR)/q_shlinux.c
+	$(DO_GL_SHLIB_CC)
+
+$(BUILDDIR)/ref_gl/glob.o :           $(LINUX_DIR)/glob.c
+	$(DO_GL_SHLIB_CC)
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean: clean-debug clean-release
+
+clean-debug:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean-release:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean2:
+	-rm -f \
+	$(QUAKE2_OBJS) \
+	$(QUAKE2_AS_OBJS) \
+	$(GAME_OBJS) \
+	$(CTF_OBJS) \
+	$(XATRIX_OBJS) \
+	$(REF_SOFT_OBJS) \
+	$(REF_SOFT_SVGA_OBJS) \
+	$(REF_SOFT_X11_OBJS) \
+	$(REF_GL_OBJS)
+
--- /dev/null
+++ b/linux/block16.h
@@ -1,0 +1,123 @@
+LEnter16_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch0:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch1:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch2:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch3:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch4:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch5:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch6:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch7:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+LEnter8_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch8:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch9:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch10:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch11:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+LEnter4_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch12:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch13:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
+
+LEnter2_16:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movw	0x12345678(,%eax,2),%ax
+LBPatch14:
+	addl	%ebp,%edx
+	movw	%ax,(%edi)
+	movw	0x12345678(,%ecx,2),%cx
+LBPatch15:
+	movw	%cx,2(%edi)
+	addl	$0x4,%edi
--- /dev/null
+++ b/linux/block8.h
@@ -1,0 +1,124 @@
+LEnter16_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch0:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch1:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch2:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch3:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch4:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch5:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch6:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch7:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+LEnter8_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch8:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch9:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch10:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch11:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+LEnter4_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch12:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch13:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
+LEnter2_8:
+	movb	(%esi),%al
+	movb	(%esi,%ebx,),%cl
+	movb	%dh,%ah
+	addl	%ebp,%edx
+	movb	%dh,%ch
+	leal	(%esi,%ebx,2),%esi
+	movb	0x12345678(%eax),%al
+LBPatch14:
+	addl	%ebp,%edx
+	movb	%al,(%edi)
+	movb	0x12345678(%ecx),%cl
+LBPatch15:
+	movb	%cl,1(%edi)
+	addl	$0x2,%edi
+
--- /dev/null
+++ b/linux/cd_linux.c
@@ -1,0 +1,420 @@
+// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
+// rights reserved.
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <linux/cdrom.h>
+
+#include "../client/client.h"
+
+static qboolean cdValid = false;
+static qboolean	playing = false;
+static qboolean	wasPlaying = false;
+static qboolean	initialized = false;
+static qboolean	enabled = true;
+static qboolean playLooping = false;
+static float	cdvolume;
+static byte 	remap[100];
+static byte		playTrack;
+static byte		maxTrack;
+
+static int cdfile = -1;
+
+//static char cd_dev[64] = "/dev/cdrom";
+
+cvar_t	*cd_volume;
+cvar_t *cd_nocd;
+cvar_t *cd_dev;
+
+void CDAudio_Pause(void);
+
+static void CDAudio_Eject(void)
+{
+	if (cdfile == -1 || !enabled)
+		return; // no cd init'd
+
+	if ( ioctl(cdfile, CDROMEJECT) == -1 ) 
+		Com_DPrintf("ioctl cdromeject failed\n");
+}
+
+
+static void CDAudio_CloseDoor(void)
+{
+	if (cdfile == -1 || !enabled)
+		return; // no cd init'd
+
+	if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) 
+		Com_DPrintf("ioctl cdromclosetray failed\n");
+}
+
+static int CDAudio_GetAudioDiskInfo(void)
+{
+	struct cdrom_tochdr tochdr;
+
+	cdValid = false;
+
+	if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 ) 
+    {
+      Com_DPrintf("ioctl cdromreadtochdr failed\n");
+	  return -1;
+    }
+
+	if (tochdr.cdth_trk0 < 1)
+	{
+		Com_DPrintf("CDAudio: no music tracks\n");
+		return -1;
+	}
+
+	cdValid = true;
+	maxTrack = tochdr.cdth_trk1;
+
+	return 0;
+}
+
+
+void CDAudio_Play(int track, qboolean looping)
+{
+	struct cdrom_tocentry entry;
+	struct cdrom_ti ti;
+
+	if (cdfile == -1 || !enabled)
+		return;
+	
+	if (!cdValid)
+	{
+		CDAudio_GetAudioDiskInfo();
+		if (!cdValid)
+			return;
+	}
+
+	track = remap[track];
+
+	if (track < 1 || track > maxTrack)
+	{
+		Com_DPrintf("CDAudio: Bad track number %u.\n", track);
+		return;
+	}
+
+	// don't try to play a non-audio track
+	entry.cdte_track = track;
+	entry.cdte_format = CDROM_MSF;
+    if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
+	{
+		Com_DPrintf("ioctl cdromreadtocentry failed\n");
+		return;
+	}
+	if (entry.cdte_ctrl == CDROM_DATA_TRACK)
+	{
+		Com_Printf("CDAudio: track %i is not audio\n", track);
+		return;
+	}
+
+	if (playing)
+	{
+		if (playTrack == track)
+			return;
+		CDAudio_Stop();
+	}
+
+	ti.cdti_trk0 = track;
+	ti.cdti_trk1 = track;
+	ti.cdti_ind0 = 1;
+	ti.cdti_ind1 = 99;
+
+	if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 ) 
+    {
+		Com_DPrintf("ioctl cdromplaytrkind failed\n");
+		return;
+    }
+
+	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
+		Com_DPrintf("ioctl cdromresume failed\n");
+
+	playLooping = looping;
+	playTrack = track;
+	playing = true;
+
+	if (cd_volume->value == 0.0)
+		CDAudio_Pause ();
+}
+
+
+void CDAudio_Stop(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	
+	if (!playing)
+		return;
+
+	if ( ioctl(cdfile, CDROMSTOP) == -1 )
+		Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
+
+	wasPlaying = false;
+	playing = false;
+}
+
+void CDAudio_Pause(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+
+	if (!playing)
+		return;
+
+	if ( ioctl(cdfile, CDROMPAUSE) == -1 ) 
+		Com_DPrintf("ioctl cdrompause failed\n");
+
+	wasPlaying = playing;
+	playing = false;
+}
+
+
+void CDAudio_Resume(void)
+{
+	if (cdfile == -1 || !enabled)
+		return;
+	
+	if (!cdValid)
+		return;
+
+	if (!wasPlaying)
+		return;
+	
+	if ( ioctl(cdfile, CDROMRESUME) == -1 ) 
+		Com_DPrintf("ioctl cdromresume failed\n");
+	playing = true;
+}
+
+static void CD_f (void)
+{
+	char	*command;
+	int		ret;
+	int		n;
+
+	if (Cmd_Argc() < 2)
+		return;
+
+	command = Cmd_Argv (1);
+
+	if (Q_strcasecmp(command, "on") == 0)
+	{
+		enabled = true;
+		return;
+	}
+
+	if (Q_strcasecmp(command, "off") == 0)
+	{
+		if (playing)
+			CDAudio_Stop();
+		enabled = false;
+		return;
+	}
+
+	if (Q_strcasecmp(command, "reset") == 0)
+	{
+		enabled = true;
+		if (playing)
+			CDAudio_Stop();
+		for (n = 0; n < 100; n++)
+			remap[n] = n;
+		CDAudio_GetAudioDiskInfo();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "remap") == 0)
+	{
+		ret = Cmd_Argc() - 2;
+		if (ret <= 0)
+		{
+			for (n = 1; n < 100; n++)
+				if (remap[n] != n)
+					Com_Printf("  %u -> %u\n", n, remap[n]);
+			return;
+		}
+		for (n = 1; n <= ret; n++)
+			remap[n] = atoi(Cmd_Argv (n+1));
+		return;
+	}
+
+	if (Q_strcasecmp(command, "close") == 0)
+	{
+		CDAudio_CloseDoor();
+		return;
+	}
+
+	if (!cdValid)
+	{
+		CDAudio_GetAudioDiskInfo();
+		if (!cdValid)
+		{
+			Com_Printf("No CD in player.\n");
+			return;
+		}
+	}
+
+	if (Q_strcasecmp(command, "play") == 0)
+	{
+		CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
+		return;
+	}
+
+	if (Q_strcasecmp(command, "loop") == 0)
+	{
+		CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
+		return;
+	}
+
+	if (Q_strcasecmp(command, "stop") == 0)
+	{
+		CDAudio_Stop();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "pause") == 0)
+	{
+		CDAudio_Pause();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "resume") == 0)
+	{
+		CDAudio_Resume();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "eject") == 0)
+	{
+		if (playing)
+			CDAudio_Stop();
+		CDAudio_Eject();
+		cdValid = false;
+		return;
+	}
+
+	if (Q_strcasecmp(command, "info") == 0)
+	{
+		Com_Printf("%u tracks\n", maxTrack);
+		if (playing)
+			Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+		else if (wasPlaying)
+			Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+		Com_Printf("Volume is %f\n", cdvolume);
+		return;
+	}
+}
+
+void CDAudio_Update(void)
+{
+	struct cdrom_subchnl subchnl;
+	static time_t lastchk;
+
+	if (cdfile == -1 || !enabled)
+		return;
+
+	if (cd_volume && cd_volume->value != cdvolume)
+	{
+		if (cdvolume)
+		{
+			Cvar_SetValue ("cd_volume", 0.0);
+			cdvolume = cd_volume->value;
+			CDAudio_Pause ();
+		}
+		else
+		{
+			Cvar_SetValue ("cd_volume", 1.0);
+			cdvolume = cd_volume->value;
+			CDAudio_Resume ();
+		}
+	}
+
+	if (playing && lastchk < time(NULL)) {
+		lastchk = time(NULL) + 2; //two seconds between chks
+		subchnl.cdsc_format = CDROM_MSF;
+		if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
+			Com_DPrintf("ioctl cdromsubchnl failed\n");
+			playing = false;
+			return;
+		}
+		if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
+			subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
+			playing = false;
+			if (playLooping)
+				CDAudio_Play(playTrack, true);
+		}
+	}
+}
+
+int CDAudio_Init(void)
+{
+	int i;
+	cvar_t			*cv;
+	extern uid_t saved_euid;
+
+	cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
+	if (cv->value)
+		return -1;
+
+	cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
+	if ( cd_nocd->value)
+		return -1;
+
+	cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
+
+	cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
+
+	seteuid(saved_euid);
+
+	cdfile = open(cd_dev->string, O_RDONLY);
+
+	seteuid(getuid());
+
+	if (cdfile == -1) {
+		Com_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev->string, errno);
+		cdfile = -1;
+		return -1;
+	}
+
+	for (i = 0; i < 100; i++)
+		remap[i] = i;
+	initialized = true;
+	enabled = true;
+
+	if (CDAudio_GetAudioDiskInfo())
+	{
+		Com_Printf("CDAudio_Init: No CD in player.\n");
+		cdValid = false;
+	}
+
+	Cmd_AddCommand ("cd", CD_f);
+
+	Com_Printf("CD Audio Initialized\n");
+
+	return 0;
+}
+
+void CDAudio_Activate (qboolean active)
+{
+	if (active)
+		CDAudio_Resume ();
+	else
+		CDAudio_Pause ();
+}
+
+void CDAudio_Shutdown(void)
+{
+	if (!initialized)
+		return;
+	CDAudio_Stop();
+	close(cdfile);
+	cdfile = -1;
+}
--- /dev/null
+++ b/linux/d_copy.s
@@ -1,0 +1,147 @@
+/
+// d_copy.s
+// x86 assembly-language screen copying code.
+//
+
+#include "qasm.h"
+
+	.data
+
+LCopyWidth:		.long	0
+LBlockSrcStep:	.long	0
+LBlockDestStep:	.long	0
+LSrcDelta:		.long	0
+LDestDelta:		.long	0
+
+#define bufptr	4+16
+
+// copies 16 rows per plane at a pop; idea is that 16*512 = 8k, and since
+// no Mode X mode is wider than 360, all the data should fit in the cache for
+// the passes for the next 3 planes
+
+	.text
+
+.globl C(VGA_UpdatePlanarScreen)
+C(VGA_UpdatePlanarScreen):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+	movl	C(VGA_bufferrowbytes),%eax
+	shll	$1,%eax
+	movl	%eax,LBlockSrcStep
+	movl	C(VGA_rowbytes),%eax
+	shll	$1,%eax
+	movl	%eax,LBlockDestStep
+
+	movl	$0x3C4,%edx
+	movb	$2,%al
+	outb	%al,%dx		// point the SC to the Map Mask
+	incl	%edx
+
+	movl	bufptr(%esp),%esi
+	movl	C(VGA_pagebase),%edi
+	movl	C(VGA_height),%ebp
+	shrl	$1,%ebp
+
+	movl	C(VGA_width),%ecx
+	movl	C(VGA_bufferrowbytes),%eax
+	subl	%ecx,%eax
+	movl	%eax,LSrcDelta
+	movl	C(VGA_rowbytes),%eax
+	shll	$2,%eax
+	subl	%ecx,%eax
+	movl	%eax,LDestDelta
+	shrl	$4,%ecx
+	movl	%ecx,LCopyWidth
+
+LRowLoop:
+	movb	$1,%al
+
+LPlaneLoop:
+	outb	%al,%dx
+	movb	$2,%ah
+
+	pushl	%esi
+	pushl	%edi
+LRowSetLoop:
+	movl	LCopyWidth,%ecx
+LColumnLoop:
+	movb	12(%esi),%bh
+	movb	8(%esi),%bl
+	shll	$16,%ebx
+	movb	4(%esi),%bh
+	movb	(%esi),%bl
+	movl	%ebx,(%edi)
+	addl	$16,%esi
+	addl	$4,%edi
+	decl	%ecx
+	jnz		LColumnLoop
+
+	addl	LDestDelta,%edi
+	addl	LSrcDelta,%esi
+	decb	%ah
+	jnz		LRowSetLoop
+
+	popl	%edi
+	popl	%esi
+	incl	%esi
+
+	shlb	$1,%al
+	cmpb	$16,%al
+	jnz		LPlaneLoop
+
+	subl	$4,%esi
+	addl	LBlockSrcStep,%esi
+	addl	LBlockDestStep,%edi
+	decl	%ebp
+	jnz		LRowLoop
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+
+	ret
+
+
+#define srcptr			4+16
+#define destptr			8+16
+#define width			12+16
+#define height			16+16
+#define srcrowbytes		20+16
+#define destrowbytes	24+16
+
+.globl C(VGA_UpdateLinearScreen)
+C(VGA_UpdateLinearScreen):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+	cld
+	movl	srcptr(%esp),%esi
+	movl	destptr(%esp),%edi
+	movl	width(%esp),%ebx
+	movl	srcrowbytes(%esp),%eax
+	subl	%ebx,%eax
+	movl	destrowbytes(%esp),%edx
+	subl	%ebx,%edx
+	shrl	$2,%ebx
+	movl	height(%esp),%ebp
+LLRowLoop:
+	movl	%ebx,%ecx
+	rep/movsl	(%esi),(%edi)
+	addl	%eax,%esi
+	addl	%edx,%edi
+	decl	%ebp
+	jnz		LLRowLoop
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+
+	ret
+
--- /dev/null
+++ b/linux/d_ifacea.h
@@ -1,0 +1,79 @@
+//
+// d_ifacea.h
+//
+// Include file for asm driver interface.
+//
+
+//
+// !!! note that this file must match the corresponding C structures in
+// d_iface.h at all times !!!
+//
+
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define ALIAS_ONSEAM				0x0020
+
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define TURB_TEX_SIZE	64		// base turbulent texture size
+
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define	CYCLE	128
+
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define	MAXHEIGHT	1024
+
+// !!! if this is changed, it must be changed in quakedef.h too !!!
+#define CACHE_SIZE	32		// used to align key data structures
+
+// particle_t structure
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+// driver-usable fields
+#define pt_org				0
+#define pt_color			12
+// drivers never touch the following fields
+#define pt_next				16
+#define pt_vel				20
+#define pt_ramp				32
+#define pt_die				36
+#define pt_type				40
+#define pt_size				44
+
+#define PARTICLE_Z_CLIP	8.0
+
+// finalvert_t structure
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define fv_v				0	// !!! if this is moved, cases where the !!!
+								// !!! address of this field is pushed in !!!
+								// !!! d_polysa.s must be changed !!!
+#define fv_flags			24
+#define fv_reserved			28
+#define fv_size				32
+#define fv_shift			5
+
+
+// stvert_t structure
+// !!! if this is changed, it must be changed in modelgen.h too !!!
+#define stv_onseam	0
+#define stv_s		4
+#define stv_t		8
+#define stv_size	12
+
+
+// trivertx_t structure
+// !!! if this is changed, it must be changed in modelgen.h too !!!
+#define tv_v				0
+#define tv_lightnormalindex	3
+#define tv_size				4
+
+// affinetridesc_t structure
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define atd_pskin			0
+#define atd_pskindesc		4
+#define atd_skinwidth		8
+#define atd_skinheight		12
+#define atd_ptriangles		16
+#define atd_pfinalverts		20
+#define atd_numtriangles	24
+#define atd_drawtype		28
+#define atd_seamfixupX16	32
+#define atd_size			36
+
--- /dev/null
+++ b/linux/d_polysa.s
@@ -1,0 +1,1250 @@
+//
+// d_polysa.s
+// x86 assembly-language polygon model drawing code
+//
+
+#include "qasm.h"
+#include "d_ifacea.h"
+
+#if	id386
+
+// !!! if this is changed, it must be changed in d_polyse.c too !!!
+#define DPS_MAXSPANS			MAXHEIGHT+1	
+									// 1 extra for spanpackage that marks end
+
+//#define	SPAN_SIZE	(((DPS_MAXSPANS + 1 + ((CACHE_SIZE - 1) / spanpackage_t_size)) + 1) * spanpackage_t_size)
+#define SPAN_SIZE (1024+1+1+1)*32
+
+
+
+	.data
+
+	.align	4
+p10_minus_p20:	.single		0
+p01_minus_p21:	.single		0
+temp0:			.single		0
+temp1:			.single		0
+Ltemp:			.single		0
+
+aff8entryvec_table:	.long	LDraw8, LDraw7, LDraw6, LDraw5
+				.long	LDraw4, LDraw3, LDraw2, LDraw1
+
+lzistepx:		.long	0
+
+
+	.text
+
+#ifndef NeXT
+	.extern C(D_PolysetSetEdgeTable)
+	.extern C(D_RasterizeAliasPolySmooth)
+#endif
+
+//----------------------------------------------------------------------
+// affine triangle gradient calculation code
+//----------------------------------------------------------------------
+
+#if 0
+#define skinwidth	4+0
+
+.globl C(R_PolysetCalcGradients)
+C(R_PolysetCalcGradients):
+
+//	p00_minus_p20 = r_p0[0] - r_p2[0];
+//	p01_minus_p21 = r_p0[1] - r_p2[1];
+//	p10_minus_p20 = r_p1[0] - r_p2[0];
+//	p11_minus_p21 = r_p1[1] - r_p2[1];
+//
+//	xstepdenominv = 1.0 / (p10_minus_p20 * p01_minus_p21 -
+//			     p00_minus_p20 * p11_minus_p21);
+//
+//	ystepdenominv = -xstepdenominv;
+
+	fildl	C(r_p0)+0		// r_p0[0]
+	fildl	C(r_p2)+0		// r_p2[0] | r_p0[0]
+	fildl	C(r_p0)+4		// r_p0[1] | r_p2[0] | r_p0[0]
+	fildl	C(r_p2)+4		// r_p2[1] | r_p0[1] | r_p2[0] | r_p0[0]
+	fildl	C(r_p1)+0		// r_p1[0] | r_p2[1] | r_p0[1] | r_p2[0] | r_p0[0]
+	fildl	C(r_p1)+4		// r_p1[1] | r_p1[0] | r_p2[1] | r_p0[1] |
+							//  r_p2[0] | r_p0[0]
+	fxch	%st(3)			// r_p0[1] | r_p1[0] | r_p2[1] | r_p1[1] |
+							//  r_p2[0] | r_p0[0]
+	fsub	%st(2),%st(0)	// p01_minus_p21 | r_p1[0] | r_p2[1] | r_p1[1] |
+							//  r_p2[0] | r_p0[0]
+	fxch	%st(1)			// r_p1[0] | p01_minus_p21 | r_p2[1] | r_p1[1] |
+							//  r_p2[0] | r_p0[0]
+	fsub	%st(4),%st(0)	// p10_minus_p20 | p01_minus_p21 | r_p2[1] |
+							//  r_p1[1] | r_p2[0] | r_p0[0]
+	fxch	%st(5)			// r_p0[0] | p01_minus_p21 | r_p2[1] |
+							//  r_p1[1] | r_p2[0] | p10_minus_p20
+	fsubp	%st(0),%st(4)	// p01_minus_p21 | r_p2[1] | r_p1[1] |
+							//  p00_minus_p20 | p10_minus_p20
+	fxch	%st(2)			// r_p1[1] | r_p2[1] | p01_minus_p21 |
+							//  p00_minus_p20 | p10_minus_p20
+	fsubp	%st(0),%st(1)	// p11_minus_p21 | p01_minus_p21 |
+							//  p00_minus_p20 | p10_minus_p20
+	fxch	%st(1)			// p01_minus_p21 | p11_minus_p21 |
+							//  p00_minus_p20 | p10_minus_p20
+	flds	C(d_xdenom)		// d_xdenom | p01_minus_p21 | p11_minus_p21 |
+							//  p00_minus_p20 | p10_minus_p20
+	fxch	%st(4)			// p10_minus_p20 | p01_minus_p21 | p11_minus_p21 |
+							//  p00_minus_p20 | d_xdenom
+	fstps	p10_minus_p20	// p01_minus_p21 | p11_minus_p21 |
+							//  p00_minus_p20 | d_xdenom
+	fstps	p01_minus_p21	// p11_minus_p21 | p00_minus_p20 | xstepdenominv
+	fxch	%st(2)			// xstepdenominv | p00_minus_p20 | p11_minus_p21
+
+//// ceil () for light so positive steps are exaggerated, negative steps
+//// diminished,  pushing us away from underflow toward overflow. Underflow is
+//// very visible, overflow is very unlikely, because of ambient lighting
+//	t0 = r_p0[4] - r_p2[4];
+//	t1 = r_p1[4] - r_p2[4];
+
+	fildl	C(r_p2)+16		// r_p2[4] | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fildl	C(r_p0)+16		// r_p0[4] | r_p2[4] | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p1)+16		// r_p1[4] | r_p0[4] | r_p2[4] | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// r_p2[4] | r_p0[4] | r_p1[4] | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// r_p2[4] | r_p2[4] | r_p0[4] | r_p1[4] |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fsubrp	%st(0),%st(2)	// r_p2[4] | t0 | r_p1[4] | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fsubrp	%st(0),%st(2)	// t0 | t1 | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+
+//	r_lstepx = (int)
+//			ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
+//	r_lstepy = (int)
+//			ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
+
+	fld		%st(0)			// t0 | t0 | t1 | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmul	%st(5),%st(0)	// t0*p11_minus_p21 | t0 | t1 | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// t1 | t0 | t0*p11_minus_p21 | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// t1 | t1 | t0 | t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmuls	p01_minus_p21	// t1*p01_minus_p21 | t1 | t0 | t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// t0 | t1 | t1*p01_minus_p21 | t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmuls	p10_minus_p20	// t0*p10_minus_p20 | t1 | t1*p01_minus_p21 |
+							//  t0*p11_minus_p21 | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fxch	%st(1)			// t1 | t0*p10_minus_p20 | t1*p01_minus_p21 |
+							//  t0*p11_minus_p21 | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fmul	%st(5),%st(0)	// t1*p00_minus_p20 | t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 | t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// t1*p01_minus_p21 | t0*p10_minus_p20 |
+							//  t1*p00_minus_p20 | t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fsubp	%st(0),%st(3)	// t0*p10_minus_p20 | t1*p00_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fsubrp	%st(0),%st(1)	// t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fld		%st(2)			// xstepdenominv |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmuls	float_minus_1	// ystepdenominv |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmul	%st(3),%st(0)	// (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//   xstepdenominv |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//   | ystepdenominv | xstepdenominv |
+							//   p00_minus_p20 | p11_minus_p21
+	fxch	%st(1)			// t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//   xstepdenominv | ystepdenominv |
+							//   xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmul	%st(2),%st(0)	// (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//  ystepdenominv |
+							//  (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//  xstepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fldcw	ceil_cw
+	fistpl	C(r_lstepy)		// r_lstepx | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fistpl	C(r_lstepx)		// ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fldcw	single_cw
+
+//	t0 = r_p0[2] - r_p2[2];
+//	t1 = r_p1[2] - r_p2[2];
+
+	fildl	C(r_p2)+8		// r_p2[2] | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p0)+8		// r_p0[2] | r_p2[2] | ystepdenominv |
+							//   xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p1)+8		// r_p1[2] | r_p0[2] | r_p2[2] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// r_p2[2] | r_p0[2] | r_p1[2] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// r_p2[2] | r_p2[2] | r_p0[2] | r_p1[2] |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubrp	%st(0),%st(2)	// r_p2[2] | t0 | r_p1[2] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fsubrp	%st(0),%st(2)	// t0 | t1 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+
+//	r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+//			xstepdenominv);
+//	r_sstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+//			ystepdenominv);
+
+	fld		%st(0)			// t0 | t0 | t1 | ystepdenominv | xstepdenominv
+	fmul	%st(6),%st(0)	// t0*p11_minus_p21 | t0 | t1 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// t1 | t0 | t0*p11_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// t1 | t1 | t0 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmuls	p01_minus_p21	// t1*p01_minus_p21 | t1 | t0 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fxch	%st(2)			// t0 | t1 | t1*p01_minus_p21 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmuls	p10_minus_p20	// t0*p10_minus_p20 | t1 | t1*p01_minus_p21 |
+							//  t0*p11_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(1)			// t1 | t0*p10_minus_p20 | t1*p01_minus_p21 |
+							//  t0*p11_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmul	%st(6),%st(0)	// t1*p00_minus_p20 | t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fxch	%st(2)			// t1*p01_minus_p21 | t0*p10_minus_p20 |
+							//  t1*p00_minus_p20 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubp	%st(0),%st(3)	// t0*p10_minus_p20 | t1*p00_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubrp	%st(0),%st(1)	// t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmul	%st(2),%st(0)	// (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//   ystepdenominv |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fxch	%st(1)			// t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//   ystepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmul	%st(3),%st(0)	// (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//  xstepdenominv |
+							//  (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//  ystepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(1)			// (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//  ystepdenominv |
+							//  (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//  xstepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fistpl	C(r_sstepy)		// r_sstepx | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fistpl	C(r_sstepx)		// ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+
+//	t0 = r_p0[3] - r_p2[3];
+//	t1 = r_p1[3] - r_p2[3];
+
+	fildl	C(r_p2)+12		// r_p2[3] | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p0)+12		// r_p0[3] | r_p2[3] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p1)+12		// r_p1[3] | r_p0[3] | r_p2[3] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// r_p2[3] | r_p0[3] | r_p1[3] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// r_p2[3] | r_p2[3] | r_p0[3] | r_p1[3] |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubrp	%st(0),%st(2)	// r_p2[3] | t0 | r_p1[3] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fsubrp	%st(0),%st(2)	// t0 | t1 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+
+//	r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+//			xstepdenominv);
+//	r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+//			ystepdenominv);
+
+	fld		%st(0)			// t0 | t0 | t1 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fmul	%st(6),%st(0)	// t0*p11_minus_p21 | t0 | t1 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// t1 | t0 | t0*p11_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// t1 | t1 | t0 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmuls	p01_minus_p21	// t1*p01_minus_p21 | t1 | t0 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fxch	%st(2)			// t0 | t1 | t1*p01_minus_p21 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmuls	p10_minus_p20	// t0*p10_minus_p20 | t1 | t1*p01_minus_p21 |
+							//  t0*p11_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(1)			// t1 | t0*p10_minus_p20 | t1*p01_minus_p21 |
+							//  t0*p11_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmul	%st(6),%st(0)	// t1*p00_minus_p20 | t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fxch	%st(2)			// t1*p01_minus_p21 | t0*p10_minus_p20 |
+							//  t1*p00_minus_p20 | t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubp	%st(0),%st(3)	// t0*p10_minus_p20 | t1*p00_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubrp	%st(0),%st(1)	// t1*p00_minus_p20 - t0*p10_minus_p20 |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fmul	%st(2),%st(0)	// (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//   ystepdenominv |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fxch	%st(1)			// t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//  ystepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fmul	%st(3),%st(0)	// (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//  xstepdenominv |
+							//  (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//  ystepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(1)			// (t1*p00_minus_p20 - t0*p10_minus_p20)*
+							//  ystepdenominv |
+							//  (t1*p01_minus_p21 - t0*p11_minus_p21)*
+							//  xstepdenominv | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fistpl	C(r_tstepy)		// r_tstepx | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fistpl	C(r_tstepx)		// ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+
+//	t0 = r_p0[5] - r_p2[5];
+//	t1 = r_p1[5] - r_p2[5];
+
+	fildl	C(r_p2)+20		// r_p2[5] | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p0)+20		// r_p0[5] | r_p2[5] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fildl	C(r_p1)+20		// r_p1[5] | r_p0[5] | r_p2[5] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fxch	%st(2)			// r_p2[5] | r_p0[5] | r_p1[5] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fld		%st(0)			// r_p2[5] | r_p2[5] | r_p0[5] | r_p1[5] |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  p11_minus_p21
+	fsubrp	%st(0),%st(2)	// r_p2[5] | t0 | r_p1[5] | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 | p11_minus_p21
+	fsubrp	%st(0),%st(2)	// t0 | t1 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+
+//	r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+//			xstepdenominv);
+//	r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+//			ystepdenominv);
+
+	fld		%st(0)			// t0 | t0 | t1 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | p11_minus_p21
+	fmulp	%st(0),%st(6)	// t0 | t1 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | t0*p11_minus_p21
+	fxch	%st(1)			// t1 | t0 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | t0*p11_minus_p21
+	fld		%st(0)			// t1 | t1 | t0 | ystepdenominv | xstepdenominv |
+							//  p00_minus_p20 | t0*p11_minus_p21
+	fmuls	p01_minus_p21	// t1*p01_minus_p21 | t1 | t0 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 |
+							//  t0*p11_minus_p21
+	fxch	%st(2)			// t0 | t1 | t1*p01_minus_p21 | ystepdenominv |
+							//  xstepdenominv | p00_minus_p20 |
+							//  t0*p11_minus_p21
+	fmuls	p10_minus_p20	// t0*p10_minus_p20 | t1 | t1*p01_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  t0*p11_minus_p21
+	fxch	%st(1)			// t1 | t0*p10_minus_p20 | t1*p01_minus_p21 |
+							//  ystepdenominv | xstepdenominv | p00_minus_p20 |
+							//  t0*p11_minus_p21
+	fmulp	%st(0),%st(5)	// t0*p10_minus_p20 | t1*p01_minus_p21 |
+							//  ystepdenominv | xstepdenominv |
+							//  t1*p00_minus_p20 | t0*p11_minus_p21
+	fxch	%st(5)			// t0*p11_minus_p21 | t1*p01_minus_p21 |
+							//  ystepdenominv | xstepdenominv |
+							//  t1*p00_minus_p20 | t0*p10_minus_p20
+	fsubrp	%st(0),%st(1)	// t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  ystepdenominv | xstepdenominv |
+							//  t1*p00_minus_p20 | t0*p10_minus_p20
+	fxch	%st(3)			// t1*p00_minus_p20 | ystepdenominv |
+							//  xstepdenominv |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  t0*p10_minus_p20
+	fsubp	%st(0),%st(4)	// ystepdenominv | xstepdenominv |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20
+	fxch	%st(1)			// xstepdenominv | ystepdenominv |
+							//  t1*p01_minus_p21 - t0*p11_minus_p21 |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20
+	fmulp	%st(0),%st(2)	// ystepdenominv |
+							//  (t1*p01_minus_p21 - t0*p11_minus_p21) *
+							//  xstepdenominv |
+							//  t1*p00_minus_p20 - t0*p10_minus_p20
+	fmulp	%st(0),%st(2)	// (t1*p01_minus_p21 - t0*p11_minus_p21) *
+							//  xstepdenominv |
+							//  (t1*p00_minus_p20 - t0*p10_minus_p20) *
+							//  ystepdenominv
+	fistpl	C(r_zistepx)	// (t1*p00_minus_p20 - t0*p10_minus_p20) *
+							//  ystepdenominv
+	fistpl	C(r_zistepy)
+
+//	a_sstepxfrac = r_sstepx << 16;
+//	a_tstepxfrac = r_tstepx << 16;
+//
+//	a_ststepxwhole = r_affinetridesc.skinwidth * (r_tstepx >> 16) +
+//			(r_sstepx >> 16);
+
+	movl	C(r_sstepx),%eax
+	movl	C(r_tstepx),%edx
+	shll	$16,%eax
+	shll	$16,%edx
+	movl	%eax,C(a_sstepxfrac)
+	movl	%edx,C(a_tstepxfrac)
+
+	movl	C(r_sstepx),%ecx
+	movl	C(r_tstepx),%eax
+	sarl	$16,%ecx
+	sarl	$16,%eax
+	imull	skinwidth(%esp)
+	addl	%ecx,%eax
+	movl	%eax,C(a_ststepxwhole)
+
+	ret
+
+#endif
+
+//----------------------------------------------------------------------
+// recursive subdivision affine triangle drawing code
+//
+// not C-callable because of stdcall return
+//----------------------------------------------------------------------
+
+#define lp1	4+16
+#define lp2	8+16
+#define lp3	12+16
+
+.globl C(D_PolysetRecursiveTriangle)
+C(D_PolysetRecursiveTriangle):
+	pushl	%ebp				// preserve caller stack frame pointer
+	pushl	%esi				// preserve register variables
+	pushl	%edi
+	pushl	%ebx
+
+//	int		*temp;
+//	int		d;
+//	int		new[6];
+//	int		i;
+//	int		z;
+//	short	*zbuf;
+	movl	lp2(%esp),%esi
+	movl	lp1(%esp),%ebx
+	movl	lp3(%esp),%edi
+
+//	d = lp2[0] - lp1[0];
+//	if (d < -1 || d > 1)
+//		goto split;
+	movl	0(%esi),%eax
+
+	movl	0(%ebx),%edx
+	movl	4(%esi),%ebp
+
+	subl	%edx,%eax
+	movl	4(%ebx),%ecx
+
+	subl	%ecx,%ebp
+	incl	%eax
+
+	cmpl	$2,%eax
+	ja		LSplit
+
+//	d = lp2[1] - lp1[1];
+//	if (d < -1 || d > 1)
+//		goto split;
+	movl	0(%edi),%eax
+	incl	%ebp
+
+	cmpl	$2,%ebp
+	ja		LSplit
+
+//	d = lp3[0] - lp2[0];
+//	if (d < -1 || d > 1)
+//		goto split2;
+	movl	0(%esi),%edx
+	movl	4(%edi),%ebp
+
+	subl	%edx,%eax
+	movl	4(%esi),%ecx
+
+	subl	%ecx,%ebp
+	incl	%eax
+
+	cmpl	$2,%eax
+	ja		LSplit2
+
+//	d = lp3[1] - lp2[1];
+//	if (d < -1 || d > 1)
+//		goto split2;
+	movl	0(%ebx),%eax
+	incl	%ebp
+
+	cmpl	$2,%ebp
+	ja		LSplit2
+
+//	d = lp1[0] - lp3[0];
+//	if (d < -1 || d > 1)
+//		goto split3;
+	movl	0(%edi),%edx
+	movl	4(%ebx),%ebp
+
+	subl	%edx,%eax
+	movl	4(%edi),%ecx
+
+	subl	%ecx,%ebp
+	incl	%eax
+
+	incl	%ebp
+	movl	%ebx,%edx
+
+	cmpl	$2,%eax
+	ja		LSplit3
+
+//	d = lp1[1] - lp3[1];
+//	if (d < -1 || d > 1)
+//	{
+//split3:
+//		temp = lp1;
+//		lp3 = lp2;
+//		lp1 = lp3;
+//		lp2 = temp;
+//		goto split;
+//	}
+//
+//	return;			// entire tri is filled
+//
+	cmpl	$2,%ebp
+	jna		LDone
+
+LSplit3:
+	movl	%edi,%ebx
+	movl	%esi,%edi
+	movl	%edx,%esi
+	jmp		LSplit
+
+//split2:
+LSplit2:
+
+//	temp = lp1;
+//	lp1 = lp2;
+//	lp2 = lp3;
+//	lp3 = temp;
+	movl	%ebx,%eax
+	movl	%esi,%ebx
+	movl	%edi,%esi
+	movl	%eax,%edi
+
+//split:
+LSplit:
+
+	subl	$24,%esp		// allocate space for a new vertex
+
+//// split this edge
+//	new[0] = (lp1[0] + lp2[0]) >> 1;
+//	new[1] = (lp1[1] + lp2[1]) >> 1;
+//	new[2] = (lp1[2] + lp2[2]) >> 1;
+//	new[3] = (lp1[3] + lp2[3]) >> 1;
+//	new[5] = (lp1[5] + lp2[5]) >> 1;
+	movl	8(%ebx),%eax
+
+	movl	8(%esi),%edx
+	movl	12(%ebx),%ecx
+
+	addl	%edx,%eax
+	movl	12(%esi),%edx
+
+	sarl	$1,%eax
+	addl	%edx,%ecx
+
+	movl	%eax,8(%esp)
+	movl	20(%ebx),%eax
+
+	sarl	$1,%ecx
+	movl	20(%esi),%edx
+
+	movl	%ecx,12(%esp)
+	addl	%edx,%eax
+
+	movl	0(%ebx),%ecx
+	movl	0(%esi),%edx
+
+	sarl	$1,%eax
+	addl	%ecx,%edx
+
+	movl	%eax,20(%esp)
+	movl	4(%ebx),%eax
+
+	sarl	$1,%edx
+	movl	4(%esi),%ebp
+
+	movl	%edx,0(%esp)
+	addl	%eax,%ebp
+
+	sarl	$1,%ebp
+	movl	%ebp,4(%esp)
+
+//// draw the point if splitting a leading edge
+//	if (lp2[1] > lp1[1])
+//		goto nodraw;
+	cmpl	%eax,4(%esi)
+	jg		LNoDraw
+
+//	if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0]))
+//		goto nodraw;
+	movl	0(%esi),%edx
+	jnz		LDraw
+
+	cmpl	%ecx,%edx
+	jl		LNoDraw
+
+LDraw:
+
+// z = new[5] >> 16;
+	movl	20(%esp),%edx
+	movl	4(%esp),%ecx
+
+	sarl	$16,%edx
+	movl	0(%esp),%ebp
+
+//	zbuf = zspantable[new[1]] + new[0];
+	movl	C(zspantable)(,%ecx,4),%eax
+
+//	if (z >= *zbuf)
+//	{
+	cmpw	(%eax,%ebp,2),%dx
+	jnge	LNoDraw
+
+//		int		pix;
+//		
+//		*zbuf = z;
+	movw	%dx,(%eax,%ebp,2)
+
+//		pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]];
+	movl	12(%esp),%eax
+
+	sarl	$16,%eax
+	movl	8(%esp),%edx
+
+	sarl	$16,%edx
+	subl	%ecx,%ecx
+
+	movl	C(skintable)(,%eax,4),%eax
+	movl	4(%esp),%ebp
+
+	movb	(%eax,%edx,),%cl
+	movl	C(d_pcolormap),%edx
+
+	movb	(%edx,%ecx,),%dl
+	movl	0(%esp),%ecx
+
+//		d_viewbuffer[d_scantable[new[1]] + new[0]] = pix;
+	movl	C(d_scantable)(,%ebp,4),%eax
+	addl	%eax,%ecx
+	movl	C(d_viewbuffer),%eax
+	movb	%dl,(%eax,%ecx,1)
+
+//	}
+//
+//nodraw:
+LNoDraw:
+
+//// recursively continue
+//	D_PolysetRecursiveTriangle (lp3, lp1, new);
+	pushl	%esp
+	pushl	%ebx
+	pushl	%edi
+	call	C(D_PolysetRecursiveTriangle)
+
+//	D_PolysetRecursiveTriangle (lp3, new, lp2);
+	movl	%esp,%ebx
+	pushl	%esi
+	pushl	%ebx
+	pushl	%edi
+	call	C(D_PolysetRecursiveTriangle)
+	addl	$24,%esp
+
+LDone:
+	popl	%ebx				// restore register variables
+	popl	%edi
+	popl	%esi
+	popl	%ebp				// restore caller stack frame pointer
+	ret		$12
+
+
+//----------------------------------------------------------------------
+// 8-bpp horizontal span drawing code for affine polygons, with smooth
+// shading and no transparency
+//----------------------------------------------------------------------
+
+#define pspans	4+8
+
+.globl C(D_PolysetAff8Start)
+C(D_PolysetAff8Start):
+
+.globl C(R_PolysetDrawSpans8_Opaque)
+C(R_PolysetDrawSpans8_Opaque):
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+	movl	pspans(%esp),%esi	// point to the first span descriptor
+	movl	C(r_zistepx),%ecx
+
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+
+	rorl	$16,%ecx			// put high 16 bits of 1/z step in low word
+	movl	spanpackage_t_count(%esi),%edx
+
+	movl	%ecx,lzistepx
+
+LSpanLoop:
+
+//		lcount = d_aspancount - pspanpackage->count;
+//
+//		errorterm += erroradjustup;
+//		if (errorterm >= 0)
+//		{
+//			d_aspancount += d_countextrastep;
+//			errorterm -= erroradjustdown;
+//		}
+//		else
+//		{
+//			d_aspancount += ubasestep;
+//		}
+	movl	C(d_aspancount),%eax
+	subl	%edx,%eax
+
+	movl	C(erroradjustup),%edx
+	movl	C(errorterm),%ebx
+	addl	%edx,%ebx
+	js		LNoTurnover
+
+	movl	C(erroradjustdown),%edx
+	movl	C(d_countextrastep),%edi
+	subl	%edx,%ebx
+	movl	C(d_aspancount),%ebp
+	movl	%ebx,C(errorterm)
+	addl	%edi,%ebp
+	movl	%ebp,C(d_aspancount)
+	jmp		LRightEdgeStepped
+
+LNoTurnover:
+	movl	C(d_aspancount),%edi
+	movl	C(ubasestep),%edx
+	movl	%ebx,C(errorterm)
+	addl	%edx,%edi
+	movl	%edi,C(d_aspancount)
+
+LRightEdgeStepped:
+	cmpl	$1,%eax
+
+	jl		LNextSpan
+	jz		LExactlyOneLong
+
+//
+// set up advancetable
+//
+	movl	C(a_ststepxwhole),%ecx
+	movl	C(r_affinetridesc)+atd_skinwidth,%edx
+
+	movl	%ecx,advancetable+4	// advance base in t
+	addl	%edx,%ecx
+
+	movl	%ecx,advancetable	// advance extra in t
+	movl	C(a_tstepxfrac),%ecx
+
+	movw	C(r_lstepx),%cx
+	movl	%eax,%edx			// count
+
+	movl	%ecx,tstep
+	addl	$7,%edx
+
+	shrl	$3,%edx				// count of full and partial loops
+	movl	spanpackage_t_sfrac(%esi),%ebx
+
+	movw	%dx,%bx
+	movl	spanpackage_t_pz(%esi),%ecx
+
+	negl	%eax
+
+	movl	spanpackage_t_pdest(%esi),%edi
+	andl	$7,%eax		// 0->0, 1->7, 2->6, ... , 7->1
+
+	subl	%eax,%edi	// compensate for hardwired offsets
+	subl	%eax,%ecx
+
+	subl	%eax,%ecx
+	movl	spanpackage_t_tfrac(%esi),%edx
+
+	movw	spanpackage_t_light(%esi),%dx
+	movl	spanpackage_t_zi(%esi),%ebp
+
+	rorl	$16,%ebp	// put high 16 bits of 1/z in low word
+	pushl	%esi
+
+	movl	spanpackage_t_ptex(%esi),%esi
+	jmp		aff8entryvec_table(,%eax,4)
+
+// %bx = count of full and partial loops
+// %ebx high word = sfrac
+// %ecx = pz
+// %dx = light
+// %edx high word = tfrac
+// %esi = ptex
+// %edi = pdest
+// %ebp = 1/z
+// tstep low word = C(r_lstepx)
+// tstep high word = C(a_tstepxfrac)
+// C(a_sstepxfrac) low word = 0
+// C(a_sstepxfrac) high word = C(a_sstepxfrac)
+
+LDrawLoop:
+
+// FIXME: do we need to clamp light? We may need at least a buffer bit to
+// keep it from poking into tfrac and causing problems
+
+LDraw8:
+	cmpw	(%ecx),%bp
+	jl		Lp1
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch8:
+	movb	%al,(%edi)
+Lp1:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw7:
+	cmpw	2(%ecx),%bp
+	jl		Lp2
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,2(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch7:
+	movb	%al,1(%edi)
+Lp2:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw6:
+	cmpw	4(%ecx),%bp
+	jl		Lp3
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,4(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch6:
+	movb	%al,2(%edi)
+Lp3:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw5:
+	cmpw	6(%ecx),%bp
+	jl		Lp4
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,6(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch5:
+	movb	%al,3(%edi)
+Lp4:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw4:
+	cmpw	8(%ecx),%bp
+	jl		Lp5
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,8(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch4:
+	movb	%al,4(%edi)
+Lp5:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw3:
+	cmpw	10(%ecx),%bp
+	jl		Lp6
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,10(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch3:
+	movb	%al,5(%edi)
+Lp6:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw2:
+	cmpw	12(%ecx),%bp
+	jl		Lp7
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,12(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch2:
+	movb	%al,6(%edi)
+Lp7:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LDraw1:
+	cmpw	14(%ecx),%bp
+	jl		Lp8
+	xorl	%eax,%eax
+	movb	%dh,%ah
+	movb	(%esi),%al
+	movw	%bp,14(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch1:
+	movb	%al,7(%edi)
+Lp8:
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	lzistepx,%ebp
+	adcl	$0,%ebp
+	addl	C(a_sstepxfrac),%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	addl	$8,%edi
+	addl	$16,%ecx
+
+	decw	%bx
+	jnz		LDrawLoop
+
+	popl	%esi				// restore spans pointer
+LNextSpan:
+	addl	$(spanpackage_t_size),%esi	// point to next span
+LNextSpanESISet:
+	movl	spanpackage_t_count(%esi),%edx
+	cmpl	$-999999,%edx		// any more spans?
+	jnz		LSpanLoop			// yes
+
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	popl	%ebx				// restore register variables
+	popl	%esi
+	ret
+
+
+// draw a one-long span
+
+LExactlyOneLong:
+
+	movl	spanpackage_t_pz(%esi),%ecx
+	movl	spanpackage_t_zi(%esi),%ebp
+
+	rorl	$16,%ebp	// put high 16 bits of 1/z in low word
+	movl	spanpackage_t_ptex(%esi),%ebx
+
+	cmpw	(%ecx),%bp
+	jl		LNextSpan
+	xorl	%eax,%eax
+	movl	spanpackage_t_pdest(%esi),%edi
+	movb	spanpackage_t_light+1(%esi),%ah
+	addl	$(spanpackage_t_size),%esi	// point to next span
+	movb	(%ebx),%al
+	movw	%bp,(%ecx)
+	movb	0x12345678(%eax),%al
+LPatch9:
+	movb	%al,(%edi)
+
+	jmp		LNextSpanESISet
+
+.globl C(D_PolysetAff8End)
+C(D_PolysetAff8End):
+
+
+.extern C(alias_colormap)
+// #define pcolormap		4
+
+.globl C(D_Aff8Patch)
+C(D_Aff8Patch):
+	movl	C(alias_colormap),%eax
+	movl	%eax,LPatch1-4
+	movl	%eax,LPatch2-4
+	movl	%eax,LPatch3-4
+	movl	%eax,LPatch4-4
+	movl	%eax,LPatch5-4
+	movl	%eax,LPatch6-4
+	movl	%eax,LPatch7-4
+	movl	%eax,LPatch8-4
+	movl	%eax,LPatch9-4
+
+	ret
+
+//----------------------------------------------------------------------
+// Alias model triangle left-edge scanning code
+//----------------------------------------------------------------------
+
+#define height	4+16
+
+.globl C(R_PolysetScanLeftEdge)
+C(R_PolysetScanLeftEdge):
+	pushl	%ebp				// preserve caller stack frame pointer
+	pushl	%esi				// preserve register variables
+	pushl	%edi
+	pushl	%ebx
+
+	movl	height(%esp),%eax
+	movl	C(d_sfrac),%ecx
+	andl	$0xFFFF,%eax
+	movl	C(d_ptex),%ebx
+	orl		%eax,%ecx
+	movl	C(d_pedgespanpackage),%esi
+	movl	C(d_tfrac),%edx
+	movl	C(d_light),%edi
+	movl	C(d_zi),%ebp
+
+// %eax: scratch
+// %ebx: d_ptex
+// %ecx: d_sfrac in high word, count in low word
+// %edx: d_tfrac
+// %esi: d_pedgespanpackage, errorterm, scratch alternately
+// %edi: d_light
+// %ebp: d_zi
+
+//	do
+//	{
+
+LScanLoop:
+
+//		d_pedgespanpackage->ptex = ptex;
+//		d_pedgespanpackage->pdest = d_pdest;
+//		d_pedgespanpackage->pz = d_pz;
+//		d_pedgespanpackage->count = d_aspancount;
+//		d_pedgespanpackage->light = d_light;
+//		d_pedgespanpackage->zi = d_zi;
+//		d_pedgespanpackage->sfrac = d_sfrac << 16;
+//		d_pedgespanpackage->tfrac = d_tfrac << 16;
+	movl	%ebx,spanpackage_t_ptex(%esi)
+	movl	C(d_pdest),%eax
+	movl	%eax,spanpackage_t_pdest(%esi)
+	movl	C(d_pz),%eax
+	movl	%eax,spanpackage_t_pz(%esi)
+	movl	C(d_aspancount),%eax
+	movl	%eax,spanpackage_t_count(%esi)
+	movl	%edi,spanpackage_t_light(%esi)
+	movl	%ebp,spanpackage_t_zi(%esi)
+	movl	%ecx,spanpackage_t_sfrac(%esi)
+	movl	%edx,spanpackage_t_tfrac(%esi)
+
+// pretouch the next cache line
+	movb	spanpackage_t_size(%esi),%al
+
+//		d_pedgespanpackage++;
+	addl	$(spanpackage_t_size),%esi
+	movl	C(erroradjustup),%eax
+	movl	%esi,C(d_pedgespanpackage)
+
+//		errorterm += erroradjustup;
+	movl	C(errorterm),%esi
+	addl	%eax,%esi
+	movl	C(d_pdest),%eax
+
+//		if (errorterm >= 0)
+//		{
+	js		LNoLeftEdgeTurnover
+
+//			errorterm -= erroradjustdown;
+//			d_pdest += d_pdestextrastep;
+	subl	C(erroradjustdown),%esi
+	addl	C(d_pdestextrastep),%eax
+	movl	%esi,C(errorterm)
+	movl	%eax,C(d_pdest)
+
+//			d_pz += d_pzextrastep;
+//			d_aspancount += d_countextrastep;
+//			d_ptex += d_ptexextrastep;
+//			d_sfrac += d_sfracextrastep;
+//			d_ptex += d_sfrac >> 16;
+//			d_sfrac &= 0xFFFF;
+//			d_tfrac += d_tfracextrastep;
+	movl	C(d_pz),%eax
+	movl	C(d_aspancount),%esi
+	addl	C(d_pzextrastep),%eax
+	addl	C(d_sfracextrastep),%ecx
+	adcl	C(d_ptexextrastep),%ebx
+	addl	C(d_countextrastep),%esi
+	movl	%eax,C(d_pz)
+	movl	C(d_tfracextrastep),%eax
+	movl	%esi,C(d_aspancount)
+	addl	%eax,%edx
+
+//			if (d_tfrac & 0x10000)
+//			{
+	jnc		LSkip1
+
+//				d_ptex += r_affinetridesc.skinwidth;
+//				d_tfrac &= 0xFFFF;
+	addl	C(r_affinetridesc)+atd_skinwidth,%ebx
+
+//			}
+
+LSkip1:
+
+//			d_light += d_lightextrastep;
+//			d_zi += d_ziextrastep;
+	addl	C(d_lightextrastep),%edi
+	addl	C(d_ziextrastep),%ebp
+
+//		}
+	movl	C(d_pedgespanpackage),%esi
+	decl	%ecx
+	testl	$0xFFFF,%ecx
+	jnz		LScanLoop
+
+	popl	%ebx
+	popl	%edi
+	popl	%esi
+	popl	%ebp
+	ret
+
+//		else
+//		{
+
+LNoLeftEdgeTurnover:
+	movl	%esi,C(errorterm)
+
+//			d_pdest += d_pdestbasestep;
+	addl	C(d_pdestbasestep),%eax
+	movl	%eax,C(d_pdest)
+
+//			d_pz += d_pzbasestep;
+//			d_aspancount += ubasestep;
+//			d_ptex += d_ptexbasestep;
+//			d_sfrac += d_sfracbasestep;
+//			d_ptex += d_sfrac >> 16;
+//			d_sfrac &= 0xFFFF;
+	movl	C(d_pz),%eax
+	movl	C(d_aspancount),%esi
+	addl	C(d_pzbasestep),%eax
+	addl	C(d_sfracbasestep),%ecx
+	adcl	C(d_ptexbasestep),%ebx
+	addl	C(ubasestep),%esi
+	movl	%eax,C(d_pz)
+	movl	%esi,C(d_aspancount)
+
+//			d_tfrac += d_tfracbasestep;
+	movl	C(d_tfracbasestep),%esi
+	addl	%esi,%edx
+
+//			if (d_tfrac & 0x10000)
+//			{
+	jnc		LSkip2
+
+//				d_ptex += r_affinetridesc.skinwidth;
+//				d_tfrac &= 0xFFFF;
+	addl	C(r_affinetridesc)+atd_skinwidth,%ebx
+
+//			}
+
+LSkip2:
+
+//			d_light += d_lightbasestep;
+//			d_zi += d_zibasestep;
+	addl	C(d_lightbasestep),%edi
+	addl	C(d_zibasestep),%ebp
+
+//		}
+//	} while (--height);
+	movl	C(d_pedgespanpackage),%esi
+	decl	%ecx
+	testl	$0xFFFF,%ecx
+	jnz		LScanLoop
+
+	popl	%ebx
+	popl	%edi
+	popl	%esi
+	popl	%ebp
+	ret
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/gl_fxmesa.c
@@ -1,0 +1,206 @@
+/*
+** GLW_IMP.C
+**
+** This file contains ALL Linux specific stuff having to do with the
+** OpenGL refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** GLimp_EndFrame
+** GLimp_Init
+** GLimp_Shutdown
+** GLimp_SwitchFullscreen
+**
+*/
+
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include "../ref_gl/gl_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+#include <GL/fxmesa.h>
+
+/*****************************************************************************/
+
+static qboolean GLimp_SwitchFullscreen( int width, int height );
+qboolean GLimp_InitGL (void);
+
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_ref;
+
+static fxMesaContext fc = NULL;
+
+#define NUM_RESOLUTIONS 3
+
+static resolutions[NUM_RESOLUTIONS][3]={ 
+  { 512, 384, GR_RESOLUTION_512x384 },
+  { 640, 400, GR_RESOLUTION_640x400 },
+  { 640, 480, GR_RESOLUTION_640x480 }
+};
+
+static int findres(int *width, int *height)
+{
+	int i;
+
+	for(i=0;i<NUM_RESOLUTIONS;i++)
+		if((*width<=resolutions[i][0]) && (*height<=resolutions[i][1])) {
+			*width = resolutions[i][0];
+			*height = resolutions[i][1];
+			return resolutions[i][2];
+		}
+        
+	*width = 640;
+	*height = 480;
+	return GR_RESOLUTION_640x480;
+}
+
+static void signal_handler(int sig)
+{
+	printf("Received signal %d, exiting...\n", sig);
+	GLimp_Shutdown();
+	_exit(0);
+}
+
+static void InitSig(void)
+{
+	signal(SIGHUP, signal_handler);
+	signal(SIGQUIT, signal_handler);
+	signal(SIGILL, signal_handler);
+	signal(SIGTRAP, signal_handler);
+	signal(SIGIOT, signal_handler);
+	signal(SIGBUS, signal_handler);
+	signal(SIGFPE, signal_handler);
+	signal(SIGSEGV, signal_handler);
+	signal(SIGTERM, signal_handler);
+}
+
+/*
+** GLimp_SetMode
+*/
+int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+	int width, height;
+	GLint attribs[32];
+
+	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
+
+	ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
+
+	if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
+	{
+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+		return rserr_invalid_mode;
+	}
+
+	ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
+
+	// destroy the existing window
+	GLimp_Shutdown ();
+
+	// set fx attribs
+	attribs[0] = FXMESA_DOUBLEBUFFER;
+	attribs[1] = FXMESA_ALPHA_SIZE;
+	attribs[2] = 1;
+	attribs[3] = FXMESA_DEPTH_SIZE;
+	attribs[4] = 1;
+	attribs[5] = FXMESA_NONE;
+
+	fc = fxMesaCreateContext(0, findres(&width, &height), GR_REFRESH_75Hz, 
+		attribs);
+	if (!fc)
+		return rserr_invalid_mode;
+
+	*pwidth = width;
+	*pheight = height;
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (width, height);
+
+	fxMesaMakeCurrent(fc);
+
+	return rserr_ok;
+}
+
+/*
+** GLimp_Shutdown
+**
+** This routine does all OS specific shutdown procedures for the OpenGL
+** subsystem.  Under OpenGL this means NULLing out the current DC and
+** HGLRC, deleting the rendering context, and releasing the DC acquired
+** for the window.  The state structure is also nulled out.
+**
+*/
+void GLimp_Shutdown( void )
+{
+	if (fc) {
+		fxMesaDestroyContext(fc);
+		fc = NULL;
+	}
+}
+
+/*
+** GLimp_Init
+**
+** This routine is responsible for initializing the OS specific portions
+** of OpenGL.  
+*/
+int GLimp_Init( void *hinstance, void *wndproc )
+{
+	InitSig();
+
+	return true;
+}
+
+/*
+** GLimp_BeginFrame
+*/
+void GLimp_BeginFrame( float camera_seperation )
+{
+}
+
+/*
+** GLimp_EndFrame
+** 
+** Responsible for doing a swapbuffers and possibly for other stuff
+** as yet to be determined.  Probably better not to make this a GLimp
+** function and instead do a call to GLimp_SwapBuffers.
+*/
+void GLimp_EndFrame (void)
+{
+	glFlush();
+	fxMesaSwapBuffers();
+}
+
+/*
+** GLimp_AppActivate
+*/
+void GLimp_AppActivate( qboolean active )
+{
+}
+
+extern void gl3DfxSetPaletteEXT(GLuint *pal);
+
+void Fake_glColorTableEXT( GLenum target, GLenum internalformat,
+                             GLsizei width, GLenum format, GLenum type,
+                             const GLvoid *table )
+{
+	byte temptable[256][4];
+	byte *intbl;
+	int i;
+
+	for (intbl = (byte *)table, i = 0; i < 256; i++) {
+		temptable[i][2] = *intbl++;
+		temptable[i][1] = *intbl++;
+		temptable[i][0] = *intbl++;
+		temptable[i][3] = 255;
+	}
+	gl3DfxSetPaletteEXT((GLuint *)temptable);
+}
+
+
--- /dev/null
+++ b/linux/glob.c
@@ -1,0 +1,164 @@
+
+#include <stdio.h>
+#include "../linux/glob.h"
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
+static int glob_match_after_star(char *pattern, char *text)
+{
+	register char *p = pattern, *t = text;
+	register char c, c1;
+
+	while ((c = *p++) == '?' || c == '*')
+		if (c == '?' && *t++ == '\0')
+			return 0;
+
+	if (c == '\0')
+		return 1;
+
+	if (c == '\\')
+		c1 = *p;
+	else
+		c1 = c;
+
+	while (1) {
+		if ((c == '[' || *t == c1) && glob_match(p - 1, t))
+			return 1;
+		if (*t++ == '\0')
+			return 0;
+	}
+}
+
+/* Return nonzero if PATTERN has any special globbing chars in it.  */
+static int glob_pattern_p(char *pattern)
+{
+	register char *p = pattern;
+	register char c;
+	int open = 0;
+
+	while ((c = *p++) != '\0')
+		switch (c) {
+		case '?':
+		case '*':
+			return 1;
+
+		case '[':		/* Only accept an open brace if there is a close */
+			open++;		/* brace to match it.  Bracket expressions must be */
+			continue;	/* complete, according to Posix.2 */
+		case ']':
+			if (open)
+				return 1;
+			continue;
+
+		case '\\':
+			if (*p++ == '\0')
+				return 0;
+		}
+
+	return 0;
+}
+
+/* Match the pattern PATTERN against the string TEXT;
+   return 1 if it matches, 0 otherwise.
+
+   A match means the entire string TEXT is used up in matching.
+
+   In the pattern string, `*' matches any sequence of characters,
+   `?' matches any character, [SET] matches any character in the specified set,
+   [!SET] matches any character not in the specified set.
+
+   A set is composed of characters or ranges; a range looks like
+   character hyphen character (as in 0-9 or A-Z).
+   [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
+   Any other character in the pattern must be matched exactly.
+
+   To suppress the special syntactic significance of any of `[]*?!-\',
+   and match the character exactly, precede it with a `\'.
+*/
+
+int glob_match(char *pattern, char *text)
+{
+	register char *p = pattern, *t = text;
+	register char c;
+
+	while ((c = *p++) != '\0')
+		switch (c) {
+		case '?':
+			if (*t == '\0')
+				return 0;
+			else
+				++t;
+			break;
+
+		case '\\':
+			if (*p++ != *t++)
+				return 0;
+			break;
+
+		case '*':
+			return glob_match_after_star(p, t);
+
+		case '[':
+			{
+				register char c1 = *t++;
+				int invert;
+
+				if (!c1)
+					return (0);
+
+				invert = ((*p == '!') || (*p == '^'));
+				if (invert)
+					p++;
+
+				c = *p++;
+				while (1) {
+					register char cstart = c, cend = c;
+
+					if (c == '\\') {
+						cstart = *p++;
+						cend = cstart;
+					}
+					if (c == '\0')
+						return 0;
+
+					c = *p++;
+					if (c == '-' && *p != ']') {
+						cend = *p++;
+						if (cend == '\\')
+							cend = *p++;
+						if (cend == '\0')
+							return 0;
+						c = *p++;
+					}
+					if (c1 >= cstart && c1 <= cend)
+						goto match;
+					if (c == ']')
+						break;
+				}
+				if (!invert)
+					return 0;
+				break;
+
+			  match:
+				/* Skip the rest of the [...] construct that already matched.  */
+				while (c != ']') {
+					if (c == '\0')
+						return 0;
+					c = *p++;
+					if (c == '\0')
+						return 0;
+					else if (c == '\\')
+						++p;
+				}
+				if (invert)
+					return 0;
+				break;
+			}
+
+		default:
+			if (c != *t++)
+				return 0;
+		}
+
+	return *t == '\0';
+}
+
--- /dev/null
+++ b/linux/glob.h
@@ -1,0 +1,1 @@
+int glob_match(char *pattern, char *text);
--- /dev/null
+++ b/linux/in_linux.c
@@ -1,0 +1,29 @@
+// in_null.c -- for systems without a mouse
+
+#include "../client/client.h"
+
+cvar_t	*in_mouse;
+cvar_t	*in_joystick;
+
+void IN_Init (void)
+{
+    in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
+    in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
+}
+
+void IN_Shutdown (void)
+{
+}
+
+void IN_Commands (void)
+{
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+}
+
+void IN_Activate (qboolean active)
+{
+}
+
--- /dev/null
+++ b/linux/math.s
@@ -1,0 +1,403 @@
+//
+// math.s
+// x86 assembly-language math routines.
+
+#define GLQUAKE	1	// don't include unneeded defs
+#include "qasm.h"
+
+
+#if	id386
+
+	.data
+
+#if 0
+	.align	4
+Ljmptab:	.long	Lcase0, Lcase1, Lcase2, Lcase3
+			.long	Lcase4, Lcase5, Lcase6, Lcase7
+#endif
+
+	.text
+
+// TODO: rounding needed?
+// stack parameter offset
+#define	val	4
+
+.globl C(Invert24To16)
+C(Invert24To16):
+
+	movl	val(%esp),%ecx
+	movl	$0x100,%edx		// 0x10000000000 as dividend
+	cmpl	%edx,%ecx
+	jle		LOutOfRange
+
+	subl	%eax,%eax
+	divl	%ecx
+
+	ret
+
+LOutOfRange:
+	movl	$0xFFFFFFFF,%eax
+	ret
+
+#define	in	4
+#define out	8
+
+	.align 2
+.globl C(TransformVector)
+C(TransformVector):
+	movl	in(%esp),%eax
+	movl	out(%esp),%edx
+
+	flds	(%eax)		// in[0]
+	fmuls	C(vright)		// in[0]*vright[0]
+	flds	(%eax)		// in[0] | in[0]*vright[0]
+	fmuls	C(vup)		// in[0]*vup[0] | in[0]*vright[0]
+	flds	(%eax)		// in[0] | in[0]*vup[0] | in[0]*vright[0]
+	fmuls	C(vpn)		// in[0]*vpn[0] | in[0]*vup[0] | in[0]*vright[0]
+
+	flds	4(%eax)		// in[1] | ...
+	fmuls	C(vright)+4	// in[1]*vright[1] | ...
+	flds	4(%eax)		// in[1] | in[1]*vright[1] | ...
+	fmuls	C(vup)+4		// in[1]*vup[1] | in[1]*vright[1] | ...
+	flds	4(%eax)		// in[1] | in[1]*vup[1] | in[1]*vright[1] | ...
+	fmuls	C(vpn)+4		// in[1]*vpn[1] | in[1]*vup[1] | in[1]*vright[1] | ...
+	fxch	%st(2)		// in[1]*vright[1] | in[1]*vup[1] | in[1]*vpn[1] | ...
+
+	faddp	%st(0),%st(5)	// in[1]*vup[1] | in[1]*vpn[1] | ...
+	faddp	%st(0),%st(3)	// in[1]*vpn[1] | ...
+	faddp	%st(0),%st(1)	// vpn_accum | vup_accum | vright_accum
+
+	flds	8(%eax)		// in[2] | ...
+	fmuls	C(vright)+8	// in[2]*vright[2] | ...
+	flds	8(%eax)		// in[2] | in[2]*vright[2] | ...
+	fmuls	C(vup)+8		// in[2]*vup[2] | in[2]*vright[2] | ...
+	flds	8(%eax)		// in[2] | in[2]*vup[2] | in[2]*vright[2] | ...
+	fmuls	C(vpn)+8		// in[2]*vpn[2] | in[2]*vup[2] | in[2]*vright[2] | ...
+	fxch	%st(2)		// in[2]*vright[2] | in[2]*vup[2] | in[2]*vpn[2] | ...
+
+	faddp	%st(0),%st(5)	// in[2]*vup[2] | in[2]*vpn[2] | ...
+	faddp	%st(0),%st(3)	// in[2]*vpn[2] | ...
+	faddp	%st(0),%st(1)	// vpn_accum | vup_accum | vright_accum
+
+	fstps	8(%edx)		// out[2]
+	fstps	4(%edx)		// out[1]
+	fstps	(%edx)		// out[0]
+
+	ret
+
+#if 0 // in C
+
+#define EMINS	4+4
+#define EMAXS	4+8
+#define P		4+12
+
+	.align 2
+.globl C(BoxOnPlaneSide)
+C(BoxOnPlaneSide):
+	pushl	%ebx
+
+	movl	P(%esp),%edx
+	movl	EMINS(%esp),%ecx
+	xorl	%eax,%eax
+	movl	EMAXS(%esp),%ebx
+	movb	pl_signbits(%edx),%al
+	cmpb	$8,%al
+	jge		Lerror
+	flds	pl_normal(%edx)		// p->normal[0]
+	fld		%st(0)				// p->normal[0] | p->normal[0]
+	jmp		Ljmptab(,%eax,4)
+
+
+//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+Lcase0:
+	fmuls	(%ebx)				// p->normal[0]*emaxs[0] | p->normal[0]
+	flds	pl_normal+4(%edx)	// p->normal[1] | p->normal[0]*emaxs[0] |
+								//  p->normal[0]
+	fxch	%st(2)				// p->normal[0] | p->normal[0]*emaxs[0] |
+								//  p->normal[1]
+	fmuls	(%ecx)				// p->normal[0]*emins[0] |
+								//  p->normal[0]*emaxs[0] | p->normal[1]
+	fxch	%st(2)				// p->normal[1] | p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fld		%st(0)				// p->normal[1] | p->normal[1] |
+								//  p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fmuls	4(%ebx)				// p->normal[1]*emaxs[1] | p->normal[1] |
+								//  p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	flds	pl_normal+8(%edx)	// p->normal[2] | p->normal[1]*emaxs[1] |
+								//  p->normal[1] | p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fxch	%st(2)				// p->normal[1] | p->normal[1]*emaxs[1] |
+								//  p->normal[2] | p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fmuls	4(%ecx)				// p->normal[1]*emins[1] |
+								//  p->normal[1]*emaxs[1] |
+								//  p->normal[2] | p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fxch	%st(2)				// p->normal[2] | p->normal[1]*emaxs[1] |
+								//  p->normal[1]*emins[1] |
+								//  p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fld		%st(0)				// p->normal[2] | p->normal[2] |
+								//  p->normal[1]*emaxs[1] |
+								//  p->normal[1]*emins[1] |
+								//  p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fmuls	8(%ebx)				// p->normal[2]*emaxs[2] |
+								//  p->normal[2] |
+								//  p->normal[1]*emaxs[1] |
+								//  p->normal[1]*emins[1] |
+								//  p->normal[0]*emaxs[0] |
+								//  p->normal[0]*emins[0]
+	fxch	%st(5)				// p->normal[0]*emins[0] |
+								//  p->normal[2] |
+								//  p->normal[1]*emaxs[1] |
+								//  p->normal[1]*emins[1] |
+								//  p->normal[0]*emaxs[0] |
+								//  p->normal[2]*emaxs[2]
+	faddp	%st(0),%st(3)		//p->normal[2] |
+								// p->normal[1]*emaxs[1] |
+								// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
+								// p->normal[0]*emaxs[0] |
+								// p->normal[2]*emaxs[2]
+	fmuls	8(%ecx)				//p->normal[2]*emins[2] |
+								// p->normal[1]*emaxs[1] |
+								// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
+								// p->normal[0]*emaxs[0] |
+								// p->normal[2]*emaxs[2]
+	fxch	%st(1)				//p->normal[1]*emaxs[1] |
+								// p->normal[2]*emins[2] |
+								// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
+								// p->normal[0]*emaxs[0] |
+								// p->normal[2]*emaxs[2]
+	faddp	%st(0),%st(3)		//p->normal[2]*emins[2] |
+								// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
+								// p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]|
+								// p->normal[2]*emaxs[2]
+	fxch	%st(3)				//p->normal[2]*emaxs[2] +
+								// p->normal[1]*emins[1]+p->normal[0]*emins[0]|
+								// p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]|
+								// p->normal[2]*emins[2]
+	faddp	%st(0),%st(2)		//p->normal[1]*emins[1]+p->normal[0]*emins[0]|
+								// dist1 | p->normal[2]*emins[2]
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+Lcase1:
+	fmuls	(%ecx)				// emins[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ebx)				// emaxs[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ebx)				// emaxs[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ecx)				// emins[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+Lcase2:
+	fmuls	(%ebx)				// emaxs[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ecx)				// emins[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ecx)				// emins[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ebx)				// emaxs[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+Lcase3:
+	fmuls	(%ecx)				// emins[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ebx)				// emaxs[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ecx)				// emins[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ebx)				// emaxs[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+Lcase4:
+	fmuls	(%ebx)				// emaxs[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ecx)				// emins[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ebx)				// emaxs[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ecx)				// emins[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
+//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
+Lcase5:
+	fmuls	(%ecx)				// emins[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ebx)				// emaxs[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ebx)				// emaxs[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ecx)				// emins[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+Lcase6:
+	fmuls	(%ebx)				// emaxs[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ecx)				// emins[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ecx)				// emins[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ebx)				// emaxs[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+	jmp		LSetSides
+
+//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
+//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
+Lcase7:
+	fmuls	(%ecx)				// emins[0]
+	flds	pl_normal+4(%edx)
+	fxch	%st(2)
+	fmuls	(%ebx)				// emaxs[0]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	4(%ecx)				// emins[1]
+	flds	pl_normal+8(%edx)
+	fxch	%st(2)
+	fmuls	4(%ebx)				// emaxs[1]
+	fxch	%st(2)
+	fld		%st(0)
+	fmuls	8(%ecx)				// emins[2]
+	fxch	%st(5)
+	faddp	%st(0),%st(3)
+	fmuls	8(%ebx)				// emaxs[2]
+	fxch	%st(1)
+	faddp	%st(0),%st(3)
+	fxch	%st(3)
+	faddp	%st(0),%st(2)
+
+LSetSides:
+
+//	sides = 0;
+//	if (dist1 >= p->dist)
+//		sides = 1;
+//	if (dist2 < p->dist)
+//		sides |= 2;
+
+	faddp	%st(0),%st(2)		// dist1 | dist2
+	fcomps	pl_dist(%edx)
+	xorl	%ecx,%ecx
+	fnstsw	%ax
+	fcomps	pl_dist(%edx)
+	andb	$1,%ah
+	xorb	$1,%ah
+	addb	%ah,%cl
+
+	fnstsw	%ax
+	andb	$1,%ah
+	addb	%ah,%ah
+	addb	%ah,%cl
+
+//	return sides;
+
+	popl	%ebx
+	movl	%ecx,%eax	// return status
+
+	ret
+
+
+Lerror:
+	call	C(BOPS_Error)
+
+#endif
+
+#endif	// id386
--- /dev/null
+++ b/linux/net_udp.c
@@ -1,0 +1,537 @@
+// net_wins.c
+
+#include "../qcommon/qcommon.h"
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+
+netadr_t	net_local_adr;
+
+#define	LOOPBACK	0x7f000001
+
+#define	MAX_LOOPBACK	4
+
+typedef struct
+{
+	byte	data[MAX_MSGLEN];
+	int		datalen;
+} loopmsg_t;
+
+typedef struct
+{
+	loopmsg_t	msgs[MAX_LOOPBACK];
+	int			get, send;
+} loopback_t;
+
+loopback_t	loopbacks[2];
+int			ip_sockets[2];
+int			ipx_sockets[2];
+
+int NET_Socket (char *net_interface, int port);
+char *NET_ErrorString (void);
+
+//=============================================================================
+
+void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
+{
+	memset (s, 0, sizeof(*s));
+
+	if (a->type == NA_BROADCAST)
+	{
+		s->sin_family = AF_INET;
+
+		s->sin_port = a->port;
+		*(int *)&s->sin_addr = -1;
+	}
+	else if (a->type == NA_IP)
+	{
+		s->sin_family = AF_INET;
+
+		*(int *)&s->sin_addr = *(int *)&a->ip;
+		s->sin_port = a->port;
+	}
+}
+
+void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
+{
+	*(int *)&a->ip = *(int *)&s->sin_addr;
+	a->port = s->sin_port;
+	a->type = NA_IP;
+}
+
+
+qboolean	NET_CompareAdr (netadr_t a, netadr_t b)
+{
+	if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
+		return true;
+	return false;
+}
+
+/*
+===================
+NET_CompareBaseAdr
+
+Compares without the port
+===================
+*/
+qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b)
+{
+	if (a.type != b.type)
+		return false;
+
+	if (a.type == NA_LOOPBACK)
+		return true;
+
+	if (a.type == NA_IP)
+	{
+		if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
+			return true;
+		return false;
+	}
+
+	if (a.type == NA_IPX)
+	{
+		if ((memcmp(a.ipx, b.ipx, 10) == 0))
+			return true;
+		return false;
+	}
+}
+
+char	*NET_AdrToString (netadr_t a)
+{
+	static	char	s[64];
+	
+	Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
+
+	return s;
+}
+
+char	*NET_BaseAdrToString (netadr_t a)
+{
+	static	char	s[64];
+	
+	Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
+
+	return s;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean	NET_StringToSockaddr (char *s, struct sockaddr *sadr)
+{
+	struct hostent	*h;
+	char	*colon;
+	char	copy[128];
+	
+	memset (sadr, 0, sizeof(*sadr));
+	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
+	
+	((struct sockaddr_in *)sadr)->sin_port = 0;
+
+	strcpy (copy, s);
+	// strip off a trailing :port if present
+	for (colon = copy ; *colon ; colon++)
+		if (*colon == ':')
+		{
+			*colon = 0;
+			((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));	
+		}
+	
+	if (copy[0] >= '0' && copy[0] <= '9')
+	{
+		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
+	}
+	else
+	{
+		if (! (h = gethostbyname(copy)) )
+			return 0;
+		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
+	}
+	
+	return true;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean	NET_StringToAdr (char *s, netadr_t *a)
+{
+	struct sockaddr_in sadr;
+	
+	if (!strcmp (s, "localhost"))
+	{
+		memset (a, 0, sizeof(*a));
+		a->type = NA_LOOPBACK;
+		return true;
+	}
+
+	if (!NET_StringToSockaddr (s, (struct sockaddr *)&sadr))
+		return false;
+	
+	SockadrToNetadr (&sadr, a);
+
+	return true;
+}
+
+
+qboolean	NET_IsLocalAddress (netadr_t adr)
+{
+	return NET_CompareAdr (adr, net_local_adr);
+}
+
+/*
+=============================================================================
+
+LOOPBACK BUFFERS FOR LOCAL PLAYER
+
+=============================================================================
+*/
+
+qboolean	NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+	int		i;
+	loopback_t	*loop;
+
+	loop = &loopbacks[sock];
+
+	if (loop->send - loop->get > MAX_LOOPBACK)
+		loop->get = loop->send - MAX_LOOPBACK;
+
+	if (loop->get >= loop->send)
+		return false;
+
+	i = loop->get & (MAX_LOOPBACK-1);
+	loop->get++;
+
+	memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
+	net_message->cursize = loop->msgs[i].datalen;
+	*net_from = net_local_adr;
+	return true;
+
+}
+
+
+void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+	int		i;
+	loopback_t	*loop;
+
+	loop = &loopbacks[sock^1];
+
+	i = loop->send & (MAX_LOOPBACK-1);
+	loop->send++;
+
+	memcpy (loop->msgs[i].data, data, length);
+	loop->msgs[i].datalen = length;
+}
+
+//=============================================================================
+
+qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+	int 	ret;
+	struct sockaddr_in	from;
+	int		fromlen;
+	int		net_socket;
+	int		protocol;
+	int		err;
+
+	if (NET_GetLoopPacket (sock, net_from, net_message))
+		return true;
+
+	for (protocol = 0 ; protocol < 2 ; protocol++)
+	{
+		if (protocol == 0)
+			net_socket = ip_sockets[sock];
+		else
+			net_socket = ipx_sockets[sock];
+
+		if (!net_socket)
+			continue;
+
+		fromlen = sizeof(from);
+		ret = recvfrom (net_socket, net_message->data, net_message->maxsize
+			, 0, (struct sockaddr *)&from, &fromlen);
+		if (ret == -1)
+		{
+			err = errno;
+
+			if (err == EWOULDBLOCK || err == ECONNREFUSED)
+				continue;
+			Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
+			continue;
+		}
+
+		if (ret == net_message->maxsize)
+		{
+			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
+			continue;
+		}
+
+		net_message->cursize = ret;
+		SockadrToNetadr (&from, net_from);
+		return true;
+	}
+
+	return false;
+}
+
+//=============================================================================
+
+void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+	int		ret;
+	struct sockaddr_in	addr;
+	int		net_socket;
+
+	if ( to.type == NA_LOOPBACK )
+	{
+		NET_SendLoopPacket (sock, length, data, to);
+		return;
+	}
+
+	if (to.type == NA_BROADCAST)
+	{
+		net_socket = ip_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_IP)
+	{
+		net_socket = ip_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_IPX)
+	{
+		net_socket = ipx_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_BROADCAST_IPX)
+	{
+		net_socket = ipx_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else
+		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
+
+	NetadrToSockadr (&to, &addr);
+
+	ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
+	if (ret == -1)
+	{
+		Com_Printf ("NET_SendPacket ERROR: %i\n", NET_ErrorString());
+	}
+}
+
+
+//=============================================================================
+
+
+
+
+/*
+====================
+NET_OpenIP
+====================
+*/
+void NET_OpenIP (void)
+{
+	cvar_t	*port, *ip;
+
+	port = Cvar_Get ("port", va("%i", PORT_SERVER), CVAR_NOSET);
+	ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
+
+	if (!ip_sockets[NS_SERVER])
+		ip_sockets[NS_SERVER] = NET_Socket (ip->string, port->value);
+	if (!ip_sockets[NS_CLIENT])
+		ip_sockets[NS_CLIENT] = NET_Socket (ip->string, PORT_ANY);
+}
+
+/*
+====================
+NET_OpenIPX
+====================
+*/
+void NET_OpenIPX (void)
+{
+}
+
+
+/*
+====================
+NET_Config
+
+A single player game will only use the loopback code
+====================
+*/
+void	NET_Config (qboolean multiplayer)
+{
+	int		i;
+
+	if (!multiplayer)
+	{	// shut down any existing sockets
+		for (i=0 ; i<2 ; i++)
+		{
+			if (ip_sockets[i])
+			{
+				close (ip_sockets[i]);
+				ip_sockets[i] = 0;
+			}
+			if (ipx_sockets[i])
+			{
+				close (ipx_sockets[i]);
+				ipx_sockets[i] = 0;
+			}
+		}
+	}
+	else
+	{	// open sockets
+		NET_OpenIP ();
+		NET_OpenIPX ();
+	}
+}
+
+
+//===================================================================
+
+
+/*
+====================
+NET_Init
+====================
+*/
+void NET_Init (void)
+{
+}
+
+
+/*
+====================
+NET_Socket
+====================
+*/
+int NET_Socket (char *net_interface, int port)
+{
+	int newsocket;
+	struct sockaddr_in address;
+	qboolean _true = true;
+	int	i = 1;
+
+	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
+		return 0;
+	}
+
+	// make it non-blocking
+	if (ioctl (newsocket, FIONBIO, &_true) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
+		return 0;
+	}
+
+	// make it broadcast capable
+	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
+		return 0;
+	}
+
+	if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
+		address.sin_addr.s_addr = INADDR_ANY;
+	else
+		NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
+
+	if (port == PORT_ANY)
+		address.sin_port = 0;
+	else
+		address.sin_port = htons((short)port);
+
+	address.sin_family = AF_INET;
+
+	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
+		close (newsocket);
+		return 0;
+	}
+
+	return newsocket;
+}
+
+
+/*
+====================
+NET_Shutdown
+====================
+*/
+void	NET_Shutdown (void)
+{
+	NET_Config (false);	// close sockets
+}
+
+
+/*
+====================
+NET_ErrorString
+====================
+*/
+char *NET_ErrorString (void)
+{
+	int		code;
+
+	code = errno;
+	return strerror (code);
+}
+
+// sleeps msec or until net socket is ready
+void NET_Sleep(int msec)
+{
+    struct timeval timeout;
+	fd_set	fdset;
+	extern cvar_t *dedicated;
+	extern qboolean stdin_active;
+
+	if (!ip_sockets[NS_SERVER] || (dedicated && !dedicated->value))
+		return; // we're not a server, just run full speed
+
+	FD_ZERO(&fdset);
+	if (stdin_active)
+		FD_SET(0, &fdset); // stdin is processed too
+	FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
+	timeout.tv_sec = msec/1000;
+	timeout.tv_usec = (msec%1000)*1000;
+	select(ip_sockets[NS_SERVER]+1, &fdset, NULL, NULL, &timeout);
+}
+
--- /dev/null
+++ b/linux/q_shlinux.c
@@ -1,0 +1,205 @@
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "../linux/glob.h"
+
+#include "../qcommon/qcommon.h"
+
+//===============================================================================
+
+byte *membase;
+int maxhunksize;
+int curhunksize;
+
+void *Hunk_Begin (int maxsize)
+{
+	// reserve a huge chunk of memory, but don't commit any yet
+	maxhunksize = maxsize + sizeof(int);
+	curhunksize = 0;
+	membase = mmap(0, maxhunksize, PROT_READ|PROT_WRITE, 
+		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+	if (membase == NULL || membase == (byte *)-1)
+		Sys_Error("unable to virtual allocate %d bytes", maxsize);
+
+	*((int *)membase) = curhunksize;
+
+	return membase + sizeof(int);
+}
+
+void *Hunk_Alloc (int size)
+{
+	byte *buf;
+
+	// round to cacheline
+	size = (size+31)&~31;
+	if (curhunksize + size > maxhunksize)
+		Sys_Error("Hunk_Alloc overflow");
+	buf = membase + sizeof(int) + curhunksize;
+	curhunksize += size;
+	return buf;
+}
+
+int Hunk_End (void)
+{
+	byte *n;
+
+	n = mremap(membase, maxhunksize, curhunksize + sizeof(int), 0);
+	if (n != membase)
+		Sys_Error("Hunk_End:  Could not remap virtual block (%d)", errno);
+	*((int *)membase) = curhunksize + sizeof(int);
+	
+	return curhunksize;
+}
+
+void Hunk_Free (void *base)
+{
+	byte *m;
+
+	if (base) {
+		m = ((byte *)base) - sizeof(int);
+		if (munmap(m, *((int *)m)))
+			Sys_Error("Hunk_Free: munmap failed (%d)", errno);
+	}
+}
+
+//===============================================================================
+
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int curtime;
+int Sys_Milliseconds (void)
+{
+	struct timeval tp;
+	struct timezone tzp;
+	static int		secbase;
+
+	gettimeofday(&tp, &tzp);
+	
+	if (!secbase)
+	{
+		secbase = tp.tv_sec;
+		return tp.tv_usec/1000;
+	}
+
+	curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
+	
+	return curtime;
+}
+
+void Sys_Mkdir (char *path)
+{
+    mkdir (path, 0777);
+}
+
+char *strlwr (char *s)
+{
+	while (*s) {
+		*s = tolower(*s);
+		s++;
+	}
+}
+
+//============================================
+
+static	char	findbase[MAX_OSPATH];
+static	char	findpath[MAX_OSPATH];
+static	char	findpattern[MAX_OSPATH];
+static	DIR		*fdir;
+
+static qboolean CompareAttributes(char *path, char *name,
+	unsigned musthave, unsigned canthave )
+{
+	struct stat st;
+	char fn[MAX_OSPATH];
+
+// . and .. never match
+	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+		return false;
+
+	sprintf(fn, "%s/%s", path, name);
+	if (stat(fn, &st) == -1)
+		return false; // shouldn't happen
+
+	if ( ( st.st_mode & S_IFDIR ) && ( canthave & SFF_SUBDIR ) )
+		return false;
+
+	if ( ( musthave & SFF_SUBDIR ) && !( st.st_mode & S_IFDIR ) )
+		return false;
+
+	return true;
+}
+
+char *Sys_FindFirst (char *path, unsigned musthave, unsigned canhave)
+{
+	struct dirent *d;
+	char *p;
+
+	if (fdir)
+		Sys_Error ("Sys_BeginFind without close");
+
+//	COM_FilePath (path, findbase);
+	strcpy(findbase, path);
+
+	if ((p = strrchr(findbase, '/')) != NULL) {
+		*p = 0;
+		strcpy(findpattern, p + 1);
+	} else
+		strcpy(findpattern, "*");
+
+	if (strcmp(findpattern, "*.*") == 0)
+		strcpy(findpattern, "*");
+	
+	if ((fdir = opendir(findbase)) == NULL)
+		return NULL;
+	while ((d = readdir(fdir)) != NULL) {
+		if (!*findpattern || glob_match(findpattern, d->d_name)) {
+//			if (*findpattern)
+//				printf("%s matched %s\n", findpattern, d->d_name);
+			if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+				sprintf (findpath, "%s/%s", findbase, d->d_name);
+				return findpath;
+			}
+		}
+	}
+	return NULL;
+}
+
+char *Sys_FindNext (unsigned musthave, unsigned canhave)
+{
+	struct dirent *d;
+
+	if (fdir == NULL)
+		return NULL;
+	while ((d = readdir(fdir)) != NULL) {
+		if (!*findpattern || glob_match(findpattern, d->d_name)) {
+//			if (*findpattern)
+//				printf("%s matched %s\n", findpattern, d->d_name);
+			if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+				sprintf (findpath, "%s/%s", findbase, d->d_name);
+				return findpath;
+			}
+		}
+	}
+	return NULL;
+}
+
+void Sys_FindClose (void)
+{
+	if (fdir != NULL)
+		closedir(fdir);
+	fdir = NULL;
+}
+
+
+//============================================
+
--- /dev/null
+++ b/linux/qasm.h
@@ -1,0 +1,459 @@
+#ifndef __ASM_I386__
+#define __ASM_I386__
+
+#ifdef ELF
+#define C(label) label
+#else
+#define C(label) _##label
+#endif
+
+
+//#define GLQUAKE	1
+
+#if defined(_WIN32) && !defined(WINDED)
+
+#if defined(_M_IX86)
+#define __i386__	1
+#endif
+
+#endif
+
+#ifdef __i386__
+#define id386	1
+#else
+#define id386	0
+#endif
+
+// !!! must be kept the same as in d_iface.h !!!
+#define TRANSPARENT_COLOR	255
+
+#ifndef GLQUAKE
+	.extern C(d_zistepu)
+	.extern C(d_pzbuffer)
+	.extern C(d_zistepv)
+	.extern C(d_zrowbytes)
+	.extern C(d_ziorigin)
+	.extern C(r_turb_s)
+	.extern C(r_turb_t)
+	.extern C(r_turb_pdest)
+	.extern C(r_turb_spancount)
+	.extern C(r_turb_turb)
+	.extern C(r_turb_pbase)
+	.extern C(r_turb_sstep)
+	.extern C(r_turb_tstep)
+	.extern	C(r_bmodelactive)
+	.extern	C(d_sdivzstepu)
+	.extern	C(d_tdivzstepu)
+	.extern	C(d_sdivzstepv)
+	.extern	C(d_tdivzstepv)
+	.extern	C(d_sdivzorigin)
+	.extern	C(d_tdivzorigin)
+	.extern	C(sadjust)
+	.extern	C(tadjust)
+	.extern	C(bbextents)
+	.extern	C(bbextentt)
+	.extern	C(cacheblock)
+	.extern	C(d_viewbuffer)
+	.extern	C(cachewidth)
+	.extern	C(d_pzbuffer)
+	.extern	C(d_zrowbytes)
+	.extern	C(d_zwidth)
+	.extern C(d_scantable)
+	.extern C(r_lightptr)
+	.extern C(r_numvblocks)
+	.extern C(prowdestbase)
+	.extern C(pbasesource)
+	.extern C(r_lightwidth)
+	.extern C(lightright)
+	.extern C(lightrightstep)
+	.extern C(lightdeltastep)
+	.extern C(lightdelta)
+	.extern C(lightright)
+	.extern C(lightdelta)
+	.extern C(sourcetstep)
+	.extern C(surfrowbytes)
+	.extern C(lightrightstep)
+	.extern C(lightdeltastep)
+	.extern C(r_sourcemax)
+	.extern C(r_stepback)
+	.extern C(colormap)
+	.extern C(blocksize)
+	.extern C(sourcesstep)
+	.extern C(lightleft)
+	.extern C(blockdivshift)
+	.extern C(blockdivmask)
+	.extern C(lightleftstep)
+	.extern C(r_origin)
+	.extern C(r_ppn)
+	.extern C(r_pup)
+	.extern C(r_pright)
+	.extern C(ycenter)
+	.extern C(xcenter)
+	.extern C(d_vrectbottom_particle)
+	.extern C(d_vrectright_particle)
+	.extern C(d_vrecty)
+	.extern C(d_vrectx)
+	.extern C(d_pix_shift)
+	.extern C(d_pix_min)
+	.extern C(d_pix_max)
+	.extern C(d_y_aspect_shift)
+	.extern C(screenwidth)
+	.extern C(r_leftclipped)
+	.extern C(r_leftenter)
+	.extern C(r_rightclipped)
+	.extern C(r_rightenter)
+	.extern C(modelorg)
+	.extern C(xscale)
+	.extern C(r_refdef)
+	.extern C(yscale)
+	.extern C(r_leftexit)
+	.extern C(r_rightexit)
+	.extern C(r_lastvertvalid)
+	.extern C(cacheoffset)
+	.extern C(newedges)
+	.extern C(removeedges)
+	.extern C(r_pedge)
+	.extern C(r_framecount)
+	.extern C(r_u1)
+	.extern C(r_emitted)
+	.extern C(edge_p)
+	.extern C(surface_p)
+	.extern C(surfaces)
+	.extern C(r_lzi1)
+	.extern C(r_v1)
+	.extern C(r_ceilv1)
+	.extern C(r_nearzi)
+	.extern C(r_nearzionly)
+	.extern C(edge_aftertail)
+	.extern C(edge_tail)
+	.extern C(current_iv)
+	.extern C(edge_head_u_shift20)
+	.extern C(span_p)
+	.extern C(edge_head)
+	.extern C(fv)
+	.extern C(edge_tail_u_shift20)
+	.extern C(r_apverts)
+	.extern C(r_anumverts)
+	.extern C(aliastransform)
+	.extern C(r_avertexnormals)
+	.extern C(r_plightvec)
+	.extern C(r_ambientlight)
+	.extern C(r_shadelight)
+	.extern C(aliasxcenter)
+	.extern C(aliasycenter)
+	.extern C(a_sstepxfrac)
+	.extern C(r_affinetridesc)
+	.extern C(acolormap)
+	.extern C(d_pcolormap)
+	.extern C(r_affinetridesc)
+	.extern C(d_sfrac)
+	.extern C(d_ptex)
+	.extern C(d_pedgespanpackage)
+	.extern C(d_tfrac)
+	.extern C(d_light)
+	.extern C(d_zi)
+	.extern C(d_pdest)
+	.extern C(d_pz)
+	.extern C(d_aspancount)
+	.extern C(erroradjustup)
+	.extern C(errorterm)
+	.extern C(d_xdenom)
+	.extern C(r_p0)
+	.extern C(r_p1)
+	.extern C(r_p2)
+	.extern C(a_tstepxfrac)
+	.extern C(r_sstepx)
+	.extern C(r_tstepx)
+	.extern C(a_ststepxwhole)
+	.extern C(zspantable)
+	.extern C(skintable)
+	.extern C(r_zistepx)
+	.extern C(erroradjustdown)
+	.extern C(d_countextrastep)
+	.extern C(ubasestep)
+	.extern C(a_ststepxwhole)
+	.extern C(a_tstepxfrac)
+	.extern C(r_lstepx)
+	.extern C(a_spans)
+	.extern C(erroradjustdown)
+	.extern C(d_pdestextrastep)
+	.extern C(d_pzextrastep)
+	.extern C(d_sfracextrastep)
+	.extern C(d_ptexextrastep)
+	.extern C(d_countextrastep)
+	.extern C(d_tfracextrastep)
+	.extern C(d_lightextrastep)
+	.extern C(d_ziextrastep)
+	.extern C(d_pdestbasestep)
+	.extern C(d_pzbasestep)
+	.extern C(d_sfracbasestep)
+	.extern C(d_ptexbasestep)
+	.extern C(ubasestep)
+	.extern C(d_tfracbasestep)
+	.extern C(d_lightbasestep)
+	.extern C(d_zibasestep)
+	.extern C(zspantable)
+	.extern C(r_lstepy)
+	.extern C(r_sstepy)
+	.extern C(r_tstepy)
+	.extern C(r_zistepy)
+	.extern C(D_PolysetSetEdgeTable)
+	.extern C(D_RasterizeAliasPolySmooth)
+
+	.extern float_point5
+	.extern Float2ToThe31nd
+	.extern izistep
+	.extern izi
+	.extern FloatMinus2ToThe31nd
+	.extern float_1
+	.extern float_particle_z_clip
+	.extern float_minus_1
+	.extern float_0
+	.extern fp_16
+	.extern fp_64k
+	.extern fp_1m
+	.extern fp_1m_minus_1
+	.extern fp_8 
+	.extern entryvec_table
+	.extern advancetable
+	.extern sstep
+	.extern tstep
+	.extern pspantemp
+	.extern counttemp
+	.extern jumptemp
+	.extern reciprocal_table
+	.extern DP_Count
+	.extern DP_u
+	.extern DP_v
+	.extern DP_32768
+	.extern DP_Color
+	.extern DP_Pix
+	.extern DP_EntryTable
+	.extern	pbase
+	.extern s
+	.extern t
+	.extern sfracf
+	.extern tfracf
+	.extern snext
+	.extern tnext
+	.extern	spancountminus1
+	.extern zi16stepu
+	.extern sdivz16stepu
+	.extern tdivz16stepu
+	.extern	zi8stepu
+	.extern sdivz8stepu
+	.extern tdivz8stepu
+	.extern reciprocal_table_16
+	.extern entryvec_table_16
+	.extern ceil_cw
+	.extern single_cw
+	.extern fp_64kx64k
+	.extern pz
+	.extern spr8entryvec_table
+#endif
+
+	.extern C(snd_scaletable)
+	.extern C(paintbuffer)
+	.extern C(snd_linear_count)
+	.extern C(snd_p)
+	.extern C(snd_vol)
+	.extern C(snd_out)
+	.extern C(vright)
+	.extern C(vup)
+	.extern C(vpn)
+	.extern C(BOPS_Error)
+
+//
+// !!! note that this file must match the corresponding C structures at all
+// times !!!
+//
+
+// plane_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+// !!! if the size of this is changed, the array lookup in SV_HullPointContents
+//     must be changed too !!!
+#define pl_normal	0
+#define pl_dist		12
+#define pl_type		16
+#define pl_signbits	17
+#define pl_pad		18
+#define pl_size		20
+
+// hull_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define	hu_clipnodes		0
+#define	hu_planes			4
+#define	hu_firstclipnode	8
+#define	hu_lastclipnode		12
+#define	hu_clip_mins		16
+#define	hu_clip_maxs		28
+#define hu_size  			40
+
+// dnode_t structure
+// !!! if this is changed, it must be changed in bspfile.h too !!!
+#define	nd_planenum		0
+#define	nd_children		4
+#define	nd_mins			8
+#define	nd_maxs			20
+#define	nd_firstface	32
+#define	nd_numfaces		36
+#define nd_size			40
+
+// sfxcache_t structure
+// !!! if this is changed, it much be changed in sound.h too !!!
+#define sfxc_length		0
+#define sfxc_loopstart	4
+#define sfxc_speed		8
+#define sfxc_width		12
+#define sfxc_stereo		16
+#define sfxc_data		20
+
+// channel_t structure
+// !!! if this is changed, it much be changed in sound.h too !!!
+#define ch_sfx			0
+#define ch_leftvol		4
+#define ch_rightvol		8
+#define ch_end			12
+#define ch_pos			16
+#define ch_looping		20
+#define ch_entnum		24
+#define ch_entchannel	28
+#define ch_origin		32
+#define ch_dist_mult	44
+#define ch_master_vol	48
+#define ch_size			52
+
+// portable_samplepair_t structure
+// !!! if this is changed, it much be changed in sound.h too !!!
+#define psp_left		0
+#define psp_right		4
+#define psp_size		8
+
+
+//
+// !!! note that this file must match the corresponding C structures at all
+// times !!!
+//
+
+// !!! if this is changed, it must be changed in r_local.h too !!!
+#define	NEAR_CLIP	0.01
+
+// !!! if this is changed, it must be changed in r_local.h too !!!
+#define	CYCLE	128
+
+// espan_t structure
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define espan_t_u    	0
+#define espan_t_v	    4
+#define espan_t_count   8
+#define espan_t_pnext	12
+#define espan_t_size    16
+
+// sspan_t structure
+// !!! if this is changed, it must be changed in d_local.h too !!!
+#define sspan_t_u    	0
+#define sspan_t_v	    4
+#define sspan_t_count   8
+#define sspan_t_size    12
+
+// spanpackage_t structure
+// !!! if this is changed, it must be changed in d_polyset.c too !!!
+#define spanpackage_t_pdest				0
+#define spanpackage_t_pz				4
+#define spanpackage_t_count				8
+#define spanpackage_t_ptex				12
+#define spanpackage_t_sfrac				16
+#define spanpackage_t_tfrac				20
+#define spanpackage_t_light				24
+#define spanpackage_t_zi				28
+#define spanpackage_t_size				32 
+
+// edge_t structure
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define et_u			0
+#define et_u_step		4
+#define et_prev			8
+#define et_next			12
+#define et_surfs		16
+#define et_nextremove	20
+#define et_nearzi		24
+#define et_owner		28
+#define et_size			32
+
+// surf_t structure
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define SURF_T_SHIFT	6
+#define st_next			0
+#define st_prev			4
+#define st_spans		8
+#define st_key			12
+#define st_last_u		16
+#define st_spanstate	20
+#define st_flags		24
+#define st_data			28
+#define st_entity		32
+#define st_nearzi		36
+#define st_insubmodel	40
+#define st_d_ziorigin	44
+#define st_d_zistepu	48
+#define st_d_zistepv	52
+#define st_pad			56
+#define st_size			64
+
+// clipplane_t structure
+// !!! if this is changed, it must be changed in r_local.h too !!!
+#define cp_normal		0
+#define cp_dist			12
+#define cp_next			16
+#define cp_leftedge		20
+#define cp_rightedge	21
+#define cp_reserved		22
+#define cp_size			24
+
+// medge_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define me_v				0
+#define me_cachededgeoffset	4
+#define me_size				8
+
+// mvertex_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define mv_position		0
+#define mv_size			12
+
+// refdef_t structure
+// !!! if this is changed, it must be changed in render.h too !!!
+#define rd_vrect					0
+#define rd_aliasvrect				20
+#define rd_vrectright				40
+#define rd_vrectbottom				44
+#define rd_aliasvrectright			48
+#define rd_aliasvrectbottom			52
+#define rd_vrectrightedge			56
+#define rd_fvrectx					60
+#define rd_fvrecty					64
+#define rd_fvrectx_adj				68
+#define rd_fvrecty_adj				72
+#define rd_vrect_x_adj_shift20		76
+#define rd_vrectright_adj_shift20	80
+#define rd_fvrectright_adj			84
+#define rd_fvrectbottom_adj			88
+#define rd_fvrectright				92
+#define rd_fvrectbottom				96
+#define rd_horizontalFieldOfView	100
+#define rd_xOrigin					104
+#define rd_yOrigin					108
+#define rd_vieworg					112
+#define rd_viewangles				124
+#define rd_ambientlight				136
+#define rd_size						140
+
+// mtriangle_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define mtri_facesfront		0
+#define mtri_vertindex		4
+#define mtri_size			16	// !!! if this changes, array indexing in !!!
+								// !!! d_polysa.s must be changed to match !!!
+#define mtri_shift			4
+
+#endif
--- /dev/null
+++ b/linux/qgl_linux.c
@@ -1,0 +1,3994 @@
+/*
+** QGL_WIN.C
+**
+** This file implements the operating system binding of GL to QGL function
+** pointers.  When doing a port of Quake2 you must implement the following
+** two functions:
+**
+** QGL_Init() - loads libraries, assigns function pointers, etc.
+** QGL_Shutdown() - unloads libraries, NULLs function pointers
+*/
+#define QGL
+#include "../ref_gl/gl_local.h"
+
+static FILE *log_fp = NULL;
+
+void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
+void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
+GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+void ( APIENTRY * qglArrayElement )(GLint i);
+void ( APIENTRY * qglBegin )(GLenum mode);
+void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);
+void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);
+void ( APIENTRY * qglCallList )(GLuint list);
+void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+void ( APIENTRY * qglClear )(GLbitfield mask);
+void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void ( APIENTRY * qglClearDepth )(GLclampd depth);
+void ( APIENTRY * qglClearIndex )(GLfloat c);
+void ( APIENTRY * qglClearStencil )(GLint s);
+void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);
+void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+void ( APIENTRY * qglColor3bv )(const GLbyte *v);
+void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+void ( APIENTRY * qglColor3dv )(const GLdouble *v);
+void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+void ( APIENTRY * qglColor3fv )(const GLfloat *v);
+void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue);
+void ( APIENTRY * qglColor3iv )(const GLint *v);
+void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue);
+void ( APIENTRY * qglColor3sv )(const GLshort *v);
+void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+void ( APIENTRY * qglColor3ubv )(const GLubyte *v);
+void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue);
+void ( APIENTRY * qglColor3uiv )(const GLuint *v);
+void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue);
+void ( APIENTRY * qglColor3usv )(const GLushort *v);
+void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+void ( APIENTRY * qglColor4bv )(const GLbyte *v);
+void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+void ( APIENTRY * qglColor4dv )(const GLdouble *v);
+void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void ( APIENTRY * qglColor4fv )(const GLfloat *v);
+void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+void ( APIENTRY * qglColor4iv )(const GLint *v);
+void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+void ( APIENTRY * qglColor4sv )(const GLshort *v);
+void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+void ( APIENTRY * qglColor4ubv )(const GLubyte *v);
+void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+void ( APIENTRY * qglColor4uiv )(const GLuint *v);
+void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+void ( APIENTRY * qglColor4usv )(const GLushort *v);
+void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode);
+void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+void ( APIENTRY * qglCullFace )(GLenum mode);
+void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range);
+void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);
+void ( APIENTRY * qglDepthFunc )(GLenum func);
+void ( APIENTRY * qglDepthMask )(GLboolean flag);
+void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);
+void ( APIENTRY * qglDisable )(GLenum cap);
+void ( APIENTRY * qglDisableClientState )(GLenum array);
+void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count);
+void ( APIENTRY * qglDrawBuffer )(GLenum mode);
+void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglEdgeFlag )(GLboolean flag);
+void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag);
+void ( APIENTRY * qglEnable )(GLenum cap);
+void ( APIENTRY * qglEnableClientState )(GLenum array);
+void ( APIENTRY * qglEnd )(void);
+void ( APIENTRY * qglEndList )(void);
+void ( APIENTRY * qglEvalCoord1d )(GLdouble u);
+void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u);
+void ( APIENTRY * qglEvalCoord1f )(GLfloat u);
+void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u);
+void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v);
+void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u);
+void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v);
+void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u);
+void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+void ( APIENTRY * qglEvalPoint1 )(GLint i);
+void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j);
+void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+void ( APIENTRY * qglFinish )(void);
+void ( APIENTRY * qglFlush )(void);
+void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglFogi )(GLenum pname, GLint param);
+void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params);
+void ( APIENTRY * qglFrontFace )(GLenum mode);
+void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLuint ( APIENTRY * qglGenLists )(GLsizei range);
+void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures);
+void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params);
+void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation);
+void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params);
+GLenum ( APIENTRY * qglGetError )(void);
+void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);
+void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v);
+void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values);
+void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values);
+void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values);
+void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params);
+void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask);
+const GLubyte * ( APIENTRY * qglGetString )(GLenum name);
+void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+void ( APIENTRY * qglHint )(GLenum target, GLenum mode);
+void ( APIENTRY * qglIndexMask )(GLuint mask);
+void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglIndexd )(GLdouble c);
+void ( APIENTRY * qglIndexdv )(const GLdouble *c);
+void ( APIENTRY * qglIndexf )(GLfloat c);
+void ( APIENTRY * qglIndexfv )(const GLfloat *c);
+void ( APIENTRY * qglIndexi )(GLint c);
+void ( APIENTRY * qglIndexiv )(const GLint *c);
+void ( APIENTRY * qglIndexs )(GLshort c);
+void ( APIENTRY * qglIndexsv )(const GLshort *c);
+void ( APIENTRY * qglIndexub )(GLubyte c);
+void ( APIENTRY * qglIndexubv )(const GLubyte *c);
+void ( APIENTRY * qglInitNames )(void);
+void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap);
+GLboolean ( APIENTRY * qglIsList )(GLuint list);
+GLboolean ( APIENTRY * qglIsTexture )(GLuint texture);
+void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param);
+void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params);
+void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param);
+void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param);
+void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params);
+void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern);
+void ( APIENTRY * qglLineWidth )(GLfloat width);
+void ( APIENTRY * qglListBase )(GLuint base);
+void ( APIENTRY * qglLoadIdentity )(void);
+void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m);
+void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);
+void ( APIENTRY * qglLoadName )(GLuint name);
+void ( APIENTRY * qglLogicOp )(GLenum opcode);
+void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param);
+void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param);
+void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+void ( APIENTRY * qglMatrixMode )(GLenum mode);
+void ( APIENTRY * qglMultMatrixd )(const GLdouble *m);
+void ( APIENTRY * qglMultMatrixf )(const GLfloat *m);
+void ( APIENTRY * qglNewList )(GLuint list, GLenum mode);
+void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+void ( APIENTRY * qglNormal3bv )(const GLbyte *v);
+void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+void ( APIENTRY * qglNormal3dv )(const GLdouble *v);
+void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+void ( APIENTRY * qglNormal3fv )(const GLfloat *v);
+void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz);
+void ( APIENTRY * qglNormal3iv )(const GLint *v);
+void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+void ( APIENTRY * qglNormal3sv )(const GLshort *v);
+void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+void ( APIENTRY * qglPassThrough )(GLfloat token);
+void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param);
+void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param);
+void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+void ( APIENTRY * qglPointSize )(GLfloat size);
+void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);
+void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);
+void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask);
+void ( APIENTRY * qglPopAttrib )(void);
+void ( APIENTRY * qglPopClientAttrib )(void);
+void ( APIENTRY * qglPopMatrix )(void);
+void ( APIENTRY * qglPopName )(void);
+void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+void ( APIENTRY * qglPushAttrib )(GLbitfield mask);
+void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask);
+void ( APIENTRY * qglPushMatrix )(void);
+void ( APIENTRY * qglPushName )(GLuint name);
+void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y);
+void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y);
+void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y);
+void ( APIENTRY * qglRasterPos2iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y);
+void ( APIENTRY * qglRasterPos2sv )(const GLshort *v);
+void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z);
+void ( APIENTRY * qglRasterPos3iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z);
+void ( APIENTRY * qglRasterPos3sv )(const GLshort *v);
+void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+void ( APIENTRY * qglRasterPos4iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+void ( APIENTRY * qglRasterPos4sv )(const GLshort *v);
+void ( APIENTRY * qglReadBuffer )(GLenum mode);
+void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2);
+void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2);
+void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2);
+void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2);
+GLint ( APIENTRY * qglRenderMode )(GLenum mode);
+void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer);
+void ( APIENTRY * qglShadeModel )(GLenum mode);
+void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);
+void ( APIENTRY * qglStencilMask )(GLuint mask);
+void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+void ( APIENTRY * qglTexCoord1d )(GLdouble s);
+void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord1f )(GLfloat s);
+void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord1i )(GLint s);
+void ( APIENTRY * qglTexCoord1iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord1s )(GLshort s);
+void ( APIENTRY * qglTexCoord1sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t);
+void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);
+void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t);
+void ( APIENTRY * qglTexCoord2iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t);
+void ( APIENTRY * qglTexCoord2sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r);
+void ( APIENTRY * qglTexCoord3iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r);
+void ( APIENTRY * qglTexCoord3sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+void ( APIENTRY * qglTexCoord4iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+void ( APIENTRY * qglTexCoord4sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param);
+void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param);
+void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param);
+void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param);
+void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y);
+void ( APIENTRY * qglVertex2dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);
+void ( APIENTRY * qglVertex2fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex2i )(GLint x, GLint y);
+void ( APIENTRY * qglVertex2iv )(const GLint *v);
+void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y);
+void ( APIENTRY * qglVertex2sv )(const GLshort *v);
+void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglVertex3dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglVertex3fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z);
+void ( APIENTRY * qglVertex3iv )(const GLint *v);
+void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z);
+void ( APIENTRY * qglVertex3sv )(const GLshort *v);
+void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+void ( APIENTRY * qglVertex4dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void ( APIENTRY * qglVertex4fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w);
+void ( APIENTRY * qglVertex4iv )(const GLint *v);
+void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+void ( APIENTRY * qglVertex4sv )(const GLshort *v);
+void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+void ( APIENTRY * qglLockArraysEXT)( int, int);
+void ( APIENTRY * qglUnlockArraysEXT) ( void );
+
+void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value );
+void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value );
+void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * );
+void ( APIENTRY * qglSelectTextureSGIS)( GLenum );
+void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat );
+
+static void ( APIENTRY * dllAccum )(GLenum op, GLfloat value);
+static void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref);
+GLboolean ( APIENTRY * dllAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+static void ( APIENTRY * dllArrayElement )(GLint i);
+static void ( APIENTRY * dllBegin )(GLenum mode);
+static void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture);
+static void ( APIENTRY * dllBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+static void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor);
+static void ( APIENTRY * dllCallList )(GLuint list);
+static void ( APIENTRY * dllCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+static void ( APIENTRY * dllClear )(GLbitfield mask);
+static void ( APIENTRY * dllClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+static void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+static void ( APIENTRY * dllClearDepth )(GLclampd depth);
+static void ( APIENTRY * dllClearIndex )(GLfloat c);
+static void ( APIENTRY * dllClearStencil )(GLint s);
+static void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation);
+static void ( APIENTRY * dllColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+static void ( APIENTRY * dllColor3bv )(const GLbyte *v);
+static void ( APIENTRY * dllColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+static void ( APIENTRY * dllColor3dv )(const GLdouble *v);
+static void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+static void ( APIENTRY * dllColor3fv )(const GLfloat *v);
+static void ( APIENTRY * dllColor3i )(GLint red, GLint green, GLint blue);
+static void ( APIENTRY * dllColor3iv )(const GLint *v);
+static void ( APIENTRY * dllColor3s )(GLshort red, GLshort green, GLshort blue);
+static void ( APIENTRY * dllColor3sv )(const GLshort *v);
+static void ( APIENTRY * dllColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+static void ( APIENTRY * dllColor3ubv )(const GLubyte *v);
+static void ( APIENTRY * dllColor3ui )(GLuint red, GLuint green, GLuint blue);
+static void ( APIENTRY * dllColor3uiv )(const GLuint *v);
+static void ( APIENTRY * dllColor3us )(GLushort red, GLushort green, GLushort blue);
+static void ( APIENTRY * dllColor3usv )(const GLushort *v);
+static void ( APIENTRY * dllColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+static void ( APIENTRY * dllColor4bv )(const GLbyte *v);
+static void ( APIENTRY * dllColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+static void ( APIENTRY * dllColor4dv )(const GLdouble *v);
+static void ( APIENTRY * dllColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+static void ( APIENTRY * dllColor4fv )(const GLfloat *v);
+static void ( APIENTRY * dllColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+static void ( APIENTRY * dllColor4iv )(const GLint *v);
+static void ( APIENTRY * dllColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+static void ( APIENTRY * dllColor4sv )(const GLshort *v);
+static void ( APIENTRY * dllColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+static void ( APIENTRY * dllColor4ubv )(const GLubyte *v);
+static void ( APIENTRY * dllColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+static void ( APIENTRY * dllColor4uiv )(const GLuint *v);
+static void ( APIENTRY * dllColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+static void ( APIENTRY * dllColor4usv )(const GLushort *v);
+static void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+static void ( APIENTRY * dllColorMaterial )(GLenum face, GLenum mode);
+static void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+static void ( APIENTRY * dllCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+static void ( APIENTRY * dllCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+static void ( APIENTRY * dllCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+static void ( APIENTRY * dllCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+static void ( APIENTRY * dllCullFace )(GLenum mode);
+static void ( APIENTRY * dllDeleteLists )(GLuint list, GLsizei range);
+static void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures);
+static void ( APIENTRY * dllDepthFunc )(GLenum func);
+static void ( APIENTRY * dllDepthMask )(GLboolean flag);
+static void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar);
+static void ( APIENTRY * dllDisable )(GLenum cap);
+static void ( APIENTRY * dllDisableClientState )(GLenum array);
+static void ( APIENTRY * dllDrawArrays )(GLenum mode, GLint first, GLsizei count);
+static void ( APIENTRY * dllDrawBuffer )(GLenum mode);
+static void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+static void ( APIENTRY * dllDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllEdgeFlag )(GLboolean flag);
+static void ( APIENTRY * dllEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllEdgeFlagv )(const GLboolean *flag);
+static void ( APIENTRY * dllEnable )(GLenum cap);
+static void ( APIENTRY * dllEnableClientState )(GLenum array);
+static void ( APIENTRY * dllEnd )(void);
+static void ( APIENTRY * dllEndList )(void);
+static void ( APIENTRY * dllEvalCoord1d )(GLdouble u);
+static void ( APIENTRY * dllEvalCoord1dv )(const GLdouble *u);
+static void ( APIENTRY * dllEvalCoord1f )(GLfloat u);
+static void ( APIENTRY * dllEvalCoord1fv )(const GLfloat *u);
+static void ( APIENTRY * dllEvalCoord2d )(GLdouble u, GLdouble v);
+static void ( APIENTRY * dllEvalCoord2dv )(const GLdouble *u);
+static void ( APIENTRY * dllEvalCoord2f )(GLfloat u, GLfloat v);
+static void ( APIENTRY * dllEvalCoord2fv )(const GLfloat *u);
+static void ( APIENTRY * dllEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+static void ( APIENTRY * dllEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+static void ( APIENTRY * dllEvalPoint1 )(GLint i);
+static void ( APIENTRY * dllEvalPoint2 )(GLint i, GLint j);
+static void ( APIENTRY * dllFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+static void ( APIENTRY * dllFinish )(void);
+static void ( APIENTRY * dllFlush )(void);
+static void ( APIENTRY * dllFogf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllFogfv )(GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllFogi )(GLenum pname, GLint param);
+static void ( APIENTRY * dllFogiv )(GLenum pname, const GLint *params);
+static void ( APIENTRY * dllFrontFace )(GLenum mode);
+static void ( APIENTRY * dllFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLuint ( APIENTRY * dllGenLists )(GLsizei range);
+static void ( APIENTRY * dllGenTextures )(GLsizei n, GLuint *textures);
+static void ( APIENTRY * dllGetBooleanv )(GLenum pname, GLboolean *params);
+static void ( APIENTRY * dllGetClipPlane )(GLenum plane, GLdouble *equation);
+static void ( APIENTRY * dllGetDoublev )(GLenum pname, GLdouble *params);
+GLenum ( APIENTRY * dllGetError )(void);
+static void ( APIENTRY * dllGetFloatv )(GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetLightiv )(GLenum light, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+static void ( APIENTRY * dllGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+static void ( APIENTRY * dllGetMapiv )(GLenum target, GLenum query, GLint *v);
+static void ( APIENTRY * dllGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetPixelMapfv )(GLenum map, GLfloat *values);
+static void ( APIENTRY * dllGetPixelMapuiv )(GLenum map, GLuint *values);
+static void ( APIENTRY * dllGetPixelMapusv )(GLenum map, GLushort *values);
+static void ( APIENTRY * dllGetPointerv )(GLenum pname, GLvoid* *params);
+static void ( APIENTRY * dllGetPolygonStipple )(GLubyte *mask);
+const GLubyte * ( APIENTRY * dllGetString )(GLenum name);
+static void ( APIENTRY * dllGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+static void ( APIENTRY * dllGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+static void ( APIENTRY * dllGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+static void ( APIENTRY * dllHint )(GLenum target, GLenum mode);
+static void ( APIENTRY * dllIndexMask )(GLuint mask);
+static void ( APIENTRY * dllIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllIndexd )(GLdouble c);
+static void ( APIENTRY * dllIndexdv )(const GLdouble *c);
+static void ( APIENTRY * dllIndexf )(GLfloat c);
+static void ( APIENTRY * dllIndexfv )(const GLfloat *c);
+static void ( APIENTRY * dllIndexi )(GLint c);
+static void ( APIENTRY * dllIndexiv )(const GLint *c);
+static void ( APIENTRY * dllIndexs )(GLshort c);
+static void ( APIENTRY * dllIndexsv )(const GLshort *c);
+static void ( APIENTRY * dllIndexub )(GLubyte c);
+static void ( APIENTRY * dllIndexubv )(const GLubyte *c);
+static void ( APIENTRY * dllInitNames )(void);
+static void ( APIENTRY * dllInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+GLboolean ( APIENTRY * dllIsEnabled )(GLenum cap);
+GLboolean ( APIENTRY * dllIsList )(GLuint list);
+GLboolean ( APIENTRY * dllIsTexture )(GLuint texture);
+static void ( APIENTRY * dllLightModelf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllLightModelfv )(GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllLightModeli )(GLenum pname, GLint param);
+static void ( APIENTRY * dllLightModeliv )(GLenum pname, const GLint *params);
+static void ( APIENTRY * dllLightf )(GLenum light, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllLighti )(GLenum light, GLenum pname, GLint param);
+static void ( APIENTRY * dllLightiv )(GLenum light, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllLineStipple )(GLint factor, GLushort pattern);
+static void ( APIENTRY * dllLineWidth )(GLfloat width);
+static void ( APIENTRY * dllListBase )(GLuint base);
+static void ( APIENTRY * dllLoadIdentity )(void);
+static void ( APIENTRY * dllLoadMatrixd )(const GLdouble *m);
+static void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m);
+static void ( APIENTRY * dllLoadName )(GLuint name);
+static void ( APIENTRY * dllLogicOp )(GLenum opcode);
+static void ( APIENTRY * dllMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+static void ( APIENTRY * dllMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+static void ( APIENTRY * dllMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+static void ( APIENTRY * dllMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+static void ( APIENTRY * dllMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+static void ( APIENTRY * dllMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+static void ( APIENTRY * dllMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+static void ( APIENTRY * dllMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+static void ( APIENTRY * dllMaterialf )(GLenum face, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllMateriali )(GLenum face, GLenum pname, GLint param);
+static void ( APIENTRY * dllMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllMatrixMode )(GLenum mode);
+static void ( APIENTRY * dllMultMatrixd )(const GLdouble *m);
+static void ( APIENTRY * dllMultMatrixf )(const GLfloat *m);
+static void ( APIENTRY * dllNewList )(GLuint list, GLenum mode);
+static void ( APIENTRY * dllNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+static void ( APIENTRY * dllNormal3bv )(const GLbyte *v);
+static void ( APIENTRY * dllNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+static void ( APIENTRY * dllNormal3dv )(const GLdouble *v);
+static void ( APIENTRY * dllNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+static void ( APIENTRY * dllNormal3fv )(const GLfloat *v);
+static void ( APIENTRY * dllNormal3i )(GLint nx, GLint ny, GLint nz);
+static void ( APIENTRY * dllNormal3iv )(const GLint *v);
+static void ( APIENTRY * dllNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+static void ( APIENTRY * dllNormal3sv )(const GLshort *v);
+static void ( APIENTRY * dllNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+static void ( APIENTRY * dllPassThrough )(GLfloat token);
+static void ( APIENTRY * dllPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+static void ( APIENTRY * dllPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+static void ( APIENTRY * dllPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+static void ( APIENTRY * dllPixelStoref )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllPixelStorei )(GLenum pname, GLint param);
+static void ( APIENTRY * dllPixelTransferf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllPixelTransferi )(GLenum pname, GLint param);
+static void ( APIENTRY * dllPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+static void ( APIENTRY * dllPointSize )(GLfloat size);
+static void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode);
+static void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units);
+static void ( APIENTRY * dllPolygonStipple )(const GLubyte *mask);
+static void ( APIENTRY * dllPopAttrib )(void);
+static void ( APIENTRY * dllPopClientAttrib )(void);
+static void ( APIENTRY * dllPopMatrix )(void);
+static void ( APIENTRY * dllPopName )(void);
+static void ( APIENTRY * dllPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+static void ( APIENTRY * dllPushAttrib )(GLbitfield mask);
+static void ( APIENTRY * dllPushClientAttrib )(GLbitfield mask);
+static void ( APIENTRY * dllPushMatrix )(void);
+static void ( APIENTRY * dllPushName )(GLuint name);
+static void ( APIENTRY * dllRasterPos2d )(GLdouble x, GLdouble y);
+static void ( APIENTRY * dllRasterPos2dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos2f )(GLfloat x, GLfloat y);
+static void ( APIENTRY * dllRasterPos2fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos2i )(GLint x, GLint y);
+static void ( APIENTRY * dllRasterPos2iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos2s )(GLshort x, GLshort y);
+static void ( APIENTRY * dllRasterPos2sv )(const GLshort *v);
+static void ( APIENTRY * dllRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllRasterPos3dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllRasterPos3fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos3i )(GLint x, GLint y, GLint z);
+static void ( APIENTRY * dllRasterPos3iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos3s )(GLshort x, GLshort y, GLshort z);
+static void ( APIENTRY * dllRasterPos3sv )(const GLshort *v);
+static void ( APIENTRY * dllRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+static void ( APIENTRY * dllRasterPos4dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+static void ( APIENTRY * dllRasterPos4fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+static void ( APIENTRY * dllRasterPos4iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+static void ( APIENTRY * dllRasterPos4sv )(const GLshort *v);
+static void ( APIENTRY * dllReadBuffer )(GLenum mode);
+static void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+static void ( APIENTRY * dllRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+static void ( APIENTRY * dllRectdv )(const GLdouble *v1, const GLdouble *v2);
+static void ( APIENTRY * dllRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+static void ( APIENTRY * dllRectfv )(const GLfloat *v1, const GLfloat *v2);
+static void ( APIENTRY * dllRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+static void ( APIENTRY * dllRectiv )(const GLint *v1, const GLint *v2);
+static void ( APIENTRY * dllRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+static void ( APIENTRY * dllRectsv )(const GLshort *v1, const GLshort *v2);
+GLint ( APIENTRY * dllRenderMode )(GLenum mode);
+static void ( APIENTRY * dllRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllScaled )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllScalef )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+static void ( APIENTRY * dllSelectBuffer )(GLsizei size, GLuint *buffer);
+static void ( APIENTRY * dllShadeModel )(GLenum mode);
+static void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask);
+static void ( APIENTRY * dllStencilMask )(GLuint mask);
+static void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+static void ( APIENTRY * dllTexCoord1d )(GLdouble s);
+static void ( APIENTRY * dllTexCoord1dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord1f )(GLfloat s);
+static void ( APIENTRY * dllTexCoord1fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord1i )(GLint s);
+static void ( APIENTRY * dllTexCoord1iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord1s )(GLshort s);
+static void ( APIENTRY * dllTexCoord1sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord2d )(GLdouble s, GLdouble t);
+static void ( APIENTRY * dllTexCoord2dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t);
+static void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord2i )(GLint s, GLint t);
+static void ( APIENTRY * dllTexCoord2iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord2s )(GLshort s, GLshort t);
+static void ( APIENTRY * dllTexCoord2sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+static void ( APIENTRY * dllTexCoord3dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+static void ( APIENTRY * dllTexCoord3fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord3i )(GLint s, GLint t, GLint r);
+static void ( APIENTRY * dllTexCoord3iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord3s )(GLshort s, GLshort t, GLshort r);
+static void ( APIENTRY * dllTexCoord3sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+static void ( APIENTRY * dllTexCoord4dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+static void ( APIENTRY * dllTexCoord4fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+static void ( APIENTRY * dllTexCoord4iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+static void ( APIENTRY * dllTexCoord4sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexEnvi )(GLenum target, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexGend )(GLenum coord, GLenum pname, GLdouble param);
+static void ( APIENTRY * dllTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+static void ( APIENTRY * dllTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexGeni )(GLenum coord, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexParameteri )(GLenum target, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTranslated )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllVertex2d )(GLdouble x, GLdouble y);
+static void ( APIENTRY * dllVertex2dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y);
+static void ( APIENTRY * dllVertex2fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex2i )(GLint x, GLint y);
+static void ( APIENTRY * dllVertex2iv )(const GLint *v);
+static void ( APIENTRY * dllVertex2s )(GLshort x, GLshort y);
+static void ( APIENTRY * dllVertex2sv )(const GLshort *v);
+static void ( APIENTRY * dllVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllVertex3dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllVertex3fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex3i )(GLint x, GLint y, GLint z);
+static void ( APIENTRY * dllVertex3iv )(const GLint *v);
+static void ( APIENTRY * dllVertex3s )(GLshort x, GLshort y, GLshort z);
+static void ( APIENTRY * dllVertex3sv )(const GLshort *v);
+static void ( APIENTRY * dllVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+static void ( APIENTRY * dllVertex4dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+static void ( APIENTRY * dllVertex4fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex4i )(GLint x, GLint y, GLint z, GLint w);
+static void ( APIENTRY * dllVertex4iv )(const GLint *v);
+static void ( APIENTRY * dllVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+static void ( APIENTRY * dllVertex4sv )(const GLshort *v);
+static void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+static void APIENTRY logAccum(GLenum op, GLfloat value)
+{
+	fprintf( log_fp, "glAccum\n" );
+	dllAccum( op, value );
+}
+
+static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref)
+{
+	fprintf( log_fp, "glAlphaFunc( 0x%x, %f )\n", func, ref );
+	dllAlphaFunc( func, ref );
+}
+
+static GLboolean APIENTRY logAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences)
+{
+	fprintf( log_fp, "glAreTexturesResident\n" );
+	return dllAreTexturesResident( n, textures, residences );
+}
+
+static void APIENTRY logArrayElement(GLint i)
+{
+	fprintf( log_fp, "glArrayElement\n" );
+	dllArrayElement( i );
+}
+
+static void APIENTRY logBegin(GLenum mode)
+{
+	fprintf( log_fp, "glBegin( 0x%x )\n", mode );
+	dllBegin( mode );
+}
+
+static void APIENTRY logBindTexture(GLenum target, GLuint texture)
+{
+	fprintf( log_fp, "glBindTexture( 0x%x, %u )\n", target, texture );
+	dllBindTexture( target, texture );
+}
+
+static void APIENTRY logBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
+{
+	fprintf( log_fp, "glBitmap\n" );
+	dllBitmap( width, height, xorig, yorig, xmove, ymove, bitmap );
+}
+
+static void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+	fprintf( log_fp, "glBlendFunc( 0x%x, 0x%x )\n", sfactor, dfactor );
+	dllBlendFunc( sfactor, dfactor );
+}
+
+static void APIENTRY logCallList(GLuint list)
+{
+	fprintf( log_fp, "glCallList( %u )\n", list );
+	dllCallList( list );
+}
+
+static void APIENTRY logCallLists(GLsizei n, GLenum type, const void *lists)
+{
+	fprintf( log_fp, "glCallLists\n" );
+	dllCallLists( n, type, lists );
+}
+
+static void APIENTRY logClear(GLbitfield mask)
+{
+	fprintf( log_fp, "glClear\n" );
+	dllClear( mask );
+}
+
+static void APIENTRY logClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+	fprintf( log_fp, "glClearAccum\n" );
+	dllClearAccum( red, green, blue, alpha );
+}
+
+static void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	fprintf( log_fp, "glClearColor\n" );
+	dllClearColor( red, green, blue, alpha );
+}
+
+static void APIENTRY logClearDepth(GLclampd depth)
+{
+	fprintf( log_fp, "glClearDepth\n" );
+	dllClearDepth( depth );
+}
+
+static void APIENTRY logClearIndex(GLfloat c)
+{
+	fprintf( log_fp, "glClearIndex\n" );
+	dllClearIndex( c );
+}
+
+static void APIENTRY logClearStencil(GLint s)
+{
+	fprintf( log_fp, "glClearStencil\n" );
+	dllClearStencil( s );
+}
+
+static void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation)
+{
+	fprintf( log_fp, "glClipPlane\n" );
+	dllClipPlane( plane, equation );
+}
+
+static void APIENTRY logColor3b(GLbyte red, GLbyte green, GLbyte blue)
+{
+	fprintf( log_fp, "glColor3b\n" );
+	dllColor3b( red, green, blue );
+}
+
+static void APIENTRY logColor3bv(const GLbyte *v)
+{
+	fprintf( log_fp, "glColor3bv\n" );
+	dllColor3bv( v );
+}
+
+static void APIENTRY logColor3d(GLdouble red, GLdouble green, GLdouble blue)
+{
+	fprintf( log_fp, "glColor3d\n" );
+	dllColor3d( red, green, blue );
+}
+
+static void APIENTRY logColor3dv(const GLdouble *v)
+{
+	fprintf( log_fp, "glColor3dv\n" );
+	dllColor3dv( v );
+}
+
+static void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue)
+{
+	fprintf( log_fp, "glColor3f\n" );
+	dllColor3f( red, green, blue );
+}
+
+static void APIENTRY logColor3fv(const GLfloat *v)
+{
+	fprintf( log_fp, "glColor3fv\n" );
+	dllColor3fv( v );
+}
+
+static void APIENTRY logColor3i(GLint red, GLint green, GLint blue)
+{
+	fprintf( log_fp, "glColor3i\n" );
+	dllColor3i( red, green, blue );
+}
+
+static void APIENTRY logColor3iv(const GLint *v)
+{
+	fprintf( log_fp, "glColor3iv\n" );
+	dllColor3iv( v );
+}
+
+static void APIENTRY logColor3s(GLshort red, GLshort green, GLshort blue)
+{
+	fprintf( log_fp, "glColor3s\n" );
+	dllColor3s( red, green, blue );
+}
+
+static void APIENTRY logColor3sv(const GLshort *v)
+{
+	fprintf( log_fp, "glColor3sv\n" );
+	dllColor3sv( v );
+}
+
+static void APIENTRY logColor3ub(GLubyte red, GLubyte green, GLubyte blue)
+{
+	fprintf( log_fp, "glColor3ub\n" );
+	dllColor3ub( red, green, blue );
+}
+
+static void APIENTRY logColor3ubv(const GLubyte *v)
+{
+	fprintf( log_fp, "glColor3ubv\n" );
+	dllColor3ubv( v );
+}
+
+#define SIG( x ) fprintf( log_fp, x "\n" )
+
+static void APIENTRY logColor3ui(GLuint red, GLuint green, GLuint blue)
+{
+	SIG( "glColor3ui" );
+	dllColor3ui( red, green, blue );
+}
+
+static void APIENTRY logColor3uiv(const GLuint *v)
+{
+	SIG( "glColor3uiv" );
+	dllColor3uiv( v );
+}
+
+static void APIENTRY logColor3us(GLushort red, GLushort green, GLushort blue)
+{
+	SIG( "glColor3us" );
+	dllColor3us( red, green, blue );
+}
+
+static void APIENTRY logColor3usv(const GLushort *v)
+{
+	SIG( "glColor3usv" );
+	dllColor3usv( v );
+}
+
+static void APIENTRY logColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha)
+{
+	SIG( "glColor4b" );
+	dllColor4b( red, green, blue, alpha );
+}
+
+static void APIENTRY logColor4bv(const GLbyte *v)
+{
+	SIG( "glColor4bv" );
+	dllColor4bv( v );
+}
+
+static void APIENTRY logColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
+{
+	SIG( "glColor4d" );
+	dllColor4d( red, green, blue, alpha );
+}
+static void APIENTRY logColor4dv(const GLdouble *v)
+{
+	SIG( "glColor4dv" );
+	dllColor4dv( v );
+}
+static void APIENTRY logColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+	SIG( "glColor4f" );
+	dllColor4f( red, green, blue, alpha );
+}
+static void APIENTRY logColor4fv(const GLfloat *v)
+{
+	SIG( "glColor4fv" );
+	dllColor4fv( v );
+}
+static void APIENTRY logColor4i(GLint red, GLint green, GLint blue, GLint alpha)
+{
+	SIG( "glColor4i" );
+	dllColor4i( red, green, blue, alpha );
+}
+static void APIENTRY logColor4iv(const GLint *v)
+{
+	SIG( "glColor4iv" );
+	dllColor4iv( v );
+}
+static void APIENTRY logColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha)
+{
+	SIG( "glColor4s" );
+	dllColor4s( red, green, blue, alpha );
+}
+static void APIENTRY logColor4sv(const GLshort *v)
+{
+	SIG( "glColor4sv" );
+	dllColor4sv( v );
+}
+static void APIENTRY logColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+{
+	SIG( "glColor4b" );
+	dllColor4b( red, green, blue, alpha );
+}
+static void APIENTRY logColor4ubv(const GLubyte *v)
+{
+	SIG( "glColor4ubv" );
+	dllColor4ubv( v );
+}
+static void APIENTRY logColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha)
+{
+	SIG( "glColor4ui" );
+	dllColor4ui( red, green, blue, alpha );
+}
+static void APIENTRY logColor4uiv(const GLuint *v)
+{
+	SIG( "glColor4uiv" );
+	dllColor4uiv( v );
+}
+static void APIENTRY logColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha)
+{
+	SIG( "glColor4us" );
+	dllColor4us( red, green, blue, alpha );
+}
+static void APIENTRY logColor4usv(const GLushort *v)
+{
+	SIG( "glColor4usv" );
+	dllColor4usv( v );
+}
+static void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+	SIG( "glColorMask" );
+	dllColorMask( red, green, blue, alpha );
+}
+static void APIENTRY logColorMaterial(GLenum face, GLenum mode)
+{
+	SIG( "glColorMaterial" );
+	dllColorMaterial( face, mode );
+}
+
+static void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glColorPointer" );
+	dllColorPointer( size, type, stride, pointer );
+}
+
+static void APIENTRY logCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)
+{
+	SIG( "glCopyPixels" );
+	dllCopyPixels( x, y, width, height, type );
+}
+
+static void APIENTRY logCopyTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border)
+{
+	SIG( "glCopyTexImage1D" );
+	dllCopyTexImage1D( target, level, internalFormat, x, y, width, border );
+}
+
+static void APIENTRY logCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+	SIG( "glCopyTexImage2D" );
+	dllCopyTexImage2D( target, level, internalFormat, x, y, width, height, border );
+}
+
+static void APIENTRY logCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+	SIG( "glCopyTexSubImage1D" );
+	dllCopyTexSubImage1D( target, level, xoffset, x, y, width );
+}
+
+static void APIENTRY logCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glCopyTexSubImage2D" );
+	dllCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height );
+}
+
+static void APIENTRY logCullFace(GLenum mode)
+{
+	SIG( "glCullFace" );
+	dllCullFace( mode );
+}
+
+static void APIENTRY logDeleteLists(GLuint list, GLsizei range)
+{
+	SIG( "glDeleteLists" );
+	dllDeleteLists( list, range );
+}
+
+static void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures)
+{
+	SIG( "glDeleteTextures" );
+	dllDeleteTextures( n, textures );
+}
+
+static void APIENTRY logDepthFunc(GLenum func)
+{
+	SIG( "glDepthFunc" );
+	dllDepthFunc( func );
+}
+
+static void APIENTRY logDepthMask(GLboolean flag)
+{
+	SIG( "glDepthMask" );
+	dllDepthMask( flag );
+}
+
+static void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar)
+{
+	SIG( "glDepthRange" );
+	dllDepthRange( zNear, zFar );
+}
+
+static void APIENTRY logDisable(GLenum cap)
+{
+	fprintf( log_fp, "glDisable( 0x%x )\n", cap );
+	dllDisable( cap );
+}
+
+static void APIENTRY logDisableClientState(GLenum array)
+{
+	SIG( "glDisableClientState" );
+	dllDisableClientState( array );
+}
+
+static void APIENTRY logDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+	SIG( "glDrawArrays" );
+	dllDrawArrays( mode, first, count );
+}
+
+static void APIENTRY logDrawBuffer(GLenum mode)
+{
+	SIG( "glDrawBuffer" );
+	dllDrawBuffer( mode );
+}
+
+static void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+	SIG( "glDrawElements" );
+	dllDrawElements( mode, count, type, indices );
+}
+
+static void APIENTRY logDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glDrawPixels" );
+	dllDrawPixels( width, height, format, type, pixels );
+}
+
+static void APIENTRY logEdgeFlag(GLboolean flag)
+{
+	SIG( "glEdgeFlag" );
+	dllEdgeFlag( flag );
+}
+
+static void APIENTRY logEdgeFlagPointer(GLsizei stride, const void *pointer)
+{
+	SIG( "glEdgeFlagPointer" );
+	dllEdgeFlagPointer( stride, pointer );
+}
+
+static void APIENTRY logEdgeFlagv(const GLboolean *flag)
+{
+	SIG( "glEdgeFlagv" );
+	dllEdgeFlagv( flag );
+}
+
+static void APIENTRY logEnable(GLenum cap)
+{
+	fprintf( log_fp, "glEnable( 0x%x )\n", cap );
+	dllEnable( cap );
+}
+
+static void APIENTRY logEnableClientState(GLenum array)
+{
+	SIG( "glEnableClientState" );
+	dllEnableClientState( array );
+}
+
+static void APIENTRY logEnd(void)
+{
+	SIG( "glEnd" );
+	dllEnd();
+}
+
+static void APIENTRY logEndList(void)
+{
+	SIG( "glEndList" );
+	dllEndList();
+}
+
+static void APIENTRY logEvalCoord1d(GLdouble u)
+{
+	SIG( "glEvalCoord1d" );
+	dllEvalCoord1d( u );
+}
+
+static void APIENTRY logEvalCoord1dv(const GLdouble *u)
+{
+	SIG( "glEvalCoord1dv" );
+	dllEvalCoord1dv( u );
+}
+
+static void APIENTRY logEvalCoord1f(GLfloat u)
+{
+	SIG( "glEvalCoord1f" );
+	dllEvalCoord1f( u );
+}
+
+static void APIENTRY logEvalCoord1fv(const GLfloat *u)
+{
+	SIG( "glEvalCoord1fv" );
+	dllEvalCoord1fv( u );
+}
+static void APIENTRY logEvalCoord2d(GLdouble u, GLdouble v)
+{
+	SIG( "glEvalCoord2d" );
+	dllEvalCoord2d( u, v );
+}
+static void APIENTRY logEvalCoord2dv(const GLdouble *u)
+{
+	SIG( "glEvalCoord2dv" );
+	dllEvalCoord2dv( u );
+}
+static void APIENTRY logEvalCoord2f(GLfloat u, GLfloat v)
+{
+	SIG( "glEvalCoord2f" );
+	dllEvalCoord2f( u, v );
+}
+static void APIENTRY logEvalCoord2fv(const GLfloat *u)
+{
+	SIG( "glEvalCoord2fv" );
+	dllEvalCoord2fv( u );
+}
+
+static void APIENTRY logEvalMesh1(GLenum mode, GLint i1, GLint i2)
+{
+	SIG( "glEvalMesh1" );
+	dllEvalMesh1( mode, i1, i2 );
+}
+static void APIENTRY logEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
+{
+	SIG( "glEvalMesh2" );
+	dllEvalMesh2( mode, i1, i2, j1, j2 );
+}
+static void APIENTRY logEvalPoint1(GLint i)
+{
+	SIG( "glEvalPoint1" );
+	dllEvalPoint1( i );
+}
+static void APIENTRY logEvalPoint2(GLint i, GLint j)
+{
+	SIG( "glEvalPoint2" );
+	dllEvalPoint2( i, j );
+}
+
+static void APIENTRY logFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer)
+{
+	SIG( "glFeedbackBuffer" );
+	dllFeedbackBuffer( size, type, buffer );
+}
+
+static void APIENTRY logFinish(void)
+{
+	SIG( "glFinish" );
+	dllFinish();
+}
+
+static void APIENTRY logFlush(void)
+{
+	SIG( "glFlush" );
+	dllFlush();
+}
+
+static void APIENTRY logFogf(GLenum pname, GLfloat param)
+{
+	SIG( "glFogf" );
+	dllFogf( pname, param );
+}
+
+static void APIENTRY logFogfv(GLenum pname, const GLfloat *params)
+{
+	SIG( "glFogfv" );
+	dllFogfv( pname, params );
+}
+
+static void APIENTRY logFogi(GLenum pname, GLint param)
+{
+	SIG( "glFogi" );
+	dllFogi( pname, param );
+}
+
+static void APIENTRY logFogiv(GLenum pname, const GLint *params)
+{
+	SIG( "glFogiv" );
+	dllFogiv( pname, params );
+}
+
+static void APIENTRY logFrontFace(GLenum mode)
+{
+	SIG( "glFrontFace" );
+	dllFrontFace( mode );
+}
+
+static void APIENTRY logFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+{
+	SIG( "glFrustum" );
+	dllFrustum( left, right, bottom, top, zNear, zFar );
+}
+
+static GLuint APIENTRY logGenLists(GLsizei range)
+{
+	SIG( "glGenLists" );
+	return dllGenLists( range );
+}
+
+static void APIENTRY logGenTextures(GLsizei n, GLuint *textures)
+{
+	SIG( "glGenTextures" );
+	dllGenTextures( n, textures );
+}
+
+static void APIENTRY logGetBooleanv(GLenum pname, GLboolean *params)
+{
+	SIG( "glGetBooleanv" );
+	dllGetBooleanv( pname, params );
+}
+
+static void APIENTRY logGetClipPlane(GLenum plane, GLdouble *equation)
+{
+	SIG( "glGetClipPlane" );
+	dllGetClipPlane( plane, equation );
+}
+
+static void APIENTRY logGetDoublev(GLenum pname, GLdouble *params)
+{
+	SIG( "glGetDoublev" );
+	dllGetDoublev( pname, params );
+}
+
+static GLenum APIENTRY logGetError(void)
+{
+	SIG( "glGetError" );
+	return dllGetError();
+}
+
+static void APIENTRY logGetFloatv(GLenum pname, GLfloat *params)
+{
+	SIG( "glGetFloatv" );
+	dllGetFloatv( pname, params );
+}
+
+static void APIENTRY logGetIntegerv(GLenum pname, GLint *params)
+{
+	SIG( "glGetIntegerv" );
+	dllGetIntegerv( pname, params );
+}
+
+static void APIENTRY logGetLightfv(GLenum light, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetLightfv" );
+	dllGetLightfv( light, pname, params );
+}
+
+static void APIENTRY logGetLightiv(GLenum light, GLenum pname, GLint *params)
+{
+	SIG( "glGetLightiv" );
+	dllGetLightiv( light, pname, params );
+}
+
+static void APIENTRY logGetMapdv(GLenum target, GLenum query, GLdouble *v)
+{
+	SIG( "glGetMapdv" );
+	dllGetMapdv( target, query, v );
+}
+
+static void APIENTRY logGetMapfv(GLenum target, GLenum query, GLfloat *v)
+{
+	SIG( "glGetMapfv" );
+	dllGetMapfv( target, query, v );
+}
+
+static void APIENTRY logGetMapiv(GLenum target, GLenum query, GLint *v)
+{
+	SIG( "glGetMapiv" );
+	dllGetMapiv( target, query, v );
+}
+
+static void APIENTRY logGetMaterialfv(GLenum face, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetMaterialfv" );
+	dllGetMaterialfv( face, pname, params );
+}
+
+static void APIENTRY logGetMaterialiv(GLenum face, GLenum pname, GLint *params)
+{
+	SIG( "glGetMaterialiv" );
+	dllGetMaterialiv( face, pname, params );
+}
+
+static void APIENTRY logGetPixelMapfv(GLenum map, GLfloat *values)
+{
+	SIG( "glGetPixelMapfv" );
+	dllGetPixelMapfv( map, values );
+}
+
+static void APIENTRY logGetPixelMapuiv(GLenum map, GLuint *values)
+{
+	SIG( "glGetPixelMapuiv" );
+	dllGetPixelMapuiv( map, values );
+}
+
+static void APIENTRY logGetPixelMapusv(GLenum map, GLushort *values)
+{
+	SIG( "glGetPixelMapusv" );
+	dllGetPixelMapusv( map, values );
+}
+
+static void APIENTRY logGetPointerv(GLenum pname, GLvoid* *params)
+{
+	SIG( "glGetPointerv" );
+	dllGetPointerv( pname, params );
+}
+
+static void APIENTRY logGetPolygonStipple(GLubyte *mask)
+{
+	SIG( "glGetPolygonStipple" );
+	dllGetPolygonStipple( mask );
+}
+
+static const GLubyte * APIENTRY logGetString(GLenum name)
+{
+	SIG( "glGetString" );
+	return dllGetString( name );
+}
+
+static void APIENTRY logGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexEnvfv" );
+	dllGetTexEnvfv( target, pname, params );
+}
+
+static void APIENTRY logGetTexEnviv(GLenum target, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexEnviv" );
+	dllGetTexEnviv( target, pname, params );
+}
+
+static void APIENTRY logGetTexGendv(GLenum coord, GLenum pname, GLdouble *params)
+{
+	SIG( "glGetTexGendv" );
+	dllGetTexGendv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexGenfv" );
+	dllGetTexGenfv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexGeniv(GLenum coord, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexGeniv" );
+	dllGetTexGeniv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels)
+{
+	SIG( "glGetTexImage" );
+	dllGetTexImage( target, level, format, type, pixels );
+}
+static void APIENTRY logGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params )
+{
+	SIG( "glGetTexLevelParameterfv" );
+	dllGetTexLevelParameterfv( target, level, pname, params );
+}
+
+static void APIENTRY logGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexLevelParameteriv" );
+	dllGetTexLevelParameteriv( target, level, pname, params );
+}
+
+static void APIENTRY logGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexParameterfv" );
+	dllGetTexParameterfv( target, pname, params );
+}
+
+static void APIENTRY logGetTexParameteriv(GLenum target, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexParameteriv" );
+	dllGetTexParameteriv( target, pname, params );
+}
+
+static void APIENTRY logHint(GLenum target, GLenum mode)
+{
+	fprintf( log_fp, "glHint( 0x%x, 0x%x )\n", target, mode );
+	dllHint( target, mode );
+}
+
+static void APIENTRY logIndexMask(GLuint mask)
+{
+	SIG( "glIndexMask" );
+	dllIndexMask( mask );
+}
+
+static void APIENTRY logIndexPointer(GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glIndexPointer" );
+	dllIndexPointer( type, stride, pointer );
+}
+
+static void APIENTRY logIndexd(GLdouble c)
+{
+	SIG( "glIndexd" );
+	dllIndexd( c );
+}
+
+static void APIENTRY logIndexdv(const GLdouble *c)
+{
+	SIG( "glIndexdv" );
+	dllIndexdv( c );
+}
+
+static void APIENTRY logIndexf(GLfloat c)
+{
+	SIG( "glIndexf" );
+	dllIndexf( c );
+}
+
+static void APIENTRY logIndexfv(const GLfloat *c)
+{
+	SIG( "glIndexfv" );
+	dllIndexfv( c );
+}
+
+static void APIENTRY logIndexi(GLint c)
+{
+	SIG( "glIndexi" );
+	dllIndexi( c );
+}
+
+static void APIENTRY logIndexiv(const GLint *c)
+{
+	SIG( "glIndexiv" );
+	dllIndexiv( c );
+}
+
+static void APIENTRY logIndexs(GLshort c)
+{
+	SIG( "glIndexs" );
+	dllIndexs( c );
+}
+
+static void APIENTRY logIndexsv(const GLshort *c)
+{
+	SIG( "glIndexsv" );
+	dllIndexsv( c );
+}
+
+static void APIENTRY logIndexub(GLubyte c)
+{
+	SIG( "glIndexub" );
+	dllIndexub( c );
+}
+
+static void APIENTRY logIndexubv(const GLubyte *c)
+{
+	SIG( "glIndexubv" );
+	dllIndexubv( c );
+}
+
+static void APIENTRY logInitNames(void)
+{
+	SIG( "glInitNames" );
+	dllInitNames();
+}
+
+static void APIENTRY logInterleavedArrays(GLenum format, GLsizei stride, const void *pointer)
+{
+	SIG( "glInterleavedArrays" );
+	dllInterleavedArrays( format, stride, pointer );
+}
+
+static GLboolean APIENTRY logIsEnabled(GLenum cap)
+{
+	SIG( "glIsEnabled" );
+	return dllIsEnabled( cap );
+}
+static GLboolean APIENTRY logIsList(GLuint list)
+{
+	SIG( "glIsList" );
+	return dllIsList( list );
+}
+static GLboolean APIENTRY logIsTexture(GLuint texture)
+{
+	SIG( "glIsTexture" );
+	return dllIsTexture( texture );
+}
+
+static void APIENTRY logLightModelf(GLenum pname, GLfloat param)
+{
+	SIG( "glLightModelf" );
+	dllLightModelf( pname, param );
+}
+
+static void APIENTRY logLightModelfv(GLenum pname, const GLfloat *params)
+{
+	SIG( "glLightModelfv" );
+	dllLightModelfv( pname, params );
+}
+
+static void APIENTRY logLightModeli(GLenum pname, GLint param)
+{
+	SIG( "glLightModeli" );
+	dllLightModeli( pname, param );
+
+}
+
+static void APIENTRY logLightModeliv(GLenum pname, const GLint *params)
+{
+	SIG( "glLightModeliv" );
+	dllLightModeliv( pname, params );
+}
+
+static void APIENTRY logLightf(GLenum light, GLenum pname, GLfloat param)
+{
+	SIG( "glLightf" );
+	dllLightf( light, pname, param );
+}
+
+static void APIENTRY logLightfv(GLenum light, GLenum pname, const GLfloat *params)
+{
+	SIG( "glLightfv" );
+	dllLightfv( light, pname, params );
+}
+
+static void APIENTRY logLighti(GLenum light, GLenum pname, GLint param)
+{
+	SIG( "glLighti" );
+	dllLighti( light, pname, param );
+}
+
+static void APIENTRY logLightiv(GLenum light, GLenum pname, const GLint *params)
+{
+	SIG( "glLightiv" );
+	dllLightiv( light, pname, params );
+}
+
+static void APIENTRY logLineStipple(GLint factor, GLushort pattern)
+{
+	SIG( "glLineStipple" );
+	dllLineStipple( factor, pattern );
+}
+
+static void APIENTRY logLineWidth(GLfloat width)
+{
+	SIG( "glLineWidth" );
+	dllLineWidth( width );
+}
+
+static void APIENTRY logListBase(GLuint base)
+{
+	SIG( "glListBase" );
+	dllListBase( base );
+}
+
+static void APIENTRY logLoadIdentity(void)
+{
+	SIG( "glLoadIdentity" );
+	dllLoadIdentity();
+}
+
+static void APIENTRY logLoadMatrixd(const GLdouble *m)
+{
+	SIG( "glLoadMatrixd" );
+	dllLoadMatrixd( m );
+}
+
+static void APIENTRY logLoadMatrixf(const GLfloat *m)
+{
+	SIG( "glLoadMatrixf" );
+	dllLoadMatrixf( m );
+}
+
+static void APIENTRY logLoadName(GLuint name)
+{
+	SIG( "glLoadName" );
+	dllLoadName( name );
+}
+
+static void APIENTRY logLogicOp(GLenum opcode)
+{
+	SIG( "glLogicOp" );
+	dllLogicOp( opcode );
+}
+
+static void APIENTRY logMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points)
+{
+	SIG( "glMap1d" );
+	dllMap1d( target, u1, u2, stride, order, points );
+}
+
+static void APIENTRY logMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points)
+{
+	SIG( "glMap1f" );
+	dllMap1f( target, u1, u2, stride, order, points );
+}
+
+static void APIENTRY logMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points)
+{
+	SIG( "glMap2d" );
+	dllMap2d( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points );
+}
+
+static void APIENTRY logMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points)
+{
+	SIG( "glMap2f" );
+	dllMap2f( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points );
+}
+
+static void APIENTRY logMapGrid1d(GLint un, GLdouble u1, GLdouble u2)
+{
+	SIG( "glMapGrid1d" );
+	dllMapGrid1d( un, u1, u2 );
+}
+
+static void APIENTRY logMapGrid1f(GLint un, GLfloat u1, GLfloat u2)
+{
+	SIG( "glMapGrid1f" );
+	dllMapGrid1f( un, u1, u2 );
+}
+
+static void APIENTRY logMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2)
+{
+	SIG( "glMapGrid2d" );
+	dllMapGrid2d( un, u1, u2, vn, v1, v2 );
+}
+static void APIENTRY logMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2)
+{
+	SIG( "glMapGrid2f" );
+	dllMapGrid2f( un, u1, u2, vn, v1, v2 );
+}
+static void APIENTRY logMaterialf(GLenum face, GLenum pname, GLfloat param)
+{
+	SIG( "glMaterialf" );
+	dllMaterialf( face, pname, param );
+}
+static void APIENTRY logMaterialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+	SIG( "glMaterialfv" );
+	dllMaterialfv( face, pname, params );
+}
+
+static void APIENTRY logMateriali(GLenum face, GLenum pname, GLint param)
+{
+	SIG( "glMateriali" );
+	dllMateriali( face, pname, param );
+}
+
+static void APIENTRY logMaterialiv(GLenum face, GLenum pname, const GLint *params)
+{
+	SIG( "glMaterialiv" );
+	dllMaterialiv( face, pname, params );
+}
+
+static void APIENTRY logMatrixMode(GLenum mode)
+{
+	SIG( "glMatrixMode" );
+	dllMatrixMode( mode );
+}
+
+static void APIENTRY logMultMatrixd(const GLdouble *m)
+{
+	SIG( "glMultMatrixd" );
+	dllMultMatrixd( m );
+}
+
+static void APIENTRY logMultMatrixf(const GLfloat *m)
+{
+	SIG( "glMultMatrixf" );
+	dllMultMatrixf( m );
+}
+
+static void APIENTRY logNewList(GLuint list, GLenum mode)
+{
+	SIG( "glNewList" );
+	dllNewList( list, mode );
+}
+
+static void APIENTRY logNormal3b(GLbyte nx, GLbyte ny, GLbyte nz)
+{
+	SIG ("glNormal3b" );
+	dllNormal3b( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3bv(const GLbyte *v)
+{
+	SIG( "glNormal3bv" );
+	dllNormal3bv( v );
+}
+
+static void APIENTRY logNormal3d(GLdouble nx, GLdouble ny, GLdouble nz)
+{
+	SIG( "glNormal3d" );
+	dllNormal3d( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3dv(const GLdouble *v)
+{
+	SIG( "glNormal3dv" );
+	dllNormal3dv( v );
+}
+
+static void APIENTRY logNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
+{
+	SIG( "glNormal3f" );
+	dllNormal3f( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3fv(const GLfloat *v)
+{
+	SIG( "glNormal3fv" );
+	dllNormal3fv( v );
+}
+static void APIENTRY logNormal3i(GLint nx, GLint ny, GLint nz)
+{
+	SIG( "glNormal3i" );
+	dllNormal3i( nx, ny, nz );
+}
+static void APIENTRY logNormal3iv(const GLint *v)
+{
+	SIG( "glNormal3iv" );
+	dllNormal3iv( v );
+}
+static void APIENTRY logNormal3s(GLshort nx, GLshort ny, GLshort nz)
+{
+	SIG( "glNormal3s" );
+	dllNormal3s( nx, ny, nz );
+}
+static void APIENTRY logNormal3sv(const GLshort *v)
+{
+	SIG( "glNormal3sv" );
+	dllNormal3sv( v );
+}
+static void APIENTRY logNormalPointer(GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glNormalPointer" );
+	dllNormalPointer( type, stride, pointer );
+}
+static void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+{
+	SIG( "glOrtho" );
+	dllOrtho( left, right, bottom, top, zNear, zFar );
+}
+
+static void APIENTRY logPassThrough(GLfloat token)
+{
+	SIG( "glPassThrough" );
+	dllPassThrough( token );
+}
+
+static void APIENTRY logPixelMapfv(GLenum map, GLsizei mapsize, const GLfloat *values)
+{
+	SIG( "glPixelMapfv" );
+	dllPixelMapfv( map, mapsize, values );
+}
+
+static void APIENTRY logPixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values)
+{
+	SIG( "glPixelMapuiv" );
+	dllPixelMapuiv( map, mapsize, values );
+}
+
+static void APIENTRY logPixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values)
+{
+	SIG( "glPixelMapusv" );
+	dllPixelMapusv( map, mapsize, values );
+}
+static void APIENTRY logPixelStoref(GLenum pname, GLfloat param)
+{
+	SIG( "glPixelStoref" );
+	dllPixelStoref( pname, param );
+}
+static void APIENTRY logPixelStorei(GLenum pname, GLint param)
+{
+	SIG( "glPixelStorei" );
+	dllPixelStorei( pname, param );
+}
+static void APIENTRY logPixelTransferf(GLenum pname, GLfloat param)
+{
+	SIG( "glPixelTransferf" );
+	dllPixelTransferf( pname, param );
+}
+
+static void APIENTRY logPixelTransferi(GLenum pname, GLint param)
+{
+	SIG( "glPixelTransferi" );
+	dllPixelTransferi( pname, param );
+}
+
+static void APIENTRY logPixelZoom(GLfloat xfactor, GLfloat yfactor)
+{
+	SIG( "glPixelZoom" );
+	dllPixelZoom( xfactor, yfactor );
+}
+
+static void APIENTRY logPointSize(GLfloat size)
+{
+	SIG( "glPointSize" );
+	dllPointSize( size );
+}
+
+static void APIENTRY logPolygonMode(GLenum face, GLenum mode)
+{
+	fprintf( log_fp, "glPolygonMode( 0x%x, 0x%x )\n", face, mode );
+	dllPolygonMode( face, mode );
+}
+
+static void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units)
+{
+	SIG( "glPolygonOffset" );
+	dllPolygonOffset( factor, units );
+}
+static void APIENTRY logPolygonStipple(const GLubyte *mask )
+{
+	SIG( "glPolygonStipple" );
+	dllPolygonStipple( mask );
+}
+static void APIENTRY logPopAttrib(void)
+{
+	SIG( "glPopAttrib" );
+	dllPopAttrib();
+}
+
+static void APIENTRY logPopClientAttrib(void)
+{
+	SIG( "glPopClientAttrib" );
+	dllPopClientAttrib();
+}
+
+static void APIENTRY logPopMatrix(void)
+{
+	SIG( "glPopMatrix" );
+	dllPopMatrix();
+}
+
+static void APIENTRY logPopName(void)
+{
+	SIG( "glPopName" );
+	dllPopName();
+}
+
+static void APIENTRY logPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities)
+{
+	SIG( "glPrioritizeTextures" );
+	dllPrioritizeTextures( n, textures, priorities );
+}
+
+static void APIENTRY logPushAttrib(GLbitfield mask)
+{
+	SIG( "glPushAttrib" );
+	dllPushAttrib( mask );
+}
+
+static void APIENTRY logPushClientAttrib(GLbitfield mask)
+{
+	SIG( "glPushClientAttrib" );
+	dllPushClientAttrib( mask );
+}
+
+static void APIENTRY logPushMatrix(void)
+{
+	SIG( "glPushMatrix" );
+	dllPushMatrix();
+}
+
+static void APIENTRY logPushName(GLuint name)
+{
+	SIG( "glPushName" );
+	dllPushName( name );
+}
+
+static void APIENTRY logRasterPos2d(GLdouble x, GLdouble y)
+{
+	SIG ("glRasterPot2d" );
+	dllRasterPos2d( x, y );
+}
+
+static void APIENTRY logRasterPos2dv(const GLdouble *v)
+{
+	SIG( "glRasterPos2dv" );
+	dllRasterPos2dv( v );
+}
+
+static void APIENTRY logRasterPos2f(GLfloat x, GLfloat y)
+{
+	SIG( "glRasterPos2f" );
+	dllRasterPos2f( x, y );
+}
+static void APIENTRY logRasterPos2fv(const GLfloat *v)
+{
+	SIG( "glRasterPos2dv" );
+	dllRasterPos2fv( v );
+}
+static void APIENTRY logRasterPos2i(GLint x, GLint y)
+{
+	SIG( "glRasterPos2if" );
+	dllRasterPos2i( x, y );
+}
+static void APIENTRY logRasterPos2iv(const GLint *v)
+{
+	SIG( "glRasterPos2iv" );
+	dllRasterPos2iv( v );
+}
+static void APIENTRY logRasterPos2s(GLshort x, GLshort y)
+{
+	SIG( "glRasterPos2s" );
+	dllRasterPos2s( x, y );
+}
+static void APIENTRY logRasterPos2sv(const GLshort *v)
+{
+	SIG( "glRasterPos2sv" );
+	dllRasterPos2sv( v );
+}
+static void APIENTRY logRasterPos3d(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glRasterPos3d" );
+	dllRasterPos3d( x, y, z );
+}
+static void APIENTRY logRasterPos3dv(const GLdouble *v)
+{
+	SIG( "glRasterPos3dv" );
+	dllRasterPos3dv( v );
+}
+static void APIENTRY logRasterPos3f(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glRasterPos3f" );
+	dllRasterPos3f( x, y, z );
+}
+static void APIENTRY logRasterPos3fv(const GLfloat *v)
+{
+	SIG( "glRasterPos3fv" );
+	dllRasterPos3fv( v );
+}
+static void APIENTRY logRasterPos3i(GLint x, GLint y, GLint z)
+{
+	SIG( "glRasterPos3i" );
+	dllRasterPos3i( x, y, z );
+}
+static void APIENTRY logRasterPos3iv(const GLint *v)
+{
+	SIG( "glRasterPos3iv" );
+	dllRasterPos3iv( v );
+}
+static void APIENTRY logRasterPos3s(GLshort x, GLshort y, GLshort z)
+{
+	SIG( "glRasterPos3s" );
+	dllRasterPos3s( x, y, z );
+}
+static void APIENTRY logRasterPos3sv(const GLshort *v)
+{
+	SIG( "glRasterPos3sv" );
+	dllRasterPos3sv( v );
+}
+static void APIENTRY logRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+	SIG( "glRasterPos4d" );
+	dllRasterPos4d( x, y, z, w );
+}
+static void APIENTRY logRasterPos4dv(const GLdouble *v)
+{
+	SIG( "glRasterPos4dv" );
+	dllRasterPos4dv( v );
+}
+static void APIENTRY logRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	SIG( "glRasterPos4f" );
+	dllRasterPos4f( x, y, z, w );
+}
+static void APIENTRY logRasterPos4fv(const GLfloat *v)
+{
+	SIG( "glRasterPos4fv" );
+	dllRasterPos4fv( v );
+}
+static void APIENTRY logRasterPos4i(GLint x, GLint y, GLint z, GLint w)
+{
+	SIG( "glRasterPos4i" );
+	dllRasterPos4i( x, y, z, w );
+}
+static void APIENTRY logRasterPos4iv(const GLint *v)
+{
+	SIG( "glRasterPos4iv" );
+	dllRasterPos4iv( v );
+}
+static void APIENTRY logRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w)
+{
+	SIG( "glRasterPos4s" );
+	dllRasterPos4s( x, y, z, w );
+}
+static void APIENTRY logRasterPos4sv(const GLshort *v)
+{
+	SIG( "glRasterPos4sv" );
+	dllRasterPos4sv( v );
+}
+static void APIENTRY logReadBuffer(GLenum mode)
+{
+	SIG( "glReadBuffer" );
+	dllReadBuffer( mode );
+}
+static void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)
+{
+	SIG( "glReadPixels" );
+	dllReadPixels( x, y, width, height, format, type, pixels );
+}
+
+static void APIENTRY logRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
+{
+	SIG( "glRectd" );
+	dllRectd( x1, y1, x2, y2 );
+}
+
+static void APIENTRY logRectdv(const GLdouble *v1, const GLdouble *v2)
+{
+	SIG( "glRectdv" );
+	dllRectdv( v1, v2 );
+}
+
+static void APIENTRY logRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+	SIG( "glRectf" );
+	dllRectf( x1, y1, x2, y2 );
+}
+
+static void APIENTRY logRectfv(const GLfloat *v1, const GLfloat *v2)
+{
+	SIG( "glRectfv" );
+	dllRectfv( v1, v2 );
+}
+static void APIENTRY logRecti(GLint x1, GLint y1, GLint x2, GLint y2)
+{
+	SIG( "glRecti" );
+	dllRecti( x1, y1, x2, y2 );
+}
+static void APIENTRY logRectiv(const GLint *v1, const GLint *v2)
+{
+	SIG( "glRectiv" );
+	dllRectiv( v1, v2 );
+}
+static void APIENTRY logRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
+{
+	SIG( "glRects" );
+	dllRects( x1, y1, x2, y2 );
+}
+static void APIENTRY logRectsv(const GLshort *v1, const GLshort *v2)
+{
+	SIG( "glRectsv" );
+	dllRectsv( v1, v2 );
+}
+static GLint APIENTRY logRenderMode(GLenum mode)
+{
+	SIG( "glRenderMode" );
+	return dllRenderMode( mode );
+}
+static void APIENTRY logRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glRotated" );
+	dllRotated( angle, x, y, z );
+}
+
+static void APIENTRY logRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glRotatef" );
+	dllRotatef( angle, x, y, z );
+}
+
+static void APIENTRY logScaled(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glScaled" );
+	dllScaled( x, y, z );
+}
+
+static void APIENTRY logScalef(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glScalef" );
+	dllScalef( x, y, z );
+}
+
+static void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glScissor" );
+	dllScissor( x, y, width, height );
+}
+
+static void APIENTRY logSelectBuffer(GLsizei size, GLuint *buffer)
+{
+	SIG( "glSelectBuffer" );
+	dllSelectBuffer( size, buffer );
+}
+
+static void APIENTRY logShadeModel(GLenum mode)
+{
+	SIG( "glShadeModel" );
+	dllShadeModel( mode );
+}
+
+static void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+	SIG( "glStencilFunc" );
+	dllStencilFunc( func, ref, mask );
+}
+
+static void APIENTRY logStencilMask(GLuint mask)
+{
+	SIG( "glStencilMask" );
+	dllStencilMask( mask );
+}
+
+static void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+	SIG( "glStencilOp" );
+	dllStencilOp( fail, zfail, zpass );
+}
+
+static void APIENTRY logTexCoord1d(GLdouble s)
+{
+	SIG( "glTexCoord1d" );
+	dllTexCoord1d( s );
+}
+
+static void APIENTRY logTexCoord1dv(const GLdouble *v)
+{
+	SIG( "glTexCoord1dv" );
+	dllTexCoord1dv( v );
+}
+
+static void APIENTRY logTexCoord1f(GLfloat s)
+{
+	SIG( "glTexCoord1f" );
+	dllTexCoord1f( s );
+}
+static void APIENTRY logTexCoord1fv(const GLfloat *v)
+{
+	SIG( "glTexCoord1fv" );
+	dllTexCoord1fv( v );
+}
+static void APIENTRY logTexCoord1i(GLint s)
+{
+	SIG( "glTexCoord1i" );
+	dllTexCoord1i( s );
+}
+static void APIENTRY logTexCoord1iv(const GLint *v)
+{
+	SIG( "glTexCoord1iv" );
+	dllTexCoord1iv( v );
+}
+static void APIENTRY logTexCoord1s(GLshort s)
+{
+	SIG( "glTexCoord1s" );
+	dllTexCoord1s( s );
+}
+static void APIENTRY logTexCoord1sv(const GLshort *v)
+{
+	SIG( "glTexCoord1sv" );
+	dllTexCoord1sv( v );
+}
+static void APIENTRY logTexCoord2d(GLdouble s, GLdouble t)
+{
+	SIG( "glTexCoord2d" );
+	dllTexCoord2d( s, t );
+}
+
+static void APIENTRY logTexCoord2dv(const GLdouble *v)
+{
+	SIG( "glTexCoord2dv" );
+	dllTexCoord2dv( v );
+}
+static void APIENTRY logTexCoord2f(GLfloat s, GLfloat t)
+{
+	SIG( "glTexCoord2f" );
+	dllTexCoord2f( s, t );
+}
+static void APIENTRY logTexCoord2fv(const GLfloat *v)
+{
+	SIG( "glTexCoord2fv" );
+	dllTexCoord2fv( v );
+}
+static void APIENTRY logTexCoord2i(GLint s, GLint t)
+{
+	SIG( "glTexCoord2i" );
+	dllTexCoord2i( s, t );
+}
+static void APIENTRY logTexCoord2iv(const GLint *v)
+{
+	SIG( "glTexCoord2iv" );
+	dllTexCoord2iv( v );
+}
+static void APIENTRY logTexCoord2s(GLshort s, GLshort t)
+{
+	SIG( "glTexCoord2s" );
+	dllTexCoord2s( s, t );
+}
+static void APIENTRY logTexCoord2sv(const GLshort *v)
+{
+	SIG( "glTexCoord2sv" );
+	dllTexCoord2sv( v );
+}
+static void APIENTRY logTexCoord3d(GLdouble s, GLdouble t, GLdouble r)
+{
+	SIG( "glTexCoord3d" );
+	dllTexCoord3d( s, t, r );
+}
+static void APIENTRY logTexCoord3dv(const GLdouble *v)
+{
+	SIG( "glTexCoord3dv" );
+	dllTexCoord3dv( v );
+}
+static void APIENTRY logTexCoord3f(GLfloat s, GLfloat t, GLfloat r)
+{
+	SIG( "glTexCoord3f" );
+	dllTexCoord3f( s, t, r );
+}
+static void APIENTRY logTexCoord3fv(const GLfloat *v)
+{
+	SIG( "glTexCoord3fv" );
+	dllTexCoord3fv( v );
+}
+static void APIENTRY logTexCoord3i(GLint s, GLint t, GLint r)
+{
+	SIG( "glTexCoord3i" );
+	dllTexCoord3i( s, t, r );
+}
+static void APIENTRY logTexCoord3iv(const GLint *v)
+{
+	SIG( "glTexCoord3iv" );
+	dllTexCoord3iv( v );
+}
+static void APIENTRY logTexCoord3s(GLshort s, GLshort t, GLshort r)
+{
+	SIG( "glTexCoord3s" );
+	dllTexCoord3s( s, t, r );
+}
+static void APIENTRY logTexCoord3sv(const GLshort *v)
+{
+	SIG( "glTexCoord3sv" );
+	dllTexCoord3sv( v );
+}
+static void APIENTRY logTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q)
+{
+	SIG( "glTexCoord4d" );
+	dllTexCoord4d( s, t, r, q );
+}
+static void APIENTRY logTexCoord4dv(const GLdouble *v)
+{
+	SIG( "glTexCoord4dv" );
+	dllTexCoord4dv( v );
+}
+static void APIENTRY logTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+	SIG( "glTexCoord4f" );
+	dllTexCoord4f( s, t, r, q );
+}
+static void APIENTRY logTexCoord4fv(const GLfloat *v)
+{
+	SIG( "glTexCoord4fv" );
+	dllTexCoord4fv( v );
+}
+static void APIENTRY logTexCoord4i(GLint s, GLint t, GLint r, GLint q)
+{
+	SIG( "glTexCoord4i" );
+	dllTexCoord4i( s, t, r, q );
+}
+static void APIENTRY logTexCoord4iv(const GLint *v)
+{
+	SIG( "glTexCoord4iv" );
+	dllTexCoord4iv( v );
+}
+static void APIENTRY logTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q)
+{
+	SIG( "glTexCoord4s" );
+	dllTexCoord4s( s, t, r, q );
+}
+static void APIENTRY logTexCoord4sv(const GLshort *v)
+{
+	SIG( "glTexCoord4sv" );
+	dllTexCoord4sv( v );
+}
+static void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glTexCoordPointer" );
+	dllTexCoordPointer( size, type, stride, pointer );
+}
+
+static void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param)
+{
+	fprintf( log_fp, "glTexEnvf( 0x%x, 0x%x, %f )\n", target, pname, param );
+	dllTexEnvf( target, pname, param );
+}
+
+static void APIENTRY logTexEnvfv(GLenum target, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexEnvfv" );
+	dllTexEnvfv( target, pname, params );
+}
+
+static void APIENTRY logTexEnvi(GLenum target, GLenum pname, GLint param)
+{
+	fprintf( log_fp, "glTexEnvi( 0x%x, 0x%x, 0x%x )\n", target, pname, param );
+	dllTexEnvi( target, pname, param );
+}
+static void APIENTRY logTexEnviv(GLenum target, GLenum pname, const GLint *params)
+{
+	SIG( "glTexEnviv" );
+	dllTexEnviv( target, pname, params );
+}
+
+static void APIENTRY logTexGend(GLenum coord, GLenum pname, GLdouble param)
+{
+	SIG( "glTexGend" );
+	dllTexGend( coord, pname, param );
+}
+
+static void APIENTRY logTexGendv(GLenum coord, GLenum pname, const GLdouble *params)
+{
+	SIG( "glTexGendv" );
+	dllTexGendv( coord, pname, params );
+}
+
+static void APIENTRY logTexGenf(GLenum coord, GLenum pname, GLfloat param)
+{
+	SIG( "glTexGenf" );
+	dllTexGenf( coord, pname, param );
+}
+static void APIENTRY logTexGenfv(GLenum coord, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexGenfv" );
+	dllTexGenfv( coord, pname, params );
+}
+static void APIENTRY logTexGeni(GLenum coord, GLenum pname, GLint param)
+{
+	SIG( "glTexGeni" );
+	dllTexGeni( coord, pname, param );
+}
+static void APIENTRY logTexGeniv(GLenum coord, GLenum pname, const GLint *params)
+{
+	SIG( "glTexGeniv" );
+	dllTexGeniv( coord, pname, params );
+}
+static void APIENTRY logTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexImage1D" );
+	dllTexImage1D( target, level, internalformat, width, border, format, type, pixels );
+}
+static void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexImage2D" );
+	dllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels );
+}
+
+static void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+	fprintf( log_fp, "glTexParameterf( 0x%x, 0x%x, %f )\n", target, pname, param );
+	dllTexParameterf( target, pname, param );
+}
+
+static void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexParameterfv" );
+	dllTexParameterfv( target, pname, params );
+}
+static void APIENTRY logTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+	fprintf( log_fp, "glTexParameteri( 0x%x, 0x%x, 0x%x )\n", target, pname, param );
+	dllTexParameteri( target, pname, param );
+}
+static void APIENTRY logTexParameteriv(GLenum target, GLenum pname, const GLint *params)
+{
+	SIG( "glTexParameteriv" );
+	dllTexParameteriv( target, pname, params );
+}
+static void APIENTRY logTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexSubImage1D" );
+	dllTexSubImage1D( target, level, xoffset, width, format, type, pixels );
+}
+static void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexSubImage2D" );
+	dllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels );
+}
+static void APIENTRY logTranslated(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glTranslated" );
+	dllTranslated( x, y, z );
+}
+
+static void APIENTRY logTranslatef(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glTranslatef" );
+	dllTranslatef( x, y, z );
+}
+
+static void APIENTRY logVertex2d(GLdouble x, GLdouble y)
+{
+	SIG( "glVertex2d" );
+	dllVertex2d( x, y );
+}
+
+static void APIENTRY logVertex2dv(const GLdouble *v)
+{
+	SIG( "glVertex2dv" );
+	dllVertex2dv( v );
+}
+static void APIENTRY logVertex2f(GLfloat x, GLfloat y)
+{
+	SIG( "glVertex2f" );
+	dllVertex2f( x, y );
+}
+static void APIENTRY logVertex2fv(const GLfloat *v)
+{
+	SIG( "glVertex2fv" );
+	dllVertex2fv( v );
+}
+static void APIENTRY logVertex2i(GLint x, GLint y)
+{
+	SIG( "glVertex2i" );
+	dllVertex2i( x, y );
+}
+static void APIENTRY logVertex2iv(const GLint *v)
+{
+	SIG( "glVertex2iv" );
+	dllVertex2iv( v );
+}
+static void APIENTRY logVertex2s(GLshort x, GLshort y)
+{
+	SIG( "glVertex2s" );
+	dllVertex2s( x, y );
+}
+static void APIENTRY logVertex2sv(const GLshort *v)
+{
+	SIG( "glVertex2sv" );
+	dllVertex2sv( v );
+}
+static void APIENTRY logVertex3d(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glVertex3d" );
+	dllVertex3d( x, y, z );
+}
+static void APIENTRY logVertex3dv(const GLdouble *v)
+{
+	SIG( "glVertex3dv" );
+	dllVertex3dv( v );
+}
+static void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glVertex3f" );
+	dllVertex3f( x, y, z );
+}
+static void APIENTRY logVertex3fv(const GLfloat *v)
+{
+	SIG( "glVertex3fv" );
+	dllVertex3fv( v );
+}
+static void APIENTRY logVertex3i(GLint x, GLint y, GLint z)
+{
+	SIG( "glVertex3i" );
+	dllVertex3i( x, y, z );
+}
+static void APIENTRY logVertex3iv(const GLint *v)
+{
+	SIG( "glVertex3iv" );
+	dllVertex3iv( v );
+}
+static void APIENTRY logVertex3s(GLshort x, GLshort y, GLshort z)
+{
+	SIG( "glVertex3s" );
+	dllVertex3s( x, y, z );
+}
+static void APIENTRY logVertex3sv(const GLshort *v)
+{
+	SIG( "glVertex3sv" );
+	dllVertex3sv( v );
+}
+static void APIENTRY logVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+	SIG( "glVertex4d" );
+	dllVertex4d( x, y, z, w );
+}
+static void APIENTRY logVertex4dv(const GLdouble *v)
+{
+	SIG( "glVertex4dv" );
+	dllVertex4dv( v );
+}
+static void APIENTRY logVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	SIG( "glVertex4f" );
+	dllVertex4f( x, y, z, w );
+}
+static void APIENTRY logVertex4fv(const GLfloat *v)
+{
+	SIG( "glVertex4fv" );
+	dllVertex4fv( v );
+}
+static void APIENTRY logVertex4i(GLint x, GLint y, GLint z, GLint w)
+{
+	SIG( "glVertex4i" );
+	dllVertex4i( x, y, z, w );
+}
+static void APIENTRY logVertex4iv(const GLint *v)
+{
+	SIG( "glVertex4iv" );
+	dllVertex4iv( v );
+}
+static void APIENTRY logVertex4s(GLshort x, GLshort y, GLshort z, GLshort w)
+{
+	SIG( "glVertex4s" );
+	dllVertex4s( x, y, z, w );
+}
+static void APIENTRY logVertex4sv(const GLshort *v)
+{
+	SIG( "glVertex4sv" );
+	dllVertex4sv( v );
+}
+static void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glVertexPointer" );
+	dllVertexPointer( size, type, stride, pointer );
+}
+static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glViewport" );
+	dllViewport( x, y, width, height );
+}
+
+/*
+** QGL_Shutdown
+**
+** Unloads the specified DLL then nulls out all the proc pointers.
+*/
+void QGL_Shutdown( void )
+{
+	qglAccum                     = NULL;
+	qglAlphaFunc                 = NULL;
+	qglAreTexturesResident       = NULL;
+	qglArrayElement              = NULL;
+	qglBegin                     = NULL;
+	qglBindTexture               = NULL;
+	qglBitmap                    = NULL;
+	qglBlendFunc                 = NULL;
+	qglCallList                  = NULL;
+	qglCallLists                 = NULL;
+	qglClear                     = NULL;
+	qglClearAccum                = NULL;
+	qglClearColor                = NULL;
+	qglClearDepth                = NULL;
+	qglClearIndex                = NULL;
+	qglClearStencil              = NULL;
+	qglClipPlane                 = NULL;
+	qglColor3b                   = NULL;
+	qglColor3bv                  = NULL;
+	qglColor3d                   = NULL;
+	qglColor3dv                  = NULL;
+	qglColor3f                   = NULL;
+	qglColor3fv                  = NULL;
+	qglColor3i                   = NULL;
+	qglColor3iv                  = NULL;
+	qglColor3s                   = NULL;
+	qglColor3sv                  = NULL;
+	qglColor3ub                  = NULL;
+	qglColor3ubv                 = NULL;
+	qglColor3ui                  = NULL;
+	qglColor3uiv                 = NULL;
+	qglColor3us                  = NULL;
+	qglColor3usv                 = NULL;
+	qglColor4b                   = NULL;
+	qglColor4bv                  = NULL;
+	qglColor4d                   = NULL;
+	qglColor4dv                  = NULL;
+	qglColor4f                   = NULL;
+	qglColor4fv                  = NULL;
+	qglColor4i                   = NULL;
+	qglColor4iv                  = NULL;
+	qglColor4s                   = NULL;
+	qglColor4sv                  = NULL;
+	qglColor4ub                  = NULL;
+	qglColor4ubv                 = NULL;
+	qglColor4ui                  = NULL;
+	qglColor4uiv                 = NULL;
+	qglColor4us                  = NULL;
+	qglColor4usv                 = NULL;
+	qglColorMask                 = NULL;
+	qglColorMaterial             = NULL;
+	qglColorPointer              = NULL;
+	qglCopyPixels                = NULL;
+	qglCopyTexImage1D            = NULL;
+	qglCopyTexImage2D            = NULL;
+	qglCopyTexSubImage1D         = NULL;
+	qglCopyTexSubImage2D         = NULL;
+	qglCullFace                  = NULL;
+	qglDeleteLists               = NULL;
+	qglDeleteTextures            = NULL;
+	qglDepthFunc                 = NULL;
+	qglDepthMask                 = NULL;
+	qglDepthRange                = NULL;
+	qglDisable                   = NULL;
+	qglDisableClientState        = NULL;
+	qglDrawArrays                = NULL;
+	qglDrawBuffer                = NULL;
+	qglDrawElements              = NULL;
+	qglDrawPixels                = NULL;
+	qglEdgeFlag                  = NULL;
+	qglEdgeFlagPointer           = NULL;
+	qglEdgeFlagv                 = NULL;
+	qglEnable                    = NULL;
+	qglEnableClientState         = NULL;
+	qglEnd                       = NULL;
+	qglEndList                   = NULL;
+	qglEvalCoord1d               = NULL;
+	qglEvalCoord1dv              = NULL;
+	qglEvalCoord1f               = NULL;
+	qglEvalCoord1fv              = NULL;
+	qglEvalCoord2d               = NULL;
+	qglEvalCoord2dv              = NULL;
+	qglEvalCoord2f               = NULL;
+	qglEvalCoord2fv              = NULL;
+	qglEvalMesh1                 = NULL;
+	qglEvalMesh2                 = NULL;
+	qglEvalPoint1                = NULL;
+	qglEvalPoint2                = NULL;
+	qglFeedbackBuffer            = NULL;
+	qglFinish                    = NULL;
+	qglFlush                     = NULL;
+	qglFogf                      = NULL;
+	qglFogfv                     = NULL;
+	qglFogi                      = NULL;
+	qglFogiv                     = NULL;
+	qglFrontFace                 = NULL;
+	qglFrustum                   = NULL;
+	qglGenLists                  = NULL;
+	qglGenTextures               = NULL;
+	qglGetBooleanv               = NULL;
+	qglGetClipPlane              = NULL;
+	qglGetDoublev                = NULL;
+	qglGetError                  = NULL;
+	qglGetFloatv                 = NULL;
+	qglGetIntegerv               = NULL;
+	qglGetLightfv                = NULL;
+	qglGetLightiv                = NULL;
+	qglGetMapdv                  = NULL;
+	qglGetMapfv                  = NULL;
+	qglGetMapiv                  = NULL;
+	qglGetMaterialfv             = NULL;
+	qglGetMaterialiv             = NULL;
+	qglGetPixelMapfv             = NULL;
+	qglGetPixelMapuiv            = NULL;
+	qglGetPixelMapusv            = NULL;
+	qglGetPointerv               = NULL;
+	qglGetPolygonStipple         = NULL;
+	qglGetString                 = NULL;
+	qglGetTexEnvfv               = NULL;
+	qglGetTexEnviv               = NULL;
+	qglGetTexGendv               = NULL;
+	qglGetTexGenfv               = NULL;
+	qglGetTexGeniv               = NULL;
+	qglGetTexImage               = NULL;
+	qglGetTexLevelParameterfv    = NULL;
+	qglGetTexLevelParameteriv    = NULL;
+	qglGetTexParameterfv         = NULL;
+	qglGetTexParameteriv         = NULL;
+	qglHint                      = NULL;
+	qglIndexMask                 = NULL;
+	qglIndexPointer              = NULL;
+	qglIndexd                    = NULL;
+	qglIndexdv                   = NULL;
+	qglIndexf                    = NULL;
+	qglIndexfv                   = NULL;
+	qglIndexi                    = NULL;
+	qglIndexiv                   = NULL;
+	qglIndexs                    = NULL;
+	qglIndexsv                   = NULL;
+	qglIndexub                   = NULL;
+	qglIndexubv                  = NULL;
+	qglInitNames                 = NULL;
+	qglInterleavedArrays         = NULL;
+	qglIsEnabled                 = NULL;
+	qglIsList                    = NULL;
+	qglIsTexture                 = NULL;
+	qglLightModelf               = NULL;
+	qglLightModelfv              = NULL;
+	qglLightModeli               = NULL;
+	qglLightModeliv              = NULL;
+	qglLightf                    = NULL;
+	qglLightfv                   = NULL;
+	qglLighti                    = NULL;
+	qglLightiv                   = NULL;
+	qglLineStipple               = NULL;
+	qglLineWidth                 = NULL;
+	qglListBase                  = NULL;
+	qglLoadIdentity              = NULL;
+	qglLoadMatrixd               = NULL;
+	qglLoadMatrixf               = NULL;
+	qglLoadName                  = NULL;
+	qglLogicOp                   = NULL;
+	qglMap1d                     = NULL;
+	qglMap1f                     = NULL;
+	qglMap2d                     = NULL;
+	qglMap2f                     = NULL;
+	qglMapGrid1d                 = NULL;
+	qglMapGrid1f                 = NULL;
+	qglMapGrid2d                 = NULL;
+	qglMapGrid2f                 = NULL;
+	qglMaterialf                 = NULL;
+	qglMaterialfv                = NULL;
+	qglMateriali                 = NULL;
+	qglMaterialiv                = NULL;
+	qglMatrixMode                = NULL;
+	qglMultMatrixd               = NULL;
+	qglMultMatrixf               = NULL;
+	qglNewList                   = NULL;
+	qglNormal3b                  = NULL;
+	qglNormal3bv                 = NULL;
+	qglNormal3d                  = NULL;
+	qglNormal3dv                 = NULL;
+	qglNormal3f                  = NULL;
+	qglNormal3fv                 = NULL;
+	qglNormal3i                  = NULL;
+	qglNormal3iv                 = NULL;
+	qglNormal3s                  = NULL;
+	qglNormal3sv                 = NULL;
+	qglNormalPointer             = NULL;
+	qglOrtho                     = NULL;
+	qglPassThrough               = NULL;
+	qglPixelMapfv                = NULL;
+	qglPixelMapuiv               = NULL;
+	qglPixelMapusv               = NULL;
+	qglPixelStoref               = NULL;
+	qglPixelStorei               = NULL;
+	qglPixelTransferf            = NULL;
+	qglPixelTransferi            = NULL;
+	qglPixelZoom                 = NULL;
+	qglPointSize                 = NULL;
+	qglPolygonMode               = NULL;
+	qglPolygonOffset             = NULL;
+	qglPolygonStipple            = NULL;
+	qglPopAttrib                 = NULL;
+	qglPopClientAttrib           = NULL;
+	qglPopMatrix                 = NULL;
+	qglPopName                   = NULL;
+	qglPrioritizeTextures        = NULL;
+	qglPushAttrib                = NULL;
+	qglPushClientAttrib          = NULL;
+	qglPushMatrix                = NULL;
+	qglPushName                  = NULL;
+	qglRasterPos2d               = NULL;
+	qglRasterPos2dv              = NULL;
+	qglRasterPos2f               = NULL;
+	qglRasterPos2fv              = NULL;
+	qglRasterPos2i               = NULL;
+	qglRasterPos2iv              = NULL;
+	qglRasterPos2s               = NULL;
+	qglRasterPos2sv              = NULL;
+	qglRasterPos3d               = NULL;
+	qglRasterPos3dv              = NULL;
+	qglRasterPos3f               = NULL;
+	qglRasterPos3fv              = NULL;
+	qglRasterPos3i               = NULL;
+	qglRasterPos3iv              = NULL;
+	qglRasterPos3s               = NULL;
+	qglRasterPos3sv              = NULL;
+	qglRasterPos4d               = NULL;
+	qglRasterPos4dv              = NULL;
+	qglRasterPos4f               = NULL;
+	qglRasterPos4fv              = NULL;
+	qglRasterPos4i               = NULL;
+	qglRasterPos4iv              = NULL;
+	qglRasterPos4s               = NULL;
+	qglRasterPos4sv              = NULL;
+	qglReadBuffer                = NULL;
+	qglReadPixels                = NULL;
+	qglRectd                     = NULL;
+	qglRectdv                    = NULL;
+	qglRectf                     = NULL;
+	qglRectfv                    = NULL;
+	qglRecti                     = NULL;
+	qglRectiv                    = NULL;
+	qglRects                     = NULL;
+	qglRectsv                    = NULL;
+	qglRenderMode                = NULL;
+	qglRotated                   = NULL;
+	qglRotatef                   = NULL;
+	qglScaled                    = NULL;
+	qglScalef                    = NULL;
+	qglScissor                   = NULL;
+	qglSelectBuffer              = NULL;
+	qglShadeModel                = NULL;
+	qglStencilFunc               = NULL;
+	qglStencilMask               = NULL;
+	qglStencilOp                 = NULL;
+	qglTexCoord1d                = NULL;
+	qglTexCoord1dv               = NULL;
+	qglTexCoord1f                = NULL;
+	qglTexCoord1fv               = NULL;
+	qglTexCoord1i                = NULL;
+	qglTexCoord1iv               = NULL;
+	qglTexCoord1s                = NULL;
+	qglTexCoord1sv               = NULL;
+	qglTexCoord2d                = NULL;
+	qglTexCoord2dv               = NULL;
+	qglTexCoord2f                = NULL;
+	qglTexCoord2fv               = NULL;
+	qglTexCoord2i                = NULL;
+	qglTexCoord2iv               = NULL;
+	qglTexCoord2s                = NULL;
+	qglTexCoord2sv               = NULL;
+	qglTexCoord3d                = NULL;
+	qglTexCoord3dv               = NULL;
+	qglTexCoord3f                = NULL;
+	qglTexCoord3fv               = NULL;
+	qglTexCoord3i                = NULL;
+	qglTexCoord3iv               = NULL;
+	qglTexCoord3s                = NULL;
+	qglTexCoord3sv               = NULL;
+	qglTexCoord4d                = NULL;
+	qglTexCoord4dv               = NULL;
+	qglTexCoord4f                = NULL;
+	qglTexCoord4fv               = NULL;
+	qglTexCoord4i                = NULL;
+	qglTexCoord4iv               = NULL;
+	qglTexCoord4s                = NULL;
+	qglTexCoord4sv               = NULL;
+	qglTexCoordPointer           = NULL;
+	qglTexEnvf                   = NULL;
+	qglTexEnvfv                  = NULL;
+	qglTexEnvi                   = NULL;
+	qglTexEnviv                  = NULL;
+	qglTexGend                   = NULL;
+	qglTexGendv                  = NULL;
+	qglTexGenf                   = NULL;
+	qglTexGenfv                  = NULL;
+	qglTexGeni                   = NULL;
+	qglTexGeniv                  = NULL;
+	qglTexImage1D                = NULL;
+	qglTexImage2D                = NULL;
+	qglTexParameterf             = NULL;
+	qglTexParameterfv            = NULL;
+	qglTexParameteri             = NULL;
+	qglTexParameteriv            = NULL;
+	qglTexSubImage1D             = NULL;
+	qglTexSubImage2D             = NULL;
+	qglTranslated                = NULL;
+	qglTranslatef                = NULL;
+	qglVertex2d                  = NULL;
+	qglVertex2dv                 = NULL;
+	qglVertex2f                  = NULL;
+	qglVertex2fv                 = NULL;
+	qglVertex2i                  = NULL;
+	qglVertex2iv                 = NULL;
+	qglVertex2s                  = NULL;
+	qglVertex2sv                 = NULL;
+	qglVertex3d                  = NULL;
+	qglVertex3dv                 = NULL;
+	qglVertex3f                  = NULL;
+	qglVertex3fv                 = NULL;
+	qglVertex3i                  = NULL;
+	qglVertex3iv                 = NULL;
+	qglVertex3s                  = NULL;
+	qglVertex3sv                 = NULL;
+	qglVertex4d                  = NULL;
+	qglVertex4dv                 = NULL;
+	qglVertex4f                  = NULL;
+	qglVertex4fv                 = NULL;
+	qglVertex4i                  = NULL;
+	qglVertex4iv                 = NULL;
+	qglVertex4s                  = NULL;
+	qglVertex4sv                 = NULL;
+	qglVertexPointer             = NULL;
+	qglViewport                  = NULL;
+}
+
+/*
+** QGL_Init
+**
+** This is responsible for binding our qgl function pointers to 
+** the appropriate GL stuff.  In Windows this means doing a 
+** LoadLibrary and a bunch of calls to GetProcAddress.  On other
+** operating systems we need to do the right thing, whatever that
+** might be.
+** 
+*/
+qboolean QGL_Init( const char *dllname )
+{
+	qglAccum                     = dllAccum = glAccum;
+	qglAlphaFunc                 = dllAlphaFunc = glAlphaFunc;
+	qglAreTexturesResident       = dllAreTexturesResident = glAreTexturesResident;
+	qglArrayElement              = dllArrayElement = glArrayElement;
+	qglBegin                     = dllBegin = glBegin;
+	qglBindTexture               = dllBindTexture = glBindTexture;
+	qglBitmap                    = dllBitmap = glBitmap;
+	qglBlendFunc                 = dllBlendFunc = glBlendFunc;
+	qglCallList                  = dllCallList = glCallList;
+	qglCallLists                 = dllCallLists = glCallLists;
+	qglClear                     = dllClear = glClear;
+	qglClearAccum                = dllClearAccum = glClearAccum;
+	qglClearColor                = dllClearColor = glClearColor;
+	qglClearDepth                = dllClearDepth = glClearDepth;
+	qglClearIndex                = dllClearIndex = glClearIndex;
+	qglClearStencil              = dllClearStencil = glClearStencil;
+	qglClipPlane                 = dllClipPlane = glClipPlane;
+	qglColor3b                   = dllColor3b = glColor3b;
+	qglColor3bv                  = dllColor3bv = glColor3bv;
+	qglColor3d                   = dllColor3d = glColor3d;
+	qglColor3dv                  = dllColor3dv = glColor3dv;
+	qglColor3f                   = dllColor3f = glColor3f;
+	qglColor3fv                  = dllColor3fv = glColor3fv;
+	qglColor3i                   = dllColor3i = glColor3i;
+	qglColor3iv                  = dllColor3iv = glColor3iv;
+	qglColor3s                   = dllColor3s = glColor3s;
+	qglColor3sv                  = dllColor3sv = glColor3sv;
+	qglColor3ub                  = dllColor3ub = glColor3ub;
+	qglColor3ubv                 = dllColor3ubv = glColor3ubv;
+	qglColor3ui                  = dllColor3ui = glColor3ui;
+	qglColor3uiv                 = dllColor3uiv = glColor3uiv;
+	qglColor3us                  = dllColor3us = glColor3us;
+	qglColor3usv                 = dllColor3usv = glColor3usv;
+	qglColor4b                   = dllColor4b = glColor4b;
+	qglColor4bv                  = dllColor4bv = glColor4bv;
+	qglColor4d                   = dllColor4d = glColor4d;
+	qglColor4dv                  = dllColor4dv = glColor4dv;
+	qglColor4f                   = dllColor4f = glColor4f;
+	qglColor4fv                  = dllColor4fv = glColor4fv;
+	qglColor4i                   = dllColor4i = glColor4i;
+	qglColor4iv                  = dllColor4iv = glColor4iv;
+	qglColor4s                   = dllColor4s = glColor4s;
+	qglColor4sv                  = dllColor4sv = glColor4sv;
+	qglColor4ub                  = dllColor4ub = glColor4ub;
+	qglColor4ubv                 = dllColor4ubv = glColor4ubv;
+	qglColor4ui                  = dllColor4ui = glColor4ui;
+	qglColor4uiv                 = dllColor4uiv = glColor4uiv;
+	qglColor4us                  = dllColor4us = glColor4us;
+	qglColor4usv                 = dllColor4usv = glColor4usv;
+	qglColorMask                 = dllColorMask = glColorMask;
+	qglColorMaterial             = dllColorMaterial = glColorMaterial;
+	qglColorPointer              = dllColorPointer = glColorPointer;
+	qglCopyPixels                = dllCopyPixels = glCopyPixels;
+	qglCopyTexImage1D            = dllCopyTexImage1D = glCopyTexImage1D;
+	qglCopyTexImage2D            = dllCopyTexImage2D = glCopyTexImage2D;
+	qglCopyTexSubImage1D         = dllCopyTexSubImage1D = glCopyTexSubImage1D;
+	qglCopyTexSubImage2D         = dllCopyTexSubImage2D = glCopyTexSubImage2D;
+	qglCullFace                  = dllCullFace = glCullFace;
+	qglDeleteLists               = dllDeleteLists = glDeleteLists;
+	qglDeleteTextures            = dllDeleteTextures = glDeleteTextures;
+	qglDepthFunc                 = dllDepthFunc = glDepthFunc;
+	qglDepthMask                 = dllDepthMask = glDepthMask;
+	qglDepthRange                = dllDepthRange = glDepthRange;
+	qglDisable                   = dllDisable = glDisable;
+	qglDisableClientState        = dllDisableClientState = glDisableClientState;
+	qglDrawArrays                = dllDrawArrays = glDrawArrays;
+	qglDrawBuffer                = dllDrawBuffer = glDrawBuffer;
+	qglDrawElements              = dllDrawElements = glDrawElements;
+	qglDrawPixels                = dllDrawPixels = glDrawPixels;
+	qglEdgeFlag                  = dllEdgeFlag = glEdgeFlag;
+	qglEdgeFlagPointer           = dllEdgeFlagPointer = glEdgeFlagPointer;
+	qglEdgeFlagv                 = dllEdgeFlagv = glEdgeFlagv;
+	qglEnable                    = 	dllEnable                    = glEnable;
+	qglEnableClientState         = 	dllEnableClientState         = glEnableClientState;
+	qglEnd                       = 	dllEnd                       = glEnd;
+	qglEndList                   = 	dllEndList                   = glEndList;
+	qglEvalCoord1d				 = 	dllEvalCoord1d				 = glEvalCoord1d;
+	qglEvalCoord1dv              = 	dllEvalCoord1dv              = glEvalCoord1dv;
+	qglEvalCoord1f               = 	dllEvalCoord1f               = glEvalCoord1f;
+	qglEvalCoord1fv              = 	dllEvalCoord1fv              = glEvalCoord1fv;
+	qglEvalCoord2d               = 	dllEvalCoord2d               = glEvalCoord2d;
+	qglEvalCoord2dv              = 	dllEvalCoord2dv              = glEvalCoord2dv;
+	qglEvalCoord2f               = 	dllEvalCoord2f               = glEvalCoord2f;
+	qglEvalCoord2fv              = 	dllEvalCoord2fv              = glEvalCoord2fv;
+	qglEvalMesh1                 = 	dllEvalMesh1                 = glEvalMesh1;
+	qglEvalMesh2                 = 	dllEvalMesh2                 = glEvalMesh2;
+	qglEvalPoint1                = 	dllEvalPoint1                = glEvalPoint1;
+	qglEvalPoint2                = 	dllEvalPoint2                = glEvalPoint2;
+	qglFeedbackBuffer            = 	dllFeedbackBuffer            = glFeedbackBuffer;
+	qglFinish                    = 	dllFinish                    = glFinish;
+	qglFlush                     = 	dllFlush                     = glFlush;
+	qglFogf                      = 	dllFogf                      = glFogf;
+	qglFogfv                     = 	dllFogfv                     = glFogfv;
+	qglFogi                      = 	dllFogi                      = glFogi;
+	qglFogiv                     = 	dllFogiv                     = glFogiv;
+	qglFrontFace                 = 	dllFrontFace                 = glFrontFace;
+	qglFrustum                   = 	dllFrustum                   = glFrustum;
+	qglGenLists                  = 	dllGenLists                  = glGenLists;
+	qglGenTextures               = 	dllGenTextures               = glGenTextures;
+	qglGetBooleanv               = 	dllGetBooleanv               = glGetBooleanv;
+	qglGetClipPlane              = 	dllGetClipPlane              = glGetClipPlane;
+	qglGetDoublev                = 	dllGetDoublev                = glGetDoublev;
+	qglGetError                  = 	dllGetError                  = glGetError;
+	qglGetFloatv                 = 	dllGetFloatv                 = glGetFloatv;
+	qglGetIntegerv               = 	dllGetIntegerv               = glGetIntegerv;
+	qglGetLightfv                = 	dllGetLightfv                = glGetLightfv;
+	qglGetLightiv                = 	dllGetLightiv                = glGetLightiv;
+	qglGetMapdv                  = 	dllGetMapdv                  = glGetMapdv;
+	qglGetMapfv                  = 	dllGetMapfv                  = glGetMapfv;
+	qglGetMapiv                  = 	dllGetMapiv                  = glGetMapiv;
+	qglGetMaterialfv             = 	dllGetMaterialfv             = glGetMaterialfv;
+	qglGetMaterialiv             = 	dllGetMaterialiv             = glGetMaterialiv;
+	qglGetPixelMapfv             = 	dllGetPixelMapfv             = glGetPixelMapfv;
+	qglGetPixelMapuiv            = 	dllGetPixelMapuiv            = glGetPixelMapuiv;
+	qglGetPixelMapusv            = 	dllGetPixelMapusv            = glGetPixelMapusv;
+	qglGetPointerv               = 	dllGetPointerv               = glGetPointerv;
+	qglGetPolygonStipple         = 	dllGetPolygonStipple         = glGetPolygonStipple;
+	qglGetString                 = 	dllGetString                 = glGetString;
+	qglGetTexEnvfv               = 	dllGetTexEnvfv               = glGetTexEnvfv;
+	qglGetTexEnviv               = 	dllGetTexEnviv               = glGetTexEnviv;
+	qglGetTexGendv               = 	dllGetTexGendv               = glGetTexGendv;
+	qglGetTexGenfv               = 	dllGetTexGenfv               = glGetTexGenfv;
+	qglGetTexGeniv               = 	dllGetTexGeniv               = glGetTexGeniv;
+	qglGetTexImage               = 	dllGetTexImage               = glGetTexImage;
+//	qglGetTexLevelParameterfv    = 	dllGetTexLevelParameterfv    = glGetLevelParameterfv;
+//	qglGetTexLevelParameteriv    = 	dllGetTexLevelParameteriv    = glGetLevelParameteriv;
+	qglGetTexParameterfv         = 	dllGetTexParameterfv         = glGetTexParameterfv;
+	qglGetTexParameteriv         = 	dllGetTexParameteriv         = glGetTexParameteriv;
+	qglHint                      = 	dllHint                      = glHint;
+	qglIndexMask                 = 	dllIndexMask                 = glIndexMask;
+	qglIndexPointer              = 	dllIndexPointer              = glIndexPointer;
+	qglIndexd                    = 	dllIndexd                    = glIndexd;
+	qglIndexdv                   = 	dllIndexdv                   = glIndexdv;
+	qglIndexf                    = 	dllIndexf                    = glIndexf;
+	qglIndexfv                   = 	dllIndexfv                   = glIndexfv;
+	qglIndexi                    = 	dllIndexi                    = glIndexi;
+	qglIndexiv                   = 	dllIndexiv                   = glIndexiv;
+	qglIndexs                    = 	dllIndexs                    = glIndexs;
+	qglIndexsv                   = 	dllIndexsv                   = glIndexsv;
+	qglIndexub                   = 	dllIndexub                   = glIndexub;
+	qglIndexubv                  = 	dllIndexubv                  = glIndexubv;
+	qglInitNames                 = 	dllInitNames                 = glInitNames;
+	qglInterleavedArrays         = 	dllInterleavedArrays         = glInterleavedArrays;
+	qglIsEnabled                 = 	dllIsEnabled                 = glIsEnabled;
+	qglIsList                    = 	dllIsList                    = glIsList;
+	qglIsTexture                 = 	dllIsTexture                 = glIsTexture;
+	qglLightModelf               = 	dllLightModelf               = glLightModelf;
+	qglLightModelfv              = 	dllLightModelfv              = glLightModelfv;
+	qglLightModeli               = 	dllLightModeli               = glLightModeli;
+	qglLightModeliv              = 	dllLightModeliv              = glLightModeliv;
+	qglLightf                    = 	dllLightf                    = glLightf;
+	qglLightfv                   = 	dllLightfv                   = glLightfv;
+	qglLighti                    = 	dllLighti                    = glLighti;
+	qglLightiv                   = 	dllLightiv                   = glLightiv;
+	qglLineStipple               = 	dllLineStipple               = glLineStipple;
+	qglLineWidth                 = 	dllLineWidth                 = glLineWidth;
+	qglListBase                  = 	dllListBase                  = glListBase;
+	qglLoadIdentity              = 	dllLoadIdentity              = glLoadIdentity;
+	qglLoadMatrixd               = 	dllLoadMatrixd               = glLoadMatrixd;
+	qglLoadMatrixf               = 	dllLoadMatrixf               = glLoadMatrixf;
+	qglLoadName                  = 	dllLoadName                  = glLoadName;
+	qglLogicOp                   = 	dllLogicOp                   = glLogicOp;
+	qglMap1d                     = 	dllMap1d                     = glMap1d;
+	qglMap1f                     = 	dllMap1f                     = glMap1f;
+	qglMap2d                     = 	dllMap2d                     = glMap2d;
+	qglMap2f                     = 	dllMap2f                     = glMap2f;
+	qglMapGrid1d                 = 	dllMapGrid1d                 = glMapGrid1d;
+	qglMapGrid1f                 = 	dllMapGrid1f                 = glMapGrid1f;
+	qglMapGrid2d                 = 	dllMapGrid2d                 = glMapGrid2d;
+	qglMapGrid2f                 = 	dllMapGrid2f                 = glMapGrid2f;
+	qglMaterialf                 = 	dllMaterialf                 = glMaterialf;
+	qglMaterialfv                = 	dllMaterialfv                = glMaterialfv;
+	qglMateriali                 = 	dllMateriali                 = glMateriali;
+	qglMaterialiv                = 	dllMaterialiv                = glMaterialiv;
+	qglMatrixMode                = 	dllMatrixMode                = glMatrixMode;
+	qglMultMatrixd               = 	dllMultMatrixd               = glMultMatrixd;
+	qglMultMatrixf               = 	dllMultMatrixf               = glMultMatrixf;
+	qglNewList                   = 	dllNewList                   = glNewList;
+	qglNormal3b                  = 	dllNormal3b                  = glNormal3b;
+	qglNormal3bv                 = 	dllNormal3bv                 = glNormal3bv;
+	qglNormal3d                  = 	dllNormal3d                  = glNormal3d;
+	qglNormal3dv                 = 	dllNormal3dv                 = glNormal3dv;
+	qglNormal3f                  = 	dllNormal3f                  = glNormal3f;
+	qglNormal3fv                 = 	dllNormal3fv                 = glNormal3fv;
+	qglNormal3i                  = 	dllNormal3i                  = glNormal3i;
+	qglNormal3iv                 = 	dllNormal3iv                 = glNormal3iv;
+	qglNormal3s                  = 	dllNormal3s                  = glNormal3s;
+	qglNormal3sv                 = 	dllNormal3sv                 = glNormal3sv;
+	qglNormalPointer             = 	dllNormalPointer             = glNormalPointer;
+	qglOrtho                     = 	dllOrtho                     = glOrtho;
+	qglPassThrough               = 	dllPassThrough               = glPassThrough;
+	qglPixelMapfv                = 	dllPixelMapfv                = glPixelMapfv;
+	qglPixelMapuiv               = 	dllPixelMapuiv               = glPixelMapuiv;
+	qglPixelMapusv               = 	dllPixelMapusv               = glPixelMapusv;
+	qglPixelStoref               = 	dllPixelStoref               = glPixelStoref;
+	qglPixelStorei               = 	dllPixelStorei               = glPixelStorei;
+	qglPixelTransferf            = 	dllPixelTransferf            = glPixelTransferf;
+	qglPixelTransferi            = 	dllPixelTransferi            = glPixelTransferi;
+	qglPixelZoom                 = 	dllPixelZoom                 = glPixelZoom;
+	qglPointSize                 = 	dllPointSize                 = glPointSize;
+	qglPolygonMode               = 	dllPolygonMode               = glPolygonMode;
+	qglPolygonOffset             = 	dllPolygonOffset             = glPolygonOffset;
+	qglPolygonStipple            = 	dllPolygonStipple            = glPolygonStipple;
+	qglPopAttrib                 = 	dllPopAttrib                 = glPopAttrib;
+	qglPopClientAttrib           = 	dllPopClientAttrib           = glPopClientAttrib;
+	qglPopMatrix                 = 	dllPopMatrix                 = glPopMatrix;
+	qglPopName                   = 	dllPopName                   = glPopName;
+	qglPrioritizeTextures        = 	dllPrioritizeTextures        = glPrioritizeTextures;
+	qglPushAttrib                = 	dllPushAttrib                = glPushAttrib;
+	qglPushClientAttrib          = 	dllPushClientAttrib          = glPushClientAttrib;
+	qglPushMatrix                = 	dllPushMatrix                = glPushMatrix;
+	qglPushName                  = 	dllPushName                  = glPushName;
+	qglRasterPos2d               = 	dllRasterPos2d               = glRasterPos2d;
+	qglRasterPos2dv              = 	dllRasterPos2dv              = glRasterPos2dv;
+	qglRasterPos2f               = 	dllRasterPos2f               = glRasterPos2f;
+	qglRasterPos2fv              = 	dllRasterPos2fv              = glRasterPos2fv;
+	qglRasterPos2i               = 	dllRasterPos2i               = glRasterPos2i;
+	qglRasterPos2iv              = 	dllRasterPos2iv              = glRasterPos2iv;
+	qglRasterPos2s               = 	dllRasterPos2s               = glRasterPos2s;
+	qglRasterPos2sv              = 	dllRasterPos2sv              = glRasterPos2sv;
+	qglRasterPos3d               = 	dllRasterPos3d               = glRasterPos3d;
+	qglRasterPos3dv              = 	dllRasterPos3dv              = glRasterPos3dv;
+	qglRasterPos3f               = 	dllRasterPos3f               = glRasterPos3f;
+	qglRasterPos3fv              = 	dllRasterPos3fv              = glRasterPos3fv;
+	qglRasterPos3i               = 	dllRasterPos3i               = glRasterPos3i;
+	qglRasterPos3iv              = 	dllRasterPos3iv              = glRasterPos3iv;
+	qglRasterPos3s               = 	dllRasterPos3s               = glRasterPos3s;
+	qglRasterPos3sv              = 	dllRasterPos3sv              = glRasterPos3sv;
+	qglRasterPos4d               = 	dllRasterPos4d               = glRasterPos4d;
+	qglRasterPos4dv              = 	dllRasterPos4dv              = glRasterPos4dv;
+	qglRasterPos4f               = 	dllRasterPos4f               = glRasterPos4f;
+	qglRasterPos4fv              = 	dllRasterPos4fv              = glRasterPos4fv;
+	qglRasterPos4i               = 	dllRasterPos4i               = glRasterPos4i;
+	qglRasterPos4iv              = 	dllRasterPos4iv              = glRasterPos4iv;
+	qglRasterPos4s               = 	dllRasterPos4s               = glRasterPos4s;
+	qglRasterPos4sv              = 	dllRasterPos4sv              = glRasterPos4sv;
+	qglReadBuffer                = 	dllReadBuffer                = glReadBuffer;
+	qglReadPixels                = 	dllReadPixels                = glReadPixels;
+	qglRectd                     = 	dllRectd                     = glRectd;
+	qglRectdv                    = 	dllRectdv                    = glRectdv;
+	qglRectf                     = 	dllRectf                     = glRectf;
+	qglRectfv                    = 	dllRectfv                    = glRectfv;
+	qglRecti                     = 	dllRecti                     = glRecti;
+	qglRectiv                    = 	dllRectiv                    = glRectiv;
+	qglRects                     = 	dllRects                     = glRects;
+	qglRectsv                    = 	dllRectsv                    = glRectsv;
+	qglRenderMode                = 	dllRenderMode                = glRenderMode;
+	qglRotated                   = 	dllRotated                   = glRotated;
+	qglRotatef                   = 	dllRotatef                   = glRotatef;
+	qglScaled                    = 	dllScaled                    = glScaled;
+	qglScalef                    = 	dllScalef                    = glScalef;
+	qglScissor                   = 	dllScissor                   = glScissor;
+	qglSelectBuffer              = 	dllSelectBuffer              = glSelectBuffer;
+	qglShadeModel                = 	dllShadeModel                = glShadeModel;
+	qglStencilFunc               = 	dllStencilFunc               = glStencilFunc;
+	qglStencilMask               = 	dllStencilMask               = glStencilMask;
+	qglStencilOp                 = 	dllStencilOp                 = glStencilOp;
+	qglTexCoord1d                = 	dllTexCoord1d                = glTexCoord1d;
+	qglTexCoord1dv               = 	dllTexCoord1dv               = glTexCoord1dv;
+	qglTexCoord1f                = 	dllTexCoord1f                = glTexCoord1f;
+	qglTexCoord1fv               = 	dllTexCoord1fv               = glTexCoord1fv;
+	qglTexCoord1i                = 	dllTexCoord1i                = glTexCoord1i;
+	qglTexCoord1iv               = 	dllTexCoord1iv               = glTexCoord1iv;
+	qglTexCoord1s                = 	dllTexCoord1s                = glTexCoord1s;
+	qglTexCoord1sv               = 	dllTexCoord1sv               = glTexCoord1sv;
+	qglTexCoord2d                = 	dllTexCoord2d                = glTexCoord2d;
+	qglTexCoord2dv               = 	dllTexCoord2dv               = glTexCoord2dv;
+	qglTexCoord2f                = 	dllTexCoord2f                = glTexCoord2f;
+	qglTexCoord2fv               = 	dllTexCoord2fv               = glTexCoord2fv;
+	qglTexCoord2i                = 	dllTexCoord2i                = glTexCoord2i;
+	qglTexCoord2iv               = 	dllTexCoord2iv               = glTexCoord2iv;
+	qglTexCoord2s                = 	dllTexCoord2s                = glTexCoord2s;
+	qglTexCoord2sv               = 	dllTexCoord2sv               = glTexCoord2sv;
+	qglTexCoord3d                = 	dllTexCoord3d                = glTexCoord3d;
+	qglTexCoord3dv               = 	dllTexCoord3dv               = glTexCoord3dv;
+	qglTexCoord3f                = 	dllTexCoord3f                = glTexCoord3f;
+	qglTexCoord3fv               = 	dllTexCoord3fv               = glTexCoord3fv;
+	qglTexCoord3i                = 	dllTexCoord3i                = glTexCoord3i;
+	qglTexCoord3iv               = 	dllTexCoord3iv               = glTexCoord3iv;
+	qglTexCoord3s                = 	dllTexCoord3s                = glTexCoord3s;
+	qglTexCoord3sv               = 	dllTexCoord3sv               = glTexCoord3sv;
+	qglTexCoord4d                = 	dllTexCoord4d                = glTexCoord4d;
+	qglTexCoord4dv               = 	dllTexCoord4dv               = glTexCoord4dv;
+	qglTexCoord4f                = 	dllTexCoord4f                = glTexCoord4f;
+	qglTexCoord4fv               = 	dllTexCoord4fv               = glTexCoord4fv;
+	qglTexCoord4i                = 	dllTexCoord4i                = glTexCoord4i;
+	qglTexCoord4iv               = 	dllTexCoord4iv               = glTexCoord4iv;
+	qglTexCoord4s                = 	dllTexCoord4s                = glTexCoord4s;
+	qglTexCoord4sv               = 	dllTexCoord4sv               = glTexCoord4sv;
+	qglTexCoordPointer           = 	dllTexCoordPointer           = glTexCoordPointer;
+	qglTexEnvf                   = 	dllTexEnvf                   = glTexEnvf;
+	qglTexEnvfv                  = 	dllTexEnvfv                  = glTexEnvfv;
+	qglTexEnvi                   = 	dllTexEnvi                   = glTexEnvi;
+	qglTexEnviv                  = 	dllTexEnviv                  = glTexEnviv;
+	qglTexGend                   = 	dllTexGend                   = glTexGend;
+	qglTexGendv                  = 	dllTexGendv                  = glTexGendv;
+	qglTexGenf                   = 	dllTexGenf                   = glTexGenf;
+	qglTexGenfv                  = 	dllTexGenfv                  = glTexGenfv;
+	qglTexGeni                   = 	dllTexGeni                   = glTexGeni;
+	qglTexGeniv                  = 	dllTexGeniv                  = glTexGeniv;
+	qglTexImage1D                = 	dllTexImage1D                = glTexImage1D;
+	qglTexImage2D                = 	dllTexImage2D                = glTexImage2D;
+	qglTexParameterf             = 	dllTexParameterf             = glTexParameterf;
+	qglTexParameterfv            = 	dllTexParameterfv            = glTexParameterfv;
+	qglTexParameteri             = 	dllTexParameteri             = glTexParameteri;
+	qglTexParameteriv            = 	dllTexParameteriv            = glTexParameteriv;
+	qglTexSubImage1D             = 	dllTexSubImage1D             = glTexSubImage1D;
+	qglTexSubImage2D             = 	dllTexSubImage2D             = glTexSubImage2D;
+	qglTranslated                = 	dllTranslated                = glTranslated;
+	qglTranslatef                = 	dllTranslatef                = glTranslatef;
+	qglVertex2d                  = 	dllVertex2d                  = glVertex2d;
+	qglVertex2dv                 = 	dllVertex2dv                 = glVertex2dv;
+	qglVertex2f                  = 	dllVertex2f                  = glVertex2f;
+	qglVertex2fv                 = 	dllVertex2fv                 = glVertex2fv;
+	qglVertex2i                  = 	dllVertex2i                  = glVertex2i;
+	qglVertex2iv                 = 	dllVertex2iv                 = glVertex2iv;
+	qglVertex2s                  = 	dllVertex2s                  = glVertex2s;
+	qglVertex2sv                 = 	dllVertex2sv                 = glVertex2sv;
+	qglVertex3d                  = 	dllVertex3d                  = glVertex3d;
+	qglVertex3dv                 = 	dllVertex3dv                 = glVertex3dv;
+	qglVertex3f                  = 	dllVertex3f                  = glVertex3f;
+	qglVertex3fv                 = 	dllVertex3fv                 = glVertex3fv;
+	qglVertex3i                  = 	dllVertex3i                  = glVertex3i;
+	qglVertex3iv                 = 	dllVertex3iv                 = glVertex3iv;
+	qglVertex3s                  = 	dllVertex3s                  = glVertex3s;
+	qglVertex3sv                 = 	dllVertex3sv                 = glVertex3sv;
+	qglVertex4d                  = 	dllVertex4d                  = glVertex4d;
+	qglVertex4dv                 = 	dllVertex4dv                 = glVertex4dv;
+	qglVertex4f                  = 	dllVertex4f                  = glVertex4f;
+	qglVertex4fv                 = 	dllVertex4fv                 = glVertex4fv;
+	qglVertex4i                  = 	dllVertex4i                  = glVertex4i;
+	qglVertex4iv                 = 	dllVertex4iv                 = glVertex4iv;
+	qglVertex4s                  = 	dllVertex4s                  = glVertex4s;
+	qglVertex4sv                 = 	dllVertex4sv                 = glVertex4sv;
+	qglVertexPointer             = 	dllVertexPointer             = glVertexPointer;
+	qglViewport                  = 	dllViewport                  = glViewport;
+
+	qglPointParameterfEXT = 0;
+	qglPointParameterfvEXT = 0;
+	qglColorTableEXT = 0;
+	qglSelectTextureSGIS = 0;
+	qglMTexCoord2fSGIS = 0;
+
+	return true;
+}
+
+void GLimp_EnableLogging( qboolean enable )
+{
+	if ( enable )
+	{
+		if ( !log_fp )
+		{
+			struct tm *newtime;
+			time_t aclock;
+			char buffer[1024];
+
+			time( &aclock );
+			newtime = localtime( &aclock );
+
+			asctime( newtime );
+
+			sprintf( buffer, "%s/gl.log", ri.FS_Gamedir() ); 
+			log_fp = fopen( buffer, "wt");
+
+			fprintf( log_fp, "%s\n", asctime( newtime ) );
+		}
+
+		qglAccum                     = logAccum;
+		qglAlphaFunc                 = logAlphaFunc;
+		qglAreTexturesResident       = logAreTexturesResident;
+		qglArrayElement              = logArrayElement;
+		qglBegin                     = logBegin;
+		qglBindTexture               = logBindTexture;
+		qglBitmap                    = logBitmap;
+		qglBlendFunc                 = logBlendFunc;
+		qglCallList                  = logCallList;
+		qglCallLists                 = logCallLists;
+		qglClear                     = logClear;
+		qglClearAccum                = logClearAccum;
+		qglClearColor                = logClearColor;
+		qglClearDepth                = logClearDepth;
+		qglClearIndex                = logClearIndex;
+		qglClearStencil              = logClearStencil;
+		qglClipPlane                 = logClipPlane;
+		qglColor3b                   = logColor3b;
+		qglColor3bv                  = logColor3bv;
+		qglColor3d                   = logColor3d;
+		qglColor3dv                  = logColor3dv;
+		qglColor3f                   = logColor3f;
+		qglColor3fv                  = logColor3fv;
+		qglColor3i                   = logColor3i;
+		qglColor3iv                  = logColor3iv;
+		qglColor3s                   = logColor3s;
+		qglColor3sv                  = logColor3sv;
+		qglColor3ub                  = logColor3ub;
+		qglColor3ubv                 = logColor3ubv;
+		qglColor3ui                  = logColor3ui;
+		qglColor3uiv                 = logColor3uiv;
+		qglColor3us                  = logColor3us;
+		qglColor3usv                 = logColor3usv;
+		qglColor4b                   = logColor4b;
+		qglColor4bv                  = logColor4bv;
+		qglColor4d                   = logColor4d;
+		qglColor4dv                  = logColor4dv;
+		qglColor4f                   = logColor4f;
+		qglColor4fv                  = logColor4fv;
+		qglColor4i                   = logColor4i;
+		qglColor4iv                  = logColor4iv;
+		qglColor4s                   = logColor4s;
+		qglColor4sv                  = logColor4sv;
+		qglColor4ub                  = logColor4ub;
+		qglColor4ubv                 = logColor4ubv;
+		qglColor4ui                  = logColor4ui;
+		qglColor4uiv                 = logColor4uiv;
+		qglColor4us                  = logColor4us;
+		qglColor4usv                 = logColor4usv;
+		qglColorMask                 = logColorMask;
+		qglColorMaterial             = logColorMaterial;
+		qglColorPointer              = logColorPointer;
+		qglCopyPixels                = logCopyPixels;
+		qglCopyTexImage1D            = logCopyTexImage1D;
+		qglCopyTexImage2D            = logCopyTexImage2D;
+		qglCopyTexSubImage1D         = logCopyTexSubImage1D;
+		qglCopyTexSubImage2D         = logCopyTexSubImage2D;
+		qglCullFace                  = logCullFace;
+		qglDeleteLists               = logDeleteLists ;
+		qglDeleteTextures            = logDeleteTextures ;
+		qglDepthFunc                 = logDepthFunc ;
+		qglDepthMask                 = logDepthMask ;
+		qglDepthRange                = logDepthRange ;
+		qglDisable                   = logDisable ;
+		qglDisableClientState        = logDisableClientState ;
+		qglDrawArrays                = logDrawArrays ;
+		qglDrawBuffer                = logDrawBuffer ;
+		qglDrawElements              = logDrawElements ;
+		qglDrawPixels                = logDrawPixels ;
+		qglEdgeFlag                  = logEdgeFlag ;
+		qglEdgeFlagPointer           = logEdgeFlagPointer ;
+		qglEdgeFlagv                 = logEdgeFlagv ;
+		qglEnable                    = 	logEnable                    ;
+		qglEnableClientState         = 	logEnableClientState         ;
+		qglEnd                       = 	logEnd                       ;
+		qglEndList                   = 	logEndList                   ;
+		qglEvalCoord1d				 = 	logEvalCoord1d				 ;
+		qglEvalCoord1dv              = 	logEvalCoord1dv              ;
+		qglEvalCoord1f               = 	logEvalCoord1f               ;
+		qglEvalCoord1fv              = 	logEvalCoord1fv              ;
+		qglEvalCoord2d               = 	logEvalCoord2d               ;
+		qglEvalCoord2dv              = 	logEvalCoord2dv              ;
+		qglEvalCoord2f               = 	logEvalCoord2f               ;
+		qglEvalCoord2fv              = 	logEvalCoord2fv              ;
+		qglEvalMesh1                 = 	logEvalMesh1                 ;
+		qglEvalMesh2                 = 	logEvalMesh2                 ;
+		qglEvalPoint1                = 	logEvalPoint1                ;
+		qglEvalPoint2                = 	logEvalPoint2                ;
+		qglFeedbackBuffer            = 	logFeedbackBuffer            ;
+		qglFinish                    = 	logFinish                    ;
+		qglFlush                     = 	logFlush                     ;
+		qglFogf                      = 	logFogf                      ;
+		qglFogfv                     = 	logFogfv                     ;
+		qglFogi                      = 	logFogi                      ;
+		qglFogiv                     = 	logFogiv                     ;
+		qglFrontFace                 = 	logFrontFace                 ;
+		qglFrustum                   = 	logFrustum                   ;
+		qglGenLists                  = 	logGenLists                  ;
+		qglGenTextures               = 	logGenTextures               ;
+		qglGetBooleanv               = 	logGetBooleanv               ;
+		qglGetClipPlane              = 	logGetClipPlane              ;
+		qglGetDoublev                = 	logGetDoublev                ;
+		qglGetError                  = 	logGetError                  ;
+		qglGetFloatv                 = 	logGetFloatv                 ;
+		qglGetIntegerv               = 	logGetIntegerv               ;
+		qglGetLightfv                = 	logGetLightfv                ;
+		qglGetLightiv                = 	logGetLightiv                ;
+		qglGetMapdv                  = 	logGetMapdv                  ;
+		qglGetMapfv                  = 	logGetMapfv                  ;
+		qglGetMapiv                  = 	logGetMapiv                  ;
+		qglGetMaterialfv             = 	logGetMaterialfv             ;
+		qglGetMaterialiv             = 	logGetMaterialiv             ;
+		qglGetPixelMapfv             = 	logGetPixelMapfv             ;
+		qglGetPixelMapuiv            = 	logGetPixelMapuiv            ;
+		qglGetPixelMapusv            = 	logGetPixelMapusv            ;
+		qglGetPointerv               = 	logGetPointerv               ;
+		qglGetPolygonStipple         = 	logGetPolygonStipple         ;
+		qglGetString                 = 	logGetString                 ;
+		qglGetTexEnvfv               = 	logGetTexEnvfv               ;
+		qglGetTexEnviv               = 	logGetTexEnviv               ;
+		qglGetTexGendv               = 	logGetTexGendv               ;
+		qglGetTexGenfv               = 	logGetTexGenfv               ;
+		qglGetTexGeniv               = 	logGetTexGeniv               ;
+		qglGetTexImage               = 	logGetTexImage               ;
+//		qglGetTexLevelParameterfv    = 	logGetTexLevelParameterfv    ;
+//		qglGetTexLevelParameteriv    = 	logGetTexLevelParameteriv    ;
+		qglGetTexParameterfv         = 	logGetTexParameterfv         ;
+		qglGetTexParameteriv         = 	logGetTexParameteriv         ;
+		qglHint                      = 	logHint                      ;
+		qglIndexMask                 = 	logIndexMask                 ;
+		qglIndexPointer              = 	logIndexPointer              ;
+		qglIndexd                    = 	logIndexd                    ;
+		qglIndexdv                   = 	logIndexdv                   ;
+		qglIndexf                    = 	logIndexf                    ;
+		qglIndexfv                   = 	logIndexfv                   ;
+		qglIndexi                    = 	logIndexi                    ;
+		qglIndexiv                   = 	logIndexiv                   ;
+		qglIndexs                    = 	logIndexs                    ;
+		qglIndexsv                   = 	logIndexsv                   ;
+		qglIndexub                   = 	logIndexub                   ;
+		qglIndexubv                  = 	logIndexubv                  ;
+		qglInitNames                 = 	logInitNames                 ;
+		qglInterleavedArrays         = 	logInterleavedArrays         ;
+		qglIsEnabled                 = 	logIsEnabled                 ;
+		qglIsList                    = 	logIsList                    ;
+		qglIsTexture                 = 	logIsTexture                 ;
+		qglLightModelf               = 	logLightModelf               ;
+		qglLightModelfv              = 	logLightModelfv              ;
+		qglLightModeli               = 	logLightModeli               ;
+		qglLightModeliv              = 	logLightModeliv              ;
+		qglLightf                    = 	logLightf                    ;
+		qglLightfv                   = 	logLightfv                   ;
+		qglLighti                    = 	logLighti                    ;
+		qglLightiv                   = 	logLightiv                   ;
+		qglLineStipple               = 	logLineStipple               ;
+		qglLineWidth                 = 	logLineWidth                 ;
+		qglListBase                  = 	logListBase                  ;
+		qglLoadIdentity              = 	logLoadIdentity              ;
+		qglLoadMatrixd               = 	logLoadMatrixd               ;
+		qglLoadMatrixf               = 	logLoadMatrixf               ;
+		qglLoadName                  = 	logLoadName                  ;
+		qglLogicOp                   = 	logLogicOp                   ;
+		qglMap1d                     = 	logMap1d                     ;
+		qglMap1f                     = 	logMap1f                     ;
+		qglMap2d                     = 	logMap2d                     ;
+		qglMap2f                     = 	logMap2f                     ;
+		qglMapGrid1d                 = 	logMapGrid1d                 ;
+		qglMapGrid1f                 = 	logMapGrid1f                 ;
+		qglMapGrid2d                 = 	logMapGrid2d                 ;
+		qglMapGrid2f                 = 	logMapGrid2f                 ;
+		qglMaterialf                 = 	logMaterialf                 ;
+		qglMaterialfv                = 	logMaterialfv                ;
+		qglMateriali                 = 	logMateriali                 ;
+		qglMaterialiv                = 	logMaterialiv                ;
+		qglMatrixMode                = 	logMatrixMode                ;
+		qglMultMatrixd               = 	logMultMatrixd               ;
+		qglMultMatrixf               = 	logMultMatrixf               ;
+		qglNewList                   = 	logNewList                   ;
+		qglNormal3b                  = 	logNormal3b                  ;
+		qglNormal3bv                 = 	logNormal3bv                 ;
+		qglNormal3d                  = 	logNormal3d                  ;
+		qglNormal3dv                 = 	logNormal3dv                 ;
+		qglNormal3f                  = 	logNormal3f                  ;
+		qglNormal3fv                 = 	logNormal3fv                 ;
+		qglNormal3i                  = 	logNormal3i                  ;
+		qglNormal3iv                 = 	logNormal3iv                 ;
+		qglNormal3s                  = 	logNormal3s                  ;
+		qglNormal3sv                 = 	logNormal3sv                 ;
+		qglNormalPointer             = 	logNormalPointer             ;
+		qglOrtho                     = 	logOrtho                     ;
+		qglPassThrough               = 	logPassThrough               ;
+		qglPixelMapfv                = 	logPixelMapfv                ;
+		qglPixelMapuiv               = 	logPixelMapuiv               ;
+		qglPixelMapusv               = 	logPixelMapusv               ;
+		qglPixelStoref               = 	logPixelStoref               ;
+		qglPixelStorei               = 	logPixelStorei               ;
+		qglPixelTransferf            = 	logPixelTransferf            ;
+		qglPixelTransferi            = 	logPixelTransferi            ;
+		qglPixelZoom                 = 	logPixelZoom                 ;
+		qglPointSize                 = 	logPointSize                 ;
+		qglPolygonMode               = 	logPolygonMode               ;
+		qglPolygonOffset             = 	logPolygonOffset             ;
+		qglPolygonStipple            = 	logPolygonStipple            ;
+		qglPopAttrib                 = 	logPopAttrib                 ;
+		qglPopClientAttrib           = 	logPopClientAttrib           ;
+		qglPopMatrix                 = 	logPopMatrix                 ;
+		qglPopName                   = 	logPopName                   ;
+		qglPrioritizeTextures        = 	logPrioritizeTextures        ;
+		qglPushAttrib                = 	logPushAttrib                ;
+		qglPushClientAttrib          = 	logPushClientAttrib          ;
+		qglPushMatrix                = 	logPushMatrix                ;
+		qglPushName                  = 	logPushName                  ;
+		qglRasterPos2d               = 	logRasterPos2d               ;
+		qglRasterPos2dv              = 	logRasterPos2dv              ;
+		qglRasterPos2f               = 	logRasterPos2f               ;
+		qglRasterPos2fv              = 	logRasterPos2fv              ;
+		qglRasterPos2i               = 	logRasterPos2i               ;
+		qglRasterPos2iv              = 	logRasterPos2iv              ;
+		qglRasterPos2s               = 	logRasterPos2s               ;
+		qglRasterPos2sv              = 	logRasterPos2sv              ;
+		qglRasterPos3d               = 	logRasterPos3d               ;
+		qglRasterPos3dv              = 	logRasterPos3dv              ;
+		qglRasterPos3f               = 	logRasterPos3f               ;
+		qglRasterPos3fv              = 	logRasterPos3fv              ;
+		qglRasterPos3i               = 	logRasterPos3i               ;
+		qglRasterPos3iv              = 	logRasterPos3iv              ;
+		qglRasterPos3s               = 	logRasterPos3s               ;
+		qglRasterPos3sv              = 	logRasterPos3sv              ;
+		qglRasterPos4d               = 	logRasterPos4d               ;
+		qglRasterPos4dv              = 	logRasterPos4dv              ;
+		qglRasterPos4f               = 	logRasterPos4f               ;
+		qglRasterPos4fv              = 	logRasterPos4fv              ;
+		qglRasterPos4i               = 	logRasterPos4i               ;
+		qglRasterPos4iv              = 	logRasterPos4iv              ;
+		qglRasterPos4s               = 	logRasterPos4s               ;
+		qglRasterPos4sv              = 	logRasterPos4sv              ;
+		qglReadBuffer                = 	logReadBuffer                ;
+		qglReadPixels                = 	logReadPixels                ;
+		qglRectd                     = 	logRectd                     ;
+		qglRectdv                    = 	logRectdv                    ;
+		qglRectf                     = 	logRectf                     ;
+		qglRectfv                    = 	logRectfv                    ;
+		qglRecti                     = 	logRecti                     ;
+		qglRectiv                    = 	logRectiv                    ;
+		qglRects                     = 	logRects                     ;
+		qglRectsv                    = 	logRectsv                    ;
+		qglRenderMode                = 	logRenderMode                ;
+		qglRotated                   = 	logRotated                   ;
+		qglRotatef                   = 	logRotatef                   ;
+		qglScaled                    = 	logScaled                    ;
+		qglScalef                    = 	logScalef                    ;
+		qglScissor                   = 	logScissor                   ;
+		qglSelectBuffer              = 	logSelectBuffer              ;
+		qglShadeModel                = 	logShadeModel                ;
+		qglStencilFunc               = 	logStencilFunc               ;
+		qglStencilMask               = 	logStencilMask               ;
+		qglStencilOp                 = 	logStencilOp                 ;
+		qglTexCoord1d                = 	logTexCoord1d                ;
+		qglTexCoord1dv               = 	logTexCoord1dv               ;
+		qglTexCoord1f                = 	logTexCoord1f                ;
+		qglTexCoord1fv               = 	logTexCoord1fv               ;
+		qglTexCoord1i                = 	logTexCoord1i                ;
+		qglTexCoord1iv               = 	logTexCoord1iv               ;
+		qglTexCoord1s                = 	logTexCoord1s                ;
+		qglTexCoord1sv               = 	logTexCoord1sv               ;
+		qglTexCoord2d                = 	logTexCoord2d                ;
+		qglTexCoord2dv               = 	logTexCoord2dv               ;
+		qglTexCoord2f                = 	logTexCoord2f                ;
+		qglTexCoord2fv               = 	logTexCoord2fv               ;
+		qglTexCoord2i                = 	logTexCoord2i                ;
+		qglTexCoord2iv               = 	logTexCoord2iv               ;
+		qglTexCoord2s                = 	logTexCoord2s                ;
+		qglTexCoord2sv               = 	logTexCoord2sv               ;
+		qglTexCoord3d                = 	logTexCoord3d                ;
+		qglTexCoord3dv               = 	logTexCoord3dv               ;
+		qglTexCoord3f                = 	logTexCoord3f                ;
+		qglTexCoord3fv               = 	logTexCoord3fv               ;
+		qglTexCoord3i                = 	logTexCoord3i                ;
+		qglTexCoord3iv               = 	logTexCoord3iv               ;
+		qglTexCoord3s                = 	logTexCoord3s                ;
+		qglTexCoord3sv               = 	logTexCoord3sv               ;
+		qglTexCoord4d                = 	logTexCoord4d                ;
+		qglTexCoord4dv               = 	logTexCoord4dv               ;
+		qglTexCoord4f                = 	logTexCoord4f                ;
+		qglTexCoord4fv               = 	logTexCoord4fv               ;
+		qglTexCoord4i                = 	logTexCoord4i                ;
+		qglTexCoord4iv               = 	logTexCoord4iv               ;
+		qglTexCoord4s                = 	logTexCoord4s                ;
+		qglTexCoord4sv               = 	logTexCoord4sv               ;
+		qglTexCoordPointer           = 	logTexCoordPointer           ;
+		qglTexEnvf                   = 	logTexEnvf                   ;
+		qglTexEnvfv                  = 	logTexEnvfv                  ;
+		qglTexEnvi                   = 	logTexEnvi                   ;
+		qglTexEnviv                  = 	logTexEnviv                  ;
+		qglTexGend                   = 	logTexGend                   ;
+		qglTexGendv                  = 	logTexGendv                  ;
+		qglTexGenf                   = 	logTexGenf                   ;
+		qglTexGenfv                  = 	logTexGenfv                  ;
+		qglTexGeni                   = 	logTexGeni                   ;
+		qglTexGeniv                  = 	logTexGeniv                  ;
+		qglTexImage1D                = 	logTexImage1D                ;
+		qglTexImage2D                = 	logTexImage2D                ;
+		qglTexParameterf             = 	logTexParameterf             ;
+		qglTexParameterfv            = 	logTexParameterfv            ;
+		qglTexParameteri             = 	logTexParameteri             ;
+		qglTexParameteriv            = 	logTexParameteriv            ;
+		qglTexSubImage1D             = 	logTexSubImage1D             ;
+		qglTexSubImage2D             = 	logTexSubImage2D             ;
+		qglTranslated                = 	logTranslated                ;
+		qglTranslatef                = 	logTranslatef                ;
+		qglVertex2d                  = 	logVertex2d                  ;
+		qglVertex2dv                 = 	logVertex2dv                 ;
+		qglVertex2f                  = 	logVertex2f                  ;
+		qglVertex2fv                 = 	logVertex2fv                 ;
+		qglVertex2i                  = 	logVertex2i                  ;
+		qglVertex2iv                 = 	logVertex2iv                 ;
+		qglVertex2s                  = 	logVertex2s                  ;
+		qglVertex2sv                 = 	logVertex2sv                 ;
+		qglVertex3d                  = 	logVertex3d                  ;
+		qglVertex3dv                 = 	logVertex3dv                 ;
+		qglVertex3f                  = 	logVertex3f                  ;
+		qglVertex3fv                 = 	logVertex3fv                 ;
+		qglVertex3i                  = 	logVertex3i                  ;
+		qglVertex3iv                 = 	logVertex3iv                 ;
+		qglVertex3s                  = 	logVertex3s                  ;
+		qglVertex3sv                 = 	logVertex3sv                 ;
+		qglVertex4d                  = 	logVertex4d                  ;
+		qglVertex4dv                 = 	logVertex4dv                 ;
+		qglVertex4f                  = 	logVertex4f                  ;
+		qglVertex4fv                 = 	logVertex4fv                 ;
+		qglVertex4i                  = 	logVertex4i                  ;
+		qglVertex4iv                 = 	logVertex4iv                 ;
+		qglVertex4s                  = 	logVertex4s                  ;
+		qglVertex4sv                 = 	logVertex4sv                 ;
+		qglVertexPointer             = 	logVertexPointer             ;
+		qglViewport                  = 	logViewport                  ;
+	}
+	else
+	{
+		qglAccum                     = dllAccum;
+		qglAlphaFunc                 = dllAlphaFunc;
+		qglAreTexturesResident       = dllAreTexturesResident;
+		qglArrayElement              = dllArrayElement;
+		qglBegin                     = dllBegin;
+		qglBindTexture               = dllBindTexture;
+		qglBitmap                    = dllBitmap;
+		qglBlendFunc                 = dllBlendFunc;
+		qglCallList                  = dllCallList;
+		qglCallLists                 = dllCallLists;
+		qglClear                     = dllClear;
+		qglClearAccum                = dllClearAccum;
+		qglClearColor                = dllClearColor;
+		qglClearDepth                = dllClearDepth;
+		qglClearIndex                = dllClearIndex;
+		qglClearStencil              = dllClearStencil;
+		qglClipPlane                 = dllClipPlane;
+		qglColor3b                   = dllColor3b;
+		qglColor3bv                  = dllColor3bv;
+		qglColor3d                   = dllColor3d;
+		qglColor3dv                  = dllColor3dv;
+		qglColor3f                   = dllColor3f;
+		qglColor3fv                  = dllColor3fv;
+		qglColor3i                   = dllColor3i;
+		qglColor3iv                  = dllColor3iv;
+		qglColor3s                   = dllColor3s;
+		qglColor3sv                  = dllColor3sv;
+		qglColor3ub                  = dllColor3ub;
+		qglColor3ubv                 = dllColor3ubv;
+		qglColor3ui                  = dllColor3ui;
+		qglColor3uiv                 = dllColor3uiv;
+		qglColor3us                  = dllColor3us;
+		qglColor3usv                 = dllColor3usv;
+		qglColor4b                   = dllColor4b;
+		qglColor4bv                  = dllColor4bv;
+		qglColor4d                   = dllColor4d;
+		qglColor4dv                  = dllColor4dv;
+		qglColor4f                   = dllColor4f;
+		qglColor4fv                  = dllColor4fv;
+		qglColor4i                   = dllColor4i;
+		qglColor4iv                  = dllColor4iv;
+		qglColor4s                   = dllColor4s;
+		qglColor4sv                  = dllColor4sv;
+		qglColor4ub                  = dllColor4ub;
+		qglColor4ubv                 = dllColor4ubv;
+		qglColor4ui                  = dllColor4ui;
+		qglColor4uiv                 = dllColor4uiv;
+		qglColor4us                  = dllColor4us;
+		qglColor4usv                 = dllColor4usv;
+		qglColorMask                 = dllColorMask;
+		qglColorMaterial             = dllColorMaterial;
+		qglColorPointer              = dllColorPointer;
+		qglCopyPixels                = dllCopyPixels;
+		qglCopyTexImage1D            = dllCopyTexImage1D;
+		qglCopyTexImage2D            = dllCopyTexImage2D;
+		qglCopyTexSubImage1D         = dllCopyTexSubImage1D;
+		qglCopyTexSubImage2D         = dllCopyTexSubImage2D;
+		qglCullFace                  = dllCullFace;
+		qglDeleteLists               = dllDeleteLists ;
+		qglDeleteTextures            = dllDeleteTextures ;
+		qglDepthFunc                 = dllDepthFunc ;
+		qglDepthMask                 = dllDepthMask ;
+		qglDepthRange                = dllDepthRange ;
+		qglDisable                   = dllDisable ;
+		qglDisableClientState        = dllDisableClientState ;
+		qglDrawArrays                = dllDrawArrays ;
+		qglDrawBuffer                = dllDrawBuffer ;
+		qglDrawElements              = dllDrawElements ;
+		qglDrawPixels                = dllDrawPixels ;
+		qglEdgeFlag                  = dllEdgeFlag ;
+		qglEdgeFlagPointer           = dllEdgeFlagPointer ;
+		qglEdgeFlagv                 = dllEdgeFlagv ;
+		qglEnable                    = 	dllEnable                    ;
+		qglEnableClientState         = 	dllEnableClientState         ;
+		qglEnd                       = 	dllEnd                       ;
+		qglEndList                   = 	dllEndList                   ;
+		qglEvalCoord1d				 = 	dllEvalCoord1d				 ;
+		qglEvalCoord1dv              = 	dllEvalCoord1dv              ;
+		qglEvalCoord1f               = 	dllEvalCoord1f               ;
+		qglEvalCoord1fv              = 	dllEvalCoord1fv              ;
+		qglEvalCoord2d               = 	dllEvalCoord2d               ;
+		qglEvalCoord2dv              = 	dllEvalCoord2dv              ;
+		qglEvalCoord2f               = 	dllEvalCoord2f               ;
+		qglEvalCoord2fv              = 	dllEvalCoord2fv              ;
+		qglEvalMesh1                 = 	dllEvalMesh1                 ;
+		qglEvalMesh2                 = 	dllEvalMesh2                 ;
+		qglEvalPoint1                = 	dllEvalPoint1                ;
+		qglEvalPoint2                = 	dllEvalPoint2                ;
+		qglFeedbackBuffer            = 	dllFeedbackBuffer            ;
+		qglFinish                    = 	dllFinish                    ;
+		qglFlush                     = 	dllFlush                     ;
+		qglFogf                      = 	dllFogf                      ;
+		qglFogfv                     = 	dllFogfv                     ;
+		qglFogi                      = 	dllFogi                      ;
+		qglFogiv                     = 	dllFogiv                     ;
+		qglFrontFace                 = 	dllFrontFace                 ;
+		qglFrustum                   = 	dllFrustum                   ;
+		qglGenLists                  = 	dllGenLists                  ;
+		qglGenTextures               = 	dllGenTextures               ;
+		qglGetBooleanv               = 	dllGetBooleanv               ;
+		qglGetClipPlane              = 	dllGetClipPlane              ;
+		qglGetDoublev                = 	dllGetDoublev                ;
+		qglGetError                  = 	dllGetError                  ;
+		qglGetFloatv                 = 	dllGetFloatv                 ;
+		qglGetIntegerv               = 	dllGetIntegerv               ;
+		qglGetLightfv                = 	dllGetLightfv                ;
+		qglGetLightiv                = 	dllGetLightiv                ;
+		qglGetMapdv                  = 	dllGetMapdv                  ;
+		qglGetMapfv                  = 	dllGetMapfv                  ;
+		qglGetMapiv                  = 	dllGetMapiv                  ;
+		qglGetMaterialfv             = 	dllGetMaterialfv             ;
+		qglGetMaterialiv             = 	dllGetMaterialiv             ;
+		qglGetPixelMapfv             = 	dllGetPixelMapfv             ;
+		qglGetPixelMapuiv            = 	dllGetPixelMapuiv            ;
+		qglGetPixelMapusv            = 	dllGetPixelMapusv            ;
+		qglGetPointerv               = 	dllGetPointerv               ;
+		qglGetPolygonStipple         = 	dllGetPolygonStipple         ;
+		qglGetString                 = 	dllGetString                 ;
+		qglGetTexEnvfv               = 	dllGetTexEnvfv               ;
+		qglGetTexEnviv               = 	dllGetTexEnviv               ;
+		qglGetTexGendv               = 	dllGetTexGendv               ;
+		qglGetTexGenfv               = 	dllGetTexGenfv               ;
+		qglGetTexGeniv               = 	dllGetTexGeniv               ;
+		qglGetTexImage               = 	dllGetTexImage               ;
+		qglGetTexLevelParameterfv    = 	dllGetTexLevelParameterfv    ;
+		qglGetTexLevelParameteriv    = 	dllGetTexLevelParameteriv    ;
+		qglGetTexParameterfv         = 	dllGetTexParameterfv         ;
+		qglGetTexParameteriv         = 	dllGetTexParameteriv         ;
+		qglHint                      = 	dllHint                      ;
+		qglIndexMask                 = 	dllIndexMask                 ;
+		qglIndexPointer              = 	dllIndexPointer              ;
+		qglIndexd                    = 	dllIndexd                    ;
+		qglIndexdv                   = 	dllIndexdv                   ;
+		qglIndexf                    = 	dllIndexf                    ;
+		qglIndexfv                   = 	dllIndexfv                   ;
+		qglIndexi                    = 	dllIndexi                    ;
+		qglIndexiv                   = 	dllIndexiv                   ;
+		qglIndexs                    = 	dllIndexs                    ;
+		qglIndexsv                   = 	dllIndexsv                   ;
+		qglIndexub                   = 	dllIndexub                   ;
+		qglIndexubv                  = 	dllIndexubv                  ;
+		qglInitNames                 = 	dllInitNames                 ;
+		qglInterleavedArrays         = 	dllInterleavedArrays         ;
+		qglIsEnabled                 = 	dllIsEnabled                 ;
+		qglIsList                    = 	dllIsList                    ;
+		qglIsTexture                 = 	dllIsTexture                 ;
+		qglLightModelf               = 	dllLightModelf               ;
+		qglLightModelfv              = 	dllLightModelfv              ;
+		qglLightModeli               = 	dllLightModeli               ;
+		qglLightModeliv              = 	dllLightModeliv              ;
+		qglLightf                    = 	dllLightf                    ;
+		qglLightfv                   = 	dllLightfv                   ;
+		qglLighti                    = 	dllLighti                    ;
+		qglLightiv                   = 	dllLightiv                   ;
+		qglLineStipple               = 	dllLineStipple               ;
+		qglLineWidth                 = 	dllLineWidth                 ;
+		qglListBase                  = 	dllListBase                  ;
+		qglLoadIdentity              = 	dllLoadIdentity              ;
+		qglLoadMatrixd               = 	dllLoadMatrixd               ;
+		qglLoadMatrixf               = 	dllLoadMatrixf               ;
+		qglLoadName                  = 	dllLoadName                  ;
+		qglLogicOp                   = 	dllLogicOp                   ;
+		qglMap1d                     = 	dllMap1d                     ;
+		qglMap1f                     = 	dllMap1f                     ;
+		qglMap2d                     = 	dllMap2d                     ;
+		qglMap2f                     = 	dllMap2f                     ;
+		qglMapGrid1d                 = 	dllMapGrid1d                 ;
+		qglMapGrid1f                 = 	dllMapGrid1f                 ;
+		qglMapGrid2d                 = 	dllMapGrid2d                 ;
+		qglMapGrid2f                 = 	dllMapGrid2f                 ;
+		qglMaterialf                 = 	dllMaterialf                 ;
+		qglMaterialfv                = 	dllMaterialfv                ;
+		qglMateriali                 = 	dllMateriali                 ;
+		qglMaterialiv                = 	dllMaterialiv                ;
+		qglMatrixMode                = 	dllMatrixMode                ;
+		qglMultMatrixd               = 	dllMultMatrixd               ;
+		qglMultMatrixf               = 	dllMultMatrixf               ;
+		qglNewList                   = 	dllNewList                   ;
+		qglNormal3b                  = 	dllNormal3b                  ;
+		qglNormal3bv                 = 	dllNormal3bv                 ;
+		qglNormal3d                  = 	dllNormal3d                  ;
+		qglNormal3dv                 = 	dllNormal3dv                 ;
+		qglNormal3f                  = 	dllNormal3f                  ;
+		qglNormal3fv                 = 	dllNormal3fv                 ;
+		qglNormal3i                  = 	dllNormal3i                  ;
+		qglNormal3iv                 = 	dllNormal3iv                 ;
+		qglNormal3s                  = 	dllNormal3s                  ;
+		qglNormal3sv                 = 	dllNormal3sv                 ;
+		qglNormalPointer             = 	dllNormalPointer             ;
+		qglOrtho                     = 	dllOrtho                     ;
+		qglPassThrough               = 	dllPassThrough               ;
+		qglPixelMapfv                = 	dllPixelMapfv                ;
+		qglPixelMapuiv               = 	dllPixelMapuiv               ;
+		qglPixelMapusv               = 	dllPixelMapusv               ;
+		qglPixelStoref               = 	dllPixelStoref               ;
+		qglPixelStorei               = 	dllPixelStorei               ;
+		qglPixelTransferf            = 	dllPixelTransferf            ;
+		qglPixelTransferi            = 	dllPixelTransferi            ;
+		qglPixelZoom                 = 	dllPixelZoom                 ;
+		qglPointSize                 = 	dllPointSize                 ;
+		qglPolygonMode               = 	dllPolygonMode               ;
+		qglPolygonOffset             = 	dllPolygonOffset             ;
+		qglPolygonStipple            = 	dllPolygonStipple            ;
+		qglPopAttrib                 = 	dllPopAttrib                 ;
+		qglPopClientAttrib           = 	dllPopClientAttrib           ;
+		qglPopMatrix                 = 	dllPopMatrix                 ;
+		qglPopName                   = 	dllPopName                   ;
+		qglPrioritizeTextures        = 	dllPrioritizeTextures        ;
+		qglPushAttrib                = 	dllPushAttrib                ;
+		qglPushClientAttrib          = 	dllPushClientAttrib          ;
+		qglPushMatrix                = 	dllPushMatrix                ;
+		qglPushName                  = 	dllPushName                  ;
+		qglRasterPos2d               = 	dllRasterPos2d               ;
+		qglRasterPos2dv              = 	dllRasterPos2dv              ;
+		qglRasterPos2f               = 	dllRasterPos2f               ;
+		qglRasterPos2fv              = 	dllRasterPos2fv              ;
+		qglRasterPos2i               = 	dllRasterPos2i               ;
+		qglRasterPos2iv              = 	dllRasterPos2iv              ;
+		qglRasterPos2s               = 	dllRasterPos2s               ;
+		qglRasterPos2sv              = 	dllRasterPos2sv              ;
+		qglRasterPos3d               = 	dllRasterPos3d               ;
+		qglRasterPos3dv              = 	dllRasterPos3dv              ;
+		qglRasterPos3f               = 	dllRasterPos3f               ;
+		qglRasterPos3fv              = 	dllRasterPos3fv              ;
+		qglRasterPos3i               = 	dllRasterPos3i               ;
+		qglRasterPos3iv              = 	dllRasterPos3iv              ;
+		qglRasterPos3s               = 	dllRasterPos3s               ;
+		qglRasterPos3sv              = 	dllRasterPos3sv              ;
+		qglRasterPos4d               = 	dllRasterPos4d               ;
+		qglRasterPos4dv              = 	dllRasterPos4dv              ;
+		qglRasterPos4f               = 	dllRasterPos4f               ;
+		qglRasterPos4fv              = 	dllRasterPos4fv              ;
+		qglRasterPos4i               = 	dllRasterPos4i               ;
+		qglRasterPos4iv              = 	dllRasterPos4iv              ;
+		qglRasterPos4s               = 	dllRasterPos4s               ;
+		qglRasterPos4sv              = 	dllRasterPos4sv              ;
+		qglReadBuffer                = 	dllReadBuffer                ;
+		qglReadPixels                = 	dllReadPixels                ;
+		qglRectd                     = 	dllRectd                     ;
+		qglRectdv                    = 	dllRectdv                    ;
+		qglRectf                     = 	dllRectf                     ;
+		qglRectfv                    = 	dllRectfv                    ;
+		qglRecti                     = 	dllRecti                     ;
+		qglRectiv                    = 	dllRectiv                    ;
+		qglRects                     = 	dllRects                     ;
+		qglRectsv                    = 	dllRectsv                    ;
+		qglRenderMode                = 	dllRenderMode                ;
+		qglRotated                   = 	dllRotated                   ;
+		qglRotatef                   = 	dllRotatef                   ;
+		qglScaled                    = 	dllScaled                    ;
+		qglScalef                    = 	dllScalef                    ;
+		qglScissor                   = 	dllScissor                   ;
+		qglSelectBuffer              = 	dllSelectBuffer              ;
+		qglShadeModel                = 	dllShadeModel                ;
+		qglStencilFunc               = 	dllStencilFunc               ;
+		qglStencilMask               = 	dllStencilMask               ;
+		qglStencilOp                 = 	dllStencilOp                 ;
+		qglTexCoord1d                = 	dllTexCoord1d                ;
+		qglTexCoord1dv               = 	dllTexCoord1dv               ;
+		qglTexCoord1f                = 	dllTexCoord1f                ;
+		qglTexCoord1fv               = 	dllTexCoord1fv               ;
+		qglTexCoord1i                = 	dllTexCoord1i                ;
+		qglTexCoord1iv               = 	dllTexCoord1iv               ;
+		qglTexCoord1s                = 	dllTexCoord1s                ;
+		qglTexCoord1sv               = 	dllTexCoord1sv               ;
+		qglTexCoord2d                = 	dllTexCoord2d                ;
+		qglTexCoord2dv               = 	dllTexCoord2dv               ;
+		qglTexCoord2f                = 	dllTexCoord2f                ;
+		qglTexCoord2fv               = 	dllTexCoord2fv               ;
+		qglTexCoord2i                = 	dllTexCoord2i                ;
+		qglTexCoord2iv               = 	dllTexCoord2iv               ;
+		qglTexCoord2s                = 	dllTexCoord2s                ;
+		qglTexCoord2sv               = 	dllTexCoord2sv               ;
+		qglTexCoord3d                = 	dllTexCoord3d                ;
+		qglTexCoord3dv               = 	dllTexCoord3dv               ;
+		qglTexCoord3f                = 	dllTexCoord3f                ;
+		qglTexCoord3fv               = 	dllTexCoord3fv               ;
+		qglTexCoord3i                = 	dllTexCoord3i                ;
+		qglTexCoord3iv               = 	dllTexCoord3iv               ;
+		qglTexCoord3s                = 	dllTexCoord3s                ;
+		qglTexCoord3sv               = 	dllTexCoord3sv               ;
+		qglTexCoord4d                = 	dllTexCoord4d                ;
+		qglTexCoord4dv               = 	dllTexCoord4dv               ;
+		qglTexCoord4f                = 	dllTexCoord4f                ;
+		qglTexCoord4fv               = 	dllTexCoord4fv               ;
+		qglTexCoord4i                = 	dllTexCoord4i                ;
+		qglTexCoord4iv               = 	dllTexCoord4iv               ;
+		qglTexCoord4s                = 	dllTexCoord4s                ;
+		qglTexCoord4sv               = 	dllTexCoord4sv               ;
+		qglTexCoordPointer           = 	dllTexCoordPointer           ;
+		qglTexEnvf                   = 	dllTexEnvf                   ;
+		qglTexEnvfv                  = 	dllTexEnvfv                  ;
+		qglTexEnvi                   = 	dllTexEnvi                   ;
+		qglTexEnviv                  = 	dllTexEnviv                  ;
+		qglTexGend                   = 	dllTexGend                   ;
+		qglTexGendv                  = 	dllTexGendv                  ;
+		qglTexGenf                   = 	dllTexGenf                   ;
+		qglTexGenfv                  = 	dllTexGenfv                  ;
+		qglTexGeni                   = 	dllTexGeni                   ;
+		qglTexGeniv                  = 	dllTexGeniv                  ;
+		qglTexImage1D                = 	dllTexImage1D                ;
+		qglTexImage2D                = 	dllTexImage2D                ;
+		qglTexParameterf             = 	dllTexParameterf             ;
+		qglTexParameterfv            = 	dllTexParameterfv            ;
+		qglTexParameteri             = 	dllTexParameteri             ;
+		qglTexParameteriv            = 	dllTexParameteriv            ;
+		qglTexSubImage1D             = 	dllTexSubImage1D             ;
+		qglTexSubImage2D             = 	dllTexSubImage2D             ;
+		qglTranslated                = 	dllTranslated                ;
+		qglTranslatef                = 	dllTranslatef                ;
+		qglVertex2d                  = 	dllVertex2d                  ;
+		qglVertex2dv                 = 	dllVertex2dv                 ;
+		qglVertex2f                  = 	dllVertex2f                  ;
+		qglVertex2fv                 = 	dllVertex2fv                 ;
+		qglVertex2i                  = 	dllVertex2i                  ;
+		qglVertex2iv                 = 	dllVertex2iv                 ;
+		qglVertex2s                  = 	dllVertex2s                  ;
+		qglVertex2sv                 = 	dllVertex2sv                 ;
+		qglVertex3d                  = 	dllVertex3d                  ;
+		qglVertex3dv                 = 	dllVertex3dv                 ;
+		qglVertex3f                  = 	dllVertex3f                  ;
+		qglVertex3fv                 = 	dllVertex3fv                 ;
+		qglVertex3i                  = 	dllVertex3i                  ;
+		qglVertex3iv                 = 	dllVertex3iv                 ;
+		qglVertex3s                  = 	dllVertex3s                  ;
+		qglVertex3sv                 = 	dllVertex3sv                 ;
+		qglVertex4d                  = 	dllVertex4d                  ;
+		qglVertex4dv                 = 	dllVertex4dv                 ;
+		qglVertex4f                  = 	dllVertex4f                  ;
+		qglVertex4fv                 = 	dllVertex4fv                 ;
+		qglVertex4i                  = 	dllVertex4i                  ;
+		qglVertex4iv                 = 	dllVertex4iv                 ;
+		qglVertex4s                  = 	dllVertex4s                  ;
+		qglVertex4sv                 = 	dllVertex4sv                 ;
+		qglVertexPointer             = 	dllVertexPointer             ;
+		qglViewport                  = 	dllViewport                  ;
+	}
+}
+
+
+void GLimp_LogNewFrame( void )
+{
+	fprintf( log_fp, "*** R_BeginFrame ***\n");
+}
+
+
--- /dev/null
+++ b/linux/r_aclipa.s
@@ -1,0 +1,195 @@
+//
+// r_aliasa.s
+// x86 assembly-language Alias model transform and project code.
+//
+
+#include "qasm.h"
+#include "d_ifacea.h"
+
+#if id386
+
+	.data
+Ltemp0:	.long	0
+Ltemp1:	.long	0
+
+	.text
+
+#define pfv0		8+4
+#define pfv1		8+8
+#define out			8+12
+
+.globl C(R_Alias_clip_bottom)
+C(R_Alias_clip_bottom):
+	pushl	%esi
+	pushl	%edi
+
+	movl	pfv0(%esp),%esi
+	movl	pfv1(%esp),%edi
+
+	movl	C(r_refdef)+rd_aliasvrectbottom,%eax
+
+LDoForwardOrBackward:
+
+	movl	fv_v+4(%esi),%edx
+	movl	fv_v+4(%edi),%ecx
+
+	cmpl	%ecx,%edx
+	jl		LDoForward
+
+	movl	fv_v+4(%esi),%ecx
+	movl	fv_v+4(%edi),%edx
+	movl	pfv0(%esp),%edi
+	movl	pfv1(%esp),%esi
+
+LDoForward:
+
+	subl	%edx,%ecx
+	subl	%edx,%eax
+	movl	%ecx,Ltemp1
+	movl	%eax,Ltemp0
+	fildl	Ltemp1
+	fildl	Ltemp0
+	movl	out(%esp),%edx
+	movl	$2,%eax
+
+	fdivp	%st(0),%st(1)					// scale
+
+LDo3Forward:
+	fildl	fv_v+0(%esi)	// fv0v0 | scale
+	fildl	fv_v+0(%edi)	// fv1v0 | fv0v0 | scale
+	fildl	fv_v+4(%esi)	// fv0v1 | fv1v0 | fv0v0 | scale
+	fildl	fv_v+4(%edi)	// fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale
+	fildl	fv_v+8(%esi)	// fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale
+	fildl	fv_v+8(%edi)	// fv1v2 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 |
+							//  scale
+	fxch	%st(5)			// fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv1v2 |
+							//  scale
+	fsubr	%st(0),%st(4)	// fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0-fv0v0 |
+							//  fv1v2 | scale
+	fxch	%st(3)			// fv0v1 | fv0v2 | fv1v1 | fv0v0 | fv1v0-fv0v0 |
+							//  fv1v2 | scale
+	fsubr	%st(0),%st(2)	// fv0v1 | fv0v2 | fv1v1-fv0v1 | fv0v0 |
+							//  fv1v0-fv0v0 | fv1v2 | scale
+	fxch	%st(1)			// fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+							//  fv1v0-fv0v0 | fv1v2 | scale
+	fsubr	%st(0),%st(5)	// fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+							//  fv1v0-fv0v0 | fv1v2-fv0v2 | scale
+	fxch	%st(6)			// scale | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+							//  fv1v0-fv0v0 | fv1v2-fv0v2 | fv0v2
+	fmul	%st(0),%st(4)	// scale | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+							//  (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2
+	addl	$12,%edi
+	fmul	%st(0),%st(2)	// scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 |
+							//  (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2
+	addl	$12,%esi
+	addl	$12,%edx
+	fmul	%st(0),%st(5)	// scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 |
+							//  (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale |
+							//  fv0v2
+	fxch	%st(3)			// fv0v0 | fv0v1 | (fv1v1-fv0v1)*scale | scale |
+							//  (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale |
+							//  fv0v2
+	faddp	%st(0),%st(4)	// fv0v1 | (fv1v1-fv0v1)*scale | scale |
+							//  fv0v0+(fv1v0-fv0v0)*scale |
+							//  (fv1v2-fv0v2)*scale | fv0v2
+	faddp	%st(0),%st(1)	// fv0v1+(fv1v1-fv0v1)*scale | scale |
+							//  fv0v0+(fv1v0-fv0v0)*scale |
+							//  (fv1v2-fv0v2)*scale | fv0v2
+	fxch	%st(4)			// fv0v2 | scale | fv0v0+(fv1v0-fv0v0)*scale |
+							//  (fv1v2-fv0v2)*scale | fv0v1+(fv1v1-fv0v1)*scale
+	faddp	%st(0),%st(3)	// scale | fv0v0+(fv1v0-fv0v0)*scale |
+							//  fv0v2+(fv1v2-fv0v2)*scale |
+							//  fv0v1+(fv1v1-fv0v1)*scale
+	fxch	%st(1)			// fv0v0+(fv1v0-fv0v0)*scale | scale | 
+							//  fv0v2+(fv1v2-fv0v2)*scale |
+							//  fv0v1+(fv1v1-fv0v1)*scale
+	fadds	float_point5
+	fxch	%st(3)			// fv0v1+(fv1v1-fv0v1)*scale | scale | 
+							//  fv0v2+(fv1v2-fv0v2)*scale |
+							//  fv0v0+(fv1v0-fv0v0)*scale
+	fadds	float_point5
+	fxch	%st(2)			// fv0v2+(fv1v2-fv0v2)*scale | scale | 
+							//  fv0v1+(fv1v1-fv0v1)*scale |
+							//  fv0v0+(fv1v0-fv0v0)*scale
+	fadds	float_point5
+	fxch	%st(3)			// fv0v0+(fv1v0-fv0v0)*scale | scale | 
+							//  fv0v1+(fv1v1-fv0v1)*scale |
+							//  fv0v2+(fv1v2-fv0v2)*scale
+	fistpl	fv_v+0-12(%edx)	// scale | fv0v1+(fv1v1-fv0v1)*scale |
+							//  fv0v2+(fv1v2-fv0v2)*scale
+	fxch	%st(1)			// fv0v1+(fv1v1-fv0v1)*scale | scale |
+							//  fv0v2+(fv1v2-fv0v2)*scale | scale
+	fistpl	fv_v+4-12(%edx)	// scale | fv0v2+(fv1v2-fv0v2)*scale
+	fxch	%st(1)			// fv0v2+(fv1v2-fv0v2)*sc | scale
+	fistpl	fv_v+8-12(%edx)	// scale
+
+	decl	%eax
+	jnz		LDo3Forward
+
+	fstp	%st(0)
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+
+.globl C(R_Alias_clip_top)
+C(R_Alias_clip_top):
+	pushl	%esi
+	pushl	%edi
+
+	movl	pfv0(%esp),%esi
+	movl	pfv1(%esp),%edi
+
+	movl	C(r_refdef)+rd_aliasvrect+4,%eax
+	jmp		LDoForwardOrBackward
+
+
+
+.globl C(R_Alias_clip_right)
+C(R_Alias_clip_right):
+	pushl	%esi
+	pushl	%edi
+
+	movl	pfv0(%esp),%esi
+	movl	pfv1(%esp),%edi
+
+	movl	C(r_refdef)+rd_aliasvrectright,%eax
+
+LRightLeftEntry:
+
+
+	movl	fv_v+4(%esi),%edx
+	movl	fv_v+4(%edi),%ecx
+
+	cmpl	%ecx,%edx
+	movl	fv_v+0(%esi),%edx
+
+	movl	fv_v+0(%edi),%ecx
+	jl		LDoForward2
+
+	movl	fv_v+0(%esi),%ecx
+	movl	fv_v+0(%edi),%edx
+	movl	pfv0(%esp),%edi
+	movl	pfv1(%esp),%esi
+
+LDoForward2:
+
+	jmp		LDoForward
+
+
+.globl C(R_Alias_clip_left)
+C(R_Alias_clip_left):
+	pushl	%esi
+	pushl	%edi
+
+	movl	pfv0(%esp),%esi
+	movl	pfv1(%esp),%edi
+
+	movl	C(r_refdef)+rd_aliasvrect+0,%eax
+	jmp		LRightLeftEntry
+
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/r_draw16.s
@@ -1,0 +1,1227 @@
+//
+// d_draw16.s
+// x86 assembly-language horizontal 8-bpp span-drawing code, with 16-pixel
+// subdivision.
+//
+
+#include "qasm.h"
+#include "d_ifacea.h"
+
+#if	id386
+
+//----------------------------------------------------------------------
+// 8-bpp horizontal span drawing code for polygons, with no transparency and
+// 16-pixel subdivision.
+//
+// Assumes there is at least one span in pspans, and that every span
+// contains at least one pixel
+//----------------------------------------------------------------------
+
+	.data
+
+	.text
+
+// out-of-line, rarely-needed clamping code
+
+LClampHigh0:
+	movl	C(bbextents),%esi
+	jmp		LClampReentry0
+LClampHighOrLow0:
+	jg		LClampHigh0
+	xorl	%esi,%esi
+	jmp		LClampReentry0
+
+LClampHigh1:
+	movl	C(bbextentt),%edx
+	jmp		LClampReentry1
+LClampHighOrLow1:
+	jg		LClampHigh1
+	xorl	%edx,%edx
+	jmp		LClampReentry1
+
+LClampLow2:
+	movl	$4096,%ebp
+	jmp		LClampReentry2
+LClampHigh2:
+	movl	C(bbextents),%ebp
+	jmp		LClampReentry2
+
+LClampLow3:
+	movl	$4096,%ecx
+	jmp		LClampReentry3
+LClampHigh3:
+	movl	C(bbextentt),%ecx
+	jmp		LClampReentry3
+
+LClampLow4:
+	movl	$4096,%eax
+	jmp		LClampReentry4
+LClampHigh4:
+	movl	C(bbextents),%eax
+	jmp		LClampReentry4
+
+LClampLow5:
+	movl	$4096,%ebx
+	jmp		LClampReentry5
+LClampHigh5:
+	movl	C(bbextentt),%ebx
+	jmp		LClampReentry5
+
+
+#define pspans	4+16
+
+	.align 4
+.globl C(D_DrawSpans16)
+C(D_DrawSpans16):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+//
+// set up scaled-by-16 steps, for 16-long segments; also set up cacheblock
+// and span list pointers
+//
+// TODO: any overlap from rearranging?
+	flds	C(d_sdivzstepu)
+	fmuls	fp_16
+	movl	C(cacheblock),%edx
+	flds	C(d_tdivzstepu)
+	fmuls	fp_16
+	movl	pspans(%esp),%ebx	// point to the first span descriptor
+	flds	C(d_zistepu)
+	fmuls	fp_16
+	movl	%edx,pbase			// pbase = cacheblock
+	fstps	zi16stepu
+	fstps	tdivz16stepu
+	fstps	sdivz16stepu
+
+LSpanLoop:
+//
+// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
+// initial s and t values
+//
+// FIXME: pipeline FILD?
+	fildl	espan_t_v(%ebx)
+	fildl	espan_t_u(%ebx)
+
+	fld		%st(1)			// dv | du | dv
+	fmuls	C(d_sdivzstepv)	// dv*d_sdivzstepv | du | dv
+	fld		%st(1)			// du | dv*d_sdivzstepv | du | dv
+	fmuls	C(d_sdivzstepu)	// du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+	fld		%st(2)			// du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+	fmuls	C(d_tdivzstepu)	// du*d_tdivzstepu | du*d_sdivzstepu |
+							//  dv*d_sdivzstepv | du | dv
+	fxch	%st(1)			// du*d_sdivzstepu | du*d_tdivzstepu |
+							//  dv*d_sdivzstepv | du | dv
+	faddp	%st(0),%st(2)	// du*d_tdivzstepu |
+							//  du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
+	fxch	%st(1)			// du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  du*d_tdivzstepu | du | dv
+	fld		%st(3)			// dv | du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  du*d_tdivzstepu | du | dv
+	fmuls	C(d_tdivzstepv)	// dv*d_tdivzstepv |
+							//  du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  du*d_tdivzstepu | du | dv
+	fxch	%st(1)			// du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
+	fadds	C(d_sdivzorigin)	// sdivz = d_sdivzorigin + dv*d_sdivzstepv +
+							//  du*d_sdivzstepu; stays in %st(2) at end
+	fxch	%st(4)			// dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
+							//  s/z
+	fmuls	C(d_zistepv)		// dv*d_zistepv | dv*d_tdivzstepv |
+							//  du*d_tdivzstepu | du | s/z
+	fxch	%st(1)			// dv*d_tdivzstepv |  dv*d_zistepv |
+							//  du*d_tdivzstepu | du | s/z
+	faddp	%st(0),%st(2)	// dv*d_zistepv |
+							//  dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
+	fxch	%st(2)			// du | dv*d_tdivzstepv + du*d_tdivzstepu |
+							//  dv*d_zistepv | s/z
+	fmuls	C(d_zistepu)		// du*d_zistepu |
+							//  dv*d_tdivzstepv + du*d_tdivzstepu |
+							//  dv*d_zistepv | s/z
+	fxch	%st(1)			// dv*d_tdivzstepv + du*d_tdivzstepu |
+							//  du*d_zistepu | dv*d_zistepv | s/z
+	fadds	C(d_tdivzorigin)	// tdivz = d_tdivzorigin + dv*d_tdivzstepv +
+							//  du*d_tdivzstepu; stays in %st(1) at end
+	fxch	%st(2)			// dv*d_zistepv | du*d_zistepu | t/z | s/z
+	faddp	%st(0),%st(1)	// dv*d_zistepv + du*d_zistepu | t/z | s/z
+
+	flds	fp_64k			// fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
+	fxch	%st(1)			// dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
+	fadds	C(d_ziorigin)		// zi = d_ziorigin + dv*d_zistepv +
+							//  du*d_zistepu; stays in %st(0) at end
+							// 1/z | fp_64k | t/z | s/z
+//
+// calculate and clamp s & t
+//
+	fdivr	%st(0),%st(1)	// 1/z | z*64k | t/z | s/z
+
+//
+// point %edi to the first pixel in the span
+//
+	movl	C(d_viewbuffer),%ecx
+	movl	espan_t_v(%ebx),%eax
+	movl	%ebx,pspantemp	// preserve spans pointer
+
+	movl	C(tadjust),%edx
+	movl	C(sadjust),%esi
+	movl	C(d_scantable)(,%eax,4),%edi	// v * screenwidth
+	addl	%ecx,%edi
+	movl	espan_t_u(%ebx),%ecx
+	addl	%ecx,%edi				// pdest = &pdestspan[scans->u];
+	movl	espan_t_count(%ebx),%ecx
+
+//
+// now start the FDIV for the end of the span
+//
+	cmpl	$16,%ecx
+	ja		LSetupNotLast1
+
+	decl	%ecx
+	jz		LCleanup1		// if only one pixel, no need to start an FDIV
+	movl	%ecx,spancountminus1
+
+// finish up the s and t calcs
+	fxch	%st(1)			// z*64k | 1/z | t/z | s/z
+
+	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
+	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
+	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
+	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
+	fxch	%st(1)			// s | t | 1/z | t/z | s/z
+	fistpl	s				// 1/z | t | t/z | s/z
+	fistpl	t				// 1/z | t/z | s/z
+
+	fildl	spancountminus1
+
+	flds	C(d_tdivzstepu)	// C(d_tdivzstepu) | spancountminus1
+	flds	C(d_zistepu)		// C(d_zistepu) | C(d_tdivzstepu) | spancountminus1
+	fmul	%st(2),%st(0)	// C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1
+	fxch	%st(1)			// C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1
+	fmul	%st(2),%st(0)	// C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1
+	fxch	%st(2)			// scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1
+	fmuls	C(d_sdivzstepu)	// C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 |
+							//  C(d_tdivzstepu)*scm1
+	fxch	%st(1)			// C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 |
+							//  C(d_tdivzstepu)*scm1
+	faddp	%st(0),%st(3)	// C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1
+	fxch	%st(1)			// C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1
+	faddp	%st(0),%st(3)	// C(d_sdivzstepu)*scm1
+	faddp	%st(0),%st(3)
+
+	flds	fp_64k
+	fdiv	%st(1),%st(0)	// this is what we've gone to all this trouble to
+							//  overlap
+	jmp		LFDIVInFlight1
+
+LCleanup1:
+// finish up the s and t calcs
+	fxch	%st(1)			// z*64k | 1/z | t/z | s/z
+
+	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
+	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
+	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
+	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
+	fxch	%st(1)			// s | t | 1/z | t/z | s/z
+	fistpl	s				// 1/z | t | t/z | s/z
+	fistpl	t				// 1/z | t/z | s/z
+	jmp		LFDIVInFlight1
+
+	.align	4
+LSetupNotLast1:
+// finish up the s and t calcs
+	fxch	%st(1)			// z*64k | 1/z | t/z | s/z
+
+	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
+	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
+	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
+	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
+	fxch	%st(1)			// s | t | 1/z | t/z | s/z
+	fistpl	s				// 1/z | t | t/z | s/z
+	fistpl	t				// 1/z | t/z | s/z
+
+	fadds	zi16stepu
+	fxch	%st(2)
+	fadds	sdivz16stepu
+	fxch	%st(2)
+	flds	tdivz16stepu
+	faddp	%st(0),%st(2)
+	flds	fp_64k
+	fdiv	%st(1),%st(0)	// z = 1/1/z
+							// this is what we've gone to all this trouble to
+							//  overlap
+LFDIVInFlight1:
+
+	addl	s,%esi
+	addl	t,%edx
+	movl	C(bbextents),%ebx
+	movl	C(bbextentt),%ebp
+	cmpl	%ebx,%esi
+	ja		LClampHighOrLow0
+LClampReentry0:
+	movl	%esi,s
+	movl	pbase,%ebx
+	shll	$16,%esi
+	cmpl	%ebp,%edx
+	movl	%esi,sfracf
+	ja		LClampHighOrLow1
+LClampReentry1:
+	movl	%edx,t
+	movl	s,%esi					// sfrac = scans->sfrac;
+	shll	$16,%edx
+	movl	t,%eax					// tfrac = scans->tfrac;
+	sarl	$16,%esi
+	movl	%edx,tfracf
+
+//
+// calculate the texture starting address
+//
+	sarl	$16,%eax
+	movl	C(cachewidth),%edx
+	imull	%edx,%eax				// (tfrac >> 16) * cachewidth
+	addl	%ebx,%esi
+	addl	%eax,%esi				// psource = pbase + (sfrac >> 16) +
+									//           ((tfrac >> 16) * cachewidth);
+//
+// determine whether last span or not
+//
+	cmpl	$16,%ecx
+	jna		LLastSegment
+
+//
+// not the last segment; do full 16-wide segment
+//
+LNotLastSegment:
+
+//
+// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+// get there
+//
+
+// pick up after the FDIV that was left in flight previously
+
+	fld		%st(0)			// duplicate it
+	fmul	%st(4),%st(0)	// s = s/z * z
+	fxch	%st(1)
+	fmul	%st(3),%st(0)	// t = t/z * z
+	fxch	%st(1)
+	fistpl	snext
+	fistpl	tnext
+	movl	snext,%eax
+	movl	tnext,%edx
+
+	movb	(%esi),%bl	// get first source texel
+	subl	$16,%ecx		// count off this segments' pixels
+	movl	C(sadjust),%ebp
+	movl	%ecx,counttemp	// remember count of remaining pixels
+
+	movl	C(tadjust),%ecx
+	movb	%bl,(%edi)	// store first dest pixel
+
+	addl	%eax,%ebp
+	addl	%edx,%ecx
+
+	movl	C(bbextents),%eax
+	movl	C(bbextentt),%edx
+
+	cmpl	$4096,%ebp
+	jl		LClampLow2
+	cmpl	%eax,%ebp
+	ja		LClampHigh2
+LClampReentry2:
+
+	cmpl	$4096,%ecx
+	jl		LClampLow3
+	cmpl	%edx,%ecx
+	ja		LClampHigh3
+LClampReentry3:
+
+	movl	%ebp,snext
+	movl	%ecx,tnext
+
+	subl	s,%ebp
+	subl	t,%ecx
+	
+//
+// set up advancetable
+//
+	movl	%ecx,%eax
+	movl	%ebp,%edx
+	sarl	$20,%eax			// tstep >>= 16;
+	jz		LZero
+	sarl	$20,%edx			// sstep >>= 16;
+	movl	C(cachewidth),%ebx
+	imull	%ebx,%eax
+	jmp		LSetUp1
+
+LZero:
+	sarl	$20,%edx			// sstep >>= 16;
+	movl	C(cachewidth),%ebx
+
+LSetUp1:
+
+	addl	%edx,%eax			// add in sstep
+								// (tstep >> 16) * cachewidth + (sstep >> 16);
+	movl	tfracf,%edx
+	movl	%eax,advancetable+4	// advance base in t
+	addl	%ebx,%eax			// ((tstep >> 16) + 1) * cachewidth +
+								//  (sstep >> 16);
+	shll	$12,%ebp			// left-justify sstep fractional part
+	movl	sfracf,%ebx
+	shll	$12,%ecx			// left-justify tstep fractional part
+	movl	%eax,advancetable	// advance extra in t
+
+	movl	%ecx,tstep
+	addl	%ecx,%edx			// advance tfrac fractional part by tstep frac
+
+	sbbl	%ecx,%ecx			// turn tstep carry into -1 (0 if none)
+	addl	%ebp,%ebx			// advance sfrac fractional part by sstep frac
+	adcl	advancetable+4(,%ecx,4),%esi	// point to next source texel
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	(%esi),%al
+	addl	%ebp,%ebx
+	movb	%al,1(%edi)
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,2(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,3(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,4(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,5(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,6(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,7(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+
+//
+// start FDIV for end of next segment in flight, so it can overlap
+//
+	movl	counttemp,%ecx
+	cmpl	$16,%ecx			// more than one segment after this?
+	ja		LSetupNotLast2	// yes
+
+	decl	%ecx
+	jz		LFDIVInFlight2	// if only one pixel, no need to start an FDIV
+	movl	%ecx,spancountminus1
+	fildl	spancountminus1
+
+	flds	C(d_zistepu)		// C(d_zistepu) | spancountminus1
+	fmul	%st(1),%st(0)	// C(d_zistepu)*scm1 | scm1
+	flds	C(d_tdivzstepu)	// C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1
+	fmul	%st(2),%st(0)	// C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1
+	fxch	%st(1)			// C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1
+	faddp	%st(0),%st(3)	// C(d_tdivzstepu)*scm1 | scm1
+	fxch	%st(1)			// scm1 | C(d_tdivzstepu)*scm1
+	fmuls	C(d_sdivzstepu)	// C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1
+	fxch	%st(1)			// C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1
+	faddp	%st(0),%st(3)	// C(d_sdivzstepu)*scm1
+	flds	fp_64k			// 64k | C(d_sdivzstepu)*scm1
+	fxch	%st(1)			// C(d_sdivzstepu)*scm1 | 64k
+	faddp	%st(0),%st(4)	// 64k
+
+	fdiv	%st(1),%st(0)	// this is what we've gone to all this trouble to
+							//  overlap
+	jmp		LFDIVInFlight2
+
+	.align	4
+LSetupNotLast2:
+	fadds	zi16stepu
+	fxch	%st(2)
+	fadds	sdivz16stepu
+	fxch	%st(2)
+	flds	tdivz16stepu
+	faddp	%st(0),%st(2)
+	flds	fp_64k
+	fdiv	%st(1),%st(0)	// z = 1/1/z
+							// this is what we've gone to all this trouble to
+							//  overlap
+LFDIVInFlight2:
+	movl	%ecx,counttemp
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,8(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,9(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,10(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,11(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,12(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,13(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,14(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	$16,%edi
+	movl	%edx,tfracf
+	movl	snext,%edx
+	movl	%ebx,sfracf
+	movl	tnext,%ebx
+	movl	%edx,s
+	movl	%ebx,t
+
+	movl	counttemp,%ecx		// retrieve count
+
+//
+// determine whether last span or not
+//
+	cmpl	$16,%ecx				// are there multiple segments remaining?
+	movb	%al,-1(%edi)
+	ja		LNotLastSegment		// yes
+
+//
+// last segment of scan
+//
+LLastSegment:
+
+//
+// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+// get there. The number of pixels left is variable, and we want to land on the
+// last pixel, not step one past it, so we can't run into arithmetic problems
+//
+	testl	%ecx,%ecx
+	jz		LNoSteps		// just draw the last pixel and we're done
+
+// pick up after the FDIV that was left in flight previously
+
+
+	fld		%st(0)			// duplicate it
+	fmul	%st(4),%st(0)	// s = s/z * z
+	fxch	%st(1)
+	fmul	%st(3),%st(0)	// t = t/z * z
+	fxch	%st(1)
+	fistpl	snext
+	fistpl	tnext
+
+	movb	(%esi),%al		// load first texel in segment
+	movl	C(tadjust),%ebx
+	movb	%al,(%edi)		// store first pixel in segment
+	movl	C(sadjust),%eax
+
+	addl	snext,%eax
+	addl	tnext,%ebx
+
+	movl	C(bbextents),%ebp
+	movl	C(bbextentt),%edx
+
+	cmpl	$4096,%eax
+	jl		LClampLow4
+	cmpl	%ebp,%eax
+	ja		LClampHigh4
+LClampReentry4:
+	movl	%eax,snext
+
+	cmpl	$4096,%ebx
+	jl		LClampLow5
+	cmpl	%edx,%ebx
+	ja		LClampHigh5
+LClampReentry5:
+
+	cmpl	$1,%ecx			// don't bother 
+	je		LOnlyOneStep	// if two pixels in segment, there's only one step,
+							//  of the segment length
+	subl	s,%eax
+	subl	t,%ebx
+
+	addl	%eax,%eax		// convert to 15.17 format so multiply by 1.31
+	addl	%ebx,%ebx		//  reciprocal yields 16.48
+
+	imull	reciprocal_table_16-8(,%ecx,4)	// sstep = (snext - s) /
+											//  (spancount-1)
+	movl	%edx,%ebp
+
+	movl	%ebx,%eax
+	imull	reciprocal_table_16-8(,%ecx,4)	// tstep = (tnext - t) /
+											//  (spancount-1)
+LSetEntryvec:
+//
+// set up advancetable
+//
+	movl	entryvec_table_16(,%ecx,4),%ebx
+	movl	%edx,%eax
+	movl	%ebx,jumptemp		// entry point into code for RET later
+	movl	%ebp,%ecx
+	sarl	$16,%edx			// tstep >>= 16;
+	movl	C(cachewidth),%ebx
+	sarl	$16,%ecx			// sstep >>= 16;
+	imull	%ebx,%edx
+
+	addl	%ecx,%edx			// add in sstep
+								// (tstep >> 16) * cachewidth + (sstep >> 16);
+	movl	tfracf,%ecx
+	movl	%edx,advancetable+4	// advance base in t
+	addl	%ebx,%edx			// ((tstep >> 16) + 1) * cachewidth +
+								//  (sstep >> 16);
+	shll	$16,%ebp			// left-justify sstep fractional part
+	movl	sfracf,%ebx
+	shll	$16,%eax			// left-justify tstep fractional part
+	movl	%edx,advancetable	// advance extra in t
+
+	movl	%eax,tstep
+	movl	%ecx,%edx
+	addl	%eax,%edx
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	jmp		*jumptemp			// jump to the number-of-pixels handler
+
+//----------------------------------------
+
+LNoSteps:
+	movb	(%esi),%al		// load first texel in segment
+	subl	$15,%edi			// adjust for hardwired offset
+	jmp		LEndSpan
+
+
+LOnlyOneStep:
+	subl	s,%eax
+	subl	t,%ebx
+	movl	%eax,%ebp
+	movl	%ebx,%edx
+	jmp		LSetEntryvec
+
+//----------------------------------------
+
+.globl	Entry2_16, Entry3_16, Entry4_16, Entry5_16
+.globl	Entry6_16, Entry7_16, Entry8_16, Entry9_16
+.globl	Entry10_16, Entry11_16, Entry12_16, Entry13_16
+.globl	Entry14_16, Entry15_16, Entry16_16
+
+Entry2_16:
+	subl	$14,%edi		// adjust for hardwired offsets
+	movb	(%esi),%al
+	jmp		LEntry2_16
+
+//----------------------------------------
+
+Entry3_16:
+	subl	$13,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	jmp		LEntry3_16
+
+//----------------------------------------
+
+Entry4_16:
+	subl	$12,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry4_16
+
+//----------------------------------------
+
+Entry5_16:
+	subl	$11,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry5_16
+
+//----------------------------------------
+
+Entry6_16:
+	subl	$10,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry6_16
+
+//----------------------------------------
+
+Entry7_16:
+	subl	$9,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry7_16
+
+//----------------------------------------
+
+Entry8_16:
+	subl	$8,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry8_16
+
+//----------------------------------------
+
+Entry9_16:
+	subl	$7,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry9_16
+
+//----------------------------------------
+
+Entry10_16:
+	subl	$6,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry10_16
+
+//----------------------------------------
+
+Entry11_16:
+	subl	$5,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry11_16
+
+//----------------------------------------
+
+Entry12_16:
+	subl	$4,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry12_16
+
+//----------------------------------------
+
+Entry13_16:
+	subl	$3,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry13_16
+
+//----------------------------------------
+
+Entry14_16:
+	subl	$2,%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry14_16
+
+//----------------------------------------
+
+Entry15_16:
+	decl	%edi		// adjust for hardwired offsets
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+	jmp		LEntry15_16
+
+//----------------------------------------
+
+Entry16_16:
+	addl	%eax,%edx
+	movb	(%esi),%al
+	sbbl	%ecx,%ecx
+	addl	%ebp,%ebx
+	adcl	advancetable+4(,%ecx,4),%esi
+
+	addl	tstep,%edx
+	sbbl	%ecx,%ecx
+	movb	%al,1(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry15_16:
+	sbbl	%ecx,%ecx
+	movb	%al,2(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry14_16:
+	sbbl	%ecx,%ecx
+	movb	%al,3(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry13_16:
+	sbbl	%ecx,%ecx
+	movb	%al,4(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry12_16:
+	sbbl	%ecx,%ecx
+	movb	%al,5(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry11_16:
+	sbbl	%ecx,%ecx
+	movb	%al,6(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry10_16:
+	sbbl	%ecx,%ecx
+	movb	%al,7(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry9_16:
+	sbbl	%ecx,%ecx
+	movb	%al,8(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry8_16:
+	sbbl	%ecx,%ecx
+	movb	%al,9(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry7_16:
+	sbbl	%ecx,%ecx
+	movb	%al,10(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry6_16:
+	sbbl	%ecx,%ecx
+	movb	%al,11(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry5_16:
+	sbbl	%ecx,%ecx
+	movb	%al,12(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+	addl	tstep,%edx
+LEntry4_16:
+	sbbl	%ecx,%ecx
+	movb	%al,13(%edi)
+	addl	%ebp,%ebx
+	movb	(%esi),%al
+	adcl	advancetable+4(,%ecx,4),%esi
+LEntry3_16:
+	movb	%al,14(%edi)
+	movb	(%esi),%al
+LEntry2_16:
+
+LEndSpan:
+
+//
+// clear s/z, t/z, 1/z from FP stack
+//
+	fstp %st(0)
+	fstp %st(0)
+	fstp %st(0)
+
+	movl	pspantemp,%ebx				// restore spans pointer
+	movl	espan_t_pnext(%ebx),%ebx	// point to next span
+	testl	%ebx,%ebx			// any more spans?
+	movb	%al,15(%edi)
+	jnz		LSpanLoop			// more spans
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+//----------------------------------------------------------------------
+// 8-bpp horizontal span z drawing codefor polygons, with no transparency.
+//
+// Assumes there is at least one span in pzspans, and that every span
+// contains at least one pixel
+//----------------------------------------------------------------------
+
+	.text
+
+// z-clamp on a non-negative gradient span
+LClamp:
+	movl	$0x40000000,%edx
+	xorl	%ebx,%ebx
+	fstp	%st(0)
+	jmp		LZDraw
+
+// z-clamp on a negative gradient span
+LClampNeg:
+	movl	$0x40000000,%edx
+	xorl	%ebx,%ebx
+	fstp	%st(0)
+	jmp		LZDrawNeg
+
+
+#define pzspans	4+16
+
+.globl C(D_DrawZSpans)
+C(D_DrawZSpans):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+	flds	C(d_zistepu)
+	movl	C(d_zistepu),%eax
+	movl	pzspans(%esp),%esi
+	testl	%eax,%eax
+	jz		LFNegSpan
+
+	fmuls	Float2ToThe31nd
+	fistpl	izistep		// note: we are relying on FP exceptions being turned
+						// off here to avoid range problems
+	movl	izistep,%ebx	// remains loaded for all spans
+
+LFSpanLoop:
+// set up the initial 1/z value
+	fildl	espan_t_v(%esi)
+	fildl	espan_t_u(%esi)
+	movl	espan_t_v(%esi),%ecx
+	movl	C(d_pzbuffer),%edi
+	fmuls	C(d_zistepu)
+	fxch	%st(1)
+	fmuls	C(d_zistepv)
+	fxch	%st(1)
+	fadds	C(d_ziorigin)
+	imull	C(d_zrowbytes),%ecx
+	faddp	%st(0),%st(1)
+
+// clamp if z is nearer than 2 (1/z > 0.5)
+	fcoms	float_point5
+	addl	%ecx,%edi
+	movl	espan_t_u(%esi),%edx
+	addl	%edx,%edx				// word count
+	movl	espan_t_count(%esi),%ecx
+	addl	%edx,%edi				// pdest = &pdestspan[scans->u];
+	pushl	%esi		// preserve spans pointer
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jz		LClamp
+
+	fmuls	Float2ToThe31nd
+	fistpl	izi			// note: we are relying on FP exceptions being turned
+						// off here to avoid problems when the span is closer
+						// than 1/(2**31)
+	movl	izi,%edx
+
+// at this point:
+// %ebx = izistep
+// %ecx = count
+// %edx = izi
+// %edi = pdest
+
+LZDraw:
+
+// do a single pixel up front, if necessary to dword align the destination
+	testl	$2,%edi
+	jz		LFMiddle
+	movl	%edx,%eax
+	addl	%ebx,%edx
+	shrl	$16,%eax
+	decl	%ecx
+	movw	%ax,(%edi)
+	addl	$2,%edi
+
+// do middle a pair of aligned dwords at a time
+LFMiddle:
+	pushl	%ecx
+	shrl	$1,%ecx				// count / 2
+	jz		LFLast				// no aligned dwords to do
+	shrl	$1,%ecx				// (count / 2) / 2
+	jnc		LFMiddleLoop		// even number of aligned dwords to do
+
+	movl	%edx,%eax
+	addl	%ebx,%edx
+	shrl	$16,%eax
+	movl	%edx,%esi
+	addl	%ebx,%edx
+	andl	$0xFFFF0000,%esi
+	orl		%esi,%eax
+	movl	%eax,(%edi)
+	addl	$4,%edi
+	andl	%ecx,%ecx
+	jz		LFLast
+
+LFMiddleLoop:
+	movl	%edx,%eax
+	addl	%ebx,%edx
+	shrl	$16,%eax
+	movl	%edx,%esi
+	addl	%ebx,%edx
+	andl	$0xFFFF0000,%esi
+	orl		%esi,%eax
+	movl	%edx,%ebp
+	movl	%eax,(%edi)
+	addl	%ebx,%edx
+	shrl	$16,%ebp
+	movl	%edx,%esi
+	addl	%ebx,%edx
+	andl	$0xFFFF0000,%esi
+	orl		%esi,%ebp
+	movl	%ebp,4(%edi)	// FIXME: eliminate register contention
+	addl	$8,%edi
+
+	decl	%ecx
+	jnz		LFMiddleLoop
+
+LFLast:
+	popl	%ecx			// retrieve count
+	popl	%esi			// retrieve span pointer
+
+// do the last, unaligned pixel, if there is one
+	andl	$1,%ecx			// is there an odd pixel left to do?
+	jz		LFSpanDone		// no
+	shrl	$16,%edx
+	movw	%dx,(%edi)		// do the final pixel's z
+
+LFSpanDone:
+	movl	espan_t_pnext(%esi),%esi
+	testl	%esi,%esi
+	jnz		LFSpanLoop
+
+	jmp		LFDone
+
+LFNegSpan:
+	fmuls	FloatMinus2ToThe31nd
+	fistpl	izistep		// note: we are relying on FP exceptions being turned
+						// off here to avoid range problems
+	movl	izistep,%ebx	// remains loaded for all spans
+
+LFNegSpanLoop:
+// set up the initial 1/z value
+	fildl	espan_t_v(%esi)
+	fildl	espan_t_u(%esi)
+	movl	espan_t_v(%esi),%ecx
+	movl	C(d_pzbuffer),%edi
+	fmuls	C(d_zistepu)
+	fxch	%st(1)
+	fmuls	C(d_zistepv)
+	fxch	%st(1)
+	fadds	C(d_ziorigin)
+	imull	C(d_zrowbytes),%ecx
+	faddp	%st(0),%st(1)
+
+// clamp if z is nearer than 2 (1/z > 0.5)
+	fcoms	float_point5
+	addl	%ecx,%edi
+	movl	espan_t_u(%esi),%edx
+	addl	%edx,%edx				// word count
+	movl	espan_t_count(%esi),%ecx
+	addl	%edx,%edi				// pdest = &pdestspan[scans->u];
+	pushl	%esi		// preserve spans pointer
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jz		LClampNeg
+
+	fmuls	Float2ToThe31nd
+	fistpl	izi			// note: we are relying on FP exceptions being turned
+						// off here to avoid problems when the span is closer
+						// than 1/(2**31)
+	movl	izi,%edx
+
+// at this point:
+// %ebx = izistep
+// %ecx = count
+// %edx = izi
+// %edi = pdest
+
+LZDrawNeg:
+
+// do a single pixel up front, if necessary to dword align the destination
+	testl	$2,%edi
+	jz		LFNegMiddle
+	movl	%edx,%eax
+	subl	%ebx,%edx
+	shrl	$16,%eax
+	decl	%ecx
+	movw	%ax,(%edi)
+	addl	$2,%edi
+
+// do middle a pair of aligned dwords at a time
+LFNegMiddle:
+	pushl	%ecx
+	shrl	$1,%ecx				// count / 2
+	jz		LFNegLast			// no aligned dwords to do
+	shrl	$1,%ecx				// (count / 2) / 2
+	jnc		LFNegMiddleLoop		// even number of aligned dwords to do
+
+	movl	%edx,%eax
+	subl	%ebx,%edx
+	shrl	$16,%eax
+	movl	%edx,%esi
+	subl	%ebx,%edx
+	andl	$0xFFFF0000,%esi
+	orl		%esi,%eax
+	movl	%eax,(%edi)
+	addl	$4,%edi
+	andl	%ecx,%ecx
+	jz		LFNegLast
+
+LFNegMiddleLoop:
+	movl	%edx,%eax
+	subl	%ebx,%edx
+	shrl	$16,%eax
+	movl	%edx,%esi
+	subl	%ebx,%edx
+	andl	$0xFFFF0000,%esi
+	orl		%esi,%eax
+	movl	%edx,%ebp
+	movl	%eax,(%edi)
+	subl	%ebx,%edx
+	shrl	$16,%ebp
+	movl	%edx,%esi
+	subl	%ebx,%edx
+	andl	$0xFFFF0000,%esi
+	orl		%esi,%ebp
+	movl	%ebp,4(%edi)	// FIXME: eliminate register contention
+	addl	$8,%edi
+
+	decl	%ecx
+	jnz		LFNegMiddleLoop
+
+LFNegLast:
+	popl	%ecx			// retrieve count
+	popl	%esi			// retrieve span pointer
+
+// do the last, unaligned pixel, if there is one
+	andl	$1,%ecx			// is there an odd pixel left to do?
+	jz		LFNegSpanDone	// no
+	shrl	$16,%edx
+	movw	%dx,(%edi)		// do the final pixel's z
+
+LFNegSpanDone:
+	movl	espan_t_pnext(%esi),%esi
+	testl	%esi,%esi
+	jnz		LFNegSpanLoop
+
+LFDone:
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/r_drawa.s
@@ -1,0 +1,817 @@
+//
+// r_drawa.s
+// x86 assembly-language edge clipping and emission code
+//
+
+#include "qasm.h"
+#include "d_ifacea.h"
+
+#if	id386
+
+// !!! if these are changed, they must be changed in r_draw.c too !!!
+#define FULLY_CLIPPED_CACHED	0x80000000
+#define FRAMECOUNT_MASK			0x7FFFFFFF
+
+	.data
+
+Ld0:			.single		0.0
+Ld1:			.single		0.0
+Lstack:			.long		0
+Lfp_near_clip:	.single		NEAR_CLIP
+Lceilv0:		.long		0
+Lv:				.long		0
+Lu0:			.long		0
+Lv0:			.long		0
+Lzi0:			.long		0
+
+	.text
+
+//----------------------------------------------------------------------
+// edge clipping code
+//----------------------------------------------------------------------
+
+#define pv0		4+12
+#define pv1		8+12
+#define clip	12+12
+
+	.align 4
+.globl C(R_ClipEdge)
+C(R_ClipEdge):
+	pushl	%esi				// preserve register variables
+	pushl	%edi
+	pushl	%ebx
+	movl	%esp,Lstack			// for clearing the stack later
+
+//	float		d0, d1, f;
+//	mvertex_t	clipvert;
+
+	movl	clip(%esp),%ebx
+	movl	pv0(%esp),%esi
+	movl	pv1(%esp),%edx
+
+//	if (clip)
+//	{
+	testl	%ebx,%ebx
+	jz		Lemit
+
+//		do
+//		{
+
+Lcliploop:
+
+//			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
+//			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
+	flds	mv_position+0(%esi)
+	fmuls	cp_normal+0(%ebx)
+	flds	mv_position+4(%esi)
+	fmuls	cp_normal+4(%ebx)
+	flds	mv_position+8(%esi)
+	fmuls	cp_normal+8(%ebx)
+	fxch	%st(1)
+	faddp	%st(0),%st(2)		// d0mul2 | d0add0
+
+	flds	mv_position+0(%edx)
+	fmuls	cp_normal+0(%ebx)
+	flds	mv_position+4(%edx)
+	fmuls	cp_normal+4(%ebx)
+	flds	mv_position+8(%edx)
+	fmuls	cp_normal+8(%ebx)
+	fxch	%st(1)
+	faddp	%st(0),%st(2)		// d1mul2 | d1add0 | d0mul2 | d0add0
+	fxch	%st(3)				// d0add0 | d1add0 | d0mul2 | d1mul2
+
+	faddp	%st(0),%st(2)		// d1add0 | dot0 | d1mul2 
+	faddp	%st(0),%st(2)		// dot0 | dot1
+
+	fsubs	cp_dist(%ebx)		// d0 | dot1
+	fxch	%st(1)				// dot1 | d0
+	fsubs	cp_dist(%ebx)		// d1 | d0
+	fxch	%st(1)
+	fstps	Ld0
+	fstps	Ld1
+
+//			if (d0 >= 0)
+//			{
+	movl	Ld0,%eax
+	movl	Ld1,%ecx
+	orl		%eax,%ecx
+	js		Lp2
+
+// both points are unclipped
+
+Lcontinue:
+
+//
+//				R_ClipEdge (&clipvert, pv1, clip->next);
+//				return;
+//			}
+//		} while ((clip = clip->next) != NULL);
+	movl	cp_next(%ebx),%ebx
+	testl	%ebx,%ebx
+	jnz		Lcliploop
+
+//	}
+
+//// add the edge
+//	R_EmitEdge (pv0, pv1);
+Lemit:
+
+//
+// set integer rounding to ceil mode, set to single precision
+//
+// FIXME: do away with by manually extracting integers from floats?
+// FIXME: set less often
+	fldcw	ceil_cw
+
+//	edge_t	*edge, *pcheck;
+//	int		u_check;
+//	float	u, u_step;
+//	vec3_t	local, transformed;
+//	float	*world;
+//	int		v, v2, ceilv0;
+//	float	scale, lzi0, u0, v0;
+//	int		side;
+
+//	if (r_lastvertvalid)
+//	{
+	cmpl	$0,C(r_lastvertvalid)
+	jz		LCalcFirst
+
+//		u0 = r_u1;
+//		v0 = r_v1;
+//		lzi0 = r_lzi1;
+//		ceilv0 = r_ceilv1;
+	movl	C(r_lzi1),%eax
+	movl	C(r_u1),%ecx
+	movl	%eax,Lzi0
+	movl	%ecx,Lu0
+	movl	C(r_v1),%ecx
+	movl	C(r_ceilv1),%eax
+	movl	%ecx,Lv0
+	movl	%eax,Lceilv0
+	jmp		LCalcSecond
+
+//	}
+
+LCalcFirst:
+
+//	else
+//	{
+//		world = &pv0->position[0];
+
+	call	LTransformAndProject	// v0 | lzi0 | u0
+
+	fsts	Lv0
+	fxch	%st(2)					// u0 | lzi0 | v0
+	fstps	Lu0						// lzi0 | v0
+	fstps	Lzi0					// v0
+
+//		ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0);
+	fistpl	Lceilv0
+
+//	}
+
+LCalcSecond:
+
+//	world = &pv1->position[0];
+	movl	%edx,%esi
+
+	call	LTransformAndProject	// v1 | lzi1 | u1
+
+	flds	Lu0						// u0 | v1 | lzi1 | u1
+	fxch	%st(3)					// u1 | v1 | lzi1 | u0
+	flds	Lzi0					// lzi0 | u1 | v1 | lzi1 | u0
+	fxch	%st(3)					// lzi1 | u1 | v1 | lzi0 | u0
+	flds	Lv0						// v0 | lzi1 | u1 | v1 | lzi0 | u0
+	fxch	%st(3)					// v1 | lzi1 | u1 | v0 | lzi0 | u0
+
+//	r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1);
+	fistl	C(r_ceilv1)
+
+	fldcw	single_cw				// put back normal floating-point state
+
+	fsts	C(r_v1)
+	fxch	%st(4)					// lzi0 | lzi1 | u1 | v0 | v1 | u0
+
+//	if (r_lzi1 > lzi0)
+//		lzi0 = r_lzi1;
+	fcom	%st(1)
+	fnstsw	%ax
+	testb	$1,%ah
+	jz		LP0
+	fstp	%st(0)
+	fld		%st(0)
+LP0:
+
+	fxch	%st(1)					// lzi1 | lzi0 | u1 | v0 | v1 | u0
+	fstps	C(r_lzi1)				// lzi0 | u1 | v0 | v1 | u0
+	fxch	%st(1)
+	fsts	C(r_u1)
+	fxch	%st(1)
+
+//	if (lzi0 > r_nearzi)	// for mipmap finding
+//		r_nearzi = lzi0;
+	fcoms	C(r_nearzi)
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jnz		LP1
+	fsts	C(r_nearzi)
+LP1:
+
+// // for right edges, all we want is the effect on 1/z
+//	if (r_nearzionly)
+//		return;
+	movl	C(r_nearzionly),%eax
+	testl	%eax,%eax
+	jz		LP2
+LPop5AndDone:
+	movl	C(cacheoffset),%eax
+	movl	C(r_framecount),%edx
+	cmpl	$0x7FFFFFFF,%eax
+	jz		LDoPop
+	andl	$(FRAMECOUNT_MASK),%edx
+	orl		$(FULLY_CLIPPED_CACHED),%edx
+	movl	%edx,C(cacheoffset)
+
+LDoPop:
+	fstp	%st(0)			// u1 | v0 | v1 | u0
+	fstp	%st(0)			// v0 | v1 | u0
+	fstp	%st(0)			// v1 | u0
+	fstp	%st(0)			// u0
+	fstp	%st(0)
+	jmp		Ldone
+
+LP2:
+
+// // create the edge
+//	if (ceilv0 == r_ceilv1)
+//		return;		// horizontal edge
+	movl	Lceilv0,%ebx
+	movl	C(edge_p),%edi
+	movl	C(r_ceilv1),%ecx
+	movl	%edi,%edx
+	movl	C(r_pedge),%esi
+	addl	$(et_size),%edx
+	cmpl	%ecx,%ebx
+	jz		LPop5AndDone
+
+	movl	C(r_pedge),%eax
+	movl	%eax,et_owner(%edi)
+
+//	side = ceilv0 > r_ceilv1;
+//
+//	edge->nearzi = lzi0;
+	fstps	et_nearzi(%edi)		// u1 | v0 | v1 | u0
+
+//	if (side == 1)
+//	{
+	jc		LSide0
+
+LSide1:
+
+//	// leading edge (go from p2 to p1)
+
+//		u_step = ((u0 - r_u1) / (v0 - r_v1));
+	fsubrp	%st(0),%st(3)		// v0 | v1 | u0-u1
+	fsub	%st(1),%st(0)		// v0-v1 | v1 | u0-u1
+	fdivrp	%st(0),%st(2)		// v1 | ustep
+
+//	r_emitted = 1;
+	movl	$1,C(r_emitted)
+
+//	edge = edge_p++;
+	movl	%edx,C(edge_p)
+
+// pretouch next edge
+	movl	(%edx),%eax
+
+//		v2 = ceilv0 - 1;
+//		v = r_ceilv1;
+	movl	%ecx,%eax
+	leal	-1(%ebx),%ecx
+	movl	%eax,%ebx
+
+//		edge->surfs[0] = 0;
+//		edge->surfs[1] = surface_p - surfaces;
+	movl	C(surface_p),%eax
+	movl	C(surfaces),%esi
+	subl	%edx,%edx
+	subl	%esi,%eax
+	shrl	$(SURF_T_SHIFT),%eax
+	movl	%edx,et_surfs(%edi)
+	movl	%eax,et_surfs+2(%edi)
+
+	subl	%esi,%esi
+
+//		u = r_u1 + ((float)v - r_v1) * u_step;
+	movl	%ebx,Lv
+	fildl	Lv					// v | v1 | ustep
+	fsubp	%st(0),%st(1)		// v-v1 | ustep
+	fmul	%st(1),%st(0)		// (v-v1)*ustep | ustep
+	fadds	C(r_u1)				// u | ustep
+
+	jmp		LSideDone
+
+//	}
+
+LSide0:
+
+//	else
+//	{
+//	// trailing edge (go from p1 to p2)
+
+//		u_step = ((r_u1 - u0) / (r_v1 - v0));
+	fsub	%st(3),%st(0)		// u1-u0 | v0 | v1 | u0
+	fxch	%st(2)				// v1 | v0 | u1-u0 | u0
+	fsub	%st(1),%st(0)		// v1-v0 | v0 | u1-u0 | u0
+	fdivrp	%st(0),%st(2)		// v0 | ustep | u0
+
+//	r_emitted = 1;
+	movl	$1,C(r_emitted)
+
+//	edge = edge_p++;
+	movl	%edx,C(edge_p)
+
+// pretouch next edge
+	movl	(%edx),%eax
+
+//		v = ceilv0;
+//		v2 = r_ceilv1 - 1;
+	decl	%ecx
+
+//		edge->surfs[0] = surface_p - surfaces;
+//		edge->surfs[1] = 0;
+	movl	C(surface_p),%eax
+	movl	C(surfaces),%esi
+	subl	%edx,%edx
+	subl	%esi,%eax
+	shrl	$(SURF_T_SHIFT),%eax
+	movl	%edx,et_surfs+2(%edi)
+	movl	%eax,et_surfs(%edi)
+
+	movl	$1,%esi
+
+//		u = u0 + ((float)v - v0) * u_step;
+	movl	%ebx,Lv
+	fildl	Lv					// v | v0 | ustep | u0
+	fsubp	%st(0),%st(1)		// v-v0 | ustep | u0
+	fmul	%st(1),%st(0)		// (v-v0)*ustep | ustep | u0
+	faddp	%st(0),%st(2)		// ustep | u
+	fxch	%st(1)				// u | ustep
+
+//	}
+
+LSideDone:
+
+//	edge->u_step = u_step*0x100000;
+//	edge->u = u*0x100000 + 0xFFFFF;
+
+	fmuls	fp_1m				// u*0x100000 | ustep
+	fxch	%st(1)				// ustep | u*0x100000
+	fmuls	fp_1m				// ustep*0x100000 | u*0x100000
+	fxch	%st(1)				// u*0x100000 | ustep*0x100000
+	fadds	fp_1m_minus_1		// u*0x100000 + 0xFFFFF | ustep*0x100000
+	fxch	%st(1)				// ustep*0x100000 | u*0x100000 + 0xFFFFF
+	fistpl	et_u_step(%edi)		// u*0x100000 + 0xFFFFF
+	fistpl	et_u(%edi)
+
+// // we need to do this to avoid stepping off the edges if a very nearly
+// // horizontal edge is less than epsilon above a scan, and numeric error
+// // causes it to incorrectly extend to the scan, and the extension of the
+// // line goes off the edge of the screen
+// // FIXME: is this actually needed?
+//	if (edge->u < r_refdef.vrect_x_adj_shift20)
+//		edge->u = r_refdef.vrect_x_adj_shift20;
+//	if (edge->u > r_refdef.vrectright_adj_shift20)
+//		edge->u = r_refdef.vrectright_adj_shift20;
+	movl	et_u(%edi),%eax
+	movl	C(r_refdef)+rd_vrect_x_adj_shift20,%edx
+	cmpl	%edx,%eax
+	jl		LP4
+	movl	C(r_refdef)+rd_vrectright_adj_shift20,%edx
+	cmpl	%edx,%eax
+	jng		LP5
+LP4:
+	movl	%edx,et_u(%edi)
+	movl	%edx,%eax
+LP5:
+
+// // sort the edge in normally
+//	u_check = edge->u;
+//
+//	if (edge->surfs[0])
+//		u_check++;	// sort trailers after leaders
+	addl	%esi,%eax
+
+//	if (!newedges[v] || newedges[v]->u >= u_check)
+//	{
+	movl	C(newedges)(,%ebx,4),%esi
+	testl	%esi,%esi
+	jz		LDoFirst
+	cmpl	%eax,et_u(%esi)
+	jl		LNotFirst
+LDoFirst:
+
+//		edge->next = newedges[v];
+//		newedges[v] = edge;
+	movl	%esi,et_next(%edi)
+	movl	%edi,C(newedges)(,%ebx,4)
+
+	jmp		LSetRemove
+
+//	}
+
+LNotFirst:
+
+//	else
+//	{
+//		pcheck = newedges[v];
+//
+//		while (pcheck->next && pcheck->next->u < u_check)
+//			pcheck = pcheck->next;
+LFindInsertLoop:
+	movl	%esi,%edx
+	movl	et_next(%esi),%esi
+	testl	%esi,%esi
+	jz		LInsertFound
+	cmpl	%eax,et_u(%esi)
+	jl		LFindInsertLoop
+
+LInsertFound:
+
+//		edge->next = pcheck->next;
+//		pcheck->next = edge;
+	movl	%esi,et_next(%edi)
+	movl	%edi,et_next(%edx)
+
+//	}
+
+LSetRemove:
+
+//	edge->nextremove = removeedges[v2];
+//	removeedges[v2] = edge;
+	movl	C(removeedges)(,%ecx,4),%eax
+	movl	%edi,C(removeedges)(,%ecx,4)
+	movl	%eax,et_nextremove(%edi)
+
+Ldone:
+	movl	Lstack,%esp			// clear temporary variables from stack
+
+	popl	%ebx				// restore register variables
+	popl	%edi
+	popl	%esi
+	ret
+
+// at least one point is clipped
+
+Lp2:
+	testl	%eax,%eax
+	jns		Lp1
+
+//			else
+//			{
+//			// point 0 is clipped
+
+//				if (d1 < 0)
+//				{
+	movl	Ld1,%eax
+	testl	%eax,%eax
+	jns		Lp3
+
+//				// both points are clipped
+//				// we do cache fully clipped edges
+//					if (!leftclipped)
+	movl	C(r_leftclipped),%eax
+	movl	C(r_pedge),%ecx
+	testl	%eax,%eax
+	jnz		Ldone
+
+//						r_pedge->framecount = r_framecount;
+	movl	C(r_framecount),%eax
+	andl	$(FRAMECOUNT_MASK),%eax
+	orl		$(FULLY_CLIPPED_CACHED),%eax
+	movl	%eax,C(cacheoffset)
+
+//					return;
+	jmp		Ldone
+
+//				}
+
+Lp1:
+
+//			// point 0 is unclipped
+//				if (d1 >= 0)
+//				{
+//				// both points are unclipped
+//					continue;
+
+//			// only point 1 is clipped
+
+//				f = d0 / (d0 - d1);
+	flds	Ld0
+	flds	Ld1
+	fsubr	%st(1),%st(0)
+
+//			// we don't cache partially clipped edges
+	movl	$0x7FFFFFFF,C(cacheoffset)
+
+	fdivrp	%st(0),%st(1)
+
+	subl	$(mv_size),%esp			// allocate space for clipvert
+
+//				clipvert.position[0] = pv0->position[0] +
+//						f * (pv1->position[0] - pv0->position[0]);
+//				clipvert.position[1] = pv0->position[1] +
+//						f * (pv1->position[1] - pv0->position[1]);
+//				clipvert.position[2] = pv0->position[2] +
+//						f * (pv1->position[2] - pv0->position[2]);
+	flds	mv_position+8(%edx)
+	fsubs	mv_position+8(%esi)
+	flds	mv_position+4(%edx)
+	fsubs	mv_position+4(%esi)
+	flds	mv_position+0(%edx)
+	fsubs	mv_position+0(%esi)		// 0 | 1 | 2
+
+// replace pv1 with the clip point
+	movl	%esp,%edx
+	movl	cp_leftedge(%ebx),%eax
+	testb	%al,%al
+
+	fmul	%st(3),%st(0)
+	fxch	%st(1)					// 1 | 0 | 2
+	fmul	%st(3),%st(0)
+	fxch	%st(2)					// 2 | 0 | 1
+	fmulp	%st(0),%st(3)			// 0 | 1 | 2
+	fadds	mv_position+0(%esi)
+	fxch	%st(1)					// 1 | 0 | 2
+	fadds	mv_position+4(%esi)
+	fxch	%st(2)					// 2 | 0 | 1
+	fadds	mv_position+8(%esi)
+	fxch	%st(1)					// 0 | 2 | 1
+	fstps	mv_position+0(%esp)		// 2 | 1
+	fstps	mv_position+8(%esp)		// 1
+	fstps	mv_position+4(%esp)
+
+//				if (clip->leftedge)
+//				{
+	jz		Ltestright
+
+//					r_leftclipped = true;
+//					r_leftexit = clipvert;
+	movl	$1,C(r_leftclipped)
+	movl	mv_position+0(%esp),%eax
+	movl	%eax,C(r_leftexit)+mv_position+0
+	movl	mv_position+4(%esp),%eax
+	movl	%eax,C(r_leftexit)+mv_position+4
+	movl	mv_position+8(%esp),%eax
+	movl	%eax,C(r_leftexit)+mv_position+8
+
+	jmp		Lcontinue
+
+//				}
+
+Ltestright:
+//				else if (clip->rightedge)
+//				{
+	testb	%ah,%ah
+	jz		Lcontinue
+
+//					r_rightclipped = true;
+//					r_rightexit = clipvert;
+	movl	$1,C(r_rightclipped)
+	movl	mv_position+0(%esp),%eax
+	movl	%eax,C(r_rightexit)+mv_position+0
+	movl	mv_position+4(%esp),%eax
+	movl	%eax,C(r_rightexit)+mv_position+4
+	movl	mv_position+8(%esp),%eax
+	movl	%eax,C(r_rightexit)+mv_position+8
+
+//				}
+//
+//				R_ClipEdge (pv0, &clipvert, clip->next);
+//				return;
+//			}
+	jmp		Lcontinue
+
+//			}
+
+Lp3:
+
+//			// only point 0 is clipped
+//				r_lastvertvalid = false;
+
+	movl	$0,C(r_lastvertvalid)
+
+//				f = d0 / (d0 - d1);
+	flds	Ld0
+	flds	Ld1
+	fsubr	%st(1),%st(0)
+
+//			// we don't cache partially clipped edges
+	movl	$0x7FFFFFFF,C(cacheoffset)
+
+	fdivrp	%st(0),%st(1)
+
+	subl	$(mv_size),%esp			// allocate space for clipvert
+
+//				clipvert.position[0] = pv0->position[0] +
+//						f * (pv1->position[0] - pv0->position[0]);
+//				clipvert.position[1] = pv0->position[1] +
+//						f * (pv1->position[1] - pv0->position[1]);
+//				clipvert.position[2] = pv0->position[2] +
+//						f * (pv1->position[2] - pv0->position[2]);
+	flds	mv_position+8(%edx)
+	fsubs	mv_position+8(%esi)
+	flds	mv_position+4(%edx)
+	fsubs	mv_position+4(%esi)
+	flds	mv_position+0(%edx)
+	fsubs	mv_position+0(%esi)		// 0 | 1 | 2
+
+	movl	cp_leftedge(%ebx),%eax
+	testb	%al,%al
+
+	fmul	%st(3),%st(0)
+	fxch	%st(1)					// 1 | 0 | 2
+	fmul	%st(3),%st(0)
+	fxch	%st(2)					// 2 | 0 | 1
+	fmulp	%st(0),%st(3)			// 0 | 1 | 2
+	fadds	mv_position+0(%esi)
+	fxch	%st(1)					// 1 | 0 | 2
+	fadds	mv_position+4(%esi)
+	fxch	%st(2)					// 2 | 0 | 1
+	fadds	mv_position+8(%esi)
+	fxch	%st(1)					// 0 | 2 | 1
+	fstps	mv_position+0(%esp)		// 2 | 1
+	fstps	mv_position+8(%esp)		// 1
+	fstps	mv_position+4(%esp)
+
+// replace pv0 with the clip point
+	movl	%esp,%esi
+
+//				if (clip->leftedge)
+//				{
+	jz		Ltestright2
+
+//					r_leftclipped = true;
+//					r_leftenter = clipvert;
+	movl	$1,C(r_leftclipped)
+	movl	mv_position+0(%esp),%eax
+	movl	%eax,C(r_leftenter)+mv_position+0
+	movl	mv_position+4(%esp),%eax
+	movl	%eax,C(r_leftenter)+mv_position+4
+	movl	mv_position+8(%esp),%eax
+	movl	%eax,C(r_leftenter)+mv_position+8
+
+	jmp		Lcontinue
+
+//				}
+
+Ltestright2:
+//				else if (clip->rightedge)
+//				{
+	testb	%ah,%ah
+	jz		Lcontinue
+
+//					r_rightclipped = true;
+//					r_rightenter = clipvert;
+	movl	$1,C(r_rightclipped)
+	movl	mv_position+0(%esp),%eax
+	movl	%eax,C(r_rightenter)+mv_position+0
+	movl	mv_position+4(%esp),%eax
+	movl	%eax,C(r_rightenter)+mv_position+4
+	movl	mv_position+8(%esp),%eax
+	movl	%eax,C(r_rightenter)+mv_position+8
+
+//				}
+	jmp		Lcontinue
+
+// %esi = vec3_t point to transform and project
+// %edx preserved
+LTransformAndProject:
+
+//	// transform and project
+//		VectorSubtract (world, modelorg, local);
+	flds	mv_position+0(%esi)
+	fsubs	C(modelorg)+0
+	flds	mv_position+4(%esi)
+	fsubs	C(modelorg)+4
+	flds	mv_position+8(%esi)	
+	fsubs	C(modelorg)+8
+	fxch	%st(2)				// local[0] | local[1] | local[2]
+
+//		TransformVector (local, transformed);
+//	
+//		if (transformed[2] < NEAR_CLIP)
+//			transformed[2] = NEAR_CLIP;
+//	
+//		lzi0 = 1.0 / transformed[2];
+	fld		%st(0)				// local[0] | local[0] | local[1] | local[2]
+	fmuls	C(vpn)+0			// zm0 | local[0] | local[1] | local[2]
+	fld		%st(1)				// local[0] | zm0 | local[0] | local[1] |
+								//  local[2]
+	fmuls	C(vright)+0			// xm0 | zm0 | local[0] | local[1] | local[2]
+	fxch	%st(2)				// local[0] | zm0 | xm0 | local[1] | local[2]
+	fmuls	C(vup)+0			// ym0 |  zm0 | xm0 | local[1] | local[2]
+	fld		%st(3)				// local[1] | ym0 |  zm0 | xm0 | local[1] |
+								//  local[2]
+	fmuls	C(vpn)+4			// zm1 | ym0 | zm0 | xm0 | local[1] |
+								//  local[2]
+	fld		%st(4)				// local[1] | zm1 | ym0 | zm0 | xm0 |
+								//  local[1] | local[2]
+	fmuls	C(vright)+4			// xm1 | zm1 | ym0 |  zm0 | xm0 |
+								//  local[1] | local[2]
+	fxch	%st(5)				// local[1] | zm1 | ym0 | zm0 | xm0 |
+								//  xm1 | local[2]
+	fmuls	C(vup)+4			// ym1 | zm1 | ym0 | zm0 | xm0 |
+								//  xm1 | local[2]
+	fxch	%st(1)				// zm1 | ym1 | ym0 | zm0 | xm0 |
+								//  xm1 | local[2]
+	faddp	%st(0),%st(3)		// ym1 | ym0 | zm2 | xm0 | xm1 | local[2]
+	fxch	%st(3)				// xm0 | ym0 | zm2 | ym1 | xm1 | local[2]
+	faddp	%st(0),%st(4)		// ym0 | zm2 | ym1 | xm2 | local[2]
+	faddp	%st(0),%st(2)		// zm2 | ym2 | xm2 | local[2]
+	fld		%st(3)				// local[2] | zm2 | ym2 | xm2 | local[2]
+	fmuls	C(vpn)+8			// zm3 | zm2 | ym2 | xm2 | local[2]
+	fld		%st(4)				// local[2] | zm3 | zm2 | ym2 | xm2 | local[2]
+	fmuls	C(vright)+8			// xm3 | zm3 | zm2 | ym2 | xm2 | local[2]
+	fxch	%st(5)				// local[2] | zm3 | zm2 | ym2 | xm2 | xm3
+	fmuls	C(vup)+8			// ym3 | zm3 | zm2 | ym2 | xm2 | xm3
+	fxch	%st(1)				// zm3 | ym3 | zm2 | ym2 | xm2 | xm3
+	faddp	%st(0),%st(2)		// ym3 | zm4 | ym2 | xm2 | xm3
+	fxch	%st(4)				// xm3 | zm4 | ym2 | xm2 | ym3
+	faddp	%st(0),%st(3)		// zm4 | ym2 | xm4 | ym3
+	fxch	%st(1)				// ym2 | zm4 | xm4 | ym3
+	faddp	%st(0),%st(3)		// zm4 | xm4 | ym4
+
+	fcoms	Lfp_near_clip
+	fnstsw	%ax
+	testb	$1,%ah
+	jz		LNoClip
+	fstp	%st(0)
+	flds	Lfp_near_clip
+
+LNoClip:
+
+	fdivrs	float_1				// lzi0 | x | y
+	fxch	%st(1)				// x | lzi0 | y
+
+//	// FIXME: build x/yscale into transform?
+//		scale = xscale * lzi0;
+//		u0 = (xcenter + scale*transformed[0]);
+	flds	C(xscale)			// xscale | x | lzi0 | y
+	fmul	%st(2),%st(0)		// scale | x | lzi0 | y
+	fmulp	%st(0),%st(1)		// scale*x | lzi0 | y
+	fadds	C(xcenter)			// u0 | lzi0 | y
+
+//		if (u0 < r_refdef.fvrectx_adj)
+//			u0 = r_refdef.fvrectx_adj;
+//		if (u0 > r_refdef.fvrectright_adj)
+//			u0 = r_refdef.fvrectright_adj;
+// FIXME: use integer compares of floats?
+	fcoms	C(r_refdef)+rd_fvrectx_adj
+	fnstsw	%ax
+	testb	$1,%ah
+	jz		LClampP0
+	fstp	%st(0)
+	flds	C(r_refdef)+rd_fvrectx_adj
+LClampP0:
+	fcoms	C(r_refdef)+rd_fvrectright_adj
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jnz		LClampP1
+	fstp	%st(0)
+	flds	C(r_refdef)+rd_fvrectright_adj
+LClampP1:
+
+	fld		%st(1)				// lzi0 | u0 | lzi0 | y
+
+//		scale = yscale * lzi0;
+//		v0 = (ycenter - scale*transformed[1]);
+	fmuls	C(yscale)			// scale | u0 | lzi0 | y
+	fmulp	%st(0),%st(3)		// u0 | lzi0 | scale*y
+	fxch	%st(2)				// scale*y | lzi0 | u0
+	fsubrs	C(ycenter)			// v0 | lzi0 | u0
+
+//		if (v0 < r_refdef.fvrecty_adj)
+//			v0 = r_refdef.fvrecty_adj;
+//		if (v0 > r_refdef.fvrectbottom_adj)
+//			v0 = r_refdef.fvrectbottom_adj;
+// FIXME: use integer compares of floats?
+	fcoms	C(r_refdef)+rd_fvrecty_adj
+	fnstsw	%ax
+	testb	$1,%ah
+	jz		LClampP2
+	fstp	%st(0)
+	flds	C(r_refdef)+rd_fvrecty_adj
+LClampP2:
+	fcoms	C(r_refdef)+rd_fvrectbottom_adj
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jnz		LClampP3
+	fstp	%st(0)
+	flds	C(r_refdef)+rd_fvrectbottom_adj
+LClampP3:
+	ret
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/r_edgea.s
@@ -1,0 +1,729 @@
+//
+// r_edgea.s
+// x86 assembly-language edge-processing code.
+//
+
+#include "qasm.h"
+
+#if	id386
+
+	.data
+Ltemp:					.long	0
+float_1_div_0100000h:	.long	0x35800000	// 1.0/(float)0x100000
+float_point_999:		.single	0.999
+float_1_point_001:		.single	1.001
+
+	.text
+
+//--------------------------------------------------------------------
+
+#define edgestoadd	4+8		// note odd stack offsets because of interleaving
+#define edgelist	8+12	// with pushes
+
+.globl C(R_EdgeCodeStart)
+C(R_EdgeCodeStart):
+
+.globl C(R_InsertNewEdges)
+C(R_InsertNewEdges):
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	movl	edgestoadd(%esp),%edx
+	pushl	%ebx
+	movl	edgelist(%esp),%ecx
+
+LDoNextEdge:
+	movl	et_u(%edx),%eax
+	movl	%edx,%edi
+
+LContinueSearch:
+	movl	et_u(%ecx),%ebx
+	movl	et_next(%ecx),%esi
+	cmpl	%ebx,%eax
+	jle		LAddedge
+	movl	et_u(%esi),%ebx
+	movl	et_next(%esi),%ecx
+	cmpl	%ebx,%eax
+	jle		LAddedge2
+	movl	et_u(%ecx),%ebx
+	movl	et_next(%ecx),%esi
+	cmpl	%ebx,%eax
+	jle		LAddedge
+	movl	et_u(%esi),%ebx
+	movl	et_next(%esi),%ecx
+	cmpl	%ebx,%eax
+	jg		LContinueSearch
+
+LAddedge2:
+	movl	et_next(%edx),%edx
+	movl	et_prev(%esi),%ebx
+	movl	%esi,et_next(%edi)
+	movl	%ebx,et_prev(%edi)
+	movl	%edi,et_next(%ebx)
+	movl	%edi,et_prev(%esi)
+	movl	%esi,%ecx
+
+	cmpl	$0,%edx
+	jnz		LDoNextEdge
+	jmp		LDone
+
+	.align 4
+LAddedge:
+	movl	et_next(%edx),%edx
+	movl	et_prev(%ecx),%ebx
+	movl	%ecx,et_next(%edi)
+	movl	%ebx,et_prev(%edi)
+	movl	%edi,et_next(%ebx)
+	movl	%edi,et_prev(%ecx)
+
+	cmpl	$0,%edx
+	jnz		LDoNextEdge
+
+LDone:
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+
+	ret
+
+//--------------------------------------------------------------------
+
+#define predge	4+4
+
+.globl C(R_RemoveEdges)
+C(R_RemoveEdges):
+	pushl	%ebx
+	movl	predge(%esp),%eax
+
+Lre_loop:
+	movl	et_next(%eax),%ecx
+	movl	et_nextremove(%eax),%ebx
+	movl	et_prev(%eax),%edx
+	testl	%ebx,%ebx
+	movl	%edx,et_prev(%ecx)
+	jz		Lre_done
+	movl	%ecx,et_next(%edx)
+
+	movl	et_next(%ebx),%ecx
+	movl	et_prev(%ebx),%edx
+	movl	et_nextremove(%ebx),%eax
+	movl	%edx,et_prev(%ecx)
+	testl	%eax,%eax
+	movl	%ecx,et_next(%edx)
+	jnz		Lre_loop
+
+	popl	%ebx
+	ret
+
+Lre_done:
+	movl	%ecx,et_next(%edx)
+	popl	%ebx
+
+	ret
+
+//--------------------------------------------------------------------
+
+#define pedgelist	4+4		// note odd stack offset because of interleaving
+							// with pushes
+
+.globl C(R_StepActiveU)
+C(R_StepActiveU):
+	pushl	%edi
+	movl	pedgelist(%esp),%edx
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+	movl	et_prev(%edx),%esi
+
+LNewEdge:
+	movl	et_u(%esi),%edi
+
+LNextEdge:
+	movl	et_u(%edx),%eax
+	movl	et_u_step(%edx),%ebx
+	addl	%ebx,%eax
+	movl	et_next(%edx),%esi
+	movl	%eax,et_u(%edx)
+	cmpl	%edi,%eax
+	jl		LPushBack
+
+	movl	et_u(%esi),%edi
+	movl	et_u_step(%esi),%ebx
+	addl	%ebx,%edi
+	movl	et_next(%esi),%edx
+	movl	%edi,et_u(%esi)
+	cmpl	%eax,%edi
+	jl		LPushBack2
+
+	movl	et_u(%edx),%eax
+	movl	et_u_step(%edx),%ebx
+	addl	%ebx,%eax
+	movl	et_next(%edx),%esi
+	movl	%eax,et_u(%edx)
+	cmpl	%edi,%eax
+	jl		LPushBack
+
+	movl	et_u(%esi),%edi
+	movl	et_u_step(%esi),%ebx
+	addl	%ebx,%edi
+	movl	et_next(%esi),%edx
+	movl	%edi,et_u(%esi)
+	cmpl	%eax,%edi
+	jnl		LNextEdge
+
+LPushBack2:
+	movl	%edx,%ebx
+	movl	%edi,%eax
+	movl	%esi,%edx
+	movl	%ebx,%esi
+
+LPushBack:
+// push it back to keep it sorted
+	movl	et_prev(%edx),%ecx
+	movl	et_next(%edx),%ebx
+
+// done if the -1 in edge_aftertail triggered this
+	cmpl	$(C(edge_aftertail)),%edx
+	jz		LUDone
+
+// pull the edge out of the edge list
+	movl	et_prev(%ecx),%edi
+	movl	%ecx,et_prev(%esi)
+	movl	%ebx,et_next(%ecx)
+
+// find out where the edge goes in the edge list
+LPushBackLoop:
+	movl	et_prev(%edi),%ecx
+	movl	et_u(%edi),%ebx
+	cmpl	%ebx,%eax
+	jnl		LPushBackFound
+
+	movl	et_prev(%ecx),%edi
+	movl	et_u(%ecx),%ebx
+	cmpl	%ebx,%eax
+	jl		LPushBackLoop
+
+	movl	%ecx,%edi
+
+// put the edge back into the edge list
+LPushBackFound:
+	movl	et_next(%edi),%ebx
+	movl	%edi,et_prev(%edx)
+	movl	%ebx,et_next(%edx)
+	movl	%edx,et_next(%edi)
+	movl	%edx,et_prev(%ebx)
+
+	movl	%esi,%edx
+	movl	et_prev(%esi),%esi
+
+	cmpl	$(C(edge_tail)),%edx
+	jnz		LNewEdge
+
+LUDone:
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+
+	ret
+
+//--------------------------------------------------------------------
+
+#define surf	4		// note this is loaded before any pushes
+
+	.align 4
+TrailingEdge:
+	movl	st_spanstate(%esi),%eax	// check for edge inversion
+	decl	%eax
+	jnz		LInverted
+
+	movl	%eax,st_spanstate(%esi)
+	movl	st_insubmodel(%esi),%ecx
+	movl	0x12345678,%edx		// surfaces[1].st_next
+LPatch0:
+	movl	C(r_bmodelactive),%eax
+	subl	%ecx,%eax
+	cmpl	%esi,%edx
+	movl	%eax,C(r_bmodelactive)
+	jnz		LNoEmit				// surface isn't on top, just remove
+
+// emit a span (current top going away)
+	movl	et_u(%ebx),%eax
+	shrl	$20,%eax				// iu = integral pixel u
+	movl	st_last_u(%esi),%edx
+	movl	st_next(%esi),%ecx
+	cmpl	%edx,%eax
+	jle		LNoEmit2				// iu <= surf->last_u, so nothing to emit
+
+	movl	%eax,st_last_u(%ecx)	// surf->next->last_u = iu;
+	subl	%edx,%eax
+	movl	%edx,espan_t_u(%ebp)		// span->u = surf->last_u;
+
+	movl	%eax,espan_t_count(%ebp)	// span->count = iu - span->u;
+	movl	C(current_iv),%eax
+	movl	%eax,espan_t_v(%ebp)		// span->v = current_iv;
+	movl	st_spans(%esi),%eax
+	movl	%eax,espan_t_pnext(%ebp)	// span->pnext = surf->spans;
+	movl	%ebp,st_spans(%esi)			// surf->spans = span;
+	addl	$(espan_t_size),%ebp
+
+	movl	st_next(%esi),%edx		// remove the surface from the surface
+	movl	st_prev(%esi),%esi		// stack
+
+	movl	%edx,st_next(%esi)
+	movl	%esi,st_prev(%edx)
+	ret
+
+LNoEmit2:
+	movl	%eax,st_last_u(%ecx)	// surf->next->last_u = iu;
+	movl	st_next(%esi),%edx		// remove the surface from the surface
+	movl	st_prev(%esi),%esi		// stack
+
+	movl	%edx,st_next(%esi)
+	movl	%esi,st_prev(%edx)
+	ret
+
+LNoEmit:
+	movl	st_next(%esi),%edx		// remove the surface from the surface
+	movl	st_prev(%esi),%esi		// stack
+
+	movl	%edx,st_next(%esi)
+	movl	%esi,st_prev(%edx)
+	ret
+
+LInverted:
+	movl	%eax,st_spanstate(%esi)
+	ret
+
+//--------------------------------------------------------------------
+
+// trailing edge only
+Lgs_trailing:
+	pushl	$Lgs_nextedge
+	jmp		TrailingEdge
+
+
+.globl C(R_GenerateSpans)
+C(R_GenerateSpans):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+// clear active surfaces to just the background surface
+	movl	C(surfaces),%eax
+	movl	C(edge_head_u_shift20),%edx
+	addl	$(st_size),%eax
+// %ebp = span_p throughout
+	movl	C(span_p),%ebp
+
+	movl	$0,C(r_bmodelactive)
+
+	movl	%eax,st_next(%eax)
+	movl	%eax,st_prev(%eax)
+	movl	%edx,st_last_u(%eax)
+	movl	C(edge_head)+et_next,%ebx		// edge=edge_head.next
+
+// generate spans
+	cmpl	$(C(edge_tail)),%ebx		// done if empty list
+	jz		Lgs_lastspan
+
+Lgs_edgeloop:
+
+	movl	et_surfs(%ebx),%edi
+	movl	C(surfaces),%eax
+	movl	%edi,%esi
+	andl	$0xFFFF0000,%edi
+	andl	$0xFFFF,%esi
+	jz		Lgs_leading		// not a trailing edge
+
+// it has a left surface, so a surface is going away for this span
+	shll	$(SURF_T_SHIFT),%esi
+	addl	%eax,%esi
+	testl	%edi,%edi
+	jz		Lgs_trailing
+
+// both leading and trailing
+	call	TrailingEdge
+	movl	C(surfaces),%eax
+
+// ---------------------------------------------------------------
+// handle a leading edge
+// ---------------------------------------------------------------
+
+Lgs_leading:
+	shrl	$16-SURF_T_SHIFT,%edi
+	movl	C(surfaces),%eax
+	addl	%eax,%edi
+	movl	0x12345678,%esi		// surf2 = surfaces[1].next;
+LPatch2:
+	movl	st_spanstate(%edi),%edx
+	movl	st_insubmodel(%edi),%eax
+	testl	%eax,%eax
+	jnz		Lbmodel_leading
+
+// handle a leading non-bmodel edge
+
+// don't start a span if this is an inverted span, with the end edge preceding
+// the start edge (that is, we've already seen the end edge)
+	testl	%edx,%edx
+	jnz		Lxl_done
+
+
+// if (surf->key < surf2->key)
+//		goto newtop;
+	incl	%edx
+	movl	st_key(%edi),%eax
+	movl	%edx,st_spanstate(%edi)
+	movl	st_key(%esi),%ecx
+	cmpl	%ecx,%eax
+	jl		Lnewtop
+
+// main sorting loop to search through surface stack until insertion point
+// found. Always terminates because background surface is sentinel
+// do
+// {
+// 		surf2 = surf2->next;
+// } while (surf->key >= surf2->key);
+Lsortloopnb:
+	movl	st_next(%esi),%esi
+	movl	st_key(%esi),%ecx
+	cmpl	%ecx,%eax
+	jge		Lsortloopnb
+
+	jmp		LInsertAndExit
+
+
+// handle a leading bmodel edge
+	.align	4
+Lbmodel_leading:
+
+// don't start a span if this is an inverted span, with the end edge preceding
+// the start edge (that is, we've already seen the end edge)
+	testl	%edx,%edx
+	jnz		Lxl_done
+
+	movl	C(r_bmodelactive),%ecx
+	incl	%edx
+	incl	%ecx
+	movl	%edx,st_spanstate(%edi)
+	movl	%ecx,C(r_bmodelactive)
+
+// if (surf->key < surf2->key)
+//		goto newtop;
+	movl	st_key(%edi),%eax
+	movl	st_key(%esi),%ecx
+	cmpl	%ecx,%eax
+	jl		Lnewtop
+
+// if ((surf->key == surf2->key) && surf->insubmodel)
+// {
+	jz		Lzcheck_for_newtop
+
+// main sorting loop to search through surface stack until insertion point
+// found. Always terminates because background surface is sentinel
+// do
+// {
+// 		surf2 = surf2->next;
+// } while (surf->key > surf2->key);
+Lsortloop:
+	movl	st_next(%esi),%esi
+	movl	st_key(%esi),%ecx
+	cmpl	%ecx,%eax
+	jg		Lsortloop
+
+	jne		LInsertAndExit
+
+// Do 1/z sorting to see if we've arrived in the right position
+	movl	et_u(%ebx),%eax
+	subl	$0xFFFFF,%eax
+	movl	%eax,Ltemp
+	fildl	Ltemp
+
+	fmuls	float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) *
+								//      (1.0 / 0x100000);
+
+	fld		%st(0)				// fu | fu
+	fmuls	st_d_zistepu(%edi)	// fu*surf->d_zistepu | fu
+	flds	C(fv)					// fv | fu*surf->d_zistepu | fu
+	fmuls	st_d_zistepv(%edi)	// fv*surf->d_zistepv | fu*surf->d_zistepu | fu
+	fxch	%st(1)				// fu*surf->d_zistepu | fv*surf->d_zistepv | fu
+	fadds	st_d_ziorigin(%edi)	// fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fv*surf->d_zistepv | fu
+
+	flds	st_d_zistepu(%esi)	// surf2->d_zistepu |
+								//  fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fv*surf->d_zistepv | fu
+	fmul	%st(3),%st(0)		// fu*surf2->d_zistepu |
+								//  fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fv*surf->d_zistepv | fu
+	fxch	%st(1)				// fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fu*surf2->d_zistepu |
+								//  fv*surf->d_zistepv | fu
+	faddp	%st(0),%st(2)		// fu*surf2->d_zistepu | newzi | fu
+
+	flds	C(fv)					// fv | fu*surf2->d_zistepu | newzi | fu
+	fmuls	st_d_zistepv(%esi)	// fv*surf2->d_zistepv |
+								//  fu*surf2->d_zistepu | newzi | fu
+	fld		%st(2)				// newzi | fv*surf2->d_zistepv |
+								//  fu*surf2->d_zistepu | newzi | fu
+	fmuls	float_point_999		// newzibottom | fv*surf2->d_zistepv |
+								//  fu*surf2->d_zistepu | newzi | fu
+
+	fxch	%st(2)				// fu*surf2->d_zistepu | fv*surf2->d_zistepv |
+								//  newzibottom | newzi | fu
+	fadds	st_d_ziorigin(%esi)	// fu*surf2->d_zistepu + surf2->d_ziorigin |
+								//  fv*surf2->d_zistepv | newzibottom | newzi |
+								//  fu
+	faddp	%st(0),%st(1)		// testzi | newzibottom | newzi | fu
+	fxch	%st(1)				// newzibottom | testzi | newzi | fu
+
+// if (newzibottom >= testzi)
+//     goto Lgotposition;
+
+	fcomp	%st(1)				// testzi | newzi | fu
+
+	fxch	%st(1)				// newzi | testzi | fu
+	fmuls	float_1_point_001	// newzitop | testzi | fu
+	fxch	%st(1)				// testzi | newzitop | fu
+
+	fnstsw	%ax
+	testb	$0x01,%ah
+	jz		Lgotposition_fpop3
+
+// if (newzitop >= testzi)
+// {
+
+	fcomp	%st(1)				// newzitop | fu
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jz		Lsortloop_fpop2
+
+// if (surf->d_zistepu >= surf2->d_zistepu)
+//     goto newtop;
+
+	flds	st_d_zistepu(%edi)	// surf->d_zistepu | newzitop| fu
+	fcomps	st_d_zistepu(%esi)	// newzitop | fu
+	fnstsw	%ax
+	testb	$0x01,%ah
+	jz		Lgotposition_fpop2
+
+	fstp	%st(0)				// clear the FPstack
+	fstp	%st(0)
+	movl	st_key(%edi),%eax
+	jmp		Lsortloop
+
+
+Lgotposition_fpop3:
+	fstp	%st(0)
+Lgotposition_fpop2:
+	fstp	%st(0)
+	fstp	%st(0)
+	jmp		LInsertAndExit
+
+
+// emit a span (obscures current top)
+
+Lnewtop_fpop3:
+	fstp	%st(0)
+Lnewtop_fpop2:
+	fstp	%st(0)
+	fstp	%st(0)
+	movl	st_key(%edi),%eax		// reload the sorting key
+
+Lnewtop:
+	movl	et_u(%ebx),%eax
+	movl	st_last_u(%esi),%edx
+	shrl	$20,%eax				// iu = integral pixel u
+	movl	%eax,st_last_u(%edi)	// surf->last_u = iu;
+	cmpl	%edx,%eax
+	jle		LInsertAndExit			// iu <= surf->last_u, so nothing to emit
+
+	subl	%edx,%eax
+	movl	%edx,espan_t_u(%ebp)		// span->u = surf->last_u;
+
+	movl	%eax,espan_t_count(%ebp)	// span->count = iu - span->u;
+	movl	C(current_iv),%eax
+	movl	%eax,espan_t_v(%ebp)		// span->v = current_iv;
+	movl	st_spans(%esi),%eax
+	movl	%eax,espan_t_pnext(%ebp)	// span->pnext = surf->spans;
+	movl	%ebp,st_spans(%esi)			// surf->spans = span;
+	addl	$(espan_t_size),%ebp
+
+LInsertAndExit:
+// insert before surf2
+	movl	%esi,st_next(%edi)		// surf->next = surf2;
+	movl	st_prev(%esi),%eax
+	movl	%eax,st_prev(%edi)		// surf->prev = surf2->prev;
+	movl	%edi,st_prev(%esi)		// surf2->prev = surf;
+	movl	%edi,st_next(%eax)		// surf2->prev->next = surf;
+
+// ---------------------------------------------------------------
+// leading edge done
+// ---------------------------------------------------------------
+
+// ---------------------------------------------------------------
+// see if there are any more edges
+// ---------------------------------------------------------------
+
+Lgs_nextedge:
+	movl	et_next(%ebx),%ebx
+	cmpl	$(C(edge_tail)),%ebx
+	jnz		Lgs_edgeloop
+
+// clean up at the right edge
+Lgs_lastspan:
+
+// now that we've reached the right edge of the screen, we're done with any
+// unfinished surfaces, so emit a span for whatever's on top
+	movl	0x12345678,%esi		// surfaces[1].st_next
+LPatch3:
+	movl	C(edge_tail_u_shift20),%eax
+	xorl	%ecx,%ecx
+	movl	st_last_u(%esi),%edx
+	subl	%edx,%eax
+	jle		Lgs_resetspanstate
+
+	movl	%edx,espan_t_u(%ebp)
+	movl	%eax,espan_t_count(%ebp)
+	movl	C(current_iv),%eax
+	movl	%eax,espan_t_v(%ebp)
+	movl	st_spans(%esi),%eax
+	movl	%eax,espan_t_pnext(%ebp)
+	movl	%ebp,st_spans(%esi)
+	addl	$(espan_t_size),%ebp
+
+// reset spanstate for all surfaces in the surface stack
+Lgs_resetspanstate:
+	movl	%ecx,st_spanstate(%esi)
+	movl	st_next(%esi),%esi
+	cmpl	$0x12345678,%esi		// &surfaces[1]
+LPatch4:
+	jnz		Lgs_resetspanstate
+
+// store the final span_p
+	movl	%ebp,C(span_p)
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+
+// ---------------------------------------------------------------
+// 1/z sorting for bmodels in the same leaf
+// ---------------------------------------------------------------
+	.align	4
+Lxl_done:
+	incl	%edx
+	movl	%edx,st_spanstate(%edi)
+
+	jmp		Lgs_nextedge
+
+
+	.align	4
+Lzcheck_for_newtop:
+	movl	et_u(%ebx),%eax
+	subl	$0xFFFFF,%eax
+	movl	%eax,Ltemp
+	fildl	Ltemp
+
+	fmuls	float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) *
+								//      (1.0 / 0x100000);
+
+	fld		%st(0)				// fu | fu
+	fmuls	st_d_zistepu(%edi)	// fu*surf->d_zistepu | fu
+	flds	C(fv)				// fv | fu*surf->d_zistepu | fu
+	fmuls	st_d_zistepv(%edi)	// fv*surf->d_zistepv | fu*surf->d_zistepu | fu
+	fxch	%st(1)				// fu*surf->d_zistepu | fv*surf->d_zistepv | fu
+	fadds	st_d_ziorigin(%edi)	// fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fv*surf->d_zistepv | fu
+
+	flds	st_d_zistepu(%esi)	// surf2->d_zistepu |
+								//  fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fv*surf->d_zistepv | fu
+	fmul	%st(3),%st(0)		// fu*surf2->d_zistepu |
+								//  fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fv*surf->d_zistepv | fu
+	fxch	%st(1)				// fu*surf->d_zistepu + surf->d_ziorigin |
+								//  fu*surf2->d_zistepu |
+								//  fv*surf->d_zistepv | fu
+	faddp	%st(0),%st(2)		// fu*surf2->d_zistepu | newzi | fu
+
+	flds	C(fv)				// fv | fu*surf2->d_zistepu | newzi | fu
+	fmuls	st_d_zistepv(%esi)	// fv*surf2->d_zistepv |
+								//  fu*surf2->d_zistepu | newzi | fu
+	fld		%st(2)				// newzi | fv*surf2->d_zistepv |
+								//  fu*surf2->d_zistepu | newzi | fu
+	fmuls	float_point_999		// newzibottom | fv*surf2->d_zistepv |
+								//  fu*surf2->d_zistepu | newzi | fu
+
+	fxch	%st(2)				// fu*surf2->d_zistepu | fv*surf2->d_zistepv |
+								//  newzibottom | newzi | fu
+	fadds	st_d_ziorigin(%esi)	// fu*surf2->d_zistepu + surf2->d_ziorigin |
+								//  fv*surf2->d_zistepv | newzibottom | newzi |
+								//  fu
+	faddp	%st(0),%st(1)		// testzi | newzibottom | newzi | fu
+	fxch	%st(1)				// newzibottom | testzi | newzi | fu
+
+// if (newzibottom >= testzi)
+//     goto newtop;
+
+	fcomp	%st(1)				// testzi | newzi | fu
+
+	fxch	%st(1)				// newzi | testzi | fu
+	fmuls	float_1_point_001	// newzitop | testzi | fu
+	fxch	%st(1)				// testzi | newzitop | fu
+
+	fnstsw	%ax
+	testb	$0x01,%ah
+	jz		Lnewtop_fpop3
+
+// if (newzitop >= testzi)
+// {
+
+	fcomp	%st(1)				// newzitop | fu
+	fnstsw	%ax
+	testb	$0x45,%ah
+	jz		Lsortloop_fpop2
+
+// if (surf->d_zistepu >= surf2->d_zistepu)
+//     goto newtop;
+
+	flds	st_d_zistepu(%edi)	// surf->d_zistepu | newzitop | fu
+	fcomps	st_d_zistepu(%esi)	// newzitop | fu
+	fnstsw	%ax
+	testb	$0x01,%ah
+	jz		Lnewtop_fpop2
+
+Lsortloop_fpop2:
+	fstp	%st(0)				// clear the FP stack
+	fstp	%st(0)
+	movl	st_key(%edi),%eax
+	jmp		Lsortloop
+
+
+.globl C(R_EdgeCodeEnd)
+C(R_EdgeCodeEnd):
+
+
+//----------------------------------------------------------------------
+// Surface array address code patching routine
+//----------------------------------------------------------------------
+
+	.align 4
+.globl C(R_SurfacePatch)
+C(R_SurfacePatch):
+
+	movl	C(surfaces),%eax
+	addl	$(st_size),%eax
+	movl	%eax,LPatch4-4
+
+	addl	$(st_next),%eax
+	movl	%eax,LPatch0-4
+	movl	%eax,LPatch2-4
+	movl	%eax,LPatch3-4
+
+	ret
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/r_scana.s
@@ -1,0 +1,68 @@
+//
+// d_scana.s
+// x86 assembly-language turbulent texture mapping code
+//
+
+#include "qasm.h"
+#include "d_ifacea.h"
+
+#if id386
+
+	.data
+
+	.text
+
+//----------------------------------------------------------------------
+// turbulent texture mapping code
+//----------------------------------------------------------------------
+
+	.align 4
+.globl C(D_DrawTurbulent8Span)
+C(D_DrawTurbulent8Span):
+	pushl	%ebp				// preserve caller's stack frame pointer
+	pushl	%esi				// preserve register variables
+	pushl	%edi
+	pushl	%ebx
+
+	movl	C(r_turb_s),%esi
+	movl	C(r_turb_t),%ecx
+	movl	C(r_turb_pdest),%edi
+	movl	C(r_turb_spancount),%ebx
+
+Llp:
+	movl	%ecx,%eax
+	movl	%esi,%edx
+	sarl	$16,%eax
+	movl	C(r_turb_turb),%ebp
+	sarl	$16,%edx
+	andl	$(CYCLE-1),%eax
+	andl	$(CYCLE-1),%edx
+	movl	(%ebp,%eax,4),%eax
+	movl	(%ebp,%edx,4),%edx
+	addl	%esi,%eax
+	sarl	$16,%eax
+	addl	%ecx,%edx
+	sarl	$16,%edx
+	andl	$(TURB_TEX_SIZE-1),%eax
+	andl	$(TURB_TEX_SIZE-1),%edx
+	shll	$6,%edx
+	movl	C(r_turb_pbase),%ebp
+	addl	%eax,%edx
+	incl	%edi
+	addl	C(r_turb_sstep),%esi
+	addl	C(r_turb_tstep),%ecx
+	movb	(%ebp,%edx,1),%dl
+	decl	%ebx
+	movb	%dl,-1(%edi)
+	jnz		Llp
+
+	movl	%edi,C(r_turb_pdest)
+
+	popl	%ebx				// restore register variables
+	popl	%edi
+	popl	%esi
+	popl	%ebp				// restore caller's stack frame pointer
+	ret
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/r_spr8.s
@@ -1,0 +1,879 @@
+//
+// d_spr8.s
+// x86 assembly-language horizontal 8-bpp transparent span-drawing code.
+//
+
+#include "qasm.h"
+
+#if id386
+
+//----------------------------------------------------------------------
+// 8-bpp horizontal span drawing code for polygons, with transparency.
+//----------------------------------------------------------------------
+
+	.text
+
+// out-of-line, rarely-needed clamping code
+
+LClampHigh0:
+	movl	C(bbextents),%esi
+	jmp		LClampReentry0
+LClampHighOrLow0:
+	jg		LClampHigh0
+	xorl	%esi,%esi
+	jmp		LClampReentry0
+
+LClampHigh1:
+	movl	C(bbextentt),%edx
+	jmp		LClampReentry1
+LClampHighOrLow1:
+	jg		LClampHigh1
+	xorl	%edx,%edx
+	jmp		LClampReentry1
+
+LClampLow2:
+	movl	$2048,%ebp
+	jmp		LClampReentry2
+LClampHigh2:
+	movl	C(bbextents),%ebp
+	jmp		LClampReentry2
+
+LClampLow3:
+	movl	$2048,%ecx
+	jmp		LClampReentry3
+LClampHigh3:
+	movl	C(bbextentt),%ecx
+	jmp		LClampReentry3
+
+LClampLow4:
+	movl	$2048,%eax
+	jmp		LClampReentry4
+LClampHigh4:
+	movl	C(bbextents),%eax
+	jmp		LClampReentry4
+
+LClampLow5:
+	movl	$2048,%ebx
+	jmp		LClampReentry5
+LClampHigh5:
+	movl	C(bbextentt),%ebx
+	jmp		LClampReentry5
+
+
+#define pspans	4+16
+
+	.align 4
+.globl C(D_SpriteDrawSpans)
+C(D_SpriteDrawSpans):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+//
+// set up scaled-by-8 steps, for 8-long segments; also set up cacheblock
+// and span list pointers, and 1/z step in 0.32 fixed-point
+//
+// FIXME: any overlap from rearranging?
+	flds	C(d_sdivzstepu)
+	fmuls	fp_8
+	movl	C(cacheblock),%edx
+	flds	C(d_tdivzstepu)
+	fmuls	fp_8
+	movl	pspans(%esp),%ebx	// point to the first span descriptor
+	flds	C(d_zistepu)
+	fmuls	fp_8
+	movl	%edx,pbase			// pbase = cacheblock
+	flds	C(d_zistepu)
+	fmuls	fp_64kx64k
+	fxch	%st(3)
+	fstps	sdivz8stepu
+	fstps	zi8stepu
+	fstps	tdivz8stepu
+	fistpl	izistep
+	movl	izistep,%eax
+	rorl	$16,%eax		// put upper 16 bits in low word
+	movl	sspan_t_count(%ebx),%ecx
+	movl	%eax,izistep
+
+	cmpl	$0,%ecx
+	jle		LNextSpan
+
+LSpanLoop:
+
+//
+// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
+// initial s and t values
+//
+// FIXME: pipeline FILD?
+	fildl	sspan_t_v(%ebx)
+	fildl	sspan_t_u(%ebx)
+
+	fld		%st(1)			// dv | du | dv
+	fmuls	C(d_sdivzstepv)	// dv*d_sdivzstepv | du | dv
+	fld		%st(1)			// du | dv*d_sdivzstepv | du | dv
+	fmuls	C(d_sdivzstepu)	// du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+	fld		%st(2)			// du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+	fmuls	C(d_tdivzstepu)	// du*d_tdivzstepu | du*d_sdivzstepu |
+							//  dv*d_sdivzstepv | du | dv
+	fxch	%st(1)			// du*d_sdivzstepu | du*d_tdivzstepu |
+							//  dv*d_sdivzstepv | du | dv
+	faddp	%st(0),%st(2)	// du*d_tdivzstepu |
+							//  du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
+	fxch	%st(1)			// du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  du*d_tdivzstepu | du | dv
+	fld		%st(3)			// dv | du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  du*d_tdivzstepu | du | dv
+	fmuls	C(d_tdivzstepv)	// dv*d_tdivzstepv |
+							//  du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  du*d_tdivzstepu | du | dv
+	fxch	%st(1)			// du*d_sdivzstepu + dv*d_sdivzstepv |
+							//  dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
+	fadds	C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv +
+							//  du*d_sdivzstepu; stays in %st(2) at end
+	fxch	%st(4)			// dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
+							//  s/z
+	fmuls	C(d_zistepv)		// dv*d_zistepv | dv*d_tdivzstepv |
+							//  du*d_tdivzstepu | du | s/z
+	fxch	%st(1)			// dv*d_tdivzstepv |  dv*d_zistepv |
+							//  du*d_tdivzstepu | du | s/z
+	faddp	%st(0),%st(2)	// dv*d_zistepv |
+							//  dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
+	fxch	%st(2)			// du | dv*d_tdivzstepv + du*d_tdivzstepu |
+							//  dv*d_zistepv | s/z
+	fmuls	C(d_zistepu)		// du*d_zistepu |
+							//  dv*d_tdivzstepv + du*d_tdivzstepu |
+							//  dv*d_zistepv | s/z
+	fxch	%st(1)			// dv*d_tdivzstepv + du*d_tdivzstepu |
+							//  du*d_zistepu | dv*d_zistepv | s/z
+	fadds	C(d_tdivzorigin)	// tdivz = d_tdivzorigin + dv*d_tdivzstepv +
+							//  du*d_tdivzstepu; stays in %st(1) at end
+	fxch	%st(2)			// dv*d_zistepv | du*d_zistepu | t/z | s/z
+	faddp	%st(0),%st(1)	// dv*d_zistepv + du*d_zistepu | t/z | s/z
+
+	flds	fp_64k			// fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
+	fxch	%st(1)			// dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
+	fadds	C(d_ziorigin)		// zi = d_ziorigin + dv*d_zistepv +
+							//  du*d_zistepu; stays in %st(0) at end
+							// 1/z | fp_64k | t/z | s/z
+
+	fld		%st(0)			// FIXME: get rid of stall on FMUL?
+	fmuls	fp_64kx64k
+	fxch	%st(1)
+
+//
+// calculate and clamp s & t
+//
+	fdivr	%st(0),%st(2)	// 1/z | z*64k | t/z | s/z
+	fxch	%st(1)
+
+	fistpl	izi				// 0.32 fixed-point 1/z
+	movl	izi,%ebp
+
+//
+// set pz to point to the first z-buffer pixel in the span
+//
+	rorl	$16,%ebp		// put upper 16 bits in low word
+	movl	sspan_t_v(%ebx),%eax
+	movl	%ebp,izi
+	movl	sspan_t_u(%ebx),%ebp
+	imull	C(d_zrowbytes)
+	shll	$1,%ebp					// a word per pixel
+	addl	C(d_pzbuffer),%eax
+	addl	%ebp,%eax
+	movl	%eax,pz
+
+//
+// point %edi to the first pixel in the span
+//
+	movl	C(d_viewbuffer),%ebp
+	movl	sspan_t_v(%ebx),%eax
+	pushl	%ebx		// preserve spans pointer
+	movl	C(tadjust),%edx
+	movl	C(sadjust),%esi
+	movl	C(d_scantable)(,%eax,4),%edi	// v * screenwidth
+	addl	%ebp,%edi
+	movl	sspan_t_u(%ebx),%ebp
+	addl	%ebp,%edi				// pdest = &pdestspan[scans->u];
+
+//
+// now start the FDIV for the end of the span
+//
+	cmpl	$8,%ecx
+	ja		LSetupNotLast1
+
+	decl	%ecx
+	jz		LCleanup1		// if only one pixel, no need to start an FDIV
+	movl	%ecx,spancountminus1
+
+// finish up the s and t calcs
+	fxch	%st(1)			// z*64k | 1/z | t/z | s/z
+
+	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
+	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
+	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
+	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
+	fxch	%st(1)			// s | t | 1/z | t/z | s/z
+	fistpl	s				// 1/z | t | t/z | s/z
+	fistpl	t				// 1/z | t/z | s/z
+
+	fildl	spancountminus1
+
+	flds	C(d_tdivzstepu)	// _d_tdivzstepu | spancountminus1
+	flds	C(d_zistepu)	// _d_zistepu | _d_tdivzstepu | spancountminus1
+	fmul	%st(2),%st(0)	// _d_zistepu*scm1 | _d_tdivzstepu | scm1
+	fxch	%st(1)			// _d_tdivzstepu | _d_zistepu*scm1 | scm1
+	fmul	%st(2),%st(0)	// _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
+	fxch	%st(2)			// scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1
+	fmuls	C(d_sdivzstepu)	// _d_sdivzstepu*scm1 | _d_zistepu*scm1 |
+							//  _d_tdivzstepu*scm1
+	fxch	%st(1)			// _d_zistepu*scm1 | _d_sdivzstepu*scm1 |
+							//  _d_tdivzstepu*scm1
+	faddp	%st(0),%st(3)	// _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
+	fxch	%st(1)			// _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
+	faddp	%st(0),%st(3)	// _d_sdivzstepu*scm1
+	faddp	%st(0),%st(3)
+
+	flds	fp_64k
+	fdiv	%st(1),%st(0)	// this is what we've gone to all this trouble to
+							//  overlap
+	jmp		LFDIVInFlight1
+
+LCleanup1:
+// finish up the s and t calcs
+	fxch	%st(1)			// z*64k | 1/z | t/z | s/z
+
+	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
+	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
+	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
+	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
+	fxch	%st(1)			// s | t | 1/z | t/z | s/z
+	fistpl	s				// 1/z | t | t/z | s/z
+	fistpl	t				// 1/z | t/z | s/z
+	jmp		LFDIVInFlight1
+
+	.align	4
+LSetupNotLast1:
+// finish up the s and t calcs
+	fxch	%st(1)			// z*64k | 1/z | t/z | s/z
+
+	fld		%st(0)			// z*64k | z*64k | 1/z | t/z | s/z
+	fmul	%st(4),%st(0)	// s | z*64k | 1/z | t/z | s/z
+	fxch	%st(1)			// z*64k | s | 1/z | t/z | s/z
+	fmul	%st(3),%st(0)	// t | s | 1/z | t/z | s/z
+	fxch	%st(1)			// s | t | 1/z | t/z | s/z
+	fistpl	s				// 1/z | t | t/z | s/z
+	fistpl	t				// 1/z | t/z | s/z
+
+	fadds	zi8stepu
+	fxch	%st(2)
+	fadds	sdivz8stepu
+	fxch	%st(2)
+	flds	tdivz8stepu
+	faddp	%st(0),%st(2)
+	flds	fp_64k
+	fdiv	%st(1),%st(0)	// z = 1/1/z
+							// this is what we've gone to all this trouble to
+							//  overlap
+LFDIVInFlight1:
+
+	addl	s,%esi
+	addl	t,%edx
+	movl	C(bbextents),%ebx
+	movl	C(bbextentt),%ebp
+	cmpl	%ebx,%esi
+	ja		LClampHighOrLow0
+LClampReentry0:
+	movl	%esi,s
+	movl	pbase,%ebx
+	shll	$16,%esi
+	cmpl	%ebp,%edx
+	movl	%esi,sfracf
+	ja		LClampHighOrLow1
+LClampReentry1:
+	movl	%edx,t
+	movl	s,%esi					// sfrac = scans->sfrac;
+	shll	$16,%edx
+	movl	t,%eax					// tfrac = scans->tfrac;
+	sarl	$16,%esi
+	movl	%edx,tfracf
+
+//
+// calculate the texture starting address
+//
+	sarl	$16,%eax
+	addl	%ebx,%esi
+	imull	C(cachewidth),%eax		// (tfrac >> 16) * cachewidth
+	addl	%eax,%esi				// psource = pbase + (sfrac >> 16) +
+									//           ((tfrac >> 16) * cachewidth);
+
+//
+// determine whether last span or not
+//
+	cmpl	$8,%ecx
+	jna		LLastSegment
+
+//
+// not the last segment; do full 8-wide segment
+//
+LNotLastSegment:
+
+//
+// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+// get there
+//
+
+// pick up after the FDIV that was left in flight previously
+
+	fld		%st(0)			// duplicate it
+	fmul	%st(4),%st(0)	// s = s/z * z
+	fxch	%st(1)
+	fmul	%st(3),%st(0)	// t = t/z * z
+	fxch	%st(1)
+	fistpl	snext
+	fistpl	tnext
+	movl	snext,%eax
+	movl	tnext,%edx
+
+	subl	$8,%ecx		// count off this segments' pixels
+	movl	C(sadjust),%ebp
+	pushl	%ecx		// remember count of remaining pixels
+	movl	C(tadjust),%ecx
+
+	addl	%eax,%ebp
+	addl	%edx,%ecx
+
+	movl	C(bbextents),%eax
+	movl	C(bbextentt),%edx
+
+	cmpl	$2048,%ebp
+	jl		LClampLow2
+	cmpl	%eax,%ebp
+	ja		LClampHigh2
+LClampReentry2:
+
+	cmpl	$2048,%ecx
+	jl		LClampLow3
+	cmpl	%edx,%ecx
+	ja		LClampHigh3
+LClampReentry3:
+
+	movl	%ebp,snext
+	movl	%ecx,tnext
+
+	subl	s,%ebp
+	subl	t,%ecx
+	
+//
+// set up advancetable
+//
+	movl	%ecx,%eax
+	movl	%ebp,%edx
+	sarl	$19,%edx			// sstep >>= 16;
+	movl	C(cachewidth),%ebx
+	sarl	$19,%eax			// tstep >>= 16;
+	jz		LIsZero
+	imull	%ebx,%eax			// (tstep >> 16) * cachewidth;
+LIsZero:
+	addl	%edx,%eax			// add in sstep
+								// (tstep >> 16) * cachewidth + (sstep >> 16);
+	movl	tfracf,%edx
+	movl	%eax,advancetable+4	// advance base in t
+	addl	%ebx,%eax			// ((tstep >> 16) + 1) * cachewidth +
+								//  (sstep >> 16);
+	shll	$13,%ebp			// left-justify sstep fractional part
+	movl	%ebp,sstep
+	movl	sfracf,%ebx
+	shll	$13,%ecx			// left-justify tstep fractional part
+	movl	%eax,advancetable	// advance extra in t
+	movl	%ecx,tstep
+
+	movl	pz,%ecx
+	movl	izi,%ebp
+
+	cmpw	(%ecx),%bp
+	jl		Lp1
+	movb	(%esi),%al			// get first source texel
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp1
+	movw	%bp,(%ecx)
+	movb	%al,(%edi)			// store first dest pixel
+Lp1:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx			// advance tfrac fractional part by tstep frac
+
+	sbbl	%eax,%eax			// turn tstep carry into -1 (0 if none)
+	addl	sstep,%ebx			// advance sfrac fractional part by sstep frac
+	adcl	advancetable+4(,%eax,4),%esi	// point to next source texel
+
+	cmpw	2(%ecx),%bp
+	jl		Lp2
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp2
+	movw	%bp,2(%ecx)
+	movb	%al,1(%edi)
+Lp2:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	cmpw	4(%ecx),%bp
+	jl		Lp3
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp3
+	movw	%bp,4(%ecx)
+	movb	%al,2(%edi)
+Lp3:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	cmpw	6(%ecx),%bp
+	jl		Lp4
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp4
+	movw	%bp,6(%ecx)
+	movb	%al,3(%edi)
+Lp4:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	cmpw	8(%ecx),%bp
+	jl		Lp5
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp5
+	movw	%bp,8(%ecx)
+	movb	%al,4(%edi)
+Lp5:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+//
+// start FDIV for end of next segment in flight, so it can overlap
+//
+	popl	%eax
+	cmpl	$8,%eax			// more than one segment after this?
+	ja		LSetupNotLast2	// yes
+
+	decl	%eax
+	jz		LFDIVInFlight2	// if only one pixel, no need to start an FDIV
+	movl	%eax,spancountminus1
+	fildl	spancountminus1
+
+	flds	C(d_zistepu)		// _d_zistepu | spancountminus1
+	fmul	%st(1),%st(0)	// _d_zistepu*scm1 | scm1
+	flds	C(d_tdivzstepu)	// _d_tdivzstepu | _d_zistepu*scm1 | scm1
+	fmul	%st(2),%st(0)	// _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
+	fxch	%st(1)			// _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1
+	faddp	%st(0),%st(3)	// _d_tdivzstepu*scm1 | scm1
+	fxch	%st(1)			// scm1 | _d_tdivzstepu*scm1
+	fmuls	C(d_sdivzstepu)	// _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
+	fxch	%st(1)			// _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
+	faddp	%st(0),%st(3)	// _d_sdivzstepu*scm1
+	flds	fp_64k			// 64k | _d_sdivzstepu*scm1
+	fxch	%st(1)			// _d_sdivzstepu*scm1 | 64k
+	faddp	%st(0),%st(4)	// 64k
+
+	fdiv	%st(1),%st(0)	// this is what we've gone to all this trouble to
+							//  overlap
+	jmp		LFDIVInFlight2
+
+	.align	4
+LSetupNotLast2:
+	fadds	zi8stepu
+	fxch	%st(2)
+	fadds	sdivz8stepu
+	fxch	%st(2)
+	flds	tdivz8stepu
+	faddp	%st(0),%st(2)
+	flds	fp_64k
+	fdiv	%st(1),%st(0)	// z = 1/1/z
+							// this is what we've gone to all this trouble to
+							//  overlap
+LFDIVInFlight2:
+	pushl	%eax
+
+	cmpw	10(%ecx),%bp
+	jl		Lp6
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp6
+	movw	%bp,10(%ecx)
+	movb	%al,5(%edi)
+Lp6:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	cmpw	12(%ecx),%bp
+	jl		Lp7
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp7
+	movw	%bp,12(%ecx)
+	movb	%al,6(%edi)
+Lp7:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	cmpw	14(%ecx),%bp
+	jl		Lp8
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp8
+	movw	%bp,14(%ecx)
+	movb	%al,7(%edi)
+Lp8:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+	addl	$8,%edi
+	addl	$16,%ecx
+	movl	%edx,tfracf
+	movl	snext,%edx
+	movl	%ebx,sfracf
+	movl	tnext,%ebx
+	movl	%edx,s
+	movl	%ebx,t
+
+	movl	%ecx,pz
+	movl	%ebp,izi
+
+	popl	%ecx				// retrieve count
+
+//
+// determine whether last span or not
+//
+	cmpl	$8,%ecx				// are there multiple segments remaining?
+	ja		LNotLastSegment		// yes
+
+//
+// last segment of scan
+//
+LLastSegment:
+
+//
+// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+// get there. The number of pixels left is variable, and we want to land on the
+// last pixel, not step one past it, so we can't run into arithmetic problems
+//
+	testl	%ecx,%ecx
+	jz		LNoSteps		// just draw the last pixel and we're done
+
+// pick up after the FDIV that was left in flight previously
+
+
+	fld		%st(0)			// duplicate it
+	fmul	%st(4),%st(0)	// s = s/z * z
+	fxch	%st(1)
+	fmul	%st(3),%st(0)	// t = t/z * z
+	fxch	%st(1)
+	fistpl	snext
+	fistpl	tnext
+
+	movl	C(tadjust),%ebx
+	movl	C(sadjust),%eax
+
+	addl	snext,%eax
+	addl	tnext,%ebx
+
+	movl	C(bbextents),%ebp
+	movl	C(bbextentt),%edx
+
+	cmpl	$2048,%eax
+	jl		LClampLow4
+	cmpl	%ebp,%eax
+	ja		LClampHigh4
+LClampReentry4:
+	movl	%eax,snext
+
+	cmpl	$2048,%ebx
+	jl		LClampLow5
+	cmpl	%edx,%ebx
+	ja		LClampHigh5
+LClampReentry5:
+
+	cmpl	$1,%ecx			// don't bother 
+	je		LOnlyOneStep	// if two pixels in segment, there's only one step,
+							//  of the segment length
+	subl	s,%eax
+	subl	t,%ebx
+
+	addl	%eax,%eax		// convert to 15.17 format so multiply by 1.31
+	addl	%ebx,%ebx		//  reciprocal yields 16.48
+	imull	reciprocal_table-8(,%ecx,4) // sstep = (snext - s) / (spancount-1)
+	movl	%edx,%ebp
+
+	movl	%ebx,%eax
+	imull	reciprocal_table-8(,%ecx,4) // tstep = (tnext - t) / (spancount-1)
+
+LSetEntryvec:
+//
+// set up advancetable
+//
+	movl	spr8entryvec_table(,%ecx,4),%ebx
+	movl	%edx,%eax
+	pushl	%ebx				// entry point into code for RET later
+	movl	%ebp,%ecx
+	sarl	$16,%ecx			// sstep >>= 16;
+	movl	C(cachewidth),%ebx
+	sarl	$16,%edx			// tstep >>= 16;
+	jz		LIsZeroLast
+	imull	%ebx,%edx			// (tstep >> 16) * cachewidth;
+LIsZeroLast:
+	addl	%ecx,%edx			// add in sstep
+								// (tstep >> 16) * cachewidth + (sstep >> 16);
+	movl	tfracf,%ecx
+	movl	%edx,advancetable+4	// advance base in t
+	addl	%ebx,%edx			// ((tstep >> 16) + 1) * cachewidth +
+								//  (sstep >> 16);
+	shll	$16,%ebp			// left-justify sstep fractional part
+	movl	sfracf,%ebx
+	shll	$16,%eax			// left-justify tstep fractional part
+	movl	%edx,advancetable	// advance extra in t
+
+	movl	%eax,tstep
+	movl	%ebp,sstep
+	movl	%ecx,%edx
+
+	movl	pz,%ecx
+	movl	izi,%ebp
+
+	ret							// jump to the number-of-pixels handler
+
+//----------------------------------------
+
+LNoSteps:
+	movl	pz,%ecx
+	subl	$7,%edi			// adjust for hardwired offset
+	subl	$14,%ecx
+	jmp		LEndSpan
+
+
+LOnlyOneStep:
+	subl	s,%eax
+	subl	t,%ebx
+	movl	%eax,%ebp
+	movl	%ebx,%edx
+	jmp		LSetEntryvec
+
+//----------------------------------------
+
+.globl	Spr8Entry2_8
+Spr8Entry2_8:
+	subl	$6,%edi		// adjust for hardwired offsets
+	subl	$12,%ecx
+	movb	(%esi),%al
+	jmp		LLEntry2_8
+
+//----------------------------------------
+
+.globl	Spr8Entry3_8
+Spr8Entry3_8:
+	subl	$5,%edi		// adjust for hardwired offsets
+	subl	$10,%ecx
+	jmp		LLEntry3_8
+
+//----------------------------------------
+
+.globl	Spr8Entry4_8
+Spr8Entry4_8:
+	subl	$4,%edi		// adjust for hardwired offsets
+	subl	$8,%ecx
+	jmp		LLEntry4_8
+
+//----------------------------------------
+
+.globl	Spr8Entry5_8
+Spr8Entry5_8:
+	subl	$3,%edi		// adjust for hardwired offsets
+	subl	$6,%ecx
+	jmp		LLEntry5_8
+
+//----------------------------------------
+
+.globl	Spr8Entry6_8
+Spr8Entry6_8:
+	subl	$2,%edi		// adjust for hardwired offsets
+	subl	$4,%ecx
+	jmp		LLEntry6_8
+
+//----------------------------------------
+
+.globl	Spr8Entry7_8
+Spr8Entry7_8:
+	decl	%edi		// adjust for hardwired offsets
+	subl	$2,%ecx
+	jmp		LLEntry7_8
+
+//----------------------------------------
+
+.globl	Spr8Entry8_8
+Spr8Entry8_8:
+	cmpw	(%ecx),%bp
+	jl		Lp9
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp9
+	movw	%bp,(%ecx)
+	movb	%al,(%edi)
+Lp9:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+LLEntry7_8:
+	cmpw	2(%ecx),%bp
+	jl		Lp10
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp10
+	movw	%bp,2(%ecx)
+	movb	%al,1(%edi)
+Lp10:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+LLEntry6_8:
+	cmpw	4(%ecx),%bp
+	jl		Lp11
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp11
+	movw	%bp,4(%ecx)
+	movb	%al,2(%edi)
+Lp11:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+LLEntry5_8:
+	cmpw	6(%ecx),%bp
+	jl		Lp12
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp12
+	movw	%bp,6(%ecx)
+	movb	%al,3(%edi)
+Lp12:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+LLEntry4_8:
+	cmpw	8(%ecx),%bp
+	jl		Lp13
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp13
+	movw	%bp,8(%ecx)
+	movb	%al,4(%edi)
+Lp13:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+LLEntry3_8:
+	cmpw	10(%ecx),%bp
+	jl		Lp14
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp14
+	movw	%bp,10(%ecx)
+	movb	%al,5(%edi)
+Lp14:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+LLEntry2_8:
+	cmpw	12(%ecx),%bp
+	jl		Lp15
+	movb	(%esi),%al
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp15
+	movw	%bp,12(%ecx)
+	movb	%al,6(%edi)
+Lp15:
+	addl	izistep,%ebp
+	adcl	$0,%ebp
+	addl	tstep,%edx
+	sbbl	%eax,%eax
+	addl	sstep,%ebx
+	adcl	advancetable+4(,%eax,4),%esi
+
+LEndSpan:
+	cmpw	14(%ecx),%bp
+	jl		Lp16
+	movb	(%esi),%al		// load first texel in segment
+	cmpb	$(TRANSPARENT_COLOR),%al
+	jz		Lp16
+	movw	%bp,14(%ecx)
+	movb	%al,7(%edi)
+Lp16:
+
+//
+// clear s/z, t/z, 1/z from FP stack
+//
+	fstp %st(0)
+	fstp %st(0)
+	fstp %st(0)
+
+	popl	%ebx				// restore spans pointer
+LNextSpan:
+	addl	$(sspan_t_size),%ebx // point to next span
+	movl	sspan_t_count(%ebx),%ecx
+	cmpl	$0,%ecx				// any more spans?
+	jg		LSpanLoop			// yes
+	jz		LNextSpan			// yes, but this one's empty
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+#endif	// id386
--- /dev/null
+++ b/linux/r_surf8.s
@@ -1,0 +1,762 @@
+//
+// surf8.s
+// x86 assembly-language 8 bpp surface block drawing code.
+//
+
+#include "qasm.h"
+
+#if	id386
+
+	.data
+
+sb_v:		.long	0
+
+	.text
+
+	.align 4
+.globl C(R_Surf8Start)
+C(R_Surf8Start):
+
+//----------------------------------------------------------------------
+// Surface block drawer for mip level 0
+//----------------------------------------------------------------------
+
+	.align 4
+.globl C(R_DrawSurfaceBlock8_mip0)
+C(R_DrawSurfaceBlock8_mip0):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+//		for (v=0 ; v<numvblocks ; v++)
+//		{
+	movl	C(r_lightptr),%ebx
+	movl	C(r_numvblocks),%eax
+
+	movl	%eax,sb_v
+	movl	C(prowdestbase),%edi
+
+	movl	C(pbasesource),%esi
+
+Lv_loop_mip0:
+
+//			lightleft = lightptr[0];
+//			lightright = lightptr[1];
+//			lightdelta = (lightleft - lightright) & 0xFFFFF;
+	movl	(%ebx),%eax			// lightleft
+	movl	4(%ebx),%edx		// lightright
+
+	movl	%eax,%ebp
+	movl	C(r_lightwidth),%ecx
+
+	movl	%edx,C(lightright)
+	subl	%edx,%ebp
+
+	andl	$0xFFFFF,%ebp
+	leal	(%ebx,%ecx,4),%ebx
+
+//			lightptr += lightwidth;
+	movl	%ebx,C(r_lightptr)
+
+//			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+//			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+//			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+//					0xF0000000;
+	movl	4(%ebx),%ecx	// lightptr[1]
+	movl	(%ebx),%ebx		// lightptr[0]
+
+	subl	%eax,%ebx
+	subl	%edx,%ecx
+
+	sarl	$4,%ecx
+	orl		$0xF0000000,%ebp
+
+	sarl	$4,%ebx
+	movl	%ecx,C(lightrightstep)
+
+	subl	%ecx,%ebx
+	andl	$0xFFFFF,%ebx
+
+	orl		$0xF0000000,%ebx
+	subl	%ecx,%ecx	// high word must be 0 in loop for addressing
+
+	movl	%ebx,C(lightdeltastep)
+	subl	%ebx,%ebx	// high word must be 0 in loop for addressing
+
+Lblockloop8_mip0:
+	movl	%ebp,C(lightdelta)
+	movb	14(%esi),%cl
+
+	sarl	$4,%ebp
+	movb	%dh,%bh
+
+	movb	15(%esi),%bl
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch0:
+	movb	13(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch1:
+	movb	12(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	addl	%ebp,%edx
+	movb	0x12345678(%ebx),%ah
+LBPatch2:
+
+	movb	11(%esi),%bl
+	movb	0x12345678(%ecx),%al
+LBPatch3:
+
+	movb	10(%esi),%cl
+	movl	%eax,12(%edi)
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch4:
+	movb	9(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch5:
+	movb	8(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	addl	%ebp,%edx
+	movb	0x12345678(%ebx),%ah
+LBPatch6:
+
+	movb	7(%esi),%bl
+	movb	0x12345678(%ecx),%al
+LBPatch7:
+
+	movb	6(%esi),%cl
+	movl	%eax,8(%edi)
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch8:
+	movb	5(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch9:
+	movb	4(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	addl	%ebp,%edx
+	movb	0x12345678(%ebx),%ah
+LBPatch10:
+
+	movb	3(%esi),%bl
+	movb	0x12345678(%ecx),%al
+LBPatch11:
+
+	movb	2(%esi),%cl
+	movl	%eax,4(%edi)
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch12:
+	movb	1(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch13:
+	movb	(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	movb	0x12345678(%ebx),%ah
+LBPatch14:
+	movl	C(lightright),%edx
+
+	movb	0x12345678(%ecx),%al
+LBPatch15:
+	movl	C(lightdelta),%ebp
+
+	movl	%eax,(%edi)
+
+	addl	C(sourcetstep),%esi
+	addl	C(surfrowbytes),%edi
+
+	addl	C(lightrightstep),%edx
+	addl	C(lightdeltastep),%ebp
+
+	movl	%edx,C(lightright)
+	jc		Lblockloop8_mip0
+
+//			if (pbasesource >= r_sourcemax)
+//				pbasesource -= stepback;
+
+	cmpl	C(r_sourcemax),%esi
+	jb		LSkip_mip0
+	subl	C(r_stepback),%esi
+LSkip_mip0:
+
+	movl	C(r_lightptr),%ebx
+	decl	sb_v
+
+	jnz		Lv_loop_mip0
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+
+//----------------------------------------------------------------------
+// Surface block drawer for mip level 1
+//----------------------------------------------------------------------
+
+	.align 4
+.globl C(R_DrawSurfaceBlock8_mip1)
+C(R_DrawSurfaceBlock8_mip1):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+//		for (v=0 ; v<numvblocks ; v++)
+//		{
+	movl	C(r_lightptr),%ebx
+	movl	C(r_numvblocks),%eax
+
+	movl	%eax,sb_v
+	movl	C(prowdestbase),%edi
+
+	movl	C(pbasesource),%esi
+
+Lv_loop_mip1:
+
+//			lightleft = lightptr[0];
+//			lightright = lightptr[1];
+//			lightdelta = (lightleft - lightright) & 0xFFFFF;
+	movl	(%ebx),%eax			// lightleft
+	movl	4(%ebx),%edx		// lightright
+
+	movl	%eax,%ebp
+	movl	C(r_lightwidth),%ecx
+
+	movl	%edx,C(lightright)
+	subl	%edx,%ebp
+
+	andl	$0xFFFFF,%ebp
+	leal	(%ebx,%ecx,4),%ebx
+
+//			lightptr += lightwidth;
+	movl	%ebx,C(r_lightptr)
+
+//			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+//			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+//			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+//					0xF0000000;
+	movl	4(%ebx),%ecx	// lightptr[1]
+	movl	(%ebx),%ebx		// lightptr[0]
+
+	subl	%eax,%ebx
+	subl	%edx,%ecx
+
+	sarl	$3,%ecx
+	orl		$0x70000000,%ebp
+
+	sarl	$3,%ebx
+	movl	%ecx,C(lightrightstep)
+
+	subl	%ecx,%ebx
+	andl	$0xFFFFF,%ebx
+
+	orl		$0xF0000000,%ebx
+	subl	%ecx,%ecx	// high word must be 0 in loop for addressing
+
+	movl	%ebx,C(lightdeltastep)
+	subl	%ebx,%ebx	// high word must be 0 in loop for addressing
+
+Lblockloop8_mip1:
+	movl	%ebp,C(lightdelta)
+	movb	6(%esi),%cl
+
+	sarl	$3,%ebp
+	movb	%dh,%bh
+
+	movb	7(%esi),%bl
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch22:
+	movb	5(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch23:
+	movb	4(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	addl	%ebp,%edx
+	movb	0x12345678(%ebx),%ah
+LBPatch24:
+
+	movb	3(%esi),%bl
+	movb	0x12345678(%ecx),%al
+LBPatch25:
+
+	movb	2(%esi),%cl
+	movl	%eax,4(%edi)
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch26:
+	movb	1(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch27:
+	movb	(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	movb	0x12345678(%ebx),%ah
+LBPatch28:
+	movl	C(lightright),%edx
+
+	movb	0x12345678(%ecx),%al
+LBPatch29:
+	movl	C(lightdelta),%ebp
+
+	movl	%eax,(%edi)
+	movl	C(sourcetstep),%eax
+
+	addl	%eax,%esi
+	movl	C(surfrowbytes),%eax
+
+	addl	%eax,%edi
+	movl	C(lightrightstep),%eax
+
+	addl	%eax,%edx
+	movl	C(lightdeltastep),%eax
+
+	addl	%eax,%ebp
+	movl	%edx,C(lightright)
+
+	jc		Lblockloop8_mip1
+
+//			if (pbasesource >= r_sourcemax)
+//				pbasesource -= stepback;
+
+	cmpl	C(r_sourcemax),%esi
+	jb		LSkip_mip1
+	subl	C(r_stepback),%esi
+LSkip_mip1:
+
+	movl	C(r_lightptr),%ebx
+	decl	sb_v
+
+	jnz		Lv_loop_mip1
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+
+//----------------------------------------------------------------------
+// Surface block drawer for mip level 2
+//----------------------------------------------------------------------
+
+	.align 4
+.globl C(R_DrawSurfaceBlock8_mip2)
+C(R_DrawSurfaceBlock8_mip2):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+//		for (v=0 ; v<numvblocks ; v++)
+//		{
+	movl	C(r_lightptr),%ebx
+	movl	C(r_numvblocks),%eax
+
+	movl	%eax,sb_v
+	movl	C(prowdestbase),%edi
+
+	movl	C(pbasesource),%esi
+
+Lv_loop_mip2:
+
+//			lightleft = lightptr[0];
+//			lightright = lightptr[1];
+//			lightdelta = (lightleft - lightright) & 0xFFFFF;
+	movl	(%ebx),%eax			// lightleft
+	movl	4(%ebx),%edx		// lightright
+
+	movl	%eax,%ebp
+	movl	C(r_lightwidth),%ecx
+
+	movl	%edx,C(lightright)
+	subl	%edx,%ebp
+
+	andl	$0xFFFFF,%ebp
+	leal	(%ebx,%ecx,4),%ebx
+
+//			lightptr += lightwidth;
+	movl	%ebx,C(r_lightptr)
+
+//			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+//			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+//			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+//					0xF0000000;
+	movl	4(%ebx),%ecx	// lightptr[1]
+	movl	(%ebx),%ebx		// lightptr[0]
+
+	subl	%eax,%ebx
+	subl	%edx,%ecx
+
+	sarl	$2,%ecx
+	orl		$0x30000000,%ebp
+
+	sarl	$2,%ebx
+	movl	%ecx,C(lightrightstep)
+
+	subl	%ecx,%ebx
+
+	andl	$0xFFFFF,%ebx
+
+	orl		$0xF0000000,%ebx
+	subl	%ecx,%ecx	// high word must be 0 in loop for addressing
+
+	movl	%ebx,C(lightdeltastep)
+	subl	%ebx,%ebx	// high word must be 0 in loop for addressing
+
+Lblockloop8_mip2:
+	movl	%ebp,C(lightdelta)
+	movb	2(%esi),%cl
+
+	sarl	$2,%ebp
+	movb	%dh,%bh
+
+	movb	3(%esi),%bl
+	addl	%ebp,%edx
+
+	movb	%dh,%ch
+	addl	%ebp,%edx
+
+	movb	0x12345678(%ebx),%ah
+LBPatch18:
+	movb	1(%esi),%bl
+
+	movb	0x12345678(%ecx),%al
+LBPatch19:
+	movb	(%esi),%cl
+
+	movb	%dh,%bh
+	addl	%ebp,%edx
+
+	rorl	$16,%eax
+	movb	%dh,%ch
+
+	movb	0x12345678(%ebx),%ah
+LBPatch20:
+	movl	C(lightright),%edx
+
+	movb	0x12345678(%ecx),%al
+LBPatch21:
+	movl	C(lightdelta),%ebp
+
+	movl	%eax,(%edi)
+	movl	C(sourcetstep),%eax
+
+	addl	%eax,%esi
+	movl	C(surfrowbytes),%eax
+
+	addl	%eax,%edi
+	movl	C(lightrightstep),%eax
+
+	addl	%eax,%edx
+	movl	C(lightdeltastep),%eax
+
+	addl	%eax,%ebp
+	movl	%edx,C(lightright)
+
+	jc		Lblockloop8_mip2
+
+//			if (pbasesource >= r_sourcemax)
+//				pbasesource -= stepback;
+
+	cmpl	C(r_sourcemax),%esi
+	jb		LSkip_mip2
+	subl	C(r_stepback),%esi
+LSkip_mip2:
+
+	movl	C(r_lightptr),%ebx
+	decl	sb_v
+
+	jnz		Lv_loop_mip2
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+
+//----------------------------------------------------------------------
+// Surface block drawer for mip level 3
+//----------------------------------------------------------------------
+
+	.align 4
+.globl C(R_DrawSurfaceBlock8_mip3)
+C(R_DrawSurfaceBlock8_mip3):
+	pushl	%ebp				// preserve caller's stack frame
+	pushl	%edi
+	pushl	%esi				// preserve register variables
+	pushl	%ebx
+
+//		for (v=0 ; v<numvblocks ; v++)
+//		{
+	movl	C(r_lightptr),%ebx
+	movl	C(r_numvblocks),%eax
+
+	movl	%eax,sb_v
+	movl	C(prowdestbase),%edi
+
+	movl	C(pbasesource),%esi
+
+Lv_loop_mip3:
+
+//			lightleft = lightptr[0];
+//			lightright = lightptr[1];
+//			lightdelta = (lightleft - lightright) & 0xFFFFF;
+	movl	(%ebx),%eax			// lightleft
+	movl	4(%ebx),%edx		// lightright
+
+	movl	%eax,%ebp
+	movl	C(r_lightwidth),%ecx
+
+	movl	%edx,C(lightright)
+	subl	%edx,%ebp
+
+	andl	$0xFFFFF,%ebp
+	leal	(%ebx,%ecx,4),%ebx
+
+	movl	%ebp,C(lightdelta)
+//			lightptr += lightwidth;
+	movl	%ebx,C(r_lightptr)
+
+//			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+//			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+//			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+//					0xF0000000;
+	movl	4(%ebx),%ecx	// lightptr[1]
+	movl	(%ebx),%ebx		// lightptr[0]
+
+	subl	%eax,%ebx
+	subl	%edx,%ecx
+
+	sarl	$1,%ecx
+
+	sarl	$1,%ebx
+	movl	%ecx,C(lightrightstep)
+
+	subl	%ecx,%ebx
+	andl	$0xFFFFF,%ebx
+
+	sarl	$1,%ebp
+	orl		$0xF0000000,%ebx
+
+	movl	%ebx,C(lightdeltastep)
+	subl	%ebx,%ebx	// high word must be 0 in loop for addressing
+
+	movb	1(%esi),%bl
+	subl	%ecx,%ecx	// high word must be 0 in loop for addressing
+
+	movb	%dh,%bh
+	movb	(%esi),%cl
+
+	addl	%ebp,%edx
+	movb	%dh,%ch
+
+	movb	0x12345678(%ebx),%al
+LBPatch16:
+	movl	C(lightright),%edx
+
+	movb	%al,1(%edi)
+	movb	0x12345678(%ecx),%al
+LBPatch17:
+
+	movb	%al,(%edi)
+	movl	C(sourcetstep),%eax
+
+	addl	%eax,%esi
+	movl	C(surfrowbytes),%eax
+
+	addl	%eax,%edi
+	movl	C(lightdeltastep),%eax
+
+	movl	C(lightdelta),%ebp
+	movb	(%esi),%cl
+
+	addl	%eax,%ebp
+	movl	C(lightrightstep),%eax
+
+	sarl	$1,%ebp
+	addl	%eax,%edx
+
+	movb	%dh,%bh
+	movb	1(%esi),%bl
+
+	addl	%ebp,%edx
+	movb	%dh,%ch
+
+	movb	0x12345678(%ebx),%al
+LBPatch30:
+	movl	C(sourcetstep),%edx
+
+	movb	%al,1(%edi)
+	movb	0x12345678(%ecx),%al
+LBPatch31:
+
+	movb	%al,(%edi)
+	movl	C(surfrowbytes),%ebp
+
+	addl	%edx,%esi
+	addl	%ebp,%edi
+
+//			if (pbasesource >= r_sourcemax)
+//				pbasesource -= stepback;
+
+	cmpl	C(r_sourcemax),%esi
+	jb		LSkip_mip3
+	subl	C(r_stepback),%esi
+LSkip_mip3:
+
+	movl	C(r_lightptr),%ebx
+	decl	sb_v
+
+	jnz		Lv_loop_mip3
+
+	popl	%ebx				// restore register variables
+	popl	%esi
+	popl	%edi
+	popl	%ebp				// restore the caller's stack frame
+	ret
+
+
+.globl C(R_Surf8End)
+C(R_Surf8End):
+
+//----------------------------------------------------------------------
+// Code patching routines
+//----------------------------------------------------------------------
+	.data
+
+	.align 4
+LPatchTable8:
+	.long	LBPatch0-4
+	.long	LBPatch1-4
+	.long	LBPatch2-4
+	.long	LBPatch3-4
+	.long	LBPatch4-4
+	.long	LBPatch5-4
+	.long	LBPatch6-4
+	.long	LBPatch7-4
+	.long	LBPatch8-4
+	.long	LBPatch9-4
+	.long	LBPatch10-4
+	.long	LBPatch11-4
+	.long	LBPatch12-4
+	.long	LBPatch13-4
+	.long	LBPatch14-4
+	.long	LBPatch15-4
+	.long	LBPatch16-4
+	.long	LBPatch17-4
+	.long	LBPatch18-4
+	.long	LBPatch19-4
+	.long	LBPatch20-4
+	.long	LBPatch21-4
+	.long	LBPatch22-4
+	.long	LBPatch23-4
+	.long	LBPatch24-4
+	.long	LBPatch25-4
+	.long	LBPatch26-4
+	.long	LBPatch27-4
+	.long	LBPatch28-4
+	.long	LBPatch29-4
+	.long	LBPatch30-4
+	.long	LBPatch31-4
+
+	.text
+
+	.align 4
+.globl C(R_Surf8Patch)
+C(R_Surf8Patch):
+	pushl	%ebx
+
+	movl	C(colormap),%eax
+	movl	$LPatchTable8,%ebx
+	movl	$32,%ecx
+LPatchLoop8:
+	movl	(%ebx),%edx
+	addl	$4,%ebx
+	movl	%eax,(%edx)
+	decl	%ecx
+	jnz		LPatchLoop8
+
+	popl	%ebx
+
+	ret
+
+#endif	// id386
--- /dev/null
+++ b/linux/r_varsa.s
@@ -1,0 +1,223 @@
+//
+// r_varsa.s
+//
+
+#include "qasm.h"
+#include "d_ifacea.h"
+
+#if id386
+
+	.data
+
+//-------------------------------------------------------
+// ASM-only variables
+//-------------------------------------------------------
+.globl	float_1, float_particle_z_clip, float_point5
+.globl	float_minus_1, float_0
+float_0:		.single	0.0
+float_1:		.single	1.0
+float_minus_1:	.single	-1.0
+float_particle_z_clip:	.single	PARTICLE_Z_CLIP
+float_point5:	.single	0.5
+
+.globl	fp_16, fp_64k, fp_1m, fp_64kx64k
+.globl	fp_1m_minus_1
+.globl	fp_8 
+fp_1m:			.single	1048576.0
+fp_1m_minus_1:	.single	1048575.0
+fp_64k:			.single	65536.0
+fp_8:			.single	8.0
+fp_16:			.single	16.0
+fp_64kx64k:		.long	0x4f000000	// (float)0x8000*0x10000
+
+
+.globl	FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd
+FloatZero:				.long	0
+Float2ToThe31nd:		.long	0x4f000000
+FloatMinus2ToThe31nd:	.long	0xcf000000
+
+.globl	C(r_bmodelactive)
+C(r_bmodelactive):	.long	0
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: put all refresh variables into one contiguous block. Make into one
+// big structure, like cl or sv?
+
+	.align	4
+.globl	C(d_sdivzstepu)
+.globl	C(d_tdivzstepu)
+.globl	C(d_zistepu)
+.globl	C(d_sdivzstepv)
+.globl	C(d_tdivzstepv)
+.globl	C(d_zistepv)
+.globl	C(d_sdivzorigin)
+.globl	C(d_tdivzorigin)
+.globl	C(d_ziorigin)
+C(d_sdivzstepu):	.single	0
+C(d_tdivzstepu):	.single	0
+C(d_zistepu):		.single	0
+C(d_sdivzstepv):	.single	0
+C(d_tdivzstepv):	.single	0
+C(d_zistepv):		.single	0
+C(d_sdivzorigin):	.single	0
+C(d_tdivzorigin):	.single	0
+C(d_ziorigin):		.single	0
+
+.globl	C(sadjust)
+.globl	C(tadjust)
+.globl	C(bbextents)
+.globl	C(bbextentt)
+C(sadjust):			.long	0
+C(tadjust):			.long	0
+C(bbextents):		.long	0
+C(bbextentt):		.long	0
+
+.globl	C(cacheblock)
+.globl	C(d_viewbuffer)
+.globl	C(cachewidth)
+.globl	C(d_pzbuffer)
+.globl	C(d_zrowbytes)
+.globl	C(d_zwidth)
+C(cacheblock):		.long	0
+C(cachewidth):		.long	0
+C(d_viewbuffer):	.long	0
+C(d_pzbuffer):		.long	0
+C(d_zrowbytes):		.long	0
+C(d_zwidth):		.long	0
+
+
+//-------------------------------------------------------
+// ASM-only variables
+//-------------------------------------------------------
+.globl	izi
+izi:			.long	0
+
+.globl	pbase, s, t, sfracf, tfracf, snext, tnext
+.globl	spancountminus1, zi16stepu, sdivz16stepu, tdivz16stepu
+.globl	zi8stepu, sdivz8stepu, tdivz8stepu, pz
+s:				.long	0
+t:				.long	0
+snext:			.long	0
+tnext:			.long	0
+sfracf:			.long	0
+tfracf:			.long	0
+pbase:			.long	0
+zi8stepu:		.long	0
+sdivz8stepu:	.long	0
+tdivz8stepu:	.long	0
+zi16stepu:		.long	0
+sdivz16stepu:	.long	0
+tdivz16stepu:	.long	0
+spancountminus1: .long	0
+pz:				.long	0
+
+.globl	izistep
+izistep:				.long	0
+
+//-------------------------------------------------------
+// local variables for d_draw16.s
+//-------------------------------------------------------
+
+.globl	reciprocal_table_16, entryvec_table_16
+// 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13,
+// 1/14, and 1/15 in 0.32 form
+reciprocal_table_16:	.long	0x40000000, 0x2aaaaaaa, 0x20000000
+						.long	0x19999999, 0x15555555, 0x12492492
+						.long	0x10000000, 0xe38e38e, 0xccccccc, 0xba2e8ba
+						.long	0xaaaaaaa, 0x9d89d89, 0x9249249, 0x8888888
+
+#ifndef NeXT
+	.extern Entry2_16
+	.extern Entry3_16
+	.extern Entry4_16
+	.extern Entry5_16
+	.extern Entry6_16
+	.extern Entry7_16
+	.extern Entry8_16
+	.extern Entry9_16
+	.extern Entry10_16
+	.extern Entry11_16
+	.extern Entry12_16
+	.extern Entry13_16
+	.extern Entry14_16
+	.extern Entry15_16
+	.extern Entry16_16
+#endif
+
+entryvec_table_16:	.long	0, Entry2_16, Entry3_16, Entry4_16
+					.long	Entry5_16, Entry6_16, Entry7_16, Entry8_16
+					.long	Entry9_16, Entry10_16, Entry11_16, Entry12_16
+					.long	Entry13_16, Entry14_16, Entry15_16, Entry16_16
+
+//-------------------------------------------------------
+// local variables for d_parta.s
+//-------------------------------------------------------
+.globl	DP_Count, DP_u, DP_v, DP_32768, DP_Color, DP_Pix, DP_EntryTable
+DP_Count:		.long	0
+DP_u:			.long	0
+DP_v:			.long	0
+DP_32768:		.single	32768.0
+DP_Color:		.long	0
+DP_Pix:			.long	0
+
+
+#if 0
+	.extern DP_1x1
+	.extern DP_2x2
+	.extern DP_3x3
+	.extern DP_4x4
+
+DP_EntryTable:	.long	DP_1x1, DP_2x2, DP_3x3, DP_4x4
+#endif
+
+//
+// advancetable is 8 bytes, but points to the middle of that range so negative
+// offsets will work
+//
+.globl	advancetable, sstep, tstep, pspantemp, counttemp, jumptemp
+advancetable:	.long	0, 0
+sstep:			.long	0
+tstep:			.long	0
+
+pspantemp:		.long	0
+counttemp:		.long	0
+jumptemp:		.long	0
+
+// 1/2, 1/3, 1/4, 1/5, 1/6, and 1/7 in 0.32 form
+.globl	reciprocal_table, entryvec_table
+reciprocal_table:	.long	0x40000000, 0x2aaaaaaa, 0x20000000
+					.long	0x19999999, 0x15555555, 0x12492492
+
+#if 0
+	.extern Entry2_8
+	.extern Entry3_8
+	.extern Entry4_8
+	.extern Entry5_8
+	.extern Entry6_8
+	.extern Entry7_8
+	.extern Entry8_8
+
+entryvec_table:	.long	0, Entry2_8, Entry3_8, Entry4_8
+				.long	Entry5_8, Entry6_8, Entry7_8, Entry8_8
+#endif
+
+#ifndef NeXT
+	.extern Spr8Entry2_8
+	.extern Spr8Entry3_8
+	.extern Spr8Entry4_8
+	.extern Spr8Entry5_8
+	.extern Spr8Entry6_8
+	.extern Spr8Entry7_8
+	.extern Spr8Entry8_8
+#endif
+	
+.globl spr8entryvec_table
+spr8entryvec_table:	.long	0, Spr8Entry2_8, Spr8Entry3_8, Spr8Entry4_8
+					.long	Spr8Entry5_8, Spr8Entry6_8, Spr8Entry7_8, Spr8Entry8_8
+
+#endif	// id386
+
+
--- /dev/null
+++ b/linux/rw_in_svgalib.c
@@ -1,0 +1,374 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/mman.h>
+
+#include <asm/io.h>
+
+#include "vga.h"
+#include "vgakeyboard.h"
+#include "vgamouse.h"
+
+#include "../ref_soft/r_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+/*****************************************************************************/
+/* KEYBOARD                                                                  */
+/*****************************************************************************/
+
+static unsigned char scantokey[128];
+Key_Event_fp_t Key_Event_fp;
+
+static void keyhandler(int scancode, int state)
+{
+	int sc;
+
+	sc = scancode & 0x7f;
+//ri.Con_Printf(PRINT_ALL, "scancode=%x (%d%s)\n", scancode, sc, scancode&0x80?"+128":"");
+	Key_Event_fp(scantokey[sc], state == KEY_EVENTPRESS);
+}
+
+void KBD_Init(Key_Event_fp_t fp)
+{
+	int i;
+
+	Key_Event_fp = fp;
+
+	for (i=0 ; i<128 ; i++)
+		scantokey[i] = ' ';
+
+	scantokey[  1] = K_ESCAPE;
+	scantokey[  2] = '1';
+	scantokey[  3] = '2';
+	scantokey[  4] = '3';
+	scantokey[  5] = '4';
+	scantokey[  6] = '5';
+	scantokey[  7] = '6';
+	scantokey[  8] = '7';
+	scantokey[  9] = '8';
+	scantokey[ 10] = '9';
+	scantokey[ 11] = '0';
+	scantokey[ 12] = '-';
+	scantokey[ 13] = '=';
+	scantokey[ 14] = K_BACKSPACE;
+	scantokey[ 15] = K_TAB;
+	scantokey[ 16] = 'q';       
+	scantokey[ 17] = 'w';       
+	scantokey[ 18] = 'e';       
+	scantokey[ 19] = 'r';       
+	scantokey[ 20] = 't';       
+	scantokey[ 21] = 'y';       
+	scantokey[ 22] = 'u';       
+	scantokey[ 23] = 'i';       
+	scantokey[ 24] = 'o';       
+	scantokey[ 25] = 'p';       
+	scantokey[ 26] = '[';
+	scantokey[ 27] = ']';
+	scantokey[ 28] = K_ENTER;
+	scantokey[ 29] = K_CTRL; //left
+	scantokey[ 30] = 'a';
+	scantokey[ 31] = 's';       
+	scantokey[ 32] = 'd';       
+	scantokey[ 33] = 'f';       
+	scantokey[ 34] = 'g';       
+	scantokey[ 35] = 'h';       
+	scantokey[ 36] = 'j';       
+	scantokey[ 37] = 'k';       
+	scantokey[ 38] = 'l';       
+	scantokey[ 39] = ';';
+	scantokey[ 40] = '\'';
+	scantokey[ 41] = '`';
+	scantokey[ 42] = K_SHIFT; //left
+	scantokey[ 43] = '\\';
+	scantokey[ 44] = 'z';       
+	scantokey[ 45] = 'x';  
+	scantokey[ 46] = 'c';
+	scantokey[ 47] = 'v';       
+	scantokey[ 48] = 'b';
+	scantokey[ 49] = 'n';       
+	scantokey[ 50] = 'm';       
+	scantokey[ 51] = ',';
+	scantokey[ 52] = '.';
+	scantokey[ 53] = '/';
+	scantokey[ 54] = K_SHIFT; //right
+	scantokey[ 55] = '*'; //keypad
+	scantokey[ 56] = K_ALT; //left
+	scantokey[ 57] = ' ';
+	// 58 caps lock
+	scantokey[ 59] = K_F1;
+	scantokey[ 60] = K_F2;
+	scantokey[ 61] = K_F3;
+	scantokey[ 62] = K_F4;
+	scantokey[ 63] = K_F5;
+	scantokey[ 64] = K_F6;
+	scantokey[ 65] = K_F7;
+	scantokey[ 66] = K_F8;
+	scantokey[ 67] = K_F9;
+	scantokey[ 68] = K_F10;
+	// 69 numlock
+	// 70 scrollock
+	scantokey[ 71] = K_KP_HOME;
+	scantokey[ 72] = K_KP_UPARROW;
+	scantokey[ 73] = K_KP_PGUP;
+	scantokey[ 74] = K_KP_MINUS;
+	scantokey[ 75] = K_KP_LEFTARROW;
+	scantokey[ 76] = K_KP_5;
+	scantokey[ 77] = K_KP_RIGHTARROW;
+	scantokey[ 79] = K_KP_END;
+	scantokey[ 78] = K_KP_PLUS;
+	scantokey[ 80] = K_KP_DOWNARROW;
+	scantokey[ 81] = K_KP_PGDN;
+	scantokey[ 82] = K_KP_INS;
+	scantokey[ 83] = K_KP_DEL;
+	// 84 to 86 not used
+	scantokey[ 87] = K_F11;
+	scantokey[ 88] = K_F12;
+	// 89 to 95 not used
+	scantokey[ 96] = K_KP_ENTER; //keypad enter
+	scantokey[ 97] = K_CTRL; //right
+	scantokey[ 98] = K_KP_SLASH;
+	scantokey[ 99] = K_F12; // print screen, bind to screenshot by default
+	scantokey[100] = K_ALT; // right
+
+	scantokey[101] = K_PAUSE; // break
+	scantokey[102] = K_HOME;
+	scantokey[103] = K_UPARROW;
+	scantokey[104] = K_PGUP;
+	scantokey[105] = K_LEFTARROW;
+	scantokey[106] = K_RIGHTARROW;
+	scantokey[107] = K_END;
+	scantokey[108] = K_DOWNARROW;
+	scantokey[109] = K_PGDN;
+	scantokey[110] = K_INS;
+	scantokey[111] = K_DEL;
+
+	scantokey[119] = K_PAUSE;
+
+	if (keyboard_init())
+		Sys_Error("keyboard_init() failed");
+	keyboard_seteventhandler(keyhandler);
+	keyboard_translatekeys(DONT_CATCH_CTRLC);
+}
+
+void KBD_Update(void)
+{
+	while (keyboard_update())
+		;
+}
+
+void KBD_Close(void)
+{
+	keyboard_close();
+}
+
+/*****************************************************************************/
+/* MOUSE                                                                     */
+/*****************************************************************************/
+
+// this is inside the renderer shared lib, so these are called from vid_so
+
+static qboolean	UseMouse = true;
+
+static int		mouserate = MOUSE_DEFAULTSAMPLERATE;
+
+static int     mouse_buttons;
+static int     mouse_buttonstate;
+static int     mouse_oldbuttonstate;
+static float   mouse_x, mouse_y;
+static float	old_mouse_x, old_mouse_y;
+static int		mx, my;
+
+static cvar_t	*m_filter;
+static cvar_t	*in_mouse;
+
+static cvar_t	*mdev;
+static cvar_t	*mrate;
+
+static qboolean	mlooking;
+
+// state struct passed in Init
+static in_state_t	*in_state;
+
+static cvar_t *sensitivity;
+static cvar_t *lookstrafe;
+static cvar_t *m_side;
+static cvar_t *m_yaw;
+static cvar_t *m_pitch;
+static cvar_t *m_forward;
+static cvar_t *freelook;
+
+static void Force_CenterView_f (void)
+{
+	in_state->viewangles[PITCH] = 0;
+}
+
+static void RW_IN_MLookDown (void) 
+{ 
+	mlooking = true; 
+}
+
+static void RW_IN_MLookUp (void) 
+{
+	mlooking = false;
+	in_state->IN_CenterView_fp ();
+}
+
+static void mousehandler(int buttonstate, int dx, int dy)
+{
+	mouse_buttonstate = buttonstate;
+	mx += dx;
+	my += dy;
+}
+
+void RW_IN_Init(in_state_t *in_state_p)
+{
+	int mtype;
+	int i;
+
+	in_state = in_state_p;
+
+	// mouse variables
+	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
+    in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
+	freelook = ri.Cvar_Get( "freelook", "0", 0 );
+	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
+	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
+	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
+	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
+	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
+	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
+
+	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
+	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
+
+	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
+
+	mouse_buttons = 3;
+
+	mtype = vga_getmousetype();
+
+	mdev = ri.Cvar_Get ("mdev", "/dev/mouse", 0);
+	mrate = ri.Cvar_Get ("mrate", "1200", 0);
+
+//		printf("Mouse: dev=%s,type=%s,speed=%d\n",
+//			mousedev, mice[mtype].name, mouserate);
+
+	if (mouse_init(mdev->string, mtype, (int)mrate->value))
+	{
+		ri.Con_Printf(PRINT_ALL, "No mouse found\n");
+		UseMouse = false;
+	}
+	else
+		mouse_seteventhandler(mousehandler);
+}
+
+void RW_IN_Shutdown(void)
+{
+	mouse_close();
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void RW_IN_Commands (void)
+{
+	if (!UseMouse)
+		return;
+
+	// poll mouse values
+	mouse_update();
+
+	// perform button actions
+	if ((mouse_buttonstate & MOUSE_LEFTBUTTON) &&
+		!(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
+		in_state->Key_Event_fp (K_MOUSE1, true);
+	else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) &&
+		(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
+		in_state->Key_Event_fp (K_MOUSE1, false);
+
+	if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
+		!(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
+		in_state->Key_Event_fp (K_MOUSE2, true);
+	else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
+		(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
+		in_state->Key_Event_fp (K_MOUSE2, false);
+
+	if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
+		!(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
+		Key_Event_fp (K_MOUSE3, true);
+	else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
+		(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
+		in_state->Key_Event_fp (K_MOUSE3, false);
+
+	mouse_oldbuttonstate = mouse_buttonstate;
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void RW_IN_Move (usercmd_t *cmd)
+{
+	if (!UseMouse)
+		return;
+
+	// poll mouse values
+	mouse_update();
+
+	if (m_filter->value)
+	{
+		mouse_x = (mx + old_mouse_x) * 0.5;
+		mouse_y = (my + old_mouse_y) * 0.5;
+	}
+	else
+	{
+		mouse_x = mx;
+		mouse_y = my;
+	}
+	old_mouse_x = mx;
+	old_mouse_y = my;
+
+	if (!mx && !my)
+		return;
+
+	mx = my = 0; // clear for next update
+
+	mouse_x *= sensitivity->value;
+	mouse_y *= sensitivity->value;
+
+// add mouse X/Y movement to cmd
+	if ( (*in_state->in_strafe_state & 1) || 
+		(lookstrafe->value && mlooking ))
+		cmd->sidemove += m_side->value * mouse_x;
+	else
+		in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
+
+	if ( (mlooking || freelook->value) && 
+		!(*in_state->in_strafe_state & 1))
+	{
+		in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
+	}
+	else
+	{
+		cmd->forwardmove -= m_forward->value * mouse_y;
+	}
+}
+
+void RW_IN_Frame (void)
+{
+}
+
+void RW_IN_Activate(void)
+{
+}
+
+
+
--- /dev/null
+++ b/linux/rw_linux.h
@@ -1,0 +1,16 @@
+
+
+typedef void (*Key_Event_fp_t)(int key, qboolean down);
+
+extern void (*KBD_Update_fp)(void);
+extern void (*KBD_Init_fp)(Key_Event_fp_t fp);
+extern void (*KBD_Close_fp)(void);
+
+typedef struct in_state {
+	// Pointers to functions back in client, set by vid_so
+	void (*IN_CenterView_fp)(void);
+	Key_Event_fp_t Key_Event_fp;
+	vec_t *viewangles;
+	int *in_strafe_state;
+} in_state_t;
+
--- /dev/null
+++ b/linux/rw_svgalib.c
@@ -1,0 +1,311 @@
+/*
+** RW_SVGALBI.C
+**
+** This file contains ALL Linux specific stuff having to do with the
+** software refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** SWimp_EndFrame
+** SWimp_Init
+** SWimp_InitGraphics
+** SWimp_SetPalette
+** SWimp_Shutdown
+** SWimp_SwitchFullscreen
+*/
+
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/mman.h>
+
+#include <asm/io.h>
+
+#include "vga.h"
+#include "vgakeyboard.h"
+#include "vgamouse.h"
+
+#include "../ref_soft/r_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+/*****************************************************************************/
+
+int		VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
+byte	*VGA_pagebase;
+char	*framebuffer_ptr;
+
+void VGA_UpdatePlanarScreen (void *srcbuffer);
+
+int num_modes;
+vga_modeinfo *modes;
+int current_mode;
+
+// Console variables that we need to access from this module
+
+/*****************************************************************************/
+
+void VID_InitModes(void)
+{
+
+int i;
+
+	// get complete information on all modes
+
+	num_modes = vga_lastmodenumber()+1;
+	modes = malloc(num_modes * sizeof(vga_modeinfo));
+	for (i=0 ; i<num_modes ; i++)
+	{
+		if (vga_hasmode(i))
+			memcpy(&modes[i], vga_getmodeinfo(i), sizeof (vga_modeinfo));
+		else
+			modes[i].width = 0; // means not available
+	}
+
+	// filter for modes i don't support
+
+	for (i=0 ; i<num_modes ; i++)
+	{
+		if (modes[i].bytesperpixel != 1 && modes[i].colors != 256) 
+			modes[i].width = 0;
+	}
+
+	for (i = 0; i < num_modes; i++)
+		if (modes[i].width)
+			ri.Con_Printf(PRINT_ALL, "mode %d: %d %d\n", modes[i].width, modes[i].height);
+
+}
+
+/*
+** SWimp_Init
+**
+** This routine is responsible for initializing the implementation
+** specific stuff in a software rendering subsystem.
+*/
+int SWimp_Init( void *hInstance, void *wndProc )
+{
+	vga_init();
+
+	VID_InitModes();
+
+	return true;
+}
+
+int get_mode(int width, int height)
+{
+
+	int i;
+	int ok, match;
+
+	for (i=0 ; i<num_modes ; i++)
+		if (modes[i].width &&
+			modes[i].width == width && modes[i].height == height)
+				break;
+	if (i==num_modes)
+		return -1; // not found
+
+	return i;
+}
+
+/*
+** SWimp_InitGraphics
+**
+** This initializes the software refresh's implementation specific
+** graphics subsystem.  In the case of Windows it creates DIB or
+** DDRAW surfaces.
+**
+** The necessary width and height parameters are grabbed from
+** vid.width and vid.height.
+*/
+static qboolean SWimp_InitGraphics( qboolean fullscreen )
+{
+	int bsize, zsize, tsize;
+
+	SWimp_Shutdown();
+
+	current_mode = get_mode(vid.width, vid.height);
+
+	if (current_mode < 0) {
+		ri.Con_Printf (PRINT_ALL, "Mode %d %d not found\n", vid.width, vid.height);
+		return false; // mode not found
+	}
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (vid.width, vid.height);
+
+	ri.Con_Printf (PRINT_ALL, "Setting VGAMode: %d\n", current_mode );
+
+//	Cvar_SetValue ("vid_mode", (float)modenum);
+	
+	VGA_width = modes[current_mode].width;
+	VGA_height = modes[current_mode].height;
+	VGA_planar = modes[current_mode].bytesperpixel == 0;
+	VGA_rowbytes = modes[current_mode].linewidth;
+
+	vid.rowbytes = modes[current_mode].linewidth;
+
+	if (VGA_planar) {
+		VGA_bufferrowbytes = modes[current_mode].linewidth * 4;
+		vid.rowbytes = modes[current_mode].linewidth*4;
+	}
+
+// get goin'
+
+	vga_setmode(current_mode);
+
+	VGA_pagebase = framebuffer_ptr = (char *) vga_getgraphmem();
+//		if (vga_setlinearaddressing()>0)
+//			framebuffer_ptr = (char *) vga_getgraphmem();
+	if (!framebuffer_ptr)
+		Sys_Error("This mode isn't hapnin'\n");
+
+	vga_setpage(0);
+
+	vid.buffer = malloc(vid.rowbytes * vid.height);
+	if (!vid.buffer)
+		Sys_Error("Unabled to alloc vid.buffer!\n");
+
+	return true;
+}
+
+/*
+** SWimp_EndFrame
+**
+** This does an implementation specific copy from the backbuffer to the
+** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
+** on whether we're using DIB sections/GDI or DDRAW.
+*/
+void SWimp_EndFrame (void)
+{
+	if (!vga_oktowrite())
+		return; // can't update screen if it's not active
+
+//	if (vid_waitforrefresh.value)
+//		vga_waitretrace();
+
+	if (VGA_planar)
+		VGA_UpdatePlanarScreen (vid.buffer);
+
+	else {
+		int total = vid.rowbytes * vid.height;
+		int offset;
+
+		for (offset=0;offset<total;offset+=0x10000) {
+			vga_setpage(offset/0x10000);
+			memcpy(framebuffer_ptr,
+					vid.buffer + offset,
+					((total-offset>0x10000)?0x10000:(total-offset)));
+		}
+	} 
+}
+
+/*
+** SWimp_SetMode
+*/
+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+	rserr_t retval = rserr_ok;
+
+	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
+
+	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
+	{
+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+		return rserr_invalid_mode;
+	}
+
+	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
+
+	if ( !SWimp_InitGraphics( false ) ) {
+		// failed to set a valid mode in windowed mode
+		return rserr_invalid_mode;
+	}
+
+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+	return retval;
+}
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine.  A NULL palette means
+** to use the existing palette.  The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+void SWimp_SetPalette( const unsigned char *palette )
+{
+	static int tmppal[256*3];
+	const unsigned char *pal;
+	int *tp;
+	int i;
+
+    if ( !palette )
+        palette = ( const unsigned char * ) sw_state.currentpalette;
+ 
+	if (vga_getcolors() == 256)
+	{
+		tp = tmppal;
+		pal = palette;
+
+		for (i=0 ; i < 256 ; i++, pal += 4, tp += 3) {
+			tp[0] = pal[0] >> 2;
+			tp[1] = pal[1] >> 2;
+			tp[2] = pal[2] >> 2;
+		}
+
+		if (vga_oktowrite())
+			vga_setpalvec(0, 256, tmppal);
+	}
+}
+
+/*
+** SWimp_Shutdown
+**
+** System specific graphics subsystem shutdown routine.  Destroys
+** DIBs or DDRAW surfaces as appropriate.
+*/
+void SWimp_Shutdown( void )
+{
+	if (vid.buffer) {
+		free(vid.buffer);
+		vid.buffer = NULL;
+	}
+	vga_setmode(TEXT);
+}
+
+/*
+** SWimp_AppActivate
+*/
+void SWimp_AppActivate( qboolean active )
+{
+}
+
+//===============================================================================
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+	int r;
+	unsigned long addr;
+	int psize = getpagesize();
+
+	addr = (startaddr & ~(psize-1)) - psize;
+
+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+//			addr, startaddr+length, length);
+
+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+	if (r < 0)
+    		Sys_Error("Protection change failed\n");
+}
+
--- /dev/null
+++ b/linux/rw_x11.c
@@ -1,0 +1,1093 @@
+/*
+** RW_X11.C
+**
+** This file contains ALL Linux specific stuff having to do with the
+** software refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** SWimp_EndFrame
+** SWimp_Init
+** SWimp_InitGraphics
+** SWimp_SetPalette
+** SWimp_Shutdown
+** SWimp_SwitchFullscreen
+*/
+
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+
+#include "../ref_soft/r_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+/*****************************************************************************/
+
+static qboolean			doShm;
+static Display			*x_disp;
+static Colormap			x_cmap;
+static Window			x_win;
+static GC				x_gc;
+static Visual			*x_vis;
+static XVisualInfo		*x_visinfo;
+//static XImage			*x_image;
+
+#define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \
+	     | KeyReleaseMask | ExposureMask | PointerMotionMask | \
+	     ButtonPressMask | ButtonReleaseMask)
+
+static int				x_shmeventtype;
+//static XShmSegmentInfo	x_shminfo;
+
+static qboolean			oktodraw = false;
+static qboolean			X11_active = false;
+
+int XShmQueryExtension(Display *);
+int XShmGetEventBase(Display *);
+
+int current_framebuffer;
+static XImage			*x_framebuffer[2] = { 0, 0 };
+static XShmSegmentInfo	x_shminfo[2];
+
+struct
+{
+	int key;
+	int down;
+} keyq[64];
+int keyq_head=0;
+int keyq_tail=0;
+
+int config_notify=0;
+int config_notify_width;
+int config_notify_height;
+						      
+typedef unsigned short PIXEL;
+
+// Console variables that we need to access from this module
+
+/*****************************************************************************/
+/* MOUSE                                                                     */
+/*****************************************************************************/
+
+// this is inside the renderer shared lib, so these are called from vid_so
+
+static qboolean        mouse_avail;
+static int     mouse_buttonstate;
+static int     mouse_oldbuttonstate;
+static int   mouse_x, mouse_y;
+static int	old_mouse_x, old_mouse_y;
+static int		mx, my;
+static float old_windowed_mouse;
+static int p_mouse_x, p_mouse_y;
+
+static cvar_t	*_windowed_mouse;
+static cvar_t	*m_filter;
+static cvar_t	*in_mouse;
+
+static qboolean	mlooking;
+
+// state struct passed in Init
+static in_state_t	*in_state;
+
+static cvar_t *sensitivity;
+static cvar_t *lookstrafe;
+static cvar_t *m_side;
+static cvar_t *m_yaw;
+static cvar_t *m_pitch;
+static cvar_t *m_forward;
+static cvar_t *freelook;
+
+static void Force_CenterView_f (void)
+{
+	in_state->viewangles[PITCH] = 0;
+}
+
+static void RW_IN_MLookDown (void) 
+{ 
+	mlooking = true; 
+}
+
+static void RW_IN_MLookUp (void) 
+{
+	mlooking = false;
+	in_state->IN_CenterView_fp ();
+}
+
+void RW_IN_Init(in_state_t *in_state_p)
+{
+	int mtype;
+	int i;
+
+	in_state = in_state_p;
+
+	// mouse variables
+	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
+	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
+    in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
+	freelook = ri.Cvar_Get( "freelook", "0", 0 );
+	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
+	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
+	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
+	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
+	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
+	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
+
+	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
+	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
+
+	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
+
+	mouse_x = mouse_y = 0.0;
+	mouse_avail = true;
+}
+
+void RW_IN_Shutdown(void)
+{
+	mouse_avail = false;
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void RW_IN_Commands (void)
+{
+	int i;
+   
+	if (!mouse_avail) 
+		return;
+   
+	for (i=0 ; i<3 ; i++) {
+		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
+			in_state->Key_Event_fp (K_MOUSE1 + i, true);
+
+		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
+			in_state->Key_Event_fp (K_MOUSE1 + i, false);
+	}
+	mouse_oldbuttonstate = mouse_buttonstate;
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void RW_IN_Move (usercmd_t *cmd)
+{
+	if (!mouse_avail)
+		return;
+   
+	if (m_filter->value)
+	{
+		mouse_x = (mx + old_mouse_x) * 0.5;
+		mouse_y = (my + old_mouse_y) * 0.5;
+	} else {
+		mouse_x = mx;
+		mouse_y = my;
+	}
+
+	old_mouse_x = mx;
+	old_mouse_y = my;
+
+	if (!mouse_x && !mouse_y)
+		return;
+
+	mouse_x *= sensitivity->value;
+	mouse_y *= sensitivity->value;
+
+// add mouse X/Y movement to cmd
+	if ( (*in_state->in_strafe_state & 1) || 
+		(lookstrafe->value && mlooking ))
+		cmd->sidemove += m_side->value * mouse_x;
+	else
+		in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
+
+	if ( (mlooking || freelook->value) && 
+		!(*in_state->in_strafe_state & 1))
+	{
+		in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
+	}
+	else
+	{
+		cmd->forwardmove -= m_forward->value * mouse_y;
+	}
+	mx = my = 0;
+}
+
+void RW_IN_Frame (void)
+{
+}
+
+void RW_IN_Activate(void)
+{
+}
+
+/*****************************************************************************/
+
+static PIXEL st2d_8to16table[256];
+static int shiftmask_fl=0;
+static long r_shift,g_shift,b_shift;
+static unsigned long r_mask,g_mask,b_mask;
+
+void shiftmask_init()
+{
+    unsigned int x;
+    r_mask=x_vis->red_mask;
+    g_mask=x_vis->green_mask;
+    b_mask=x_vis->blue_mask;
+    for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
+    for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
+    for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
+    shiftmask_fl=1;
+}
+
+PIXEL xlib_rgb(int r,int g,int b)
+{
+    PIXEL p;
+    if(shiftmask_fl==0) shiftmask_init();
+    p=0;
+
+    if(r_shift>0) {
+        p=(r<<(r_shift))&r_mask;
+    } else if(r_shift<0) {
+        p=(r>>(-r_shift))&r_mask;
+    } else p|=(r&r_mask);
+
+    if(g_shift>0) {
+        p|=(g<<(g_shift))&g_mask;
+    } else if(g_shift<0) {
+        p|=(g>>(-g_shift))&g_mask;
+    } else p|=(g&g_mask);
+
+    if(b_shift>0) {
+        p|=(b<<(b_shift))&b_mask;
+    } else if(b_shift<0) {
+        p|=(b>>(-b_shift))&b_mask;
+    } else p|=(b&b_mask);
+
+    return p;
+}
+
+void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
+{
+	int xi,yi;
+	unsigned char *src;
+	PIXEL *dest;
+
+	if( (x<0)||(y<0) )return;
+
+	for (yi = y; yi < (y+height); yi++) {
+		src = &framebuf->data [yi * framebuf->bytes_per_line];
+		dest = (PIXEL*)src;
+		for(xi = (x+width-1); xi >= x; xi -= 8) {
+			dest[xi  ] = st2d_8to16table[src[xi  ]];
+			dest[xi-1] = st2d_8to16table[src[xi-1]];
+			dest[xi-2] = st2d_8to16table[src[xi-2]];
+			dest[xi-3] = st2d_8to16table[src[xi-3]];
+			dest[xi-4] = st2d_8to16table[src[xi-4]];
+			dest[xi-5] = st2d_8to16table[src[xi-5]];
+			dest[xi-6] = st2d_8to16table[src[xi-6]];
+			dest[xi-7] = st2d_8to16table[src[xi-7]];
+		}
+	}
+}
+
+// ========================================================================
+// makes a null cursor
+// ========================================================================
+
+static Cursor CreateNullCursor(Display *display, Window root)
+{
+    Pixmap cursormask; 
+    XGCValues xgc;
+    GC gc;
+    XColor dummycolour;
+    Cursor cursor;
+
+    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
+    xgc.function = GXclear;
+    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
+    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
+    dummycolour.pixel = 0;
+    dummycolour.red = 0;
+    dummycolour.flags = 04;
+    cursor = XCreatePixmapCursor(display, cursormask, cursormask,
+          &dummycolour,&dummycolour, 0,0);
+    XFreePixmap(display,cursormask);
+    XFreeGC(display,gc);
+    return cursor;
+}
+
+void ResetFrameBuffer(void)
+{
+	int mem;
+	int pwidth;
+
+	if (x_framebuffer[0])
+	{
+		free(x_framebuffer[0]->data);
+		free(x_framebuffer[0]);
+	}
+
+// alloc an extra line in case we want to wrap, and allocate the z-buffer
+	pwidth = x_visinfo->depth / 8;
+	if (pwidth == 3) pwidth = 4;
+	mem = ((vid.width*pwidth+7)&~7) * vid.height;
+
+	x_framebuffer[0] = XCreateImage(	x_disp,
+		x_vis,
+		x_visinfo->depth,
+		ZPixmap,
+		0,
+		malloc(mem),
+		vid.width, vid.height,
+		32,
+		0);
+
+	if (!x_framebuffer[0])
+		Sys_Error("VID: XCreateImage failed\n");
+
+	vid.buffer = (byte*) (x_framebuffer[0]);
+}
+
+void ResetSharedFrameBuffers(void)
+{
+	int size;
+	int key;
+	int minsize = getpagesize();
+	int frm;
+
+	for (frm=0 ; frm<2 ; frm++)
+	{
+	// free up old frame buffer memory
+		if (x_framebuffer[frm])
+		{
+			XShmDetach(x_disp, &x_shminfo[frm]);
+			free(x_framebuffer[frm]);
+			shmdt(x_shminfo[frm].shmaddr);
+		}
+
+	// create the image
+		x_framebuffer[frm] = XShmCreateImage(	x_disp,
+						x_vis,
+						x_visinfo->depth,
+						ZPixmap,
+						0,
+						&x_shminfo[frm],
+						vid.width,
+						vid.height );
+
+	// grab shared memory
+
+		size = x_framebuffer[frm]->bytes_per_line
+			* x_framebuffer[frm]->height;
+		if (size < minsize)
+			Sys_Error("VID: Window must use at least %d bytes\n", minsize);
+
+		key = random();
+		x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
+		if (x_shminfo[frm].shmid==-1)
+			Sys_Error("VID: Could not get any shared memory\n");
+
+		// attach to the shared memory segment
+		x_shminfo[frm].shmaddr =
+			(void *) shmat(x_shminfo[frm].shmid, 0, 0);
+
+		ri.Con_Printf(PRINT_ALL, 
+			"MITSHM shared memory (id=%d, addr=0x%lx)\n", 
+			x_shminfo[frm].shmid,
+			(long) x_shminfo[frm].shmaddr);
+
+		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
+
+	// get the X server to attach to it
+
+		if (!XShmAttach(x_disp, &x_shminfo[frm]))
+			Sys_Error("VID: XShmAttach() failed\n");
+		XSync(x_disp, 0);
+		shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
+	}
+
+}
+
+// ========================================================================
+// Tragic death handler
+// ========================================================================
+
+void TragicDeath(int signal_num)
+{
+	XAutoRepeatOn(x_disp);
+	XCloseDisplay(x_disp);
+	Sys_Error("This death brought to you by the number %d\n", signal_num);
+}
+
+int XLateKey(XKeyEvent *ev)
+{
+
+	int key;
+	char buf[64];
+	KeySym keysym;
+
+	key = 0;
+
+	XLookupString(ev, buf, sizeof buf, &keysym, 0);
+
+	switch(keysym)
+	{
+		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;
+		case XK_Page_Up:	 key = K_PGUP; break;
+
+		case XK_KP_Page_Down: key = K_KP_PGDN; break;
+		case XK_Page_Down:	 key = K_PGDN; break;
+
+		case XK_KP_Home: key = K_KP_HOME; break;
+		case XK_Home:	 key = K_HOME; break;
+
+		case XK_KP_End:  key = K_KP_END; break;
+		case XK_End:	 key = K_END; break;
+
+		case XK_KP_Left: key = K_KP_LEFTARROW; break;
+		case XK_Left:	 key = K_LEFTARROW; break;
+
+		case XK_KP_Right: key = K_KP_RIGHTARROW; break;
+		case XK_Right:	key = K_RIGHTARROW;		break;
+
+		case XK_KP_Down: key = K_KP_DOWNARROW; break;
+		case XK_Down:	 key = K_DOWNARROW; break;
+
+		case XK_KP_Up:   key = K_KP_UPARROW; break;
+		case XK_Up:		 key = K_UPARROW;	 break;
+
+		case XK_Escape: key = K_ESCAPE;		break;
+
+		case XK_KP_Enter: key = K_KP_ENTER;	break;
+		case XK_Return: key = K_ENTER;		 break;
+
+		case XK_Tab:		key = K_TAB;			 break;
+
+		case XK_F1:		 key = K_F1;				break;
+
+		case XK_F2:		 key = K_F2;				break;
+
+		case XK_F3:		 key = K_F3;				break;
+
+		case XK_F4:		 key = K_F4;				break;
+
+		case XK_F5:		 key = K_F5;				break;
+
+		case XK_F6:		 key = K_F6;				break;
+
+		case XK_F7:		 key = K_F7;				break;
+
+		case XK_F8:		 key = K_F8;				break;
+
+		case XK_F9:		 key = K_F9;				break;
+
+		case XK_F10:		key = K_F10;			 break;
+
+		case XK_F11:		key = K_F11;			 break;
+
+		case XK_F12:		key = K_F12;			 break;
+
+		case XK_BackSpace: key = K_BACKSPACE; break;
+
+		case XK_KP_Delete: key = K_KP_DEL; break;
+		case XK_Delete: key = K_DEL; break;
+
+		case XK_Pause:	key = K_PAUSE;		 break;
+
+		case XK_Shift_L:
+		case XK_Shift_R:	key = K_SHIFT;		break;
+
+		case XK_Execute: 
+		case XK_Control_L: 
+		case XK_Control_R:	key = K_CTRL;		 break;
+
+		case XK_Alt_L:	
+		case XK_Meta_L: 
+		case XK_Alt_R:	
+		case XK_Meta_R: key = K_ALT;			break;
+
+		case XK_KP_Begin: key = K_KP_5;	break;
+
+		case XK_Insert:key = K_INS; break;
+		case XK_KP_Insert: key = K_KP_INS; break;
+
+		case XK_KP_Multiply: key = '*'; break;
+		case XK_KP_Add:  key = K_KP_PLUS; break;
+		case XK_KP_Subtract: key = K_KP_MINUS; break;
+		case XK_KP_Divide: key = K_KP_SLASH; break;
+
+#if 0
+		case 0x021: key = '1';break;/* [!] */
+		case 0x040: key = '2';break;/* [@] */
+		case 0x023: key = '3';break;/* [#] */
+		case 0x024: key = '4';break;/* [$] */
+		case 0x025: key = '5';break;/* [%] */
+		case 0x05e: key = '6';break;/* [^] */
+		case 0x026: key = '7';break;/* [&] */
+		case 0x02a: key = '8';break;/* [*] */
+		case 0x028: key = '9';;break;/* [(] */
+		case 0x029: key = '0';break;/* [)] */
+		case 0x05f: key = '-';break;/* [_] */
+		case 0x02b: key = '=';break;/* [+] */
+		case 0x07c: key = '\'';break;/* [|] */
+		case 0x07d: key = '[';break;/* [}] */
+		case 0x07b: key = ']';break;/* [{] */
+		case 0x022: key = '\'';break;/* ["] */
+		case 0x03a: key = ';';break;/* [:] */
+		case 0x03f: key = '/';break;/* [?] */
+		case 0x03e: key = '.';break;/* [>] */
+		case 0x03c: key = ',';break;/* [<] */
+#endif
+
+		default:
+			key = *(unsigned char*)buf;
+			if (key >= 'A' && key <= 'Z')
+				key = key - 'A' + 'a';
+			break;
+	} 
+
+	return key;
+}
+
+void GetEvent(void)
+{
+	XEvent x_event;
+	int b;
+   
+	XNextEvent(x_disp, &x_event);
+	switch(x_event.type) {
+	case KeyPress:
+		keyq[keyq_head].key = XLateKey(&x_event.xkey);
+		keyq[keyq_head].down = true;
+		keyq_head = (keyq_head + 1) & 63;
+		break;
+	case KeyRelease:
+		keyq[keyq_head].key = XLateKey(&x_event.xkey);
+		keyq[keyq_head].down = false;
+		keyq_head = (keyq_head + 1) & 63;
+		break;
+
+	case MotionNotify:
+		if (_windowed_mouse->value) {
+			mx += ((int)x_event.xmotion.x - (int)(vid.width/2));
+			my += ((int)x_event.xmotion.y - (int)(vid.height/2));
+
+			/* move the mouse to the window center again */
+			XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
+			XWarpPointer(x_disp,None,x_win,0,0,0,0, 
+				(vid.width/2),(vid.height/2));
+			XSelectInput(x_disp,x_win, STD_EVENT_MASK);
+		} else {
+			mx = ((int)x_event.xmotion.x - (int)p_mouse_x);
+			my = ((int)x_event.xmotion.y - (int)p_mouse_y);
+			p_mouse_x=x_event.xmotion.x;
+			p_mouse_y=x_event.xmotion.y;
+		}
+		break;
+
+	case ButtonPress:
+		b=-1;
+		if (x_event.xbutton.button == 1)
+			b = 0;
+		else if (x_event.xbutton.button == 2)
+			b = 2;
+		else if (x_event.xbutton.button == 3)
+			b = 1;
+		if (b>=0)
+			mouse_buttonstate |= 1<<b;
+		break;
+
+	case ButtonRelease:
+		b=-1;
+		if (x_event.xbutton.button == 1)
+			b = 0;
+		else if (x_event.xbutton.button == 2)
+			b = 2;
+		else if (x_event.xbutton.button == 3)
+			b = 1;
+		if (b>=0)
+			mouse_buttonstate &= ~(1<<b);
+		break;
+	
+	case ConfigureNotify:
+		config_notify_width = x_event.xconfigure.width;
+		config_notify_height = x_event.xconfigure.height;
+		config_notify = 1;
+		break;
+
+	default:
+		if (doShm && x_event.type == x_shmeventtype)
+			oktodraw = true;
+	}
+   
+	if (old_windowed_mouse != _windowed_mouse->value) {
+		old_windowed_mouse = _windowed_mouse->value;
+
+		if (!_windowed_mouse->value) {
+			/* ungrab the pointer */
+			XUngrabPointer(x_disp,CurrentTime);
+		} else {
+			/* grab the pointer */
+			XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
+				GrabModeAsync,x_win,None,CurrentTime);
+		}
+	}
+}
+
+/*****************************************************************************/
+
+/*
+** SWimp_Init
+**
+** This routine is responsible for initializing the implementation
+** specific stuff in a software rendering subsystem.
+*/
+int SWimp_Init( void *hInstance, void *wndProc )
+{
+// open the display
+	x_disp = XOpenDisplay(0);
+	if (!x_disp)
+	{
+		if (getenv("DISPLAY"))
+			Sys_Error("VID: Could not open display [%s]\n",
+				getenv("DISPLAY"));
+		else
+			Sys_Error("VID: Could not open local display\n");
+	}
+
+// catch signals so i can turn on auto-repeat
+
+	{
+		struct sigaction sa;
+		sigaction(SIGINT, 0, &sa);
+		sa.sa_handler = TragicDeath;
+		sigaction(SIGINT, &sa, 0);
+		sigaction(SIGTERM, &sa, 0);
+	}
+
+	return true;
+}
+
+/*
+** SWimp_InitGraphics
+**
+** This initializes the software refresh's implementation specific
+** graphics subsystem.  In the case of Windows it creates DIB or
+** DDRAW surfaces.
+**
+** The necessary width and height parameters are grabbed from
+** vid.width and vid.height.
+*/
+static qboolean SWimp_InitGraphics( qboolean fullscreen )
+{
+	int pnum, i;
+	XVisualInfo template;
+	int num_visuals;
+	int template_mask;
+
+	srandom(getpid());
+
+	// free resources in use
+	SWimp_Shutdown ();
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (vid.width, vid.height);
+
+	XAutoRepeatOff(x_disp);
+
+// for debugging only
+	XSynchronize(x_disp, True);
+
+// check for command-line window size
+	template_mask = 0;
+
+#if 0
+// specify a visual id
+	if ((pnum=COM_CheckParm("-visualid")))
+	{
+		if (pnum >= com_argc-1)
+			Sys_Error("VID: -visualid <id#>\n");
+		template.visualid = Q_atoi(com_argv[pnum+1]);
+		template_mask = VisualIDMask;
+	}
+
+// If not specified, use default visual
+	else
+#endif
+	{
+		int screen;
+		screen = XDefaultScreen(x_disp);
+		template.visualid =
+			XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
+		template_mask = VisualIDMask;
+	}
+
+// pick a visual- warn if more than one was available
+	x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
+	if (num_visuals > 1)
+	{
+		printf("Found more than one visual id at depth %d:\n", template.depth);
+		for (i=0 ; i<num_visuals ; i++)
+			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));
+	}
+	else if (num_visuals == 0)
+	{
+		if (template_mask == VisualIDMask)
+			Sys_Error("VID: Bad visual id %d\n", template.visualid);
+		else
+			Sys_Error("VID: No visuals at depth %d\n", template.depth);
+	}
+
+#if 0
+	if (verbose)
+	{
+		printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
+		printf("	screen %d\n", x_visinfo->screen);
+		printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
+		printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
+		printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
+		printf("	colormap_size %d\n", x_visinfo->colormap_size);
+		printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
+	}
+#endif
+
+	x_vis = x_visinfo->visual;
+
+// setup attributes for main window
+	{
+	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
+	   XSetWindowAttributes attribs;
+	   Colormap tmpcmap;
+	   
+	   tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
+							 x_visinfo->screen), x_vis, AllocNone);
+	   
+	   attribs.event_mask = STD_EVENT_MASK;
+	   attribs.border_pixel = 0;
+	   attribs.colormap = tmpcmap;
+
+// create the main window
+		x_win = XCreateWindow(	x_disp,
+			XRootWindow(x_disp, x_visinfo->screen),
+			0, 0,	// x, y
+			vid.width, vid.height,
+			0, // borderwidth
+			x_visinfo->depth,
+			InputOutput,
+			x_vis,
+			attribmask,
+			&attribs );
+		XStoreName(x_disp, x_win, "Quake II");
+
+		if (x_visinfo->class != TrueColor)
+			XFreeColormap(x_disp, tmpcmap);
+	}
+
+	if (x_visinfo->depth == 8)
+	{
+	// create and upload the palette
+		if (x_visinfo->class == PseudoColor)
+		{
+			x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
+			XSetWindowColormap(x_disp, x_win, x_cmap);
+		}
+
+	}
+
+// inviso cursor
+	XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
+
+// create the GC
+	{
+		XGCValues xgcvalues;
+		int valuemask = GCGraphicsExposures;
+		xgcvalues.graphics_exposures = False;
+		x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
+	}
+
+// map the window
+	XMapWindow(x_disp, x_win);
+
+// wait for first exposure event
+	{
+		XEvent event;
+		do
+		{
+			XNextEvent(x_disp, &event);
+			if (event.type == Expose && !event.xexpose.count)
+				oktodraw = true;
+		} while (!oktodraw);
+	}
+// now safe to draw
+
+// even if MITSHM is available, make sure it's a local connection
+	if (XShmQueryExtension(x_disp))
+	{
+		char *displayname;
+		doShm = true;
+		displayname = (char *) getenv("DISPLAY");
+		if (displayname)
+		{
+			char *d = displayname;
+			while (*d && (*d != ':')) d++;
+			if (*d) *d = 0;
+			if (!(!strcasecmp(displayname, "unix") || !*displayname))
+				doShm = false;
+		}
+	}
+
+	if (doShm)
+	{
+		x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
+		ResetSharedFrameBuffers();
+	}
+	else
+		ResetFrameBuffer();
+
+	current_framebuffer = 0;
+	vid.rowbytes = x_framebuffer[0]->bytes_per_line;
+	vid.buffer = x_framebuffer[0]->data;
+
+//	XSynchronize(x_disp, False);
+
+	X11_active = true;
+
+	return true;
+}
+
+/*
+** SWimp_EndFrame
+**
+** This does an implementation specific copy from the backbuffer to the
+** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
+** on whether we're using DIB sections/GDI or DDRAW.
+*/
+void SWimp_EndFrame (void)
+{
+// if the window changes dimension, skip this frame
+#if 0
+	if (config_notify)
+	{
+		fprintf(stderr, "config notify\n");
+		config_notify = 0;
+		vid.width = config_notify_width & ~7;
+		vid.height = config_notify_height;
+		if (doShm)
+			ResetSharedFrameBuffers();
+		else
+			ResetFrameBuffer();
+		vid.rowbytes = x_framebuffer[0]->bytes_per_line;
+		vid.buffer = x_framebuffer[current_framebuffer]->data;
+		vid.recalc_refdef = 1;				// force a surface cache flush
+		Con_CheckResize();
+		Con_Clear_f();
+		return;
+	}
+#endif
+
+	if (doShm)
+	{
+
+		if (x_visinfo->depth != 8)
+			st2_fixup( x_framebuffer[current_framebuffer], 
+				0, 0, vid.width, vid.height);	
+		if (!XShmPutImage(x_disp, x_win, x_gc,
+			x_framebuffer[current_framebuffer], 0, 0,
+			0, 0, vid.width, vid.height, True))
+				Sys_Error("VID_Update: XShmPutImage failed\n");
+		oktodraw = false;
+		while (!oktodraw) 
+			GetEvent();
+		current_framebuffer = !current_framebuffer;
+		vid.buffer = x_framebuffer[current_framebuffer]->data;
+		XSync(x_disp, False);
+	}
+	else
+	{
+		if (x_visinfo->depth != 8)
+			st2_fixup( x_framebuffer[current_framebuffer], 
+				0, 0, vid.width, vid.height);
+		XPutImage(x_disp, x_win, x_gc, x_framebuffer[0],
+			0, 0, 0, 0, vid.width, vid.height);
+		XSync(x_disp, False);
+	}
+}
+
+/*
+** SWimp_SetMode
+*/
+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+	rserr_t retval = rserr_ok;
+
+	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
+
+	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
+	{
+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+		return rserr_invalid_mode;
+	}
+
+	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
+
+	if ( !SWimp_InitGraphics( false ) ) {
+		// failed to set a valid mode in windowed mode
+		return rserr_invalid_mode;
+	}
+
+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+	return retval;
+}
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine.  A NULL palette means
+** to use the existing palette.  The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+void SWimp_SetPalette( const unsigned char *palette )
+{
+	int i;
+	XColor colors[256];
+
+	if (!X11_active)
+		return;
+
+    if ( !palette )
+        palette = ( const unsigned char * ) sw_state.currentpalette;
+ 
+	for(i=0;i<256;i++)
+		st2d_8to16table[i]= xlib_rgb(palette[i*4],
+			palette[i*4+1],palette[i*4+2]);
+
+	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
+	{
+		for (i=0 ; i<256 ; i++)
+		{
+			colors[i].pixel = i;
+			colors[i].flags = DoRed|DoGreen|DoBlue;
+			colors[i].red = palette[i*4] * 257;
+			colors[i].green = palette[i*4+1] * 257;
+			colors[i].blue = palette[i*4+2] * 257;
+		}
+		XStoreColors(x_disp, x_cmap, colors, 256);
+	}
+}
+
+/*
+** SWimp_Shutdown
+**
+** System specific graphics subsystem shutdown routine.  Destroys
+** DIBs or DDRAW surfaces as appropriate.
+*/
+void SWimp_Shutdown( void )
+{
+	int i;
+
+	if (!X11_active)
+		return;
+
+	if (doShm) {
+		for (i = 0; i < 2; i++)
+			if (x_framebuffer[i]) {
+				XShmDetach(x_disp, &x_shminfo[i]);
+				free(x_framebuffer[i]);
+				shmdt(x_shminfo[i].shmaddr);
+				x_framebuffer[i] = NULL;
+			}
+	} else if (x_framebuffer[0]) {
+		free(x_framebuffer[0]->data);
+		free(x_framebuffer[0]);
+		x_framebuffer[0] = NULL;
+	}
+
+	XDestroyWindow(	x_disp, x_win );
+
+	XAutoRepeatOn(x_disp);
+//	XCloseDisplay(x_disp);
+
+	X11_active = false;
+}
+
+/*
+** SWimp_AppActivate
+*/
+void SWimp_AppActivate( qboolean active )
+{
+}
+
+//===============================================================================
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+	int r;
+	unsigned long addr;
+	int psize = getpagesize();
+
+	addr = (startaddr & ~(psize-1)) - psize;
+
+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+//			addr, startaddr+length, length);
+
+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+	if (r < 0)
+    		Sys_Error("Protection change failed\n");
+
+}
+
+/*****************************************************************************/
+/* KEYBOARD                                                                  */
+/*****************************************************************************/
+
+Key_Event_fp_t Key_Event_fp;
+
+void KBD_Init(Key_Event_fp_t fp)
+{
+	Key_Event_fp = fp;
+}
+
+void KBD_Update(void)
+{
+// get events from x server
+	if (x_disp)
+	{
+		while (XPending(x_disp)) 
+			GetEvent();
+		while (keyq_head != keyq_tail)
+		{
+			Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down);
+			keyq_tail = (keyq_tail + 1) & 63;
+		}
+	}
+}
+
+void KBD_Close(void)
+{
+}
+
+
--- /dev/null
+++ b/linux/snd_linux.c
@@ -1,0 +1,266 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <linux/soundcard.h>
+#include <stdio.h>
+
+#include "../client/client.h"
+#include "../client/snd_loc.h"
+
+int audio_fd;
+int snd_inited;
+
+cvar_t *sndbits;
+cvar_t *sndspeed;
+cvar_t *sndchannels;
+cvar_t *snddevice;
+
+static int tryrates[] = { 11025, 22051, 44100, 8000 };
+
+qboolean SNDDMA_Init(void)
+{
+
+	int rc;
+    int fmt;
+	int tmp;
+    int i;
+    char *s;
+	struct audio_buf_info info;
+	int caps;
+	extern uid_t saved_euid;
+
+	if (snd_inited)
+		return;
+
+	if (!snddevice) {
+		sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
+		sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
+		sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
+		snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
+	}
+
+// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
+
+	if (!audio_fd) {
+		seteuid(saved_euid);
+
+		audio_fd = open(snddevice->string, O_RDWR);
+
+		seteuid(getuid());
+
+		if (audio_fd < 0)
+		{
+			perror(snddevice->string);
+			Com_Printf("Could not open %s\n", snddevice->string);
+			return 0;
+		}
+	}
+
+    rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
+    if (rc < 0)
+	{
+		perror(snddevice->string);
+		Com_Printf("Could not reset %s\n", snddevice->string);
+		close(audio_fd);
+		return 0;
+	}
+
+	if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
+	{
+		perror(snddevice->string);
+        Com_Printf("Sound driver too old\n");
+		close(audio_fd);
+		return 0;
+	}
+
+	if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))
+	{
+		Com_Printf("Sorry but your soundcard can't do this\n");
+		close(audio_fd);
+		return 0;
+	}
+
+    if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
+    {   
+        perror("GETOSPACE");
+		Com_Printf("Um, can't do GETOSPACE?\n");
+		close(audio_fd);
+		return 0;
+    }
+    
+// set sample bits & speed
+
+    dma.samplebits = (int)sndbits->value;
+	if (dma.samplebits != 16 && dma.samplebits != 8)
+    {
+        ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
+        if (fmt & AFMT_S16_LE) dma.samplebits = 16;
+        else if (fmt & AFMT_U8) dma.samplebits = 8;
+    }
+
+	dma.speed = (int)sndspeed->value;
+	if (!dma.speed) {
+        for (i=0 ; i<sizeof(tryrates)/4 ; i++)
+            if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) break;
+        dma.speed = tryrates[i];
+    }
+
+	dma.channels = (int)sndchannels->value;
+	if (dma.channels < 1 || dma.channels > 2)
+		dma.channels = 2;
+	
+	dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8);
+	dma.submission_chunk = 1;
+
+// memory map the dma buffer
+
+	if (!dma.buffer)
+		dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
+			* info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
+	if (!dma.buffer)
+	{
+		perror(snddevice->string);
+		Com_Printf("Could not mmap %s\n", snddevice->string);
+		close(audio_fd);
+		return 0;
+	}
+
+	tmp = 0;
+	if (dma.channels == 2)
+		tmp = 1;
+    rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
+    if (rc < 0)
+    {
+		perror(snddevice->string);
+        Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels);
+		close(audio_fd);
+        return 0;
+    }
+	if (tmp)
+		dma.channels = 2;
+	else
+		dma.channels = 1;
+
+    rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed);
+    if (rc < 0)
+    {
+		perror(snddevice->string);
+        Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed);
+		close(audio_fd);
+        return 0;
+    }
+
+    if (dma.samplebits == 16)
+    {
+        rc = AFMT_S16_LE;
+        rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
+        if (rc < 0)
+		{
+			perror(snddevice->string);
+			Com_Printf("Could not support 16-bit data.  Try 8-bit.\n");
+			close(audio_fd);
+			return 0;
+		}
+    }
+    else if (dma.samplebits == 8)
+    {
+        rc = AFMT_U8;
+        rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
+        if (rc < 0)
+		{
+			perror(snddevice->string);
+			Com_Printf("Could not support 8-bit data.\n");
+			close(audio_fd);
+			return 0;
+		}
+    }
+	else
+	{
+		perror(snddevice->string);
+		Com_Printf("%d-bit sound not supported.", dma.samplebits);
+		close(audio_fd);
+		return 0;
+	}
+
+// toggle the trigger & start her up
+
+    tmp = 0;
+    rc  = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
+	if (rc < 0)
+	{
+		perror(snddevice->string);
+		Com_Printf("Could not toggle.\n");
+		close(audio_fd);
+		return 0;
+	}
+    tmp = PCM_ENABLE_OUTPUT;
+    rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
+	if (rc < 0)
+	{
+		perror(snddevice->string);
+		Com_Printf("Could not toggle.\n");
+		close(audio_fd);
+		return 0;
+	}
+
+	dma.samplepos = 0;
+
+	snd_inited = 1;
+	return 1;
+
+}
+
+int SNDDMA_GetDMAPos(void)
+{
+
+	struct count_info count;
+
+	if (!snd_inited) return 0;
+
+	if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1)
+	{
+		perror(snddevice->string);
+		Com_Printf("Uh, sound dead.\n");
+		close(audio_fd);
+		snd_inited = 0;
+		return 0;
+	}
+//	dma.samplepos = (count.bytes / (dma.samplebits / 8)) & (dma.samples-1);
+//	fprintf(stderr, "%d    \r", count.ptr);
+	dma.samplepos = count.ptr / (dma.samplebits / 8);
+
+	return dma.samplepos;
+
+}
+
+void SNDDMA_Shutdown(void)
+{
+#if 0
+	if (snd_inited)
+	{
+		close(audio_fd);
+		snd_inited = 0;
+	}
+#endif
+}
+
+/*
+==============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+===============
+*/
+void SNDDMA_Submit(void)
+{
+}
+
+void SNDDMA_BeginPainting (void)
+{
+}
+
--- /dev/null
+++ b/linux/snd_mixa.s
@@ -1,0 +1,193 @@
+//
+// snd_mixa.s
+// x86 assembly-language sound code
+//
+
+#include "qasm.h"
+
+#if	id386
+
+	.text
+
+//----------------------------------------------------------------------
+// 8-bit sound-mixing code
+//----------------------------------------------------------------------
+
+#define ch		4+16
+#define sc		8+16
+#define count	12+16
+
+.globl C(S_PaintChannelFrom8)
+C(S_PaintChannelFrom8):
+	pushl	%esi				// preserve register variables
+	pushl	%edi
+	pushl	%ebx
+	pushl	%ebp
+
+//	int 	data;
+//	short	*lscale, *rscale;
+//	unsigned char *sfx;
+//	int		i;
+
+	movl	ch(%esp),%ebx
+	movl	sc(%esp),%esi
+
+//	if (ch->leftvol > 255)
+//		ch->leftvol = 255;
+//	if (ch->rightvol > 255)
+//		ch->rightvol = 255;
+	movl	ch_leftvol(%ebx),%eax
+	movl	ch_rightvol(%ebx),%edx
+	cmpl	$255,%eax
+	jna		LLeftSet
+	movl	$255,%eax
+LLeftSet:
+	cmpl	$255,%edx
+	jna		LRightSet
+	movl	$255,%edx
+LRightSet:
+
+//	lscale = snd_scaletable[ch->leftvol >> 3];
+//	rscale = snd_scaletable[ch->rightvol >> 3];
+//	sfx = (signed char *)sc->data + ch->pos;
+//	ch->pos += count;
+	andl	$0xF8,%eax
+	addl	$(sfxc_data),%esi
+	andl	$0xF8,%edx
+	movl	ch_pos(%ebx),%edi
+	movl	count(%esp),%ecx
+	addl	%edi,%esi
+	shll	$7,%eax
+	addl	%ecx,%edi
+	shll	$7,%edx
+	movl	%edi,ch_pos(%ebx)
+	addl	$(C(snd_scaletable)),%eax
+	addl	$(C(snd_scaletable)),%edx
+	subl	%ebx,%ebx
+	movb	-1(%esi,%ecx,1),%bl
+
+	testl	$1,%ecx
+	jz		LMix8Loop
+
+	movl	(%eax,%ebx,4),%edi
+	movl	(%edx,%ebx,4),%ebp
+	addl	C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
+	addl	C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
+	movl	%edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
+	movl	%ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
+	movb	-2(%esi,%ecx,1),%bl
+
+	decl	%ecx
+	jz		LDone
+
+//	for (i=0 ; i<count ; i++)
+//	{
+LMix8Loop:
+
+//		data = sfx[i];
+//		paintbuffer[i].left += lscale[data];
+//		paintbuffer[i].right += rscale[data];
+	movl	(%eax,%ebx,4),%edi
+	movl	(%edx,%ebx,4),%ebp
+	addl	C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi
+	addl	C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp
+	movb	-2(%esi,%ecx,1),%bl
+	movl	%edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size)
+	movl	%ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size)
+
+	movl	(%eax,%ebx,4),%edi
+	movl	(%edx,%ebx,4),%ebp
+	movb	-3(%esi,%ecx,1),%bl
+	addl	C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size),%edi
+	addl	C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size),%ebp
+	movl	%edi,C(paintbuffer)+psp_left-psp_size*2(,%ecx,psp_size)
+	movl	%ebp,C(paintbuffer)+psp_right-psp_size*2(,%ecx,psp_size)
+
+//	}
+	subl	$2,%ecx
+	jnz		LMix8Loop
+
+LDone:
+	popl	%ebp
+	popl	%ebx
+	popl	%edi
+	popl	%esi
+
+	ret
+
+
+//----------------------------------------------------------------------
+// Transfer of stereo buffer to 16-bit DMA buffer code
+//----------------------------------------------------------------------
+
+.globl C(S_WriteLinearBlastStereo16)
+C(S_WriteLinearBlastStereo16):
+	pushl	%edi
+	pushl	%ebx
+
+//	int		i;
+//	int		val;
+	movl	C(snd_linear_count),%ecx
+	movl	C(snd_p),%ebx
+	movl	C(snd_out),%edi
+
+//	for (i=0 ; i<snd_linear_count ; i+=2)
+//	{
+LWLBLoopTop:
+
+//		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;
+	movl	-8(%ebx,%ecx,4),%eax
+	sarl	$8,%eax
+	cmpl	$0x7FFF,%eax
+	jg		LClampHigh
+	cmpl	$0xFFFF8000,%eax
+	jnl		LClampDone
+	movl	$0xFFFF8000,%eax
+	jmp		LClampDone
+LClampHigh:
+	movl	$0x7FFF,%eax
+LClampDone:
+
+//		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;
+	movl	-4(%ebx,%ecx,4),%edx
+	sarl	$8,%edx
+	cmpl	$0x7FFF,%edx
+	jg		LClampHigh2
+	cmpl	$0xFFFF8000,%edx
+	jnl		LClampDone2
+	movl	$0xFFFF8000,%edx
+	jmp		LClampDone2
+LClampHigh2:
+	movl	$0x7FFF,%edx
+LClampDone2:
+	shll	$16,%edx
+	andl	$0xFFFF,%eax
+	orl		%eax,%edx
+	movl	%edx,-4(%edi,%ecx,2)
+
+//	}
+	subl	$2,%ecx
+	jnz		LWLBLoopTop
+
+//	snd_p += snd_linear_count;
+
+	popl	%ebx
+	popl	%edi
+
+	ret
+
+
+#endif	// id386
+
--- /dev/null
+++ b/linux/sys_dosa.s
@@ -1,0 +1,94 @@
+//
+// sys_dosa.s
+// x86 assembly-language DOS-dependent routines.
+
+#include "qasm.h"
+
+
+	.data
+
+	.align	4
+fpenv:
+	.long	0, 0, 0, 0, 0, 0, 0, 0
+
+	.text
+
+.globl C(MaskExceptions)
+C(MaskExceptions):
+	fnstenv	fpenv
+	orl		$0x3F,fpenv
+	fldenv	fpenv
+
+	ret
+
+#if 0
+.globl C(unmaskexceptions)
+C(unmaskexceptions):
+	fnstenv	fpenv
+	andl		$0xFFFFFFE0,fpenv
+	fldenv	fpenv
+
+	ret
+#endif
+
+	.data
+
+	.align	4
+.globl	ceil_cw, single_cw, full_cw, cw, pushed_cw
+ceil_cw:	.long	0
+single_cw:	.long	0
+full_cw:	.long	0
+cw:			.long	0
+pushed_cw:	.long	0
+
+	.text
+
+.globl C(Sys_LowFPPrecision)
+C(Sys_LowFPPrecision):
+	fldcw	single_cw
+
+	ret
+
+.globl C(Sys_HighFPPrecision)
+C(Sys_HighFPPrecision):
+	fldcw	full_cw
+
+	ret
+
+.globl C(Sys_PushFPCW_SetHigh)
+C(Sys_PushFPCW_SetHigh):
+	fnstcw	pushed_cw
+	fldcw	full_cw
+
+	ret
+
+.globl C(Sys_PopFPCW)
+C(Sys_PopFPCW):
+	fldcw	pushed_cw
+
+	ret
+
+.globl C(Sys_SetFPCW)
+C(Sys_SetFPCW):
+	fnstcw	cw
+	movl	cw,%eax
+#if	id386
+	andb	$0xF0,%ah
+	orb		$0x03,%ah	// round mode, 64-bit precision
+#endif
+	movl	%eax,full_cw
+
+#if	id386
+	andb	$0xF0,%ah
+	orb		$0x0C,%ah	// chop mode, single precision
+#endif
+	movl	%eax,single_cw
+
+#if	id386
+	andb	$0xF0,%ah
+	orb		$0x08,%ah	// ceil mode, single precision
+#endif
+	movl	%eax,ceil_cw
+
+	ret
+
--- /dev/null
+++ b/linux/sys_linux.c
@@ -1,0 +1,379 @@
+#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 <mntent.h>
+
+#include <dlfcn.h>
+
+#include "../qcommon/qcommon.h"
+
+#include "../linux/rw_linux.h"
+
+cvar_t *nostdout;
+
+unsigned	sys_frame_time;
+
+uid_t saved_euid;
+qboolean stdin_active = true;
+
+// =======================================================================
+// General routines
+// =======================================================================
+
+void Sys_ConsoleOutput (char *string)
+{
+	if (nostdout && nostdout->value)
+		return;
+
+	fputs(string, stdout);
+}
+
+void Sys_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+	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 && nostdout->value)
+        return;
+
+	for (p = (unsigned char *)text; *p; p++) {
+		*p &= 0x7f;
+		if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
+			printf("[%02x]", *p);
+		else
+			putc(*p, stdout);
+	}
+}
+
+void Sys_Quit (void)
+{
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+    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);
+
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+    
+    va_start (argptr,error);
+    vsprintf (string,error,argptr);
+    va_end (argptr);
+	fprintf(stderr, "Error: %s\n", string);
+
+	_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 floating_point_exception_handler(int whatever)
+{
+//	Sys_Warn("floating point exception\n");
+	signal(SIGFPE, floating_point_exception_handler);
+}
+
+char *Sys_ConsoleInput(void)
+{
+    static char text[256];
+    int     len;
+	fd_set	fdset;
+    struct timeval timeout;
+
+	if (!dedicated || !dedicated->value)
+		return NULL;
+
+	if (!stdin_active)
+		return NULL;
+
+	FD_ZERO(&fdset);
+	FD_SET(0, &fdset); // stdin
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+	if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
+		return NULL;
+
+	len = read (0, text, sizeof(text));
+	if (len == 0) { // eof!
+		stdin_active = false;
+		return NULL;
+	}
+
+	if (len < 1)
+		return NULL;
+	text[len-1] = 0;    // rip off the /n and terminate
+
+	return text;
+}
+
+/*****************************************************************************/
+
+static void *game_library;
+
+/*
+=================
+Sys_UnloadGame
+=================
+*/
+void Sys_UnloadGame (void)
+{
+	if (game_library) 
+		dlclose (game_library);
+	game_library = NULL;
+}
+
+/*
+=================
+Sys_GetGameAPI
+
+Loads the game dll
+=================
+*/
+void *Sys_GetGameAPI (void *parms)
+{
+	void	*(*GetGameAPI) (void *);
+
+	char	name[MAX_OSPATH];
+	char	curpath[MAX_OSPATH];
+	char	*path;
+#ifdef __i386__
+	const char *gamename = "gamei386.so";
+#elif defined __alpha__
+	const char *gamename = "gameaxp.so";
+#else
+#error Unknown arch
+#endif
+
+	setreuid(getuid(), getuid());
+	setegid(getgid());
+
+	if (game_library)
+		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
+
+	getcwd(curpath, sizeof(curpath));
+
+	Com_Printf("------- Loading %s -------", gamename);
+
+	// now run through the search paths
+	path = NULL;
+	while (1)
+	{
+		path = FS_NextPath (path);
+		if (!path)
+			return NULL;		// couldn't find one anywhere
+		sprintf (name, "%s/%s/%s", curpath, path, gamename);
+		game_library = dlopen (name, RTLD_NOW );
+		if (game_library)
+		{
+			Com_DPrintf ("LoadLibrary (%s)\n",name);
+			break;
+		}
+	}
+
+	GetGameAPI = (void *)dlsym (game_library, "GetGameAPI");
+	if (!GetGameAPI)
+	{
+		Sys_UnloadGame ();		
+		return NULL;
+	}
+
+	return GetGameAPI (parms);
+}
+
+/*****************************************************************************/
+
+void Sys_AppActivate (void)
+{
+}
+
+void Sys_SendKeyEvents (void)
+{
+#ifndef DEDICATED_ONLY
+	if (KBD_Update_fp)
+		KBD_Update_fp();
+#endif
+
+	// grab frame time 
+	sys_frame_time = Sys_Milliseconds();
+}
+
+/*****************************************************************************/
+
+char *Sys_GetClipboardData(void)
+{
+	return NULL;
+}
+
+int main (int argc, char **argv)
+{
+	int 	time, oldtime, newtime;
+
+	// go back to real user for config loads
+	saved_euid = geteuid();
+	seteuid(getuid());
+
+	Qcommon_Init(argc, argv);
+
+	fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+
+	nostdout = Cvar_Get("nostdout", "0", 0);
+	if (!nostdout->value) {
+		fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+//		printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
+	}
+
+    oldtime = Sys_Milliseconds ();
+    while (1)
+    {
+// find time spent rendering last frame
+		do {
+			newtime = Sys_Milliseconds ();
+			time = newtime - oldtime;
+		} while (time < 1);
+        Qcommon_Frame (time);
+		oldtime = newtime;
+    }
+
+}
+
+void Sys_CopyProtect(void)
+{
+	FILE *mnt;
+	struct mntent *ent;
+	char path[MAX_OSPATH];
+	struct stat st;
+	qboolean found_cd = false;
+
+	static qboolean checked = false;
+
+	if (checked)
+		return;
+
+	if ((mnt = setmntent("/etc/mtab", "r")) == NULL)
+		Com_Error(ERR_FATAL, "Can't read mount table to determine mounted cd location.");
+
+	while ((ent = getmntent(mnt)) != NULL) {
+		if (strcmp(ent->mnt_type, "iso9660") == 0) {
+			// found a cd file system
+			found_cd = true;
+			sprintf(path, "%s/%s", ent->mnt_dir, "install/data/quake2.exe");
+			if (stat(path, &st) == 0) {
+				// found it
+				checked = true;
+				endmntent(mnt);
+				return;
+			}
+			sprintf(path, "%s/%s", ent->mnt_dir, "Install/Data/quake2.exe");
+			if (stat(path, &st) == 0) {
+				// found it
+				checked = true;
+				endmntent(mnt);
+				return;
+			}
+			sprintf(path, "%s/%s", ent->mnt_dir, "quake2.exe");
+			if (stat(path, &st) == 0) {
+				// found it
+				checked = true;
+				endmntent(mnt);
+				return;
+			}
+		}
+	}
+	endmntent(mnt);
+
+	if (found_cd)
+		Com_Error (ERR_FATAL, "Could not find a Quake2 CD in your CD drive.");
+	Com_Error (ERR_FATAL, "Unable to find a mounted iso9660 file system.\n"
+		"You must mount the Quake2 CD in a cdrom drive in order to play.");
+}
+
+#if 0
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+	int r;
+	unsigned long addr;
+	int psize = getpagesize();
+
+	addr = (startaddr & ~(psize-1)) - psize;
+
+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+//			addr, startaddr+length, length);
+
+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+	if (r < 0)
+    		Sys_Error("Protection change failed\n");
+
+}
+
+#endif
--- /dev/null
+++ b/linux/vid_menu.c
@@ -1,0 +1,437 @@
+#include "../client/client.h"
+#include "../client/qmenu.h"
+
+#define REF_SOFT	0
+#define REF_SOFTX11	1
+#define REF_OPENGL	2
+
+extern cvar_t *vid_ref;
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+
+static cvar_t *gl_mode;
+static cvar_t *gl_driver;
+static cvar_t *gl_picmip;
+static cvar_t *gl_ext_palettedtexture;
+
+static cvar_t *sw_mode;
+static cvar_t *sw_stipplealpha;
+
+static cvar_t *_windowed_mouse;
+
+extern void M_ForceMenuOff( void );
+
+/*
+====================================================================
+
+MENU INTERACTION
+
+====================================================================
+*/
+#define SOFTWARE_MENU 0
+#define OPENGL_MENU   1
+
+static menuframework_s  s_software_menu;
+static menuframework_s	s_opengl_menu;
+static menuframework_s *s_current_menu;
+static int				s_current_menu_index;
+
+static menulist_s		s_mode_list[2];
+static menulist_s		s_ref_list[2];
+static menuslider_s		s_tq_slider;
+static menuslider_s		s_screensize_slider[2];
+static menuslider_s		s_brightness_slider[2];
+static menulist_s  		s_fs_box[2];
+static menulist_s  		s_stipple_box;
+static menulist_s  		s_paletted_texture_box;
+static menulist_s  		s_windowed_mouse;
+static menuaction_s		s_apply_action[2];
+static menuaction_s		s_defaults_action[2];
+
+static void DriverCallback( void *unused )
+{
+	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+	if ( s_ref_list[s_current_menu_index].curvalue < 2 )
+	{
+		s_current_menu = &s_software_menu;
+		s_current_menu_index = 0;
+	}
+	else
+	{
+		s_current_menu = &s_opengl_menu;
+		s_current_menu_index = 1;
+	}
+
+}
+
+static void ScreenSizeCallback( void *s )
+{
+	menuslider_s *slider = ( menuslider_s * ) s;
+
+	Cvar_SetValue( "viewsize", slider->curvalue * 10 );
+}
+
+static void BrightnessCallback( void *s )
+{
+	menuslider_s *slider = ( menuslider_s * ) s;
+
+	if ( s_current_menu_index == 0)
+		s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
+	else
+		s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
+
+	if ( stricmp( vid_ref->string, "soft" ) == 0 ||
+		 stricmp( vid_ref->string, "softx" ) == 0 )
+	{
+		float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5;
+
+		Cvar_SetValue( "vid_gamma", gamma );
+	}
+}
+
+static void ResetDefaults( void *unused )
+{
+	VID_MenuInit();
+}
+
+static void ApplyChanges( void *unused )
+{
+	float gamma;
+
+	/*
+	** make values consistent
+	*/
+	s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
+	s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
+	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+	/*
+	** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+	*/
+	gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5;
+
+	Cvar_SetValue( "vid_gamma", gamma );
+	Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
+	Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
+	Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
+	Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
+	Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
+	Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
+	Cvar_SetValue( "_windowed_mouse", s_windowed_mouse.curvalue);
+
+	switch ( s_ref_list[s_current_menu_index].curvalue )
+	{
+	case REF_SOFT:
+		Cvar_Set( "vid_ref", "soft" );
+		break;
+	case REF_SOFTX11:
+		Cvar_Set( "vid_ref", "softx" );
+		break;
+	case REF_OPENGL:
+		Cvar_Set( "vid_ref", "gl" );
+		Cvar_Set( "gl_driver", "opengl32" );
+		break;
+	}
+
+#if 0
+	/*
+	** update appropriate stuff if we're running OpenGL and gamma
+	** has been modified
+	*/
+	if ( stricmp( vid_ref->string, "gl" ) == 0 )
+	{
+		if ( vid_gamma->modified )
+		{
+			vid_ref->modified = true;
+			if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
+			{
+				char envbuffer[1024];
+				float g;
+
+				vid_ref->modified = true;
+
+				g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
+				Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
+				putenv( envbuffer );
+
+				vid_gamma->modified = false;
+			}
+		}
+	}
+#endif
+
+	M_ForceMenuOff();
+}
+
+/*
+** VID_MenuInit
+*/
+void VID_MenuInit( void )
+{
+	static const char *resolutions[] = 
+	{
+		"[320 240  ]",
+		"[400 300  ]",
+		"[512 384  ]",
+		"[640 480  ]",
+		"[800 600  ]",
+		"[960 720  ]",
+		"[1024 768 ]",
+		"[1152 864 ]",
+		"[1280 1024]",
+		"[1600 1200]",
+		0
+	};
+	static const char *refs[] =
+	{
+		"[software      ]",
+		"[software X11  ]",
+		"[default OpenGL]",
+		0
+	};
+	static const char *yesno_names[] =
+	{
+		"no",
+		"yes",
+		0
+	};
+	int i;
+
+	if ( !gl_driver )
+		gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
+	if ( !gl_picmip )
+		gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
+	if ( !gl_mode )
+		gl_mode = Cvar_Get( "gl_mode", "3", 0 );
+	if ( !sw_mode )
+		sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+	if ( !gl_ext_palettedtexture )
+		gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
+
+	if ( !sw_stipplealpha )
+		sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+
+	if ( !_windowed_mouse)
+        _windowed_mouse = Cvar_Get( "_windowed_mouse", "0", CVAR_ARCHIVE );
+
+	s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value;
+	s_mode_list[OPENGL_MENU].curvalue = gl_mode->value;
+
+	if ( !scr_viewsize )
+		scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+
+	s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10;
+	s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10;
+
+	if ( strcmp( vid_ref->string, "soft" ) == 0)
+	{
+		s_current_menu_index = SOFTWARE_MENU;
+		s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
+	}
+	else if (strcmp( vid_ref->string, "softx" ) == 0 ) 
+	{
+		s_current_menu_index = SOFTWARE_MENU;
+		s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFTX11;
+	}
+	else if ( strcmp( vid_ref->string, "gl" ) == 0 )
+	{
+		s_current_menu_index = OPENGL_MENU;
+		s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+#if 0
+		if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_3DFX;
+		else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_POWERVR;
+		else if ( strcmp( gl_driver->string, "opengl32" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+		else
+			s_ref_list[s_current_menu_index].curvalue = REF_VERITE;
+#endif
+	}
+
+	s_software_menu.x = viddef.width * 0.50;
+	s_software_menu.nitems = 0;
+	s_opengl_menu.x = viddef.width * 0.50;
+	s_opengl_menu.nitems = 0;
+
+	for ( i = 0; i < 2; i++ )
+	{
+		s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
+		s_ref_list[i].generic.name = "driver";
+		s_ref_list[i].generic.x = 0;
+		s_ref_list[i].generic.y = 0;
+		s_ref_list[i].generic.callback = DriverCallback;
+		s_ref_list[i].itemnames = refs;
+
+		s_mode_list[i].generic.type = MTYPE_SPINCONTROL;
+		s_mode_list[i].generic.name = "video mode";
+		s_mode_list[i].generic.x = 0;
+		s_mode_list[i].generic.y = 10;
+		s_mode_list[i].itemnames = resolutions;
+
+		s_screensize_slider[i].generic.type	= MTYPE_SLIDER;
+		s_screensize_slider[i].generic.x		= 0;
+		s_screensize_slider[i].generic.y		= 20;
+		s_screensize_slider[i].generic.name	= "screen size";
+		s_screensize_slider[i].minvalue = 3;
+		s_screensize_slider[i].maxvalue = 12;
+		s_screensize_slider[i].generic.callback = ScreenSizeCallback;
+
+		s_brightness_slider[i].generic.type	= MTYPE_SLIDER;
+		s_brightness_slider[i].generic.x	= 0;
+		s_brightness_slider[i].generic.y	= 30;
+		s_brightness_slider[i].generic.name	= "brightness";
+		s_brightness_slider[i].generic.callback = BrightnessCallback;
+		s_brightness_slider[i].minvalue = 5;
+		s_brightness_slider[i].maxvalue = 13;
+		s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10;
+
+		s_fs_box[i].generic.type = MTYPE_SPINCONTROL;
+		s_fs_box[i].generic.x	= 0;
+		s_fs_box[i].generic.y	= 40;
+		s_fs_box[i].generic.name	= "fullscreen";
+		s_fs_box[i].itemnames = yesno_names;
+		s_fs_box[i].curvalue = vid_fullscreen->value;
+
+		s_defaults_action[i].generic.type = MTYPE_ACTION;
+		s_defaults_action[i].generic.name = "reset to default";
+		s_defaults_action[i].generic.x    = 0;
+		s_defaults_action[i].generic.y    = 90;
+		s_defaults_action[i].generic.callback = ResetDefaults;
+
+		s_apply_action[i].generic.type = MTYPE_ACTION;
+		s_apply_action[i].generic.name = "apply";
+		s_apply_action[i].generic.x    = 0;
+		s_apply_action[i].generic.y    = 100;
+		s_apply_action[i].generic.callback = ApplyChanges;
+	}
+
+	s_stipple_box.generic.type = MTYPE_SPINCONTROL;
+	s_stipple_box.generic.x	= 0;
+	s_stipple_box.generic.y	= 60;
+	s_stipple_box.generic.name	= "stipple alpha";
+	s_stipple_box.curvalue = sw_stipplealpha->value;
+	s_stipple_box.itemnames = yesno_names;
+
+	s_windowed_mouse.generic.type = MTYPE_SPINCONTROL;
+	s_windowed_mouse.generic.x  = 0;
+	s_windowed_mouse.generic.y  = 72;
+	s_windowed_mouse.generic.name   = "windowed mouse";
+	s_windowed_mouse.curvalue = _windowed_mouse->value;
+	s_windowed_mouse.itemnames = yesno_names;
+
+	s_tq_slider.generic.type	= MTYPE_SLIDER;
+	s_tq_slider.generic.x		= 0;
+	s_tq_slider.generic.y		= 60;
+	s_tq_slider.generic.name	= "texture quality";
+	s_tq_slider.minvalue = 0;
+	s_tq_slider.maxvalue = 3;
+	s_tq_slider.curvalue = 3-gl_picmip->value;
+
+	s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL;
+	s_paletted_texture_box.generic.x	= 0;
+	s_paletted_texture_box.generic.y	= 70;
+	s_paletted_texture_box.generic.name	= "8-bit textures";
+	s_paletted_texture_box.itemnames = yesno_names;
+	s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value;
+
+	Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_windowed_mouse );
+
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box );
+
+	Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_apply_action[SOFTWARE_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_apply_action[OPENGL_MENU] );
+
+	Menu_Center( &s_software_menu );
+	Menu_Center( &s_opengl_menu );
+	s_opengl_menu.x -= 8;
+	s_software_menu.x -= 8;
+}
+
+/*
+================
+VID_MenuDraw
+================
+*/
+void VID_MenuDraw (void)
+{
+	int w, h;
+
+	if ( s_current_menu_index == 0 )
+		s_current_menu = &s_software_menu;
+	else
+		s_current_menu = &s_opengl_menu;
+
+	/*
+	** draw the banner
+	*/
+	re.DrawGetPicSize( &w, &h, "m_banner_video" );
+	re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
+
+	/*
+	** move cursor to a reasonable starting position
+	*/
+	Menu_AdjustCursor( s_current_menu, 1 );
+
+	/*
+	** draw the menu
+	*/
+	Menu_Draw( s_current_menu );
+}
+
+/*
+================
+VID_MenuKey
+================
+*/
+const char *VID_MenuKey( int key )
+{
+	extern void M_PopMenu( void );
+
+	menuframework_s *m = s_current_menu;
+	static const char *sound = "misc/menu1.wav";
+
+	switch ( key )
+	{
+	case K_ESCAPE:
+		M_PopMenu();
+		return NULL;
+	case K_UPARROW:
+		m->cursor--;
+		Menu_AdjustCursor( m, -1 );
+		break;
+	case K_DOWNARROW:
+		m->cursor++;
+		Menu_AdjustCursor( m, 1 );
+		break;
+	case K_LEFTARROW:
+		Menu_SlideItem( m, -1 );
+		break;
+	case K_RIGHTARROW:
+		Menu_SlideItem( m, 1 );
+		break;
+	case K_ENTER:
+		Menu_SelectItem( m );
+		break;
+	}
+
+	return sound;
+}
+
+
--- /dev/null
+++ b/linux/vid_so.c
@@ -1,0 +1,489 @@
+// Main windowed and fullscreen graphics interface module. This module
+// is used for both the software and OpenGL rendering versions of the
+// Quake refresh engine.
+
+#define SO_FILE "/etc/quake2.conf"
+
+#include <assert.h>
+#include <dlfcn.h> // ELF dl loader
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "../client/client.h"
+
+#include "../linux/rw_linux.h"
+
+// Structure containing functions exported from refresh DLL
+refexport_t	re;
+
+// Console variables that we need to access from this module
+cvar_t		*vid_gamma;
+cvar_t		*vid_ref;			// Name of Refresh DLL loaded
+cvar_t		*vid_xpos;			// X coordinate of window position
+cvar_t		*vid_ypos;			// Y coordinate of window position
+cvar_t		*vid_fullscreen;
+
+// Global variables used internally by this module
+viddef_t	viddef;				// global video state; used by other modules
+void		*reflib_library;		// Handle to refresh DLL 
+qboolean	reflib_active = 0;
+
+#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
+
+/** KEYBOARD **************************************************************/
+
+void Do_Key_Event(int key, qboolean down);
+
+void (*KBD_Update_fp)(void);
+void (*KBD_Init_fp)(Key_Event_fp_t fp);
+void (*KBD_Close_fp)(void);
+
+/** MOUSE *****************************************************************/
+
+in_state_t in_state;
+
+void (*RW_IN_Init_fp)(in_state_t *in_state_p);
+void (*RW_IN_Shutdown_fp)(void);
+void (*RW_IN_Activate_fp)(qboolean active);
+void (*RW_IN_Commands_fp)(void);
+void (*RW_IN_Move_fp)(usercmd_t *cmd);
+void (*RW_IN_Frame_fp)(void);
+
+void Real_IN_Init (void);
+
+/*
+==========================================================================
+
+DLL GLUE
+
+==========================================================================
+*/
+
+#define	MAXPRINTMSG	4096
+void VID_Printf (int print_level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	if (print_level == PRINT_ALL)
+		Com_Printf ("%s", msg);
+	else
+		Com_DPrintf ("%s", msg);
+}
+
+void VID_Error (int err_level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	Com_Error (err_level,"%s", msg);
+}
+
+//==========================================================================
+
+/*
+============
+VID_Restart_f
+
+Console command to re-start the video mode and refresh DLL. We do this
+simply by setting the modified flag for the vid_ref variable, which will
+cause the entire video mode and refresh DLL to be reset on the next frame.
+============
+*/
+void VID_Restart_f (void)
+{
+	vid_ref->modified = true;
+}
+
+/*
+** VID_GetModeInfo
+*/
+typedef struct vidmode_s
+{
+	const char *description;
+	int         width, height;
+	int         mode;
+} vidmode_t;
+
+vidmode_t vid_modes[] =
+{
+	{ "Mode 0: 320x240",   320, 240,   0 },
+	{ "Mode 1: 400x300",   400, 300,   1 },
+	{ "Mode 2: 512x384",   512, 384,   2 },
+	{ "Mode 3: 640x480",   640, 480,   3 },
+	{ "Mode 4: 800x600",   800, 600,   4 },
+	{ "Mode 5: 960x720",   960, 720,   5 },
+	{ "Mode 6: 1024x768",  1024, 768,  6 },
+	{ "Mode 7: 1152x864",  1152, 864,  7 },
+	{ "Mode 8: 1280x1024",  1280, 1024, 8 },
+	{ "Mode 9: 1600x1200", 1600, 1200, 9 }
+};
+
+qboolean VID_GetModeInfo( int *width, int *height, int mode )
+{
+	if ( mode < 0 || mode >= VID_NUM_MODES )
+		return false;
+
+	*width  = vid_modes[mode].width;
+	*height = vid_modes[mode].height;
+
+	return true;
+}
+
+/*
+** VID_NewWindow
+*/
+void VID_NewWindow ( int width, int height)
+{
+	viddef.width  = width;
+	viddef.height = height;
+}
+
+void VID_FreeReflib (void)
+{
+	if (reflib_library) {
+		if (KBD_Close_fp)
+			KBD_Close_fp();
+		if (RW_IN_Shutdown_fp)
+			RW_IN_Shutdown_fp();
+		dlclose(reflib_library);
+	}
+
+	KBD_Init_fp = NULL;
+	KBD_Update_fp = NULL;
+	KBD_Close_fp = NULL;
+	RW_IN_Init_fp = NULL;
+	RW_IN_Shutdown_fp = NULL;
+	RW_IN_Activate_fp = NULL;
+	RW_IN_Commands_fp = NULL;
+	RW_IN_Move_fp = NULL;
+	RW_IN_Frame_fp = NULL;
+
+	memset (&re, 0, sizeof(re));
+	reflib_library = NULL;
+	reflib_active  = false;
+}
+
+/*
+==============
+VID_LoadRefresh
+==============
+*/
+qboolean VID_LoadRefresh( char *name )
+{
+	refimport_t	ri;
+	GetRefAPI_t	GetRefAPI;
+	char	fn[MAX_OSPATH];
+	struct stat st;
+	extern uid_t saved_euid;
+	FILE *fp;
+	
+	if ( reflib_active )
+	{
+		if (KBD_Close_fp)
+			KBD_Close_fp();
+		if (RW_IN_Shutdown_fp)
+			RW_IN_Shutdown_fp();
+		KBD_Close_fp = NULL;
+		RW_IN_Shutdown_fp = NULL;
+		re.Shutdown();
+		VID_FreeReflib ();
+	}
+
+	Com_Printf( "------- Loading %s -------\n", name );
+
+	//regain root
+	seteuid(saved_euid);
+
+	if ((fp = fopen(SO_FILE, "r")) == NULL) {
+		Com_Printf( "LoadLibrary(\"%s\") failed: can't open " SO_FILE " (required for location of ref libraries)\n", name);
+		return false;
+	}
+	fgets(fn, sizeof(fn), fp);
+	fclose(fp);
+	if (*fn && fn[strlen(fn) - 1] == '\n')
+		fn[strlen(fn) - 1] = 0;
+
+	strcat(fn, "/");
+	strcat(fn, name);
+
+	// permission checking
+	if (strstr(fn, "softx") == NULL) { // softx doesn't require root
+		if (stat(fn, &st) == -1) {
+			Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name, strerror(errno));
+			return false;
+		}
+		if (st.st_uid != 0) {
+			Com_Printf( "LoadLibrary(\"%s\") failed: ref is not owned by root\n", name);
+			return false;
+		}
+#if 0
+		if ((st.st_mode & 0777) & ~0700) {
+			Com_Printf( "LoadLibrary(\"%s\") failed: invalid permissions, must be 700 for security considerations\n", name);
+			return false;
+		}
+#endif
+	} else {
+		// softx requires we give up root now
+		setreuid(getuid(), getuid());
+		setegid(getgid());
+	}
+
+	if ( ( reflib_library = dlopen( fn, RTLD_NOW ) ) == 0 )
+	{
+		Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name , dlerror());
+		return false;
+	}
+
+	ri.Cmd_AddCommand = Cmd_AddCommand;
+	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+	ri.Cmd_Argc = Cmd_Argc;
+	ri.Cmd_Argv = Cmd_Argv;
+	ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+	ri.Con_Printf = VID_Printf;
+	ri.Sys_Error = VID_Error;
+	ri.FS_LoadFile = FS_LoadFile;
+	ri.FS_FreeFile = FS_FreeFile;
+	ri.FS_Gamedir = FS_Gamedir;
+	ri.Cvar_Get = Cvar_Get;
+	ri.Cvar_Set = Cvar_Set;
+	ri.Cvar_SetValue = Cvar_SetValue;
+	ri.Vid_GetModeInfo = VID_GetModeInfo;
+	ri.Vid_MenuInit = VID_MenuInit;
+	ri.Vid_NewWindow = VID_NewWindow;
+
+	if ( ( GetRefAPI = (void *) dlsym( reflib_library, "GetRefAPI" ) ) == 0 )
+		Com_Error( ERR_FATAL, "dlsym failed on %s", name );
+
+	re = GetRefAPI( ri );
+
+	if (re.api_version != API_VERSION)
+	{
+		VID_FreeReflib ();
+		Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
+	}
+
+	/* Init IN (Mouse) */
+	in_state.IN_CenterView_fp = IN_CenterView;
+	in_state.Key_Event_fp = Do_Key_Event;
+	in_state.viewangles = cl.viewangles;
+	in_state.in_strafe_state = &in_strafe.state;
+
+	if ((RW_IN_Init_fp = dlsym(reflib_library, "RW_IN_Init")) == NULL ||
+		(RW_IN_Shutdown_fp = dlsym(reflib_library, "RW_IN_Shutdown")) == NULL ||
+		(RW_IN_Activate_fp = dlsym(reflib_library, "RW_IN_Activate")) == NULL ||
+		(RW_IN_Commands_fp = dlsym(reflib_library, "RW_IN_Commands")) == NULL ||
+		(RW_IN_Move_fp = dlsym(reflib_library, "RW_IN_Move")) == NULL ||
+		(RW_IN_Frame_fp = dlsym(reflib_library, "RW_IN_Frame")) == NULL)
+		Sys_Error("No RW_IN functions in REF.\n");
+
+	Real_IN_Init();
+
+	if ( re.Init( 0, 0 ) == -1 )
+	{
+		re.Shutdown();
+		VID_FreeReflib ();
+		return false;
+	}
+
+	/* Init KBD */
+#if 1
+	if ((KBD_Init_fp = dlsym(reflib_library, "KBD_Init")) == NULL ||
+		(KBD_Update_fp = dlsym(reflib_library, "KBD_Update")) == NULL ||
+		(KBD_Close_fp = dlsym(reflib_library, "KBD_Close")) == NULL)
+		Sys_Error("No KBD functions in REF.\n");
+#else
+	{
+		void KBD_Init(void);
+		void KBD_Update(void);
+		void KBD_Close(void);
+
+		KBD_Init_fp = KBD_Init;
+		KBD_Update_fp = KBD_Update;
+		KBD_Close_fp = KBD_Close;
+	}
+#endif
+	KBD_Init_fp(Do_Key_Event);
+
+	// give up root now
+	setreuid(getuid(), getuid());
+	setegid(getgid());
+
+	Com_Printf( "------------------------------------\n");
+	reflib_active = true;
+	return true;
+}
+
+/*
+============
+VID_CheckChanges
+
+This function gets called once just before drawing each frame, and it's sole purpose in life
+is to check to see if any of the video mode parameters have changed, and if they have to 
+update the rendering DLL and/or video mode to match.
+============
+*/
+void VID_CheckChanges (void)
+{
+	char name[100];
+	cvar_t *sw_mode;
+
+	if ( vid_ref->modified )
+	{
+		S_StopAllSounds();
+	}
+
+	while (vid_ref->modified)
+	{
+		/*
+		** refresh has changed
+		*/
+		vid_ref->modified = false;
+		vid_fullscreen->modified = true;
+		cl.refresh_prepped = false;
+		cls.disable_screen = true;
+
+		sprintf( name, "ref_%s.so", vid_ref->string );
+		if ( !VID_LoadRefresh( name ) )
+		{
+			if ( strcmp (vid_ref->string, "soft") == 0 ||
+				strcmp (vid_ref->string, "softx") == 0 ) {
+Com_Printf("Refresh failed\n");
+				sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+				if (sw_mode->value != 0) {
+Com_Printf("Trying mode 0\n");
+					Cvar_SetValue("sw_mode", 0);
+					if ( !VID_LoadRefresh( name ) )
+						Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+				} else
+					Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+			}
+
+			Cvar_Set( "vid_ref", "soft" );
+
+			/*
+			** drop the console if we fail to load a refresh
+			*/
+			if ( cls.key_dest != key_console )
+			{
+				Con_ToggleConsole_f();
+			}
+		}
+		cls.disable_screen = false;
+	}
+
+}
+
+/*
+============
+VID_Init
+============
+*/
+void VID_Init (void)
+{
+	/* Create the video variables so we know how to start the graphics drivers */
+	// if DISPLAY is defined, try X
+	if (getenv("DISPLAY"))
+		vid_ref = Cvar_Get ("vid_ref", "softx", CVAR_ARCHIVE);
+	else
+		vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
+	vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
+	vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
+	vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
+	vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
+
+	/* Add some console commands that we want to handle */
+	Cmd_AddCommand ("vid_restart", VID_Restart_f);
+
+	/* Disable the 3Dfx splash screen */
+	putenv("FX_GLIDE_NO_SPLASH=0");
+		
+	/* Start the graphics mode and load refresh DLL */
+	VID_CheckChanges();
+}
+
+/*
+============
+VID_Shutdown
+============
+*/
+void VID_Shutdown (void)
+{
+	if ( reflib_active )
+	{
+		if (KBD_Close_fp)
+			KBD_Close_fp();
+		if (RW_IN_Shutdown_fp)
+			RW_IN_Shutdown_fp();
+		KBD_Close_fp = NULL;
+		RW_IN_Shutdown_fp = NULL;
+		re.Shutdown ();
+		VID_FreeReflib ();
+	}
+}
+
+
+/*****************************************************************************/
+/* INPUT                                                                     */
+/*****************************************************************************/
+
+cvar_t	*in_joystick;
+
+// This if fake, it's acutally done by the Refresh load
+void IN_Init (void)
+{
+	in_joystick	= Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
+}
+
+void Real_IN_Init (void)
+{
+	if (RW_IN_Init_fp)
+		RW_IN_Init_fp(&in_state);
+}
+
+void IN_Shutdown (void)
+{
+	if (RW_IN_Shutdown_fp)
+		RW_IN_Shutdown_fp();
+}
+
+void IN_Commands (void)
+{
+	if (RW_IN_Commands_fp)
+		RW_IN_Commands_fp();
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+	if (RW_IN_Move_fp)
+		RW_IN_Move_fp(cmd);
+}
+
+void IN_Frame (void)
+{
+	if (RW_IN_Frame_fp)
+		RW_IN_Frame_fp();
+}
+
+void IN_Activate (qboolean active)
+{
+	if (RW_IN_Activate_fp)
+		RW_IN_Activate_fp(active);
+}
+
+void Do_Key_Event(int key, qboolean down)
+{
+	Key_Event(key, down, Sys_Milliseconds());
+}
+
--- /dev/null
+++ b/makefile
@@ -1,0 +1,259 @@
+
+CFLAGS = -Wall -c -g -DNO_PRIVATE
+LDFLAGS = -sectcreate __ICON __header rhapsody/QuakeWorld.iconheader -segprot __ICON r r -sectcreate __ICON app rhapsody/QuakeWorld.tiff -framework AppKit -framework Foundation
+ODIR = rhapsody/output
+
+EXEBASE = QuakeWorld
+EXE = $(ODIR)/$(EXEBASE)
+all: $(EXE)
+
+_next:
+	make "CFLAGS = -Wall -c -g -DNO_PRIVATE" "ODIR = rhapsody/output"
+	
+_nextopt:
+	make "CFLAGS = -O2 -c -g -DNO_PRIVATE" "ODIR = rhapsody/output"
+	
+_irix:
+	make "CFLAGS = -c -Ofast=ip32_10k -Xcpluscomm -DNO_PRIVATE" "LDFLAGS = -Ofast=ip32_10k -lm" "ODIR = irix"
+	
+_osf:
+	make "CFLAGS = -c -O4 -DNO_PRIVATE" "LDFLAGS = -lm" "ODIR = osf"
+
+clean:
+	rm -f $(ODIR)/*.o $(EXE)
+
+REF_SOFT_SYSTEM_FILES = $(ODIR)/r_next.o 
+
+REF_SOFT_FILES = $(ODIR)/d_polyse.o $(ODIR)/d_scan.o $(ODIR)/draw.o  $(ODIR)/model.o $(ODIR)/r_aclip.o $(ODIR)/r_alias.o $(ODIR)/r_bsp.o $(ODIR)/r_draw.o $(ODIR)/r_edge.o $(ODIR)/r_efrag.o $(ODIR)/r_inter.o $(ODIR)/r_light.o $(ODIR)/r_main.o $(ODIR)/r_misc.o $(ODIR)/r_part.o $(ODIR)/r_sky.o $(ODIR)/r_sprite.o $(ODIR)/r_surf.o $(REF_SOFT_SYSTEM_FILES)
+
+CLIENT_SYSTEM_FILES = $(ODIR)/in_next.o $(ODIR)/cd_null.o $(ODIR)/snd_next.o $(ODIR)/vid_null.o 
+SOUND_FILES = $(ODIR)/snd_dma.o $(ODIR)/snd_mix.o $(ODIR)/snd_mem.o
+CLIENT_FILES = $(ODIR)/cl_demo.o $(ODIR)/cl_ents.o $(ODIR)/cl_input.o  $(ODIR)/cl_main.o $(ODIR)/cl_parse.o $(ODIR)/cl_pred.o $(ODIR)/cl_tent.o $(ODIR)/console.o $(ODIR)/keys.o $(ODIR)/menu.o $(ODIR)/sbar.o $(ODIR)/screen.o $(ODIR)/view.o $(SOUND_FILES) $(CLIENT_SYSTEM_FILES) $(REF_SOFT_FILES)
+#CLIENT_FILES = $(ODIR)/cl_null.o
+
+
+SERVER_FILES = $(ODIR)/pr_cmds.o $(ODIR)/pr_edict.o $(ODIR)/pr_exec.o $(ODIR)/sv_ccmds.o  $(ODIR)/sv_ents.o $(ODIR)/sv_init.o $(ODIR)/sv_main.o $(ODIR)/sv_move.o $(ODIR)/sv_phys.o $(ODIR)/sv_send.o $(ODIR)/sv_user.o $(ODIR)/world.o
+#SERVER_FILES = $(ODIR)/sv_null.o
+
+
+QCOMMON_SYSTEM_FILES = $(ODIR)/net_udp.o $(ODIR)/sys_next.o 
+QCOMMON_FILES = $(ODIR)/cmd.o $(ODIR)/cmodel.o $(ODIR)/common.o $(ODIR)/crc.o   $(ODIR)/cvar.o $(ODIR)/files.o $(ODIR)/mathlib.o $(ODIR)/net_chan.o $(ODIR)/pmove.o $(QCOMMON_SYSTEM_FILES)
+
+$(EXE): $(CLIENT_FILES) $(SERVER_FILES) $(QCOMMON_FILES)
+	cc -o $(EXE) $(CLIENT_FILES) $(SERVER_FILES) $(QCOMMON_FILES) $(LDFLAGS) 
+
+#===========================================================================
+
+$(ODIR)/cl_null.o : client/cl_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+	
+$(ODIR)/cl_demo.o : client/cl_demo.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cl_ents.o : client/cl_ents.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cl_input.o : client/cl_input.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cl_main.o : client/cl_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cl_parse.o : client/cl_parse.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cl_pred.o : client/cl_pred.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cl_tent.o : client/cl_tent.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/console.o : client/console.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/keys.o : client/keys.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/menu.o : client/menu.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sbar.o : client/sbar.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/screen.o : client/screen.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/view.o : client/view.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_dma.o : client/snd_dma.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/snd_mix.o : client/snd_mix.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/snd_mem.o : client/snd_mem.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cd_null.o : client/cd_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/in_null.o : client/in_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/snd_null.o : client/snd_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/vid_null.o : client/vid_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/in_next.o : rhapsody/in_next.m
+	cc $(CFLAGS) -o $@ $?
+$(ODIR)/snd_next.o : rhapsody/snd_next.m
+	cc $(CFLAGS) -o $@ $?
+
+#===========================================================================
+
+$(ODIR)/sv_null.o : server/sv_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/pr_cmds.o : server/pr_cmds.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/pr_edict.o : server/pr_edict.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/pr_exec.o : server/pr_exec.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_ccmds.o : server/sv_ccmds.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_ents.o : server/sv_ents.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_init.o : server/sv_init.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_main.o : server/sv_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_move.o : server/sv_move.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_phys.o : server/sv_phys.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_send.o : server/sv_send.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sv_user.o : server/sv_user.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/world.o : server/world.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#===========================================================================
+
+$(ODIR)/d_polyse.o : ref_soft/d_polyse.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/d_scan.o : ref_soft/d_scan.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/draw.o : ref_soft/draw.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/model.o : ref_soft/model.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_aclip.o : ref_soft/r_aclip.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_alias.o : ref_soft/r_alias.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_bsp.o : ref_soft/r_bsp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_draw.o : ref_soft/r_draw.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_edge.o : ref_soft/r_edge.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_efrag.o : ref_soft/r_efrag.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_inter.o : ref_soft/r_inter.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_light.o : ref_soft/r_light.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_main.o : ref_soft/r_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_misc.o : ref_soft/r_misc.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_part.o : ref_soft/r_part.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_sky.o : ref_soft/r_sky.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_sprite.o : ref_soft/r_sprite.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/r_surf.o : ref_soft/r_surf.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_next.o : rhapsody/r_next.m
+	cc $(CFLAGS) -o $@ $?
+
+#===========================================================================
+
+$(ODIR)/cmd.o : qcommon/cmd.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cmodel.o : qcommon/cmodel.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/common.o : qcommon/common.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/crc.o : qcommon/crc.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/cvar.o : qcommon/cvar.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/files.o : qcommon/files.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/mathlib.o : qcommon/mathlib.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/net_chan.o : qcommon/net_chan.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/net_udp.o : qcommon/net_udp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/pmove.o : qcommon/pmove.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sys_null.o : qcommon/sys_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/sys_next.o : rhapsody/sys_next.m
+	cc $(CFLAGS) -o $@ $?
--- /dev/null
+++ b/makezip
@@ -1,0 +1,2 @@
+zip -9 -r code . 
+
--- /dev/null
+++ b/makezip.bat
@@ -1,0 +1,1 @@
+zip -9 -r -D -X code .
--- /dev/null
+++ b/null/cd_null.c
@@ -1,0 +1,31 @@
+#include "../client/client.h"
+
+void CDAudio_Play(int track, qboolean looping)
+{
+}
+
+
+void CDAudio_Stop(void)
+{
+}
+
+
+void CDAudio_Resume(void)
+{
+}
+
+
+void CDAudio_Update(void)
+{
+}
+
+
+int CDAudio_Init(void)
+{
+	return 0;
+}
+
+
+void CDAudio_Shutdown(void)
+{
+}
--- /dev/null
+++ b/null/cl_null.c
@@ -1,0 +1,55 @@
+
+// cl_null.c -- this file can stub out the entire client system
+// for pure dedicated servers
+
+#include "../qcommon/qcommon.h"
+
+void Key_Bind_Null_f(void)
+{
+}
+
+void CL_Init (void)
+{
+}
+
+void CL_Drop (void)
+{
+}
+
+void CL_Shutdown (void)
+{
+}
+
+void CL_Frame (int msec)
+{
+}
+
+void Con_Print (char *text)
+{
+}
+
+void Cmd_ForwardToServer (void)
+{
+	char *cmd;
+
+	cmd = Cmd_Argv(0);
+	Com_Printf ("Unknown command \"%s\"\n", cmd);
+}
+
+void SCR_DebugGraph (float value, int color)
+{
+}
+
+void SCR_BeginLoadingPlaque (void)
+{
+}
+
+void SCR_EndLoadingPlaque (void)
+{
+}
+
+void Key_Init (void)
+{
+	Cmd_AddCommand ("bind", Key_Bind_Null_f);
+}
+
--- /dev/null
+++ b/null/glimp_null.c
@@ -1,0 +1,34 @@
+#include "../ref_gl/gl_local.h"
+
+void		GLimp_BeginFrame( float camera_separation )
+{
+}
+
+void		GLimp_EndFrame( void )
+{
+}
+
+int 		GLimp_Init( void *hinstance, void *hWnd )
+{
+}
+
+void		GLimp_Shutdown( void )
+{
+}
+
+int     	GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+}
+
+void		GLimp_AppActivate( qboolean active )
+{
+}
+
+void		GLimp_EnableLogging( qboolean enable )
+{
+}
+
+void		GLimp_LogNewFrame( void )
+{
+}
+
--- /dev/null
+++ b/null/in_null.c
@@ -1,0 +1,36 @@
+// in_null.c -- for systems without a mouse
+
+#include "../client/client.h"
+
+void IN_Init (void)
+{
+}
+
+void IN_Shutdown (void)
+{
+}
+
+void IN_Commands (void)
+{
+}
+
+void IN_Frame (void)
+{
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+}
+
+void IN_Activate (qboolean active)
+{
+}
+
+void IN_ActivateMouse (void)
+{
+}
+
+void IN_DeactivateMouse (void)
+{
+}
+
--- /dev/null
+++ b/null/snddma_null.c
@@ -1,0 +1,28 @@
+
+// snddma_null.c
+// all other sound mixing is portable
+
+#include "../client/client.h"
+#include "../client/snd_loc.h"
+
+qboolean SNDDMA_Init(void)
+{
+	return false;
+}
+
+int	SNDDMA_GetDMAPos(void)
+{
+	return 0;
+}
+
+void SNDDMA_Shutdown(void)
+{
+}
+
+void SNDDMA_BeginPainting (void)
+{
+}
+
+void SNDDMA_Submit(void)
+{
+}
--- /dev/null
+++ b/null/swimp_null.c
@@ -1,0 +1,30 @@
+#include "../ref_soft/r_local.h"
+
+void		SWimp_BeginFrame( float camera_separation )
+{
+}
+
+void		SWimp_EndFrame (void)
+{
+}
+
+int			SWimp_Init( void *hInstance, void *wndProc )
+{
+}
+
+void		SWimp_SetPalette( const unsigned char *palette)
+{
+}
+
+void		SWimp_Shutdown( void )
+{
+}
+
+rserr_t		SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+}
+
+void		SWimp_AppActivate( qboolean active )
+{
+}
+
--- /dev/null
+++ b/null/sys_null.c
@@ -1,0 +1,127 @@
+// sys_null.h -- null system driver to aid porting efforts
+
+#include "../qcommon/qcommon.h"
+#include "errno.h"
+
+int	curtime;
+
+unsigned	sys_frame_time;
+
+
+void Sys_mkdir (char *path)
+{
+}
+
+void Sys_Error (char *error, ...)
+{
+	va_list		argptr;
+
+	printf ("Sys_Error: ");	
+	va_start (argptr,error);
+	vprintf (error,argptr);
+	va_end (argptr);
+	printf ("\n");
+
+	exit (1);
+}
+
+void Sys_Quit (void)
+{
+	exit (0);
+}
+
+void	Sys_UnloadGame (void)
+{
+}
+
+void	*Sys_GetGameAPI (void *parms)
+{
+	return NULL;
+}
+
+char *Sys_ConsoleInput (void)
+{
+	return NULL;
+}
+
+void	Sys_ConsoleOutput (char *string)
+{
+}
+
+void Sys_SendKeyEvents (void)
+{
+}
+
+void Sys_AppActivate (void)
+{
+}
+
+void Sys_CopyProtect (void)
+{
+}
+
+char *Sys_GetClipboardData( void )
+{
+	return NULL;
+}
+
+void	*Hunk_Begin (int maxsize)
+{
+	return NULL;
+}
+
+void	*Hunk_Alloc (int size)
+{
+	return NULL;
+}
+
+void	Hunk_Free (void *buf)
+{
+}
+
+int		Hunk_End (void)
+{
+	return 0;
+}
+
+int		Sys_Milliseconds (void)
+{
+	return 0;
+}
+
+void	Sys_Mkdir (char *path)
+{
+}
+
+char	*Sys_FindFirst (char *path, unsigned musthave, unsigned canthave)
+{
+	return NULL;
+}
+
+char	*Sys_FindNext (unsigned musthave, unsigned canthave)
+{
+	return NULL;
+}
+
+void	Sys_FindClose (void)
+{
+}
+
+void	Sys_Init (void)
+{
+}
+
+
+//=============================================================================
+
+void main (int argc, char **argv)
+{
+	Qcommon_Init (argc, argv);
+
+	while (1)
+	{
+		Qcommon_Frame (0.1);
+	}
+}
+
+
--- /dev/null
+++ b/null/vid_null.c
@@ -1,0 +1,145 @@
+// vid_null.c -- null video driver to aid porting efforts
+// this assumes that one of the refs is statically linked to the executable
+
+#include "../client/client.h"
+
+viddef_t	viddef;				// global video state
+
+refexport_t	re;
+
+refexport_t GetRefAPI (refimport_t rimp);
+
+/*
+==========================================================================
+
+DIRECT LINK GLUE
+
+==========================================================================
+*/
+
+#define	MAXPRINTMSG	4096
+void VID_Printf (int print_level, char *fmt, ...)
+{
+        va_list		argptr;
+        char		msg[MAXPRINTMSG];
+
+        va_start (argptr,fmt);
+        vsprintf (msg,fmt,argptr);
+        va_end (argptr);
+
+        if (print_level == PRINT_ALL)
+                Com_Printf ("%s", msg);
+        else
+                Com_DPrintf ("%s", msg);
+}
+
+void VID_Error (int err_level, char *fmt, ...)
+{
+        va_list		argptr;
+        char		msg[MAXPRINTMSG];
+
+        va_start (argptr,fmt);
+        vsprintf (msg,fmt,argptr);
+        va_end (argptr);
+
+		Com_Error (err_level, "%s", msg);
+}
+
+void VID_NewWindow (int width, int height)
+{
+        viddef.width = width;
+        viddef.height = height;
+}
+
+/*
+** VID_GetModeInfo
+*/
+typedef struct vidmode_s
+{
+    const char *description;
+    int         width, height;
+    int         mode;
+} vidmode_t;
+
+vidmode_t vid_modes[] =
+{
+    { "Mode 0: 320x240",   320, 240,   0 },
+    { "Mode 1: 400x300",   400, 300,   1 },
+    { "Mode 2: 512x384",   512, 384,   2 },
+    { "Mode 3: 640x480",   640, 480,   3 },
+    { "Mode 4: 800x600",   800, 600,   4 },
+    { "Mode 5: 960x720",   960, 720,   5 },
+    { "Mode 6: 1024x768",  1024, 768,  6 },
+    { "Mode 7: 1152x864",  1152, 864,  7 },
+    { "Mode 8: 1280x960",  1280, 960, 8 },
+    { "Mode 9: 1600x1200", 1600, 1200, 9 }
+};
+#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
+
+qboolean VID_GetModeInfo( int *width, int *height, int mode )
+{
+    if ( mode < 0 || mode >= VID_NUM_MODES )
+        return false;
+
+    *width  = vid_modes[mode].width;
+    *height = vid_modes[mode].height;
+
+    return true;
+}
+
+
+void	VID_Init (void)
+{
+    refimport_t	ri;
+
+    viddef.width = 320;
+    viddef.height = 240;
+
+    ri.Cmd_AddCommand = Cmd_AddCommand;
+    ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+    ri.Cmd_Argc = Cmd_Argc;
+    ri.Cmd_Argv = Cmd_Argv;
+    ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+    ri.Con_Printf = VID_Printf;
+    ri.Sys_Error = VID_Error;
+    ri.FS_LoadFile = FS_LoadFile;
+    ri.FS_FreeFile = FS_FreeFile;
+    ri.FS_Gamedir = FS_Gamedir;
+	ri.Vid_NewWindow = VID_NewWindow;
+    ri.Cvar_Get = Cvar_Get;
+    ri.Cvar_Set = Cvar_Set;
+    ri.Cvar_SetValue = Cvar_SetValue;
+    ri.Vid_GetModeInfo = VID_GetModeInfo;
+
+    re = GetRefAPI(ri);
+
+    if (re.api_version != API_VERSION)
+        Com_Error (ERR_FATAL, "Re has incompatible api_version");
+    
+        // call the init function
+    if (re.Init (NULL, NULL) == -1)
+		Com_Error (ERR_FATAL, "Couldn't start refresh");
+}
+
+void	VID_Shutdown (void)
+{
+    if (re.Shutdown)
+	    re.Shutdown ();
+}
+
+void	VID_CheckChanges (void)
+{
+}
+
+void	VID_MenuInit (void)
+{
+}
+
+void	VID_MenuDraw (void)
+{
+}
+
+const char *VID_MenuKey( int k)
+{
+	return NULL;
+}
--- /dev/null
+++ b/qcommon/cmd.c
@@ -1,0 +1,892 @@
+/*
+Copyright (C) 1997-2001 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 "qcommon.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;
+
+#define	ALIAS_LOOP_COUNT	16
+int		alias_count;		// for detecting runaway loops
+
+
+//=============================================================================
+
+/*
+============
+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];
+
+byte		defer_text_buf[8192];
+
+/*
+============
+Cbuf_Init
+============
+*/
+void Cbuf_Init (void)
+{
+	SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
+}
+
+/*
+============
+Cbuf_AddText
+
+Adds command text at the end of the buffer
+============
+*/
+void Cbuf_AddText (char *text)
+{
+	int		l;
+	
+	l = strlen (text);
+
+	if (cmd_text.cursize + l >= cmd_text.maxsize)
+	{
+		Com_Printf ("Cbuf_AddText: overflow\n");
+		return;
+	}
+	SZ_Write (&cmd_text, text, 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);
+		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_CopyToDefer
+============
+*/
+void Cbuf_CopyToDefer (void)
+{
+	memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
+	defer_text_buf[cmd_text.cursize] = 0;
+	cmd_text.cursize = 0;
+}
+
+/*
+============
+Cbuf_InsertFromDefer
+============
+*/
+void Cbuf_InsertFromDefer (void)
+{
+	Cbuf_InsertText (defer_text_buf);
+	defer_text_buf[0] = 0;
+}
+
+
+/*
+============
+Cbuf_ExecuteText
+============
+*/
+void Cbuf_ExecuteText (int exec_when, char *text)
+{
+	switch (exec_when)
+	{
+	case EXEC_NOW:
+		Cmd_ExecuteString (text);
+		break;
+	case EXEC_INSERT:
+		Cbuf_InsertText (text);
+		break;
+	case EXEC_APPEND:
+		Cbuf_AddText (text);
+		break;
+	default:
+		Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
+	}
+}
+
+/*
+============
+Cbuf_Execute
+============
+*/
+void Cbuf_Execute (void)
+{
+	int		i;
+	char	*text;
+	char	line[1024];
+	int		quotes;
+
+	alias_count = 0;		// don't allow infinite alias loops
+
+	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;
+			memmove (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;
+		}
+	}
+}
+
+
+/*
+===============
+Cbuf_AddEarlyCommands
+
+Adds command line parameters as script statements
+Commands lead with a +, and continue until another +
+
+Set commands are added early, so they are guaranteed to be set before
+the client and server initialize for the first time.
+
+Other commands are added late, after all initialization is complete.
+===============
+*/
+void Cbuf_AddEarlyCommands (qboolean clear)
+{
+	int		i;
+	char	*s;
+
+	for (i=0 ; i<COM_Argc() ; i++)
+	{
+		s = COM_Argv(i);
+		if (strcmp (s, "+set"))
+			continue;
+		Cbuf_AddText (va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
+		if (clear)
+		{
+			COM_ClearArgv(i);
+			COM_ClearArgv(i+1);
+			COM_ClearArgv(i+2);
+		}
+		i+=2;
+	}
+}
+
+/*
+=================
+Cbuf_AddLateCommands
+
+Adds command line parameters as script statements
+Commands lead with a + and continue until another + or -
+quake +vid_ref gl +map amlev1
+
+Returns true if any late commands were added, which
+will keep the demoloop from immediately starting
+=================
+*/
+qboolean Cbuf_AddLateCommands (void)
+{
+	int		i, j;
+	int		s;
+	char	*text, *build, c;
+	int		argc;
+	qboolean	ret;
+
+// build the combined string to parse from
+	s = 0;
+	argc = COM_Argc();
+	for (i=1 ; i<argc ; i++)
+	{
+		s += strlen (COM_Argv(i)) + 1;
+	}
+	if (!s)
+		return false;
+		
+	text = Z_Malloc (s+1);
+	text[0] = 0;
+	for (i=1 ; i<argc ; i++)
+	{
+		strcat (text,COM_Argv(i));
+		if (i != argc-1)
+			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;
+			
+			strcat (build, text+i);
+			strcat (build, "\n");
+			text[j] = c;
+			i = j-1;
+		}
+	}
+
+	ret = (build[0] != 0);
+	if (ret)
+		Cbuf_AddText (build);
+	
+	Z_Free (text);
+	Z_Free (build);
+
+	return ret;
+}
+
+
+/*
+==============================================================================
+
+						SCRIPT COMMANDS
+
+==============================================================================
+*/
+
+
+/*
+===============
+Cmd_Exec_f
+===============
+*/
+void Cmd_Exec_f (void)
+{
+	char	*f, *f2;
+	int		len;
+
+	if (Cmd_Argc () != 2)
+	{
+		Com_Printf ("exec <filename> : execute a script file\n");
+		return;
+	}
+
+	len = FS_LoadFile (Cmd_Argv(1), (void **)&f);
+	if (!f)
+	{
+		Com_Printf ("couldn't exec %s\n",Cmd_Argv(1));
+		return;
+	}
+	Com_Printf ("execing %s\n",Cmd_Argv(1));
+	
+	// the file doesn't have a trailing 0, so we need to copy it off
+	f2 = Z_Malloc(len+1);
+	memcpy (f2, f, len);
+	f2[len] = 0;
+
+	Cbuf_InsertText (f2);
+
+	Z_Free (f2);
+	FS_FreeFile (f);
+}
+
+
+/*
+===============
+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++)
+		Com_Printf ("%s ",Cmd_Argv(i));
+	Com_Printf ("\n");
+}
+
+/*
+===============
+Cmd_Alias_f
+
+Creates a new command that executes a command string (possibly ; seperated)
+===============
+*/
+void Cmd_Alias_f (void)
+{
+	cmdalias_t	*a;
+	char		cmd[1024];
+	int			i, c;
+	char		*s;
+
+	if (Cmd_Argc() == 1)
+	{
+		Com_Printf ("Current alias commands:\n");
+		for (a = cmd_alias ; a ; a=a->next)
+			Com_Printf ("%s : %s\n", a->name, a->value);
+		return;
+	}
+
+	s = Cmd_Argv(1);
+	if (strlen(s) >= MAX_ALIAS_NAME)
+	{
+		Com_Printf ("Alias name is too long\n");
+		return;
+	}
+
+	// if the alias already 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 - 1))
+			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;
+
+
+static	int			cmd_argc;
+static	char		*cmd_argv[MAX_STRING_TOKENS];
+static	char		*cmd_null_string = "";
+static	char		cmd_args[MAX_STRING_CHARS];
+
+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 ( (unsigned)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)
+{
+	return cmd_args;
+}
+
+
+/*
+======================
+Cmd_MacroExpandString
+======================
+*/
+char *Cmd_MacroExpandString (char *text)
+{
+	int		i, j, count, len;
+	qboolean	inquote;
+	char	*scan;
+	static	char	expanded[MAX_STRING_CHARS];
+	char	temporary[MAX_STRING_CHARS];
+	char	*token, *start;
+
+	inquote = false;
+	scan = text;
+
+	len = strlen (scan);
+	if (len >= MAX_STRING_CHARS)
+	{
+		Com_Printf ("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
+		return NULL;
+	}
+
+	count = 0;
+
+	for (i=0 ; i<len ; i++)
+	{
+		if (scan[i] == '"')
+			inquote ^= 1;
+		if (inquote)
+			continue;	// don't expand inside quotes
+		if (scan[i] != '$')
+			continue;
+		// scan out the complete macro
+		start = scan+i+1;
+		token = COM_Parse (&start);
+		if (!start)
+			continue;
+	
+		token = Cvar_VariableString (token);
+
+		j = strlen(token);
+		len += j;
+		if (len >= MAX_STRING_CHARS)
+		{
+			Com_Printf ("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
+			return NULL;
+		}
+
+		strncpy (temporary, scan, i);
+		strcpy (temporary+i, token);
+		strcpy (temporary+i+j, start);
+
+		strcpy (expanded, temporary);
+		scan = expanded;
+		i--;
+
+		if (++count == 100)
+		{
+			Com_Printf ("Macro expansion loop, discarded.\n");
+			return NULL;
+		}
+	}
+
+	if (inquote)
+	{
+		Com_Printf ("Line has unmatched quote, discarded.\n");
+		return NULL;
+	}
+
+	return scan;
+}
+
+
+/*
+============
+Cmd_TokenizeString
+
+Parses the given string into command line tokens.
+$Cvars will be expanded unless they are in a quoted token
+============
+*/
+void Cmd_TokenizeString (char *text, qboolean macroExpand)
+{
+	int		i;
+	char	*com_token;
+
+// clear the args from the last string
+	for (i=0 ; i<cmd_argc ; i++)
+		Z_Free (cmd_argv[i]);
+		
+	cmd_argc = 0;
+	cmd_args[0] = 0;
+	
+	// macro expand the text
+	if (macroExpand)
+		text = Cmd_MacroExpandString (text);
+	if (!text)
+		return;
+
+	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;
+
+		// set cmd_args to everything after the first arg
+		if (cmd_argc == 1)
+		{
+			int		l;
+
+			strcpy (cmd_args, text);
+
+			// strip off any trailing whitespace
+			l = strlen(cmd_args) - 1;
+			for ( ; l >= 0 ; l--)
+				if (cmd_args[l] <= ' ')
+					cmd_args[l] = 0;
+				else
+					break;
+		}
+			
+		com_token = COM_Parse (&text);
+		if (!text)
+			return;
+
+		if (cmd_argc < MAX_STRING_TOKENS)
+		{
+			cmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1);
+			strcpy (cmd_argv[cmd_argc], com_token);
+			cmd_argc++;
+		}
+	}
+	
+}
+
+
+/*
+============
+Cmd_AddCommand
+============
+*/
+void	Cmd_AddCommand (char *cmd_name, xcommand_t function)
+{
+	cmd_function_t	*cmd;
+	
+// fail if the command is a variable name
+	if (Cvar_VariableString(cmd_name)[0])
+	{
+		Com_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 (!strcmp (cmd_name, cmd->name))
+		{
+			Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
+			return;
+		}
+	}
+
+	cmd = Z_Malloc (sizeof(cmd_function_t));
+	cmd->name = cmd_name;
+	cmd->function = function;
+	cmd->next = cmd_functions;
+	cmd_functions = cmd;
+}
+
+/*
+============
+Cmd_RemoveCommand
+============
+*/
+void	Cmd_RemoveCommand (char *cmd_name)
+{
+	cmd_function_t	*cmd, **back;
+
+	back = &cmd_functions;
+	while (1)
+	{
+		cmd = *back;
+		if (!cmd)
+		{
+			Com_Printf ("Cmd_RemoveCommand: %s not added\n", cmd_name);
+			return;
+		}
+		if (!strcmp (cmd_name, cmd->name))
+		{
+			*back = cmd->next;
+			Z_Free (cmd);
+			return;
+		}
+		back = &cmd->next;
+	}
+}
+
+/*
+============
+Cmd_Exists
+============
+*/
+qboolean	Cmd_Exists (char *cmd_name)
+{
+	cmd_function_t	*cmd;
+
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!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 = 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;
+}
+
+
+/*
+============
+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, true);
+			
+	// 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)
+			{	// forward to server command
+				Cmd_ExecuteString (va("cmd %s", text));
+			}
+			else
+				cmd->function ();
+			return;
+		}
+	}
+
+	// check alias
+	for (a=cmd_alias ; a ; a=a->next)
+	{
+		if (!Q_strcasecmp (cmd_argv[0], a->name))
+		{
+			if (++alias_count == ALIAS_LOOP_COUNT)
+			{
+				Com_Printf ("ALIAS_LOOP_COUNT\n");
+				return;
+			}
+			Cbuf_InsertText (a->value);
+			return;
+		}
+	}
+	
+	// check cvars
+	if (Cvar_Command ())
+		return;
+
+	// send it as a server command if we are connected
+	Cmd_ForwardToServer ();
+}
+
+/*
+============
+Cmd_List_f
+============
+*/
+void Cmd_List_f (void)
+{
+	cmd_function_t	*cmd;
+	int				i;
+
+	i = 0;
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next, i++)
+		Com_Printf ("%s\n", cmd->name);
+	Com_Printf ("%i commands\n", i);
+}
+
+/*
+============
+Cmd_Init
+============
+*/
+void Cmd_Init (void)
+{
+//
+// register our commands
+//
+	Cmd_AddCommand ("cmdlist",Cmd_List_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);
+}
+
--- /dev/null
+++ b/qcommon/cmodel.c
@@ -1,0 +1,1770 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// cmodel.c -- model loading
+
+#include "qcommon.h"
+
+typedef struct
+{
+	cplane_t	*plane;
+	int			children[2];		// negative numbers are leafs
+} cnode_t;
+
+typedef struct
+{
+	cplane_t	*plane;
+	mapsurface_t	*surface;
+} cbrushside_t;
+
+typedef struct
+{
+	int			contents;
+	int			cluster;
+	int			area;
+	unsigned short	firstleafbrush;
+	unsigned short	numleafbrushes;
+} cleaf_t;
+
+typedef struct
+{
+	int			contents;
+	int			numsides;
+	int			firstbrushside;
+	int			checkcount;		// to avoid repeated testings
+} cbrush_t;
+
+typedef struct
+{
+	int		numareaportals;
+	int		firstareaportal;
+	int		floodnum;			// if two areas have equal floodnums, they are connected
+	int		floodvalid;
+} carea_t;
+
+int			checkcount;
+
+char		map_name[MAX_QPATH];
+
+int			numbrushsides;
+cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
+
+int			numtexinfo;
+mapsurface_t	map_surfaces[MAX_MAP_TEXINFO];
+
+int			numplanes;
+cplane_t	map_planes[MAX_MAP_PLANES+6];		// extra for box hull
+
+int			numnodes;
+cnode_t		map_nodes[MAX_MAP_NODES+6];		// extra for box hull
+
+int			numleafs = 1;	// allow leaf funcs to be called without a map
+cleaf_t		map_leafs[MAX_MAP_LEAFS];
+int			emptyleaf, solidleaf;
+
+int			numleafbrushes;
+unsigned short	map_leafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int			numcmodels;
+cmodel_t	map_cmodels[MAX_MAP_MODELS];
+
+int			numbrushes;
+cbrush_t	map_brushes[MAX_MAP_BRUSHES];
+
+int			numvisibility;
+byte		map_visibility[MAX_MAP_VISIBILITY];
+dvis_t		*map_vis = (dvis_t *)map_visibility;
+
+int			numentitychars;
+char		map_entitystring[MAX_MAP_ENTSTRING];
+
+int			numareas = 1;
+carea_t		map_areas[MAX_MAP_AREAS];
+
+int			numareaportals;
+dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
+
+int			numclusters = 1;
+
+mapsurface_t	nullsurface;
+
+int			floodvalid;
+
+qboolean	portalopen[MAX_MAP_AREAPORTALS];
+
+
+cvar_t		*map_noareas;
+
+void	CM_InitBoxHull (void);
+void	FloodAreaConnections (void);
+
+
+int		c_pointcontents;
+int		c_traces, c_brush_traces;
+
+
+/*
+===============================================================================
+
+					MAP LOADING
+
+===============================================================================
+*/
+
+byte	*cmod_base;
+
+/*
+=================
+CMod_LoadSubmodels
+=================
+*/
+void CMod_LoadSubmodels (lump_t *l)
+{
+	dmodel_t	*in;
+	cmodel_t	*out;
+	int			i, j, count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no models");
+	if (count > MAX_MAP_MODELS)
+		Com_Error (ERR_DROP, "Map has too many models");
+
+	numcmodels = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out = &map_cmodels[i];
+
+		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]);
+		}
+		out->headnode = LittleLong (in->headnode);
+	}
+}
+
+
+/*
+=================
+CMod_LoadSurfaces
+=================
+*/
+void CMod_LoadSurfaces (lump_t *l)
+{
+	texinfo_t	*in;
+	mapsurface_t	*out;
+	int			i, count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no surfaces");
+	if (count > MAX_MAP_TEXINFO)
+		Com_Error (ERR_DROP, "Map has too many surfaces");
+
+	numtexinfo = count;
+	out = map_surfaces;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
+		strncpy (out->rname, in->texture, sizeof(out->rname)-1);
+		out->c.flags = LittleLong (in->flags);
+		out->c.value = LittleLong (in->value);
+	}
+}
+
+
+/*
+=================
+CMod_LoadNodes
+
+=================
+*/
+void CMod_LoadNodes (lump_t *l)
+{
+	dnode_t		*in;
+	int			child;
+	cnode_t		*out;
+	int			i, j, count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map has no nodes");
+	if (count > MAX_MAP_NODES)
+		Com_Error (ERR_DROP, "Map has too many nodes");
+
+	out = map_nodes;
+
+	numnodes = count;
+
+	for (i=0 ; i<count ; i++, out++, in++)
+	{
+		out->plane = map_planes + LittleLong(in->planenum);
+		for (j=0 ; j<2 ; j++)
+		{
+			child = LittleLong (in->children[j]);
+			out->children[j] = child;
+		}
+	}
+
+}
+
+/*
+=================
+CMod_LoadBrushes
+
+=================
+*/
+void CMod_LoadBrushes (lump_t *l)
+{
+	dbrush_t	*in;
+	cbrush_t	*out;
+	int			i, count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count > MAX_MAP_BRUSHES)
+		Com_Error (ERR_DROP, "Map has too many brushes");
+
+	out = map_brushes;
+
+	numbrushes = count;
+
+	for (i=0 ; i<count ; i++, out++, in++)
+	{
+		out->firstbrushside = LittleLong(in->firstside);
+		out->numsides = LittleLong(in->numsides);
+		out->contents = LittleLong(in->contents);
+	}
+
+}
+
+/*
+=================
+CMod_LoadLeafs
+=================
+*/
+void CMod_LoadLeafs (lump_t *l)
+{
+	int			i;
+	cleaf_t		*out;
+	dleaf_t 	*in;
+	int			count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no leafs");
+	// need to save space for box planes
+	if (count > MAX_MAP_PLANES)
+		Com_Error (ERR_DROP, "Map has too many planes");
+
+	out = map_leafs;	
+	numleafs = count;
+	numclusters = 0;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->contents = LittleLong (in->contents);
+		out->cluster = LittleShort (in->cluster);
+		out->area = LittleShort (in->area);
+		out->firstleafbrush = LittleShort (in->firstleafbrush);
+		out->numleafbrushes = LittleShort (in->numleafbrushes);
+
+		if (out->cluster >= numclusters)
+			numclusters = out->cluster + 1;
+	}
+
+	if (map_leafs[0].contents != CONTENTS_SOLID)
+		Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
+	solidleaf = 0;
+	emptyleaf = -1;
+	for (i=1 ; i<numleafs ; i++)
+	{
+		if (!map_leafs[i].contents)
+		{
+			emptyleaf = i;
+			break;
+		}
+	}
+	if (emptyleaf == -1)
+		Com_Error (ERR_DROP, "Map does not have an empty leaf");
+}
+
+/*
+=================
+CMod_LoadPlanes
+=================
+*/
+void CMod_LoadPlanes (lump_t *l)
+{
+	int			i, j;
+	cplane_t	*out;
+	dplane_t 	*in;
+	int			count;
+	int			bits;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no planes");
+	// need to save space for box planes
+	if (count > MAX_MAP_PLANES)
+		Com_Error (ERR_DROP, "Map has too many planes");
+
+	out = map_planes;	
+	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;
+	}
+}
+
+/*
+=================
+CMod_LoadLeafBrushes
+=================
+*/
+void CMod_LoadLeafBrushes (lump_t *l)
+{
+	int			i;
+	unsigned short	*out;
+	unsigned short 	*in;
+	int			count;
+	
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count < 1)
+		Com_Error (ERR_DROP, "Map with no planes");
+	// need to save space for box planes
+	if (count > MAX_MAP_LEAFBRUSHES)
+		Com_Error (ERR_DROP, "Map has too many leafbrushes");
+
+	out = map_leafbrushes;
+	numleafbrushes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+		*out = LittleShort (*in);
+}
+
+/*
+=================
+CMod_LoadBrushSides
+=================
+*/
+void CMod_LoadBrushSides (lump_t *l)
+{
+	int			i, j;
+	cbrushside_t	*out;
+	dbrushside_t 	*in;
+	int			count;
+	int			num;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	// need to save space for box planes
+	if (count > MAX_MAP_BRUSHSIDES)
+		Com_Error (ERR_DROP, "Map has too many planes");
+
+	out = map_brushsides;	
+	numbrushsides = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		num = LittleShort (in->planenum);
+		out->plane = &map_planes[num];
+		j = LittleShort (in->texinfo);
+		if (j >= numtexinfo)
+			Com_Error (ERR_DROP, "Bad brushside texinfo");
+		out->surface = &map_surfaces[j];
+	}
+}
+
+/*
+=================
+CMod_LoadAreas
+=================
+*/
+void CMod_LoadAreas (lump_t *l)
+{
+	int			i;
+	carea_t		*out;
+	darea_t 	*in;
+	int			count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count > MAX_MAP_AREAS)
+		Com_Error (ERR_DROP, "Map has too many areas");
+
+	out = map_areas;
+	numareas = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->numareaportals = LittleLong (in->numareaportals);
+		out->firstareaportal = LittleLong (in->firstareaportal);
+		out->floodvalid = 0;
+		out->floodnum = 0;
+	}
+}
+
+/*
+=================
+CMod_LoadAreaPortals
+=================
+*/
+void CMod_LoadAreaPortals (lump_t *l)
+{
+	int			i;
+	dareaportal_t		*out;
+	dareaportal_t 	*in;
+	int			count;
+
+	in = (void *)(cmod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+	count = l->filelen / sizeof(*in);
+
+	if (count > MAX_MAP_AREAS)
+		Com_Error (ERR_DROP, "Map has too many areas");
+
+	out = map_areaportals;
+	numareaportals = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->portalnum = LittleLong (in->portalnum);
+		out->otherarea = LittleLong (in->otherarea);
+	}
+}
+
+/*
+=================
+CMod_LoadVisibility
+=================
+*/
+void CMod_LoadVisibility (lump_t *l)
+{
+	int		i;
+
+	numvisibility = l->filelen;
+	if (l->filelen > MAX_MAP_VISIBILITY)
+		Com_Error (ERR_DROP, "Map has too large visibility lump");
+
+	memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
+
+	map_vis->numclusters = LittleLong (map_vis->numclusters);
+	for (i=0 ; i<map_vis->numclusters ; i++)
+	{
+		map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
+		map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
+	}
+}
+
+
+/*
+=================
+CMod_LoadEntityString
+=================
+*/
+void CMod_LoadEntityString (lump_t *l)
+{
+	numentitychars = l->filelen;
+	if (l->filelen > MAX_MAP_ENTSTRING)
+		Com_Error (ERR_DROP, "Map has too large entity lump");
+
+	memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
+}
+
+
+
+/*
+==================
+CM_LoadMap
+
+Loads in the map and all submodels
+==================
+*/
+cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
+{
+	unsigned		*buf;
+	int				i;
+	dheader_t		header;
+	int				length;
+	static unsigned	last_checksum;
+
+	map_noareas = Cvar_Get ("map_noareas", "0", 0);
+
+	if (  !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
+	{
+		*checksum = last_checksum;
+		if (!clientload)
+		{
+			memset (portalopen, 0, sizeof(portalopen));
+			FloodAreaConnections ();
+		}
+		return &map_cmodels[0];		// still have the right version
+	}
+
+	// free old stuff
+	numplanes = 0;
+	numnodes = 0;
+	numleafs = 0;
+	numcmodels = 0;
+	numvisibility = 0;
+	numentitychars = 0;
+	map_entitystring[0] = 0;
+	map_name[0] = 0;
+
+	if (!name || !name[0])
+	{
+		numleafs = 1;
+		numclusters = 1;
+		numareas = 1;
+		*checksum = 0;
+		return &map_cmodels[0];			// cinematic servers won't have anything at all
+	}
+
+	//
+	// load the file
+	//
+	length = FS_LoadFile (name, (void **)&buf);
+	if (!buf)
+		Com_Error (ERR_DROP, "Couldn't load %s", name);
+
+	last_checksum = LittleLong (Com_BlockChecksum (buf, length));
+	*checksum = last_checksum;
+
+	header = *(dheader_t *)buf;
+	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
+		((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
+
+	if (header.version != BSPVERSION)
+		Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
+		, name, header.version, BSPVERSION);
+
+	cmod_base = (byte *)buf;
+
+	// load into heap
+	CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
+	CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
+	CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
+	CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
+	CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
+	CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
+	CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
+	CMod_LoadNodes (&header.lumps[LUMP_NODES]);
+	CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
+	CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
+	CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
+	CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
+
+	FS_FreeFile (buf);
+
+	CM_InitBoxHull ();
+
+	memset (portalopen, 0, sizeof(portalopen));
+	FloodAreaConnections ();
+
+	strcpy (map_name, name);
+
+	return &map_cmodels[0];
+}
+
+/*
+==================
+CM_InlineModel
+==================
+*/
+cmodel_t	*CM_InlineModel (char *name)
+{
+	int		num;
+
+	if (!name || name[0] != '*')
+		Com_Error (ERR_DROP, "CM_InlineModel: bad name");
+	num = atoi (name+1);
+	if (num < 1 || num >= numcmodels)
+		Com_Error (ERR_DROP, "CM_InlineModel: bad number");
+
+	return &map_cmodels[num];
+}
+
+int		CM_NumClusters (void)
+{
+	return numclusters;
+}
+
+int		CM_NumInlineModels (void)
+{
+	return numcmodels;
+}
+
+char	*CM_EntityString (void)
+{
+	return map_entitystring;
+}
+
+int		CM_LeafContents (int leafnum)
+{
+	if (leafnum < 0 || leafnum >= numleafs)
+		Com_Error (ERR_DROP, "CM_LeafContents: bad number");
+	return map_leafs[leafnum].contents;
+}
+
+int		CM_LeafCluster (int leafnum)
+{
+	if (leafnum < 0 || leafnum >= numleafs)
+		Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
+	return map_leafs[leafnum].cluster;
+}
+
+int		CM_LeafArea (int leafnum)
+{
+	if (leafnum < 0 || leafnum >= numleafs)
+		Com_Error (ERR_DROP, "CM_LeafArea: bad number");
+	return map_leafs[leafnum].area;
+}
+
+//=======================================================================
+
+
+cplane_t	*box_planes;
+int			box_headnode;
+cbrush_t	*box_brush;
+cleaf_t		*box_leaf;
+
+/*
+===================
+CM_InitBoxHull
+
+Set up the planes and nodes so that the six floats of a bounding box
+can just be stored out and get a proper clipping hull structure.
+===================
+*/
+void CM_InitBoxHull (void)
+{
+	int			i;
+	int			side;
+	cnode_t		*c;
+	cplane_t	*p;
+	cbrushside_t	*s;
+
+	box_headnode = numnodes;
+	box_planes = &map_planes[numplanes];
+	if (numnodes+6 > MAX_MAP_NODES
+		|| numbrushes+1 > MAX_MAP_BRUSHES
+		|| numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
+		|| numbrushsides+6 > MAX_MAP_BRUSHSIDES
+		|| numplanes+12 > MAX_MAP_PLANES)
+		Com_Error (ERR_DROP, "Not enough room for box tree");
+
+	box_brush = &map_brushes[numbrushes];
+	box_brush->numsides = 6;
+	box_brush->firstbrushside = numbrushsides;
+	box_brush->contents = CONTENTS_MONSTER;
+
+	box_leaf = &map_leafs[numleafs];
+	box_leaf->contents = CONTENTS_MONSTER;
+	box_leaf->firstleafbrush = numleafbrushes;
+	box_leaf->numleafbrushes = 1;
+
+	map_leafbrushes[numleafbrushes] = numbrushes;
+
+	for (i=0 ; i<6 ; i++)
+	{
+		side = i&1;
+
+		// brush sides
+		s = &map_brushsides[numbrushsides+i];
+		s->plane = 	map_planes + (numplanes+i*2+side);
+		s->surface = &nullsurface;
+
+		// nodes
+		c = &map_nodes[box_headnode+i];
+		c->plane = map_planes + (numplanes+i*2);
+		c->children[side] = -1 - emptyleaf;
+		if (i != 5)
+			c->children[side^1] = box_headnode+i + 1;
+		else
+			c->children[side^1] = -1 - numleafs;
+
+		// planes
+		p = &box_planes[i*2];
+		p->type = i>>1;
+		p->signbits = 0;
+		VectorClear (p->normal);
+		p->normal[i>>1] = 1;
+
+		p = &box_planes[i*2+1];
+		p->type = 3 + (i>>1);
+		p->signbits = 0;
+		VectorClear (p->normal);
+		p->normal[i>>1] = -1;
+	}	
+}
+
+
+/*
+===================
+CM_HeadnodeForBox
+
+To keep everything totally uniform, bounding boxes are turned into small
+BSP trees instead of being compared directly.
+===================
+*/
+int	CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
+{
+	box_planes[0].dist = maxs[0];
+	box_planes[1].dist = -maxs[0];
+	box_planes[2].dist = mins[0];
+	box_planes[3].dist = -mins[0];
+	box_planes[4].dist = maxs[1];
+	box_planes[5].dist = -maxs[1];
+	box_planes[6].dist = mins[1];
+	box_planes[7].dist = -mins[1];
+	box_planes[8].dist = maxs[2];
+	box_planes[9].dist = -maxs[2];
+	box_planes[10].dist = mins[2];
+	box_planes[11].dist = -mins[2];
+
+	return box_headnode;
+}
+
+
+/*
+==================
+CM_PointLeafnum_r
+
+==================
+*/
+int CM_PointLeafnum_r (vec3_t p, int num)
+{
+	float		d;
+	cnode_t		*node;
+	cplane_t	*plane;
+
+	while (num >= 0)
+	{
+		node = map_nodes + num;
+		plane = node->plane;
+		
+		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];
+	}
+
+	c_pointcontents++;		// optimize counter
+
+	return -1 - num;
+}
+
+int CM_PointLeafnum (vec3_t p)
+{
+	if (!numplanes)
+		return 0;		// sound may call this without map loaded
+	return CM_PointLeafnum_r (p, 0);
+}
+
+
+
+/*
+=============
+CM_BoxLeafnums
+
+Fills in a list of all the leafs touched
+=============
+*/
+int		leaf_count, leaf_maxcount;
+int		*leaf_list;
+float	*leaf_mins, *leaf_maxs;
+int		leaf_topnode;
+
+void CM_BoxLeafnums_r (int nodenum)
+{
+	cplane_t	*plane;
+	cnode_t		*node;
+	int		s;
+
+	while (1)
+	{
+		if (nodenum < 0)
+		{
+			if (leaf_count >= leaf_maxcount)
+			{
+//				Com_Printf ("CM_BoxLeafnums_r: overflow\n");
+				return;
+			}
+			leaf_list[leaf_count++] = -1 - nodenum;
+			return;
+		}
+	
+		node = &map_nodes[nodenum];
+		plane = node->plane;
+//		s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
+		s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
+		if (s == 1)
+			nodenum = node->children[0];
+		else if (s == 2)
+			nodenum = node->children[1];
+		else
+		{	// go down both
+			if (leaf_topnode == -1)
+				leaf_topnode = nodenum;
+			CM_BoxLeafnums_r (node->children[0]);
+			nodenum = node->children[1];
+		}
+
+	}
+}
+
+int	CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
+{
+	leaf_list = list;
+	leaf_count = 0;
+	leaf_maxcount = listsize;
+	leaf_mins = mins;
+	leaf_maxs = maxs;
+
+	leaf_topnode = -1;
+
+	CM_BoxLeafnums_r (headnode);
+
+	if (topnode)
+		*topnode = leaf_topnode;
+
+	return leaf_count;
+}
+
+int	CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
+{
+	return CM_BoxLeafnums_headnode (mins, maxs, list,
+		listsize, map_cmodels[0].headnode, topnode);
+}
+
+
+
+/*
+==================
+CM_PointContents
+
+==================
+*/
+int CM_PointContents (vec3_t p, int headnode)
+{
+	int		l;
+
+	if (!numnodes)	// map not loaded
+		return 0;
+
+	l = CM_PointLeafnum_r (p, headnode);
+
+	return map_leafs[l].contents;
+}
+
+/*
+==================
+CM_TransformedPointContents
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+int	CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
+{
+	vec3_t		p_l;
+	vec3_t		temp;
+	vec3_t		forward, right, up;
+	int			l;
+
+	// subtract origin offset
+	VectorSubtract (p, origin, p_l);
+
+	// rotate start and end into the models frame of reference
+	if (headnode != box_headnode && 
+	(angles[0] || angles[1] || angles[2]) )
+	{
+		AngleVectors (angles, forward, right, up);
+
+		VectorCopy (p_l, temp);
+		p_l[0] = DotProduct (temp, forward);
+		p_l[1] = -DotProduct (temp, right);
+		p_l[2] = DotProduct (temp, up);
+	}
+
+	l = CM_PointLeafnum_r (p_l, headnode);
+
+	return map_leafs[l].contents;
+}
+
+
+/*
+===============================================================================
+
+BOX TRACING
+
+===============================================================================
+*/
+
+// 1/32 epsilon to keep floating point happy
+#define	DIST_EPSILON	(0.03125)
+
+vec3_t	trace_start, trace_end;
+vec3_t	trace_mins, trace_maxs;
+vec3_t	trace_extents;
+
+trace_t	trace_trace;
+int		trace_contents;
+qboolean	trace_ispoint;		// optimized case
+
+/*
+================
+CM_ClipBoxToBrush
+================
+*/
+void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
+					  trace_t *trace, cbrush_t *brush)
+{
+	int			i, j;
+	cplane_t	*plane, *clipplane;
+	float		dist;
+	float		enterfrac, leavefrac;
+	vec3_t		ofs;
+	float		d1, d2;
+	qboolean	getout, startout;
+	float		f;
+	cbrushside_t	*side, *leadside;
+
+	enterfrac = -1;
+	leavefrac = 1;
+	clipplane = NULL;
+
+	if (!brush->numsides)
+		return;
+
+	c_brush_traces++;
+
+	getout = false;
+	startout = false;
+	leadside = NULL;
+
+	for (i=0 ; i<brush->numsides ; i++)
+	{
+		side = &map_brushsides[brush->firstbrushside+i];
+		plane = side->plane;
+
+		// FIXME: special case for axial
+
+		if (!trace_ispoint)
+		{	// general box case
+
+			// push the plane out apropriately for mins/maxs
+
+			// FIXME: use signbits into 8 way lookup for each mins/maxs
+			for (j=0 ; j<3 ; j++)
+			{
+				if (plane->normal[j] < 0)
+					ofs[j] = maxs[j];
+				else
+					ofs[j] = mins[j];
+			}
+			dist = DotProduct (ofs, plane->normal);
+			dist = plane->dist - dist;
+		}
+		else
+		{	// special point case
+			dist = plane->dist;
+		}
+
+		d1 = DotProduct (p1, plane->normal) - dist;
+		d2 = DotProduct (p2, plane->normal) - dist;
+
+		if (d2 > 0)
+			getout = true;	// endpoint is not in solid
+		if (d1 > 0)
+			startout = true;
+
+		// if completely in front of face, no intersection
+		if (d1 > 0 && d2 >= d1)
+			return;
+
+		if (d1 <= 0 && d2 <= 0)
+			continue;
+
+		// crosses face
+		if (d1 > d2)
+		{	// enter
+			f = (d1-DIST_EPSILON) / (d1-d2);
+			if (f > enterfrac)
+			{
+				enterfrac = f;
+				clipplane = plane;
+				leadside = side;
+			}
+		}
+		else
+		{	// leave
+			f = (d1+DIST_EPSILON) / (d1-d2);
+			if (f < leavefrac)
+				leavefrac = f;
+		}
+	}
+
+	if (!startout)
+	{	// original point was inside brush
+		trace->startsolid = true;
+		if (!getout)
+			trace->allsolid = true;
+		return;
+	}
+	if (enterfrac < leavefrac)
+	{
+		if (enterfrac > -1 && enterfrac < trace->fraction)
+		{
+			if (enterfrac < 0)
+				enterfrac = 0;
+			trace->fraction = enterfrac;
+			trace->plane = *clipplane;
+			trace->surface = &(leadside->surface->c);
+			trace->contents = brush->contents;
+		}
+	}
+}
+
+/*
+================
+CM_TestBoxInBrush
+================
+*/
+void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
+					  trace_t *trace, cbrush_t *brush)
+{
+	int			i, j;
+	cplane_t	*plane;
+	float		dist;
+	vec3_t		ofs;
+	float		d1;
+	cbrushside_t	*side;
+
+	if (!brush->numsides)
+		return;
+
+	for (i=0 ; i<brush->numsides ; i++)
+	{
+		side = &map_brushsides[brush->firstbrushside+i];
+		plane = side->plane;
+
+		// FIXME: special case for axial
+
+		// general box case
+
+		// push the plane out apropriately for mins/maxs
+
+		// FIXME: use signbits into 8 way lookup for each mins/maxs
+		for (j=0 ; j<3 ; j++)
+		{
+			if (plane->normal[j] < 0)
+				ofs[j] = maxs[j];
+			else
+				ofs[j] = mins[j];
+		}
+		dist = DotProduct (ofs, plane->normal);
+		dist = plane->dist - dist;
+
+		d1 = DotProduct (p1, plane->normal) - dist;
+
+		// if completely in front of face, no intersection
+		if (d1 > 0)
+			return;
+
+	}
+
+	// inside this brush
+	trace->startsolid = trace->allsolid = true;
+	trace->fraction = 0;
+	trace->contents = brush->contents;
+}
+
+
+/*
+================
+CM_TraceToLeaf
+================
+*/
+void CM_TraceToLeaf (int leafnum)
+{
+	int			k;
+	int			brushnum;
+	cleaf_t		*leaf;
+	cbrush_t	*b;
+
+	leaf = &map_leafs[leafnum];
+	if ( !(leaf->contents & trace_contents))
+		return;
+	// trace line against all brushes in the leaf
+	for (k=0 ; k<leaf->numleafbrushes ; k++)
+	{
+		brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+		b = &map_brushes[brushnum];
+		if (b->checkcount == checkcount)
+			continue;	// already checked this brush in another leaf
+		b->checkcount = checkcount;
+
+		if ( !(b->contents & trace_contents))
+			continue;
+		CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
+		if (!trace_trace.fraction)
+			return;
+	}
+
+}
+
+
+/*
+================
+CM_TestInLeaf
+================
+*/
+void CM_TestInLeaf (int leafnum)
+{
+	int			k;
+	int			brushnum;
+	cleaf_t		*leaf;
+	cbrush_t	*b;
+
+	leaf = &map_leafs[leafnum];
+	if ( !(leaf->contents & trace_contents))
+		return;
+	// trace line against all brushes in the leaf
+	for (k=0 ; k<leaf->numleafbrushes ; k++)
+	{
+		brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+		b = &map_brushes[brushnum];
+		if (b->checkcount == checkcount)
+			continue;	// already checked this brush in another leaf
+		b->checkcount = checkcount;
+
+		if ( !(b->contents & trace_contents))
+			continue;
+		CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
+		if (!trace_trace.fraction)
+			return;
+	}
+
+}
+
+
+/*
+==================
+CM_RecursiveHullCheck
+
+==================
+*/
+void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
+{
+	cnode_t		*node;
+	cplane_t	*plane;
+	float		t1, t2, offset;
+	float		frac, frac2;
+	float		idist;
+	int			i;
+	vec3_t		mid;
+	int			side;
+	float		midf;
+
+	if (trace_trace.fraction <= p1f)
+		return;		// already hit something nearer
+
+	// if < 0, we are in a leaf node
+	if (num < 0)
+	{
+		CM_TraceToLeaf (-1-num);
+		return;
+	}
+
+	//
+	// find the point distances to the seperating plane
+	// and the offset for the size of the box
+	//
+	node = map_nodes + num;
+	plane = node->plane;
+
+	if (plane->type < 3)
+	{
+		t1 = p1[plane->type] - plane->dist;
+		t2 = p2[plane->type] - plane->dist;
+		offset = trace_extents[plane->type];
+	}
+	else
+	{
+		t1 = DotProduct (plane->normal, p1) - plane->dist;
+		t2 = DotProduct (plane->normal, p2) - plane->dist;
+		if (trace_ispoint)
+			offset = 0;
+		else
+			offset = fabs(trace_extents[0]*plane->normal[0]) +
+				fabs(trace_extents[1]*plane->normal[1]) +
+				fabs(trace_extents[2]*plane->normal[2]);
+	}
+
+
+#if 0
+CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+return;
+#endif
+
+	// see which sides we need to consider
+	if (t1 >= offset && t2 >= offset)
+	{
+		CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+		return;
+	}
+	if (t1 < -offset && t2 < -offset)
+	{
+		CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+		return;
+	}
+
+	// put the crosspoint DIST_EPSILON pixels on the near side
+	if (t1 < t2)
+	{
+		idist = 1.0/(t1-t2);
+		side = 1;
+		frac2 = (t1 + offset + DIST_EPSILON)*idist;
+		frac = (t1 - offset + DIST_EPSILON)*idist;
+	}
+	else if (t1 > t2)
+	{
+		idist = 1.0/(t1-t2);
+		side = 0;
+		frac2 = (t1 - offset - DIST_EPSILON)*idist;
+		frac = (t1 + offset + DIST_EPSILON)*idist;
+	}
+	else
+	{
+		side = 0;
+		frac = 1;
+		frac2 = 0;
+	}
+
+	// move up to the node
+	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]);
+
+	CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
+
+
+	// go past the node
+	if (frac2 < 0)
+		frac2 = 0;
+	if (frac2 > 1)
+		frac2 = 1;
+		
+	midf = p1f + (p2f - p1f)*frac2;
+	for (i=0 ; i<3 ; i++)
+		mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
+
+	CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
+}
+
+
+
+//======================================================================
+
+/*
+==================
+CM_BoxTrace
+==================
+*/
+trace_t		CM_BoxTrace (vec3_t start, vec3_t end,
+						  vec3_t mins, vec3_t maxs,
+						  int headnode, int brushmask)
+{
+	int		i;
+
+	checkcount++;		// for multi-check avoidance
+
+	c_traces++;			// for statistics, may be zeroed
+
+	// fill in a default trace
+	memset (&trace_trace, 0, sizeof(trace_trace));
+	trace_trace.fraction = 1;
+	trace_trace.surface = &(nullsurface.c);
+
+	if (!numnodes)	// map not loaded
+		return trace_trace;
+
+	trace_contents = brushmask;
+	VectorCopy (start, trace_start);
+	VectorCopy (end, trace_end);
+	VectorCopy (mins, trace_mins);
+	VectorCopy (maxs, trace_maxs);
+
+	//
+	// check for position test special case
+	//
+	if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
+	{
+		int		leafs[1024];
+		int		i, numleafs;
+		vec3_t	c1, c2;
+		int		topnode;
+
+		VectorAdd (start, mins, c1);
+		VectorAdd (start, maxs, c2);
+		for (i=0 ; i<3 ; i++)
+		{
+			c1[i] -= 1;
+			c2[i] += 1;
+		}
+
+		numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
+		for (i=0 ; i<numleafs ; i++)
+		{
+			CM_TestInLeaf (leafs[i]);
+			if (trace_trace.allsolid)
+				break;
+		}
+		VectorCopy (start, trace_trace.endpos);
+		return trace_trace;
+	}
+
+	//
+	// check for point special case
+	//
+	if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
+		&& maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
+	{
+		trace_ispoint = true;
+		VectorClear (trace_extents);
+	}
+	else
+	{
+		trace_ispoint = false;
+		trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
+		trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
+		trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
+	}
+
+	//
+	// general sweeping through world
+	//
+	CM_RecursiveHullCheck (headnode, 0, 1, start, end);
+
+	if (trace_trace.fraction == 1)
+	{
+		VectorCopy (end, trace_trace.endpos);
+	}
+	else
+	{
+		for (i=0 ; i<3 ; i++)
+			trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
+	}
+	return trace_trace;
+}
+
+
+/*
+==================
+CM_TransformedBoxTrace
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+#ifdef _WIN32
+#pragma optimize( "", off )
+#endif
+
+
+trace_t		CM_TransformedBoxTrace (vec3_t start, vec3_t end,
+						  vec3_t mins, vec3_t maxs,
+						  int headnode, int brushmask,
+						  vec3_t origin, vec3_t angles)
+{
+	trace_t		trace;
+	vec3_t		start_l, end_l;
+	vec3_t		a;
+	vec3_t		forward, right, up;
+	vec3_t		temp;
+	qboolean	rotated;
+
+	// subtract origin offset
+	VectorSubtract (start, origin, start_l);
+	VectorSubtract (end, origin, end_l);
+
+	// rotate start and end into the models frame of reference
+	if (headnode != box_headnode && 
+	(angles[0] || angles[1] || angles[2]) )
+		rotated = true;
+	else
+		rotated = false;
+
+	if (rotated)
+	{
+		AngleVectors (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);
+	}
+
+	// sweep the box through the model
+	trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
+
+	if (rotated && trace.fraction != 1.0)
+	{
+		// FIXME: figure out how to do this with existing angles
+		VectorNegate (angles, a);
+		AngleVectors (a, forward, right, 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);
+	}
+
+	trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+	trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+	trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+	return trace;
+}
+
+#ifdef _WIN32
+#pragma optimize( "", on )
+#endif
+
+
+
+/*
+===============================================================================
+
+PVS / PHS
+
+===============================================================================
+*/
+
+/*
+===================
+CM_DecompressVis
+===================
+*/
+void CM_DecompressVis (byte *in, byte *out)
+{
+	int		c;
+	byte	*out_p;
+	int		row;
+
+	row = (numclusters+7)>>3;	
+	out_p = out;
+
+	if (!in || !numvisibility)
+	{	// no vis info, so make all visible
+		while (row)
+		{
+			*out_p++ = 0xff;
+			row--;
+		}
+		return;		
+	}
+
+	do
+	{
+		if (*in)
+		{
+			*out_p++ = *in++;
+			continue;
+		}
+	
+		c = in[1];
+		in += 2;
+		if ((out_p - out) + c > row)
+		{
+			c = row - (out_p - out);
+			Com_DPrintf ("warning: Vis decompression overrun\n");
+		}
+		while (c)
+		{
+			*out_p++ = 0;
+			c--;
+		}
+	} while (out_p - out < row);
+}
+
+byte	pvsrow[MAX_MAP_LEAFS/8];
+byte	phsrow[MAX_MAP_LEAFS/8];
+
+byte	*CM_ClusterPVS (int cluster)
+{
+	if (cluster == -1)
+		memset (pvsrow, 0, (numclusters+7)>>3);
+	else
+		CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
+	return pvsrow;
+}
+
+byte	*CM_ClusterPHS (int cluster)
+{
+	if (cluster == -1)
+		memset (phsrow, 0, (numclusters+7)>>3);
+	else
+		CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
+	return phsrow;
+}
+
+
+/*
+===============================================================================
+
+AREAPORTALS
+
+===============================================================================
+*/
+
+void FloodArea_r (carea_t *area, int floodnum)
+{
+	int		i;
+	dareaportal_t	*p;
+
+	if (area->floodvalid == floodvalid)
+	{
+		if (area->floodnum == floodnum)
+			return;
+		Com_Error (ERR_DROP, "FloodArea_r: reflooded");
+	}
+
+	area->floodnum = floodnum;
+	area->floodvalid = floodvalid;
+	p = &map_areaportals[area->firstareaportal];
+	for (i=0 ; i<area->numareaportals ; i++, p++)
+	{
+		if (portalopen[p->portalnum])
+			FloodArea_r (&map_areas[p->otherarea], floodnum);
+	}
+}
+
+/*
+====================
+FloodAreaConnections
+
+
+====================
+*/
+void	FloodAreaConnections (void)
+{
+	int		i;
+	carea_t	*area;
+	int		floodnum;
+
+	// all current floods are now invalid
+	floodvalid++;
+	floodnum = 0;
+
+	// area 0 is not used
+	for (i=1 ; i<numareas ; i++)
+	{
+		area = &map_areas[i];
+		if (area->floodvalid == floodvalid)
+			continue;		// already flooded into
+		floodnum++;
+		FloodArea_r (area, floodnum);
+	}
+
+}
+
+void	CM_SetAreaPortalState (int portalnum, qboolean open)
+{
+	if (portalnum > numareaportals)
+		Com_Error (ERR_DROP, "areaportal > numareaportals");
+
+	portalopen[portalnum] = open;
+	FloodAreaConnections ();
+}
+
+qboolean	CM_AreasConnected (int area1, int area2)
+{
+	if (map_noareas->value)
+		return true;
+
+	if (area1 > numareas || area2 > numareas)
+		Com_Error (ERR_DROP, "area > numareas");
+
+	if (map_areas[area1].floodnum == map_areas[area2].floodnum)
+		return true;
+	return false;
+}
+
+
+/*
+=================
+CM_WriteAreaBits
+
+Writes a length byte followed by a bit vector of all the areas
+that area in the same flood as the area parameter
+
+This is used by the client refreshes to cull visibility
+=================
+*/
+int CM_WriteAreaBits (byte *buffer, int area)
+{
+	int		i;
+	int		floodnum;
+	int		bytes;
+
+	bytes = (numareas+7)>>3;
+
+	if (map_noareas->value)
+	{	// for debugging, send everything
+		memset (buffer, 255, bytes);
+	}
+	else
+	{
+		memset (buffer, 0, bytes);
+
+		floodnum = map_areas[area].floodnum;
+		for (i=0 ; i<numareas ; i++)
+		{
+			if (map_areas[i].floodnum == floodnum || !area)
+				buffer[i>>3] |= 1<<(i&7);
+		}
+	}
+
+	return bytes;
+}
+
+
+/*
+===================
+CM_WritePortalState
+
+Writes the portal state to a savegame file
+===================
+*/
+void	CM_WritePortalState (FILE *f)
+{
+	fwrite (portalopen, sizeof(portalopen), 1, f);
+}
+
+/*
+===================
+CM_ReadPortalState
+
+Reads the portal state from a savegame file
+and recalculates the area connections
+===================
+*/
+void	CM_ReadPortalState (FILE *f)
+{
+	FS_Read (portalopen, sizeof(portalopen), f);
+	FloodAreaConnections ();
+}
+
+/*
+=============
+CM_HeadnodeVisible
+
+Returns true if any leaf under headnode has a cluster that
+is potentially visible
+=============
+*/
+qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
+{
+	int		leafnum;
+	int		cluster;
+	cnode_t	*node;
+
+	if (nodenum < 0)
+	{
+		leafnum = -1-nodenum;
+		cluster = map_leafs[leafnum].cluster;
+		if (cluster == -1)
+			return false;
+		if (visbits[cluster>>3] & (1<<(cluster&7)))
+			return true;
+		return false;
+	}
+
+	node = &map_nodes[nodenum];
+	if (CM_HeadnodeVisible(node->children[0], visbits))
+		return true;
+	return CM_HeadnodeVisible(node->children[1], visbits);
+}
+
--- /dev/null
+++ b/qcommon/common.c
@@ -1,0 +1,1588 @@
+/*
+Copyright (C) 1997-2001 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 "qcommon.h"
+#include <setjmp.h>
+
+#define	MAXPRINTMSG	4096
+
+#define MAX_NUM_ARGVS	50
+
+
+int		com_argc;
+char	*com_argv[MAX_NUM_ARGVS+1];
+
+int		realtime;
+
+jmp_buf abortframe;		// an ERR_DROP occured, exit the entire frame
+
+
+FILE	*log_stats_file;
+
+cvar_t	*host_speeds;
+cvar_t	*log_stats;
+cvar_t	*developer;
+cvar_t	*timescale;
+cvar_t	*fixedtime;
+cvar_t	*logfile_active;	// 1 = buffer log, 2 = flush after each print
+cvar_t	*showtrace;
+cvar_t	*dedicated;
+
+FILE	*logfile;
+
+int			server_state;
+
+// host_speeds times
+int		time_before_game;
+int		time_after_game;
+int		time_before_ref;
+int		time_after_ref;
+
+/*
+============================================================================
+
+CLIENT / SERVER interactions
+
+============================================================================
+*/
+
+static int	rd_target;
+static char	*rd_buffer;
+static int	rd_buffersize;
+static void	(*rd_flush)(int target, char *buffer);
+
+void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
+{
+	if (!target || !buffer || !buffersize || !flush)
+		return;
+	rd_target = target;
+	rd_buffer = buffer;
+	rd_buffersize = buffersize;
+	rd_flush = flush;
+
+	*rd_buffer = 0;
+}
+
+void Com_EndRedirect (void)
+{
+	rd_flush(rd_target, rd_buffer);
+
+	rd_target = 0;
+	rd_buffer = NULL;
+	rd_buffersize = 0;
+	rd_flush = NULL;
+}
+
+/*
+=============
+Com_Printf
+
+Both client and server can use this, and it will output
+to the apropriate place.
+=============
+*/
+void Com_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	if (rd_target)
+	{
+		if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1))
+		{
+			rd_flush(rd_target, rd_buffer);
+			*rd_buffer = 0;
+		}
+		strcat (rd_buffer, msg);
+		return;
+	}
+
+	Con_Print (msg);
+		
+	// also echo to debugging console
+	Sys_ConsoleOutput (msg);
+
+	// logfile
+	if (logfile_active && logfile_active->value)
+	{
+		char	name[MAX_QPATH];
+		
+		if (!logfile)
+		{
+			Com_sprintf (name, sizeof(name), "%s/qconsole.log", FS_Gamedir ());
+			logfile = fopen (name, "w");
+		}
+		if (logfile)
+			fprintf (logfile, "%s", msg);
+		if (logfile_active->value > 1)
+			fflush (logfile);		// force it to save every time
+	}
+}
+
+
+/*
+================
+Com_DPrintf
+
+A Com_Printf that only shows up if the "developer" cvar is set
+================
+*/
+void Com_DPrintf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+		
+	if (!developer || !developer->value)
+		return;			// don't confuse non-developers with techie stuff...
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+	
+	Com_Printf ("%s", msg);
+}
+
+
+/*
+=============
+Com_Error
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Error (int code, char *fmt, ...)
+{
+	va_list		argptr;
+	static char		msg[MAXPRINTMSG];
+	static	qboolean	recursive;
+
+	if (recursive)
+		Sys_Error ("recursive error after: %s", msg);
+	recursive = true;
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+	
+	if (code == ERR_DISCONNECT)
+	{
+		CL_Drop ();
+		recursive = false;
+		longjmp (abortframe, -1);
+	}
+	else if (code == ERR_DROP)
+	{
+		Com_Printf ("********************\nERROR: %s\n********************\n", msg);
+		SV_Shutdown (va("Server crashed: %s\n", msg), false);
+		CL_Drop ();
+		recursive = false;
+		longjmp (abortframe, -1);
+	}
+	else
+	{
+		SV_Shutdown (va("Server fatal crashed: %s\n", msg), false);
+		CL_Shutdown ();
+	}
+
+	if (logfile)
+	{
+		fclose (logfile);
+		logfile = NULL;
+	}
+
+	Sys_Error ("%s", msg);
+}
+
+
+/*
+=============
+Com_Quit
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Quit (void)
+{
+	SV_Shutdown ("Server quit\n", false);
+	CL_Shutdown ();
+
+	if (logfile)
+	{
+		fclose (logfile);
+		logfile = NULL;
+	}
+
+	Sys_Quit ();
+}
+
+
+/*
+==================
+Com_ServerState
+==================
+*/
+int Com_ServerState (void)
+{
+	return server_state;
+}
+
+/*
+==================
+Com_SetServerState
+==================
+*/
+void Com_SetServerState (int state)
+{
+	server_state = state;
+}
+
+
+/*
+==============================================================================
+
+			MESSAGE IO FUNCTIONS
+
+Handles byte ordering and avoids alignment errors
+==============================================================================
+*/
+
+vec3_t	bytedirs[NUMVERTEXNORMALS] =
+{
+#include "../client/anorms.h"
+};
+
+//
+// writing functions
+//
+
+void MSG_WriteChar (sizebuf_t *sb, int c)
+{
+	byte	*buf;
+	
+#ifdef PARANOID
+	if (c < -128 || c > 127)
+		Com_Error (ERR_FATAL, "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)
+		Com_Error (ERR_FATAL, "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)
+		Com_Error (ERR_FATAL, "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, strlen(s)+1);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f)
+{
+	MSG_WriteShort (sb, (int)(f*8));
+}
+
+void MSG_WritePos (sizebuf_t *sb, vec3_t pos)
+{
+	MSG_WriteShort (sb, (int)(pos[0]*8));
+	MSG_WriteShort (sb, (int)(pos[1]*8));
+	MSG_WriteShort (sb, (int)(pos[2]*8));
+}
+
+void MSG_WriteAngle (sizebuf_t *sb, float f)
+{
+	MSG_WriteByte (sb, (int)(f*256/360) & 255);
+}
+
+void MSG_WriteAngle16 (sizebuf_t *sb, float f)
+{
+	MSG_WriteShort (sb, ANGLE2SHORT(f));
+}
+
+
+void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
+{
+	int		bits;
+
+//
+// send the movement message
+//
+	bits = 0;
+	if (cmd->angles[0] != from->angles[0])
+		bits |= CM_ANGLE1;
+	if (cmd->angles[1] != from->angles[1])
+		bits |= CM_ANGLE2;
+	if (cmd->angles[2] != from->angles[2])
+		bits |= CM_ANGLE3;
+	if (cmd->forwardmove != from->forwardmove)
+		bits |= CM_FORWARD;
+	if (cmd->sidemove != from->sidemove)
+		bits |= CM_SIDE;
+	if (cmd->upmove != from->upmove)
+		bits |= CM_UP;
+	if (cmd->buttons != from->buttons)
+		bits |= CM_BUTTONS;
+	if (cmd->impulse != from->impulse)
+		bits |= CM_IMPULSE;
+
+    MSG_WriteByte (buf, bits);
+
+	if (bits & CM_ANGLE1)
+		MSG_WriteShort (buf, cmd->angles[0]);
+	if (bits & CM_ANGLE2)
+		MSG_WriteShort (buf, cmd->angles[1]);
+	if (bits & CM_ANGLE3)
+		MSG_WriteShort (buf, cmd->angles[2]);
+	
+	if (bits & CM_FORWARD)
+		MSG_WriteShort (buf, cmd->forwardmove);
+	if (bits & CM_SIDE)
+	  	MSG_WriteShort (buf, cmd->sidemove);
+	if (bits & CM_UP)
+		MSG_WriteShort (buf, cmd->upmove);
+
+ 	if (bits & CM_BUTTONS)
+	  	MSG_WriteByte (buf, cmd->buttons);
+ 	if (bits & CM_IMPULSE)
+	    MSG_WriteByte (buf, cmd->impulse);
+
+    MSG_WriteByte (buf, cmd->msec);
+	MSG_WriteByte (buf, cmd->lightlevel);
+}
+
+
+void MSG_WriteDir (sizebuf_t *sb, vec3_t dir)
+{
+	int		i, best;
+	float	d, bestd;
+	
+	if (!dir)
+	{
+		MSG_WriteByte (sb, 0);
+		return;
+	}
+
+	bestd = 0;
+	best = 0;
+	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+	{
+		d = DotProduct (dir, bytedirs[i]);
+		if (d > bestd)
+		{
+			bestd = d;
+			best = i;
+		}
+	}
+	MSG_WriteByte (sb, best);
+}
+
+
+void MSG_ReadDir (sizebuf_t *sb, vec3_t dir)
+{
+	int		b;
+
+	b = MSG_ReadByte (sb);
+	if (b >= NUMVERTEXNORMALS)
+		Com_Error (ERR_DROP, "MSF_ReadDir: out of range");
+	VectorCopy (bytedirs[b], dir);
+}
+
+
+/*
+==================
+MSG_WriteDeltaEntity
+
+Writes part of a packetentities message.
+Can delta from either a baseline or a previous packet_entity
+==================
+*/
+void MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity)
+{
+	int		bits;
+
+	if (!to->number)
+		Com_Error (ERR_FATAL, "Unset entity number");
+	if (to->number >= MAX_EDICTS)
+		Com_Error (ERR_FATAL, "Entity number >= MAX_EDICTS");
+
+// send an update
+	bits = 0;
+
+	if (to->number >= 256)
+		bits |= U_NUMBER16;		// number8 is implicit otherwise
+
+	if (to->origin[0] != from->origin[0])
+		bits |= U_ORIGIN1;
+	if (to->origin[1] != from->origin[1])
+		bits |= U_ORIGIN2;
+	if (to->origin[2] != from->origin[2])
+		bits |= U_ORIGIN3;
+
+	if ( to->angles[0] != from->angles[0] )
+		bits |= U_ANGLE1;		
+	if ( to->angles[1] != from->angles[1] )
+		bits |= U_ANGLE2;
+	if ( to->angles[2] != from->angles[2] )
+		bits |= U_ANGLE3;
+		
+	if ( to->skinnum != from->skinnum )
+	{
+		if ((unsigned)to->skinnum < 256)
+			bits |= U_SKIN8;
+		else if ((unsigned)to->skinnum < 0x10000)
+			bits |= U_SKIN16;
+		else
+			bits |= (U_SKIN8|U_SKIN16);
+	}
+		
+	if ( to->frame != from->frame )
+	{
+		if (to->frame < 256)
+			bits |= U_FRAME8;
+		else
+			bits |= U_FRAME16;
+	}
+
+	if ( to->effects != from->effects )
+	{
+		if (to->effects < 256)
+			bits |= U_EFFECTS8;
+		else if (to->effects < 0x8000)
+			bits |= U_EFFECTS16;
+		else
+			bits |= U_EFFECTS8|U_EFFECTS16;
+	}
+	
+	if ( to->renderfx != from->renderfx )
+	{
+		if (to->renderfx < 256)
+			bits |= U_RENDERFX8;
+		else if (to->renderfx < 0x8000)
+			bits |= U_RENDERFX16;
+		else
+			bits |= U_RENDERFX8|U_RENDERFX16;
+	}
+	
+	if ( to->solid != from->solid )
+		bits |= U_SOLID;
+
+	// event is not delta compressed, just 0 compressed
+	if ( to->event  )
+		bits |= U_EVENT;
+	
+	if ( to->modelindex != from->modelindex )
+		bits |= U_MODEL;
+	if ( to->modelindex2 != from->modelindex2 )
+		bits |= U_MODEL2;
+	if ( to->modelindex3 != from->modelindex3 )
+		bits |= U_MODEL3;
+	if ( to->modelindex4 != from->modelindex4 )
+		bits |= U_MODEL4;
+
+	if ( to->sound != from->sound )
+		bits |= U_SOUND;
+
+	if (newentity || (to->renderfx & RF_BEAM))
+		bits |= U_OLDORIGIN;
+
+	//
+	// write the message
+	//
+	if (!bits && !force)
+		return;		// nothing to send!
+
+	//----------
+
+	if (bits & 0xff000000)
+		bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
+	else if (bits & 0x00ff0000)
+		bits |= U_MOREBITS2 | U_MOREBITS1;
+	else if (bits & 0x0000ff00)
+		bits |= U_MOREBITS1;
+
+	MSG_WriteByte (msg,	bits&255 );
+
+	if (bits & 0xff000000)
+	{
+		MSG_WriteByte (msg,	(bits>>8)&255 );
+		MSG_WriteByte (msg,	(bits>>16)&255 );
+		MSG_WriteByte (msg,	(bits>>24)&255 );
+	}
+	else if (bits & 0x00ff0000)
+	{
+		MSG_WriteByte (msg,	(bits>>8)&255 );
+		MSG_WriteByte (msg,	(bits>>16)&255 );
+	}
+	else if (bits & 0x0000ff00)
+	{
+		MSG_WriteByte (msg,	(bits>>8)&255 );
+	}
+
+	//----------
+
+	if (bits & U_NUMBER16)
+		MSG_WriteShort (msg, to->number);
+	else
+		MSG_WriteByte (msg,	to->number);
+
+	if (bits & U_MODEL)
+		MSG_WriteByte (msg,	to->modelindex);
+	if (bits & U_MODEL2)
+		MSG_WriteByte (msg,	to->modelindex2);
+	if (bits & U_MODEL3)
+		MSG_WriteByte (msg,	to->modelindex3);
+	if (bits & U_MODEL4)
+		MSG_WriteByte (msg,	to->modelindex4);
+
+	if (bits & U_FRAME8)
+		MSG_WriteByte (msg, to->frame);
+	if (bits & U_FRAME16)
+		MSG_WriteShort (msg, to->frame);
+
+	if ((bits & U_SKIN8) && (bits & U_SKIN16))		//used for laser colors
+		MSG_WriteLong (msg, to->skinnum);
+	else if (bits & U_SKIN8)
+		MSG_WriteByte (msg, to->skinnum);
+	else if (bits & U_SKIN16)
+		MSG_WriteShort (msg, to->skinnum);
+
+
+	if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+		MSG_WriteLong (msg, to->effects);
+	else if (bits & U_EFFECTS8)
+		MSG_WriteByte (msg, to->effects);
+	else if (bits & U_EFFECTS16)
+		MSG_WriteShort (msg, to->effects);
+
+	if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+		MSG_WriteLong (msg, to->renderfx);
+	else if (bits & U_RENDERFX8)
+		MSG_WriteByte (msg, to->renderfx);
+	else if (bits & U_RENDERFX16)
+		MSG_WriteShort (msg, to->renderfx);
+
+	if (bits & U_ORIGIN1)
+		MSG_WriteCoord (msg, to->origin[0]);		
+	if (bits & U_ORIGIN2)
+		MSG_WriteCoord (msg, to->origin[1]);
+	if (bits & U_ORIGIN3)
+		MSG_WriteCoord (msg, to->origin[2]);
+
+	if (bits & U_ANGLE1)
+		MSG_WriteAngle(msg, to->angles[0]);
+	if (bits & U_ANGLE2)
+		MSG_WriteAngle(msg, to->angles[1]);
+	if (bits & U_ANGLE3)
+		MSG_WriteAngle(msg, to->angles[2]);
+
+	if (bits & U_OLDORIGIN)
+	{
+		MSG_WriteCoord (msg, to->old_origin[0]);
+		MSG_WriteCoord (msg, to->old_origin[1]);
+		MSG_WriteCoord (msg, to->old_origin[2]);
+	}
+
+	if (bits & U_SOUND)
+		MSG_WriteByte (msg, to->sound);
+	if (bits & U_EVENT)
+		MSG_WriteByte (msg, to->event);
+	if (bits & U_SOLID)
+		MSG_WriteShort (msg, to->solid);
+}
+
+
+//============================================================
+
+//
+// reading functions
+//
+
+void MSG_BeginReading (sizebuf_t *msg)
+{
+	msg->readcount = 0;
+}
+
+// returns -1 if no more characters are available
+int MSG_ReadChar (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+1 > msg_read->cursize)
+		c = -1;
+	else
+		c = (signed char)msg_read->data[msg_read->readcount];
+	msg_read->readcount++;
+	
+	return c;
+}
+
+int MSG_ReadByte (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+1 > msg_read->cursize)
+		c = -1;
+	else
+		c = (unsigned char)msg_read->data[msg_read->readcount];
+	msg_read->readcount++;
+	
+	return c;
+}
+
+int MSG_ReadShort (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+2 > msg_read->cursize)
+		c = -1;
+	else		
+		c = (short)(msg_read->data[msg_read->readcount]
+		+ (msg_read->data[msg_read->readcount+1]<<8));
+	
+	msg_read->readcount += 2;
+	
+	return c;
+}
+
+int MSG_ReadLong (sizebuf_t *msg_read)
+{
+	int	c;
+	
+	if (msg_read->readcount+4 > msg_read->cursize)
+		c = -1;
+	else
+		c = msg_read->data[msg_read->readcount]
+		+ (msg_read->data[msg_read->readcount+1]<<8)
+		+ (msg_read->data[msg_read->readcount+2]<<16)
+		+ (msg_read->data[msg_read->readcount+3]<<24);
+	
+	msg_read->readcount += 4;
+	
+	return c;
+}
+
+float MSG_ReadFloat (sizebuf_t *msg_read)
+{
+	union
+	{
+		byte	b[4];
+		float	f;
+		int	l;
+	} dat;
+	
+	if (msg_read->readcount+4 > msg_read->cursize)
+		dat.f = -1;
+	else
+	{
+		dat.b[0] =	msg_read->data[msg_read->readcount];
+		dat.b[1] =	msg_read->data[msg_read->readcount+1];
+		dat.b[2] =	msg_read->data[msg_read->readcount+2];
+		dat.b[3] =	msg_read->data[msg_read->readcount+3];
+	}
+	msg_read->readcount += 4;
+	
+	dat.l = LittleLong (dat.l);
+
+	return dat.f;	
+}
+
+char *MSG_ReadString (sizebuf_t *msg_read)
+{
+	static char	string[2048];
+	int		l,c;
+	
+	l = 0;
+	do
+	{
+		c = MSG_ReadChar (msg_read);
+		if (c == -1 || c == 0)
+			break;
+		string[l] = c;
+		l++;
+	} while (l < sizeof(string)-1);
+	
+	string[l] = 0;
+	
+	return string;
+}
+
+char *MSG_ReadStringLine (sizebuf_t *msg_read)
+{
+	static char	string[2048];
+	int		l,c;
+	
+	l = 0;
+	do
+	{
+		c = MSG_ReadChar (msg_read);
+		if (c == -1 || c == 0 || c == '\n')
+			break;
+		string[l] = c;
+		l++;
+	} while (l < sizeof(string)-1);
+	
+	string[l] = 0;
+	
+	return string;
+}
+
+float MSG_ReadCoord (sizebuf_t *msg_read)
+{
+	return MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos)
+{
+	pos[0] = MSG_ReadShort(msg_read) * (1.0/8);
+	pos[1] = MSG_ReadShort(msg_read) * (1.0/8);
+	pos[2] = MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+float MSG_ReadAngle (sizebuf_t *msg_read)
+{
+	return MSG_ReadChar(msg_read) * (360.0/256);
+}
+
+float MSG_ReadAngle16 (sizebuf_t *msg_read)
+{
+	return SHORT2ANGLE(MSG_ReadShort(msg_read));
+}
+
+void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
+{
+	int bits;
+
+	memcpy (move, from, sizeof(*move));
+
+	bits = MSG_ReadByte (msg_read);
+		
+// read current angles
+	if (bits & CM_ANGLE1)
+		move->angles[0] = MSG_ReadShort (msg_read);
+	if (bits & CM_ANGLE2)
+		move->angles[1] = MSG_ReadShort (msg_read);
+	if (bits & CM_ANGLE3)
+		move->angles[2] = MSG_ReadShort (msg_read);
+		
+// read movement
+	if (bits & CM_FORWARD)
+		move->forwardmove = MSG_ReadShort (msg_read);
+	if (bits & CM_SIDE)
+		move->sidemove = MSG_ReadShort (msg_read);
+	if (bits & CM_UP)
+		move->upmove = MSG_ReadShort (msg_read);
+	
+// read buttons
+	if (bits & CM_BUTTONS)
+		move->buttons = MSG_ReadByte (msg_read);
+
+	if (bits & CM_IMPULSE)
+		move->impulse = MSG_ReadByte (msg_read);
+
+// read time to run command
+	move->msec = MSG_ReadByte (msg_read);
+
+// read the light level
+	move->lightlevel = MSG_ReadByte (msg_read);
+}
+
+
+void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
+{
+	int		i;
+
+	for (i=0 ; i<len ; i++)
+		((byte *)data)[i] = MSG_ReadByte (msg_read);
+}
+
+
+//===========================================================================
+
+void SZ_Init (sizebuf_t *buf, byte *data, int length)
+{
+	memset (buf, 0, sizeof(*buf));
+	buf->data = data;
+	buf->maxsize = length;
+}
+
+void SZ_Clear (sizebuf_t *buf)
+{
+	buf->cursize = 0;
+	buf->overflowed = false;
+}
+
+void *SZ_GetSpace (sizebuf_t *buf, int length)
+{
+	void	*data;
+	
+	if (buf->cursize + length > buf->maxsize)
+	{
+		if (!buf->allowoverflow)
+			Com_Error (ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set");
+		
+		if (length > buf->maxsize)
+			Com_Error (ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", length);
+			
+		Com_Printf ("SZ_GetSpace: overflow\n");
+		SZ_Clear (buf); 
+		buf->overflowed = true;
+	}
+
+	data = buf->data + buf->cursize;
+	buf->cursize += length;
+	
+	return data;
+}
+
+void SZ_Write (sizebuf_t *buf, void *data, int length)
+{
+	memcpy (SZ_GetSpace(buf,length),data,length);		
+}
+
+void SZ_Print (sizebuf_t *buf, char *data)
+{
+	int		len;
+	
+	len = strlen(data)+1;
+
+	if (buf->cursize)
+	{
+		if (buf->data[buf->cursize-1])
+			memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
+		else
+			memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
+	}
+	else
+		memcpy ((byte *)SZ_GetSpace(buf, len),data,len);
+}
+
+
+//============================================================================
+
+
+/*
+================
+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 (!strcmp (parm,com_argv[i]))
+			return i;
+	}
+		
+	return 0;
+}
+
+int COM_Argc (void)
+{
+	return com_argc;
+}
+
+char *COM_Argv (int arg)
+{
+	if (arg < 0 || arg >= com_argc || !com_argv[arg])
+		return "";
+	return com_argv[arg];
+}
+
+void COM_ClearArgv (int arg)
+{
+	if (arg < 0 || arg >= com_argc || !com_argv[arg])
+		return;
+	com_argv[arg] = "";
+}
+
+
+/*
+================
+COM_InitArgv
+================
+*/
+void COM_InitArgv (int argc, char **argv)
+{
+	int		i;
+
+	if (argc > MAX_NUM_ARGVS)
+		Com_Error (ERR_FATAL, "argc > MAX_NUM_ARGVS");
+	com_argc = argc;
+	for (i=0 ; i<argc ; i++)
+	{
+		if (!argv[i] || strlen(argv[i]) >= MAX_TOKEN_CHARS )
+			com_argv[i] = "";
+		else
+			com_argv[i] = argv[i];
+	}
+}
+
+/*
+================
+COM_AddParm
+
+Adds the given string at the end of the current argument list
+================
+*/
+void COM_AddParm (char *parm)
+{
+	if (com_argc == MAX_NUM_ARGVS)
+		Com_Error (ERR_FATAL, "COM_AddParm: MAX_NUM)ARGS");
+	com_argv[com_argc++] = parm;
+}
+
+
+
+
+/// 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;
+}
+
+
+char *CopyString (char *in)
+{
+	char	*out;
+	
+	out = Z_Malloc (strlen(in)+1);
+	strcpy (out, in);
+	return out;
+}
+
+
+
+void Info_Print (char *s)
+{
+	char	key[512];
+	char	value[512];
+	char	*o;
+	int		l;
+
+	if (*s == '\\')
+		s++;
+	while (*s)
+	{
+		o = key;
+		while (*s && *s != '\\')
+			*o++ = *s++;
+
+		l = o - key;
+		if (l < 20)
+		{
+			memset (o, ' ', 20-l);
+			key[20] = 0;
+		}
+		else
+			*o = 0;
+		Com_Printf ("%s", key);
+
+		if (!*s)
+		{
+			Com_Printf ("MISSING VALUE\n");
+			return;
+		}
+
+		o = value;
+		s++;
+		while (*s && *s != '\\')
+			*o++ = *s++;
+		*o = 0;
+
+		if (*s)
+			s++;
+		Com_Printf ("%s\n", value);
+	}
+}
+
+
+/*
+==============================================================================
+
+						ZONE MEMORY ALLOCATION
+
+just cleared malloc with counters now...
+
+==============================================================================
+*/
+
+#define	Z_MAGIC		0x1d1d
+
+
+typedef struct zhead_s
+{
+	struct zhead_s	*prev, *next;
+	short	magic;
+	short	tag;			// for group free
+	int		size;
+} zhead_t;
+
+zhead_t		z_chain;
+int		z_count, z_bytes;
+
+/*
+========================
+Z_Free
+========================
+*/
+void Z_Free (void *ptr)
+{
+	zhead_t	*z;
+
+	z = ((zhead_t *)ptr) - 1;
+
+	if (z->magic != Z_MAGIC)
+		Com_Error (ERR_FATAL, "Z_Free: bad magic");
+
+	z->prev->next = z->next;
+	z->next->prev = z->prev;
+
+	z_count--;
+	z_bytes -= z->size;
+	free (z);
+}
+
+
+/*
+========================
+Z_Stats_f
+========================
+*/
+void Z_Stats_f (void)
+{
+	Com_Printf ("%i bytes in %i blocks\n", z_bytes, z_count);
+}
+
+/*
+========================
+Z_FreeTags
+========================
+*/
+void Z_FreeTags (int tag)
+{
+	zhead_t	*z, *next;
+
+	for (z=z_chain.next ; z != &z_chain ; z=next)
+	{
+		next = z->next;
+		if (z->tag == tag)
+			Z_Free ((void *)(z+1));
+	}
+}
+
+/*
+========================
+Z_TagMalloc
+========================
+*/
+void *Z_TagMalloc (int size, int tag)
+{
+	zhead_t	*z;
+	
+	size = size + sizeof(zhead_t);
+	z = malloc(size);
+	if (!z)
+		Com_Error (ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes",size);
+	memset (z, 0, size);
+	z_count++;
+	z_bytes += size;
+	z->magic = Z_MAGIC;
+	z->tag = tag;
+	z->size = size;
+
+	z->next = z_chain.next;
+	z->prev = &z_chain;
+	z_chain.next->prev = z;
+	z_chain.next = z;
+
+	return (void *)(z+1);
+}
+
+/*
+========================
+Z_Malloc
+========================
+*/
+void *Z_Malloc (int size)
+{
+	return Z_TagMalloc (size, 0);
+}
+
+
+//============================================================================
+
+
+/*
+====================
+COM_BlockSequenceCheckByte
+
+For proxy protecting
+
+// THIS IS MASSIVELY BROKEN!  CHALLENGE MAY BE NEGATIVE
+// DON'T USE THIS FUNCTION!!!!!
+
+====================
+*/
+byte	COM_BlockSequenceCheckByte (byte *base, int length, int sequence, int challenge)
+{
+	Sys_Error("COM_BlockSequenceCheckByte called\n");
+
+#if 0
+	int		checksum;
+	byte	buf[68];
+	byte	*p;
+	float temp;
+	byte c;
+
+	temp = bytedirs[(sequence/3) % NUMVERTEXNORMALS][sequence % 3];
+	temp = LittleFloat(temp);
+	p = ((byte *)&temp);
+
+	if (length > 60)
+		length = 60;
+	memcpy (buf, base, length);
+
+	buf[length] = (sequence & 0xff) ^ p[0];
+	buf[length+1] = p[1];
+	buf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
+	buf[length+3] = p[3];
+
+	temp = bytedirs[((sequence+challenge)/3) % NUMVERTEXNORMALS][(sequence+challenge) % 3];
+	temp = LittleFloat(temp);
+	p = ((byte *)&temp);
+
+	buf[length+4] = (sequence & 0xff) ^ p[3];
+	buf[length+5] = (challenge & 0xff) ^ p[2];
+	buf[length+6] = ((sequence>>8) & 0xff) ^ p[1];
+	buf[length+7] = ((challenge >> 7) & 0xff) ^ p[0];
+
+	length += 8;
+
+	checksum = LittleLong(Com_BlockChecksum (buf, length));
+
+	checksum &= 0xff;
+
+	return checksum;
+#endif
+	return 0;
+}
+
+static byte chktbl[1024] = {
+0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
+0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
+0xcb, 0xfb, 0xf1, 0x0c, 0x2e, 0xa0, 0xd7, 0xc9, 0x1f, 0xd6, 0x06, 0x9a, 0x09, 0x41, 0x54,
+0x67, 0x46, 0xc7, 0x74, 0xe3, 0xc8, 0xb6, 0x5d, 0xa6, 0x36, 0xc4, 0xab, 0x2c, 0x7e, 0x85,
+0xa8, 0xa4, 0xa6, 0x4d, 0x96, 0x19, 0x19, 0x9a, 0xcc, 0xd8, 0xac, 0x39, 0x5e, 0x3c, 0xf2,
+0xf5, 0x5a, 0x72, 0xe5, 0xa9, 0xd1, 0xb3, 0x23, 0x82, 0x6f, 0x29, 0xcb, 0xd1, 0xcc, 0x71,
+0xfb, 0xea, 0x92, 0xeb, 0x1c, 0xca, 0x4c, 0x70, 0xfe, 0x4d, 0xc9, 0x67, 0x43, 0x47, 0x94,
+0xb9, 0x47, 0xbc, 0x3f, 0x01, 0xab, 0x7b, 0xa6, 0xe2, 0x76, 0xef, 0x5a, 0x7a, 0x29, 0x0b,
+0x51, 0x54, 0x67, 0xd8, 0x1c, 0x14, 0x3e, 0x29, 0xec, 0xe9, 0x2d, 0x48, 0x67, 0xff, 0xed,
+0x54, 0x4f, 0x48, 0xc0, 0xaa, 0x61, 0xf7, 0x78, 0x12, 0x03, 0x7a, 0x9e, 0x8b, 0xcf, 0x83,
+0x7b, 0xae, 0xca, 0x7b, 0xd9, 0xe9, 0x53, 0x2a, 0xeb, 0xd2, 0xd8, 0xcd, 0xa3, 0x10, 0x25,
+0x78, 0x5a, 0xb5, 0x23, 0x06, 0x93, 0xb7, 0x84, 0xd2, 0xbd, 0x96, 0x75, 0xa5, 0x5e, 0xcf,
+0x4e, 0xe9, 0x50, 0xa1, 0xe6, 0x9d, 0xb1, 0xe3, 0x85, 0x66, 0x28, 0x4e, 0x43, 0xdc, 0x6e,
+0xbb, 0x33, 0x9e, 0xf3, 0x0d, 0x00, 0xc1, 0xcf, 0x67, 0x34, 0x06, 0x7c, 0x71, 0xe3, 0x63,
+0xb7, 0xb7, 0xdf, 0x92, 0xc4, 0xc2, 0x25, 0x5c, 0xff, 0xc3, 0x6e, 0xfc, 0xaa, 0x1e, 0x2a,
+0x48, 0x11, 0x1c, 0x36, 0x68, 0x78, 0x86, 0x79, 0x30, 0xc3, 0xd6, 0xde, 0xbc, 0x3a, 0x2a,
+0x6d, 0x1e, 0x46, 0xdd, 0xe0, 0x80, 0x1e, 0x44, 0x3b, 0x6f, 0xaf, 0x31, 0xda, 0xa2, 0xbd,
+0x77, 0x06, 0x56, 0xc0, 0xb7, 0x92, 0x4b, 0x37, 0xc0, 0xfc, 0xc2, 0xd5, 0xfb, 0xa8, 0xda,
+0xf5, 0x57, 0xa8, 0x18, 0xc0, 0xdf, 0xe7, 0xaa, 0x2a, 0xe0, 0x7c, 0x6f, 0x77, 0xb1, 0x26,
+0xba, 0xf9, 0x2e, 0x1d, 0x16, 0xcb, 0xb8, 0xa2, 0x44, 0xd5, 0x2f, 0x1a, 0x79, 0x74, 0x87,
+0x4b, 0x00, 0xc9, 0x4a, 0x3a, 0x65, 0x8f, 0xe6, 0x5d, 0xe5, 0x0a, 0x77, 0xd8, 0x1a, 0x14,
+0x41, 0x75, 0xb1, 0xe2, 0x50, 0x2c, 0x93, 0x38, 0x2b, 0x6d, 0xf3, 0xf6, 0xdb, 0x1f, 0xcd,
+0xff, 0x14, 0x70, 0xe7, 0x16, 0xe8, 0x3d, 0xf0, 0xe3, 0xbc, 0x5e, 0xb6, 0x3f, 0xcc, 0x81,
+0x24, 0x67, 0xf3, 0x97, 0x3b, 0xfe, 0x3a, 0x96, 0x85, 0xdf, 0xe4, 0x6e, 0x3c, 0x85, 0x05,
+0x0e, 0xa3, 0x2b, 0x07, 0xc8, 0xbf, 0xe5, 0x13, 0x82, 0x62, 0x08, 0x61, 0x69, 0x4b, 0x47,
+0x62, 0x73, 0x44, 0x64, 0x8e, 0xe2, 0x91, 0xa6, 0x9a, 0xb7, 0xe9, 0x04, 0xb6, 0x54, 0x0c,
+0xc5, 0xa9, 0x47, 0xa6, 0xc9, 0x08, 0xfe, 0x4e, 0xa6, 0xcc, 0x8a, 0x5b, 0x90, 0x6f, 0x2b,
+0x3f, 0xb6, 0x0a, 0x96, 0xc0, 0x78, 0x58, 0x3c, 0x76, 0x6d, 0x94, 0x1a, 0xe4, 0x4e, 0xb8,
+0x38, 0xbb, 0xf5, 0xeb, 0x29, 0xd8, 0xb0, 0xf3, 0x15, 0x1e, 0x99, 0x96, 0x3c, 0x5d, 0x63,
+0xd5, 0xb1, 0xad, 0x52, 0xb8, 0x55, 0x70, 0x75, 0x3e, 0x1a, 0xd5, 0xda, 0xf6, 0x7a, 0x48,
+0x7d, 0x44, 0x41, 0xf9, 0x11, 0xce, 0xd7, 0xca, 0xa5, 0x3d, 0x7a, 0x79, 0x7e, 0x7d, 0x25,
+0x1b, 0x77, 0xbc, 0xf7, 0xc7, 0x0f, 0x84, 0x95, 0x10, 0x92, 0x67, 0x15, 0x11, 0x5a, 0x5e,
+0x41, 0x66, 0x0f, 0x38, 0x03, 0xb2, 0xf1, 0x5d, 0xf8, 0xab, 0xc0, 0x02, 0x76, 0x84, 0x28,
+0xf4, 0x9d, 0x56, 0x46, 0x60, 0x20, 0xdb, 0x68, 0xa7, 0xbb, 0xee, 0xac, 0x15, 0x01, 0x2f,
+0x20, 0x09, 0xdb, 0xc0, 0x16, 0xa1, 0x89, 0xf9, 0x94, 0x59, 0x00, 0xc1, 0x76, 0xbf, 0xc1,
+0x4d, 0x5d, 0x2d, 0xa9, 0x85, 0x2c, 0xd6, 0xd3, 0x14, 0xcc, 0x02, 0xc3, 0xc2, 0xfa, 0x6b,
+0xb7, 0xa6, 0xef, 0xdd, 0x12, 0x26, 0xa4, 0x63, 0xe3, 0x62, 0xbd, 0x56, 0x8a, 0x52, 0x2b,
+0xb9, 0xdf, 0x09, 0xbc, 0x0e, 0x97, 0xa9, 0xb0, 0x82, 0x46, 0x08, 0xd5, 0x1a, 0x8e, 0x1b,
+0xa7, 0x90, 0x98, 0xb9, 0xbb, 0x3c, 0x17, 0x9a, 0xf2, 0x82, 0xba, 0x64, 0x0a, 0x7f, 0xca,
+0x5a, 0x8c, 0x7c, 0xd3, 0x79, 0x09, 0x5b, 0x26, 0xbb, 0xbd, 0x25, 0xdf, 0x3d, 0x6f, 0x9a,
+0x8f, 0xee, 0x21, 0x66, 0xb0, 0x8d, 0x84, 0x4c, 0x91, 0x45, 0xd4, 0x77, 0x4f, 0xb3, 0x8c,
+0xbc, 0xa8, 0x99, 0xaa, 0x19, 0x53, 0x7c, 0x02, 0x87, 0xbb, 0x0b, 0x7c, 0x1a, 0x2d, 0xdf,
+0x48, 0x44, 0x06, 0xd6, 0x7d, 0x0c, 0x2d, 0x35, 0x76, 0xae, 0xc4, 0x5f, 0x71, 0x85, 0x97,
+0xc4, 0x3d, 0xef, 0x52, 0xbe, 0x00, 0xe4, 0xcd, 0x49, 0xd1, 0xd1, 0x1c, 0x3c, 0xd0, 0x1c,
+0x42, 0xaf, 0xd4, 0xbd, 0x58, 0x34, 0x07, 0x32, 0xee, 0xb9, 0xb5, 0xea, 0xff, 0xd7, 0x8c,
+0x0d, 0x2e, 0x2f, 0xaf, 0x87, 0xbb, 0xe6, 0x52, 0x71, 0x22, 0xf5, 0x25, 0x17, 0xa1, 0x82,
+0x04, 0xc2, 0x4a, 0xbd, 0x57, 0xc6, 0xab, 0xc8, 0x35, 0x0c, 0x3c, 0xd9, 0xc2, 0x43, 0xdb,
+0x27, 0x92, 0xcf, 0xb8, 0x25, 0x60, 0xfa, 0x21, 0x3b, 0x04, 0x52, 0xc8, 0x96, 0xba, 0x74,
+0xe3, 0x67, 0x3e, 0x8e, 0x8d, 0x61, 0x90, 0x92, 0x59, 0xb6, 0x1a, 0x1c, 0x5e, 0x21, 0xc1,
+0x65, 0xe5, 0xa6, 0x34, 0x05, 0x6f, 0xc5, 0x60, 0xb1, 0x83, 0xc1, 0xd5, 0xd5, 0xed, 0xd9,
+0xc7, 0x11, 0x7b, 0x49, 0x7a, 0xf9, 0xf9, 0x84, 0x47, 0x9b, 0xe2, 0xa5, 0x82, 0xe0, 0xc2,
+0x88, 0xd0, 0xb2, 0x58, 0x88, 0x7f, 0x45, 0x09, 0x67, 0x74, 0x61, 0xbf, 0xe6, 0x40, 0xe2,
+0x9d, 0xc2, 0x47, 0x05, 0x89, 0xed, 0xcb, 0xbb, 0xb7, 0x27, 0xe7, 0xdc, 0x7a, 0xfd, 0xbf,
+0xa8, 0xd0, 0xaa, 0x10, 0x39, 0x3c, 0x20, 0xf0, 0xd3, 0x6e, 0xb1, 0x72, 0xf8, 0xe6, 0x0f,
+0xef, 0x37, 0xe5, 0x09, 0x33, 0x5a, 0x83, 0x43, 0x80, 0x4f, 0x65, 0x2f, 0x7c, 0x8c, 0x6a,
+0xa0, 0x82, 0x0c, 0xd4, 0xd4, 0xfa, 0x81, 0x60, 0x3d, 0xdf, 0x06, 0xf1, 0x5f, 0x08, 0x0d,
+0x6d, 0x43, 0xf2, 0xe3, 0x11, 0x7d, 0x80, 0x32, 0xc5, 0xfb, 0xc5, 0xd9, 0x27, 0xec, 0xc6,
+0x4e, 0x65, 0x27, 0x76, 0x87, 0xa6, 0xee, 0xee, 0xd7, 0x8b, 0xd1, 0xa0, 0x5c, 0xb0, 0x42,
+0x13, 0x0e, 0x95, 0x4a, 0xf2, 0x06, 0xc6, 0x43, 0x33, 0xf4, 0xc7, 0xf8, 0xe7, 0x1f, 0xdd,
+0xe4, 0x46, 0x4a, 0x70, 0x39, 0x6c, 0xd0, 0xed, 0xca, 0xbe, 0x60, 0x3b, 0xd1, 0x7b, 0x57,
+0x48, 0xe5, 0x3a, 0x79, 0xc1, 0x69, 0x33, 0x53, 0x1b, 0x80, 0xb8, 0x91, 0x7d, 0xb4, 0xf6,
+0x17, 0x1a, 0x1d, 0x5a, 0x32, 0xd6, 0xcc, 0x71, 0x29, 0x3f, 0x28, 0xbb, 0xf3, 0x5e, 0x71,
+0xb8, 0x43, 0xaf, 0xf8, 0xb9, 0x64, 0xef, 0xc4, 0xa5, 0x6c, 0x08, 0x53, 0xc7, 0x00, 0x10,
+0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32
+};
+
+/*
+====================
+COM_BlockSequenceCRCByte
+
+For proxy protecting
+====================
+*/
+byte	COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
+{
+	int		n;
+	byte	*p;
+	int		x;
+	byte chkb[60 + 4];
+	unsigned short crc;
+
+
+	if (sequence < 0)
+		Sys_Error("sequence < 0, this shouldn't happen\n");
+
+	p = chktbl + (sequence % (sizeof(chktbl) - 4));
+
+	if (length > 60)
+		length = 60;
+	memcpy (chkb, base, length);
+
+	chkb[length] = p[0];
+	chkb[length+1] = p[1];
+	chkb[length+2] = p[2];
+	chkb[length+3] = p[3];
+
+	length += 4;
+
+	crc = CRC_Block(chkb, length);
+
+	for (x=0, n=0; n<length; n++)
+		x += chkb[n];
+
+	crc = (crc ^ x) & 0xff;
+
+	return crc;
+}
+
+//========================================================
+
+float	frand(void)
+{
+	return (rand()&32767)* (1.0/32767);
+}
+
+float	crand(void)
+{
+	return (rand()&32767)* (2.0/32767) - 1;
+}
+
+void Key_Init (void);
+void SCR_EndLoadingPlaque (void);
+
+/*
+=============
+Com_Error_f
+
+Just throw a fatal error to
+test error shutdown procedures
+=============
+*/
+void Com_Error_f (void)
+{
+	Com_Error (ERR_FATAL, "%s", Cmd_Argv(1));
+}
+
+
+/*
+=================
+Qcommon_Init
+=================
+*/
+void Qcommon_Init (int argc, char **argv)
+{
+	char	*s;
+
+	if (setjmp (abortframe) )
+		Sys_Error ("Error during initialization");
+
+	z_chain.next = z_chain.prev = &z_chain;
+
+	// prepare enough of the subsystems to handle
+	// cvar and command buffer management
+	COM_InitArgv (argc, argv);
+
+	Swap_Init ();
+	Cbuf_Init ();
+
+	Cmd_Init ();
+	Cvar_Init ();
+
+	Key_Init ();
+
+	// we need to add the early commands twice, because
+	// a basedir or cddir needs to be set before execing
+	// config files, but we want other parms to override
+	// the settings of the config files
+	Cbuf_AddEarlyCommands (false);
+	Cbuf_Execute ();
+
+	FS_InitFilesystem ();
+
+	Cbuf_AddText ("exec default.cfg\n");
+	Cbuf_AddText ("exec config.cfg\n");
+
+	Cbuf_AddEarlyCommands (true);
+	Cbuf_Execute ();
+
+	//
+	// init commands and vars
+	//
+    Cmd_AddCommand ("z_stats", Z_Stats_f);
+    Cmd_AddCommand ("error", Com_Error_f);
+
+	host_speeds = Cvar_Get ("host_speeds", "0", 0);
+	log_stats = Cvar_Get ("log_stats", "0", 0);
+	developer = Cvar_Get ("developer", "0", 0);
+	timescale = Cvar_Get ("timescale", "1", 0);
+	fixedtime = Cvar_Get ("fixedtime", "0", 0);
+	logfile_active = Cvar_Get ("logfile", "0", 0);
+	showtrace = Cvar_Get ("showtrace", "0", 0);
+#ifdef DEDICATED_ONLY
+	dedicated = Cvar_Get ("dedicated", "1", CVAR_NOSET);
+#else
+	dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
+#endif
+
+	s = va("%4.2f %s %s %s", VERSION, CPUSTRING, __DATE__, BUILDSTRING);
+	Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_NOSET);
+
+
+	if (dedicated->value)
+		Cmd_AddCommand ("quit", Com_Quit);
+
+	Sys_Init ();
+
+	NET_Init ();
+	Netchan_Init ();
+
+	SV_Init ();
+	CL_Init ();
+
+	// add + commands from command line
+	if (!Cbuf_AddLateCommands ())
+	{	// if the user didn't give any commands, run default action
+		if (!dedicated->value)
+			Cbuf_AddText ("d1\n");
+		else
+			Cbuf_AddText ("dedicated_start\n");
+		Cbuf_Execute ();
+	}
+	else
+	{	// the user asked for something explicit
+		// so drop the loading plaque
+		SCR_EndLoadingPlaque ();
+	}
+
+	Com_Printf ("====== Quake2 Initialized ======\n\n");	
+}
+
+/*
+=================
+Qcommon_Frame
+=================
+*/
+void Qcommon_Frame (int msec)
+{
+	char	*s;
+	int		time_before, time_between, time_after;
+
+	if (setjmp (abortframe) )
+		return;			// an ERR_DROP was thrown
+
+	if ( log_stats->modified )
+	{
+		log_stats->modified = false;
+		if ( log_stats->value )
+		{
+			if ( log_stats_file )
+			{
+				fclose( log_stats_file );
+				log_stats_file = 0;
+			}
+			log_stats_file = fopen( "stats.log", "w" );
+			if ( log_stats_file )
+				fprintf( log_stats_file, "entities,dlights,parts,frame time\n" );
+		}
+		else
+		{
+			if ( log_stats_file )
+			{
+				fclose( log_stats_file );
+				log_stats_file = 0;
+			}
+		}
+	}
+
+	if (fixedtime->value)
+		msec = fixedtime->value;
+	else if (timescale->value)
+	{
+		msec *= timescale->value;
+		if (msec < 1)
+			msec = 1;
+	}
+
+	if (showtrace->value)
+	{
+		extern	int c_traces, c_brush_traces;
+		extern	int	c_pointcontents;
+
+		Com_Printf ("%4i traces  %4i points\n", c_traces, c_pointcontents);
+		c_traces = 0;
+		c_brush_traces = 0;
+		c_pointcontents = 0;
+	}
+
+	do
+	{
+		s = Sys_ConsoleInput ();
+		if (s)
+			Cbuf_AddText (va("%s\n",s));
+	} while (s);
+	Cbuf_Execute ();
+
+	if (host_speeds->value)
+		time_before = Sys_Milliseconds ();
+
+	SV_Frame (msec);
+
+	if (host_speeds->value)
+		time_between = Sys_Milliseconds ();		
+
+	CL_Frame (msec);
+
+	if (host_speeds->value)
+		time_after = Sys_Milliseconds ();		
+
+
+	if (host_speeds->value)
+	{
+		int			all, sv, gm, cl, rf;
+
+		all = time_after - time_before;
+		sv = time_between - time_before;
+		cl = time_after - time_between;
+		gm = time_after_game - time_before_game;
+		rf = time_after_ref - time_before_ref;
+		sv -= gm;
+		cl -= rf;
+		Com_Printf ("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
+			all, sv, gm, cl, rf);
+	}	
+}
+
+/*
+=================
+Qcommon_Shutdown
+=================
+*/
+void Qcommon_Shutdown (void)
+{
+}
--- /dev/null
+++ b/qcommon/crc.c
@@ -1,0 +1,92 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/* crc.c */
+
+#include "qcommon.h"
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below...  in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE	0xffff
+#define CRC_XOR_VALUE	0x0000
+
+static unsigned short crctable[256] =
+{
+	0x0000,	0x1021,	0x2042,	0x3063,	0x4084,	0x50a5,	0x60c6,	0x70e7,
+	0x8108,	0x9129,	0xa14a,	0xb16b,	0xc18c,	0xd1ad,	0xe1ce,	0xf1ef,
+	0x1231,	0x0210,	0x3273,	0x2252,	0x52b5,	0x4294,	0x72f7,	0x62d6,
+	0x9339,	0x8318,	0xb37b,	0xa35a,	0xd3bd,	0xc39c,	0xf3ff,	0xe3de,
+	0x2462,	0x3443,	0x0420,	0x1401,	0x64e6,	0x74c7,	0x44a4,	0x5485,
+	0xa56a,	0xb54b,	0x8528,	0x9509,	0xe5ee,	0xf5cf,	0xc5ac,	0xd58d,
+	0x3653,	0x2672,	0x1611,	0x0630,	0x76d7,	0x66f6,	0x5695,	0x46b4,
+	0xb75b,	0xa77a,	0x9719,	0x8738,	0xf7df,	0xe7fe,	0xd79d,	0xc7bc,
+	0x48c4,	0x58e5,	0x6886,	0x78a7,	0x0840,	0x1861,	0x2802,	0x3823,
+	0xc9cc,	0xd9ed,	0xe98e,	0xf9af,	0x8948,	0x9969,	0xa90a,	0xb92b,
+	0x5af5,	0x4ad4,	0x7ab7,	0x6a96,	0x1a71,	0x0a50,	0x3a33,	0x2a12,
+	0xdbfd,	0xcbdc,	0xfbbf,	0xeb9e,	0x9b79,	0x8b58,	0xbb3b,	0xab1a,
+	0x6ca6,	0x7c87,	0x4ce4,	0x5cc5,	0x2c22,	0x3c03,	0x0c60,	0x1c41,
+	0xedae,	0xfd8f,	0xcdec,	0xddcd,	0xad2a,	0xbd0b,	0x8d68,	0x9d49,
+	0x7e97,	0x6eb6,	0x5ed5,	0x4ef4,	0x3e13,	0x2e32,	0x1e51,	0x0e70,
+	0xff9f,	0xefbe,	0xdfdd,	0xcffc,	0xbf1b,	0xaf3a,	0x9f59,	0x8f78,
+	0x9188,	0x81a9,	0xb1ca,	0xa1eb,	0xd10c,	0xc12d,	0xf14e,	0xe16f,
+	0x1080,	0x00a1,	0x30c2,	0x20e3,	0x5004,	0x4025,	0x7046,	0x6067,
+	0x83b9,	0x9398,	0xa3fb,	0xb3da,	0xc33d,	0xd31c,	0xe37f,	0xf35e,
+	0x02b1,	0x1290,	0x22f3,	0x32d2,	0x4235,	0x5214,	0x6277,	0x7256,
+	0xb5ea,	0xa5cb,	0x95a8,	0x8589,	0xf56e,	0xe54f,	0xd52c,	0xc50d,
+	0x34e2,	0x24c3,	0x14a0,	0x0481,	0x7466,	0x6447,	0x5424,	0x4405,
+	0xa7db,	0xb7fa,	0x8799,	0x97b8,	0xe75f,	0xf77e,	0xc71d,	0xd73c,
+	0x26d3,	0x36f2,	0x0691,	0x16b0,	0x6657,	0x7676,	0x4615,	0x5634,
+	0xd94c,	0xc96d,	0xf90e,	0xe92f,	0x99c8,	0x89e9,	0xb98a,	0xa9ab,
+	0x5844,	0x4865,	0x7806,	0x6827,	0x18c0,	0x08e1,	0x3882,	0x28a3,
+	0xcb7d,	0xdb5c,	0xeb3f,	0xfb1e,	0x8bf9,	0x9bd8,	0xabbb,	0xbb9a,
+	0x4a75,	0x5a54,	0x6a37,	0x7a16,	0x0af1,	0x1ad0,	0x2ab3,	0x3a92,
+	0xfd2e,	0xed0f,	0xdd6c,	0xcd4d,	0xbdaa,	0xad8b,	0x9de8,	0x8dc9,
+	0x7c26,	0x6c07,	0x5c64,	0x4c45,	0x3ca2,	0x2c83,	0x1ce0,	0x0cc1,
+	0xef1f,	0xff3e,	0xcf5d,	0xdf7c,	0xaf9b,	0xbfba,	0x8fd9,	0x9ff8,
+	0x6e17,	0x7e36,	0x4e55,	0x5e74,	0x2e93,	0x3eb2,	0x0ed1,	0x1ef0
+};
+
+void CRC_Init(unsigned short *crcvalue)
+{
+	*crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+	*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short CRC_Value(unsigned short crcvalue)
+{
+	return crcvalue ^ CRC_XOR_VALUE;
+}
+
+unsigned short CRC_Block (byte *start, int count)
+{
+	unsigned short	crc;
+
+	CRC_Init (&crc);
+	while (count--)
+		crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
+
+	return crc;
+}
+
--- /dev/null
+++ b/qcommon/crc.h
@@ -1,0 +1,6 @@
+/* crc.h */
+
+void CRC_Init(unsigned short *crcvalue);
+void CRC_ProcessByte(unsigned short *crcvalue, byte data);
+unsigned short CRC_Value(unsigned short crcvalue);
+unsigned short CRC_Block (byte *start, int count);
--- /dev/null
+++ b/qcommon/cvar.c
@@ -1,0 +1,527 @@
+/*
+Copyright (C) 1997-2001 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 "qcommon.h"
+
+cvar_t	*cvar_vars;
+
+/*
+============
+Cvar_InfoValidate
+============
+*/
+static qboolean Cvar_InfoValidate (char *s)
+{
+	if (strstr (s, "\\"))
+		return false;
+	if (strstr (s, "\""))
+		return false;
+	if (strstr (s, ";"))
+		return false;
+	return true;
+}
+
+/*
+============
+Cvar_FindVar
+============
+*/
+static cvar_t *Cvar_FindVar (char *var_name)
+{
+	cvar_t	*var;
+	
+	for (var=cvar_vars ; var ; var=var->next)
+		if (!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 atof (var->string);
+}
+
+
+/*
+============
+Cvar_VariableString
+============
+*/
+char *Cvar_VariableString (char *var_name)
+{
+	cvar_t *var;
+	
+	var = Cvar_FindVar (var_name);
+	if (!var)
+		return "";
+	return var->string;
+}
+
+
+/*
+============
+Cvar_CompleteVariable
+============
+*/
+char *Cvar_CompleteVariable (char *partial)
+{
+	cvar_t		*cvar;
+	int			len;
+	
+	len = strlen(partial);
+	
+	if (!len)
+		return NULL;
+		
+	// check exact match
+	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
+		if (!strcmp (partial,cvar->name))
+			return cvar->name;
+
+	// check partial match
+	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
+		if (!strncmp (partial,cvar->name, len))
+			return cvar->name;
+
+	return NULL;
+}
+
+
+/*
+============
+Cvar_Get
+
+If the variable already exists, the value will not be set
+The flags will be or'ed in if the variable exists.
+============
+*/
+cvar_t *Cvar_Get (char *var_name, char *var_value, int flags)
+{
+	cvar_t	*var;
+	
+	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
+	{
+		if (!Cvar_InfoValidate (var_name))
+		{
+			Com_Printf("invalid info cvar name\n");
+			return NULL;
+		}
+	}
+
+	var = Cvar_FindVar (var_name);
+	if (var)
+	{
+		var->flags |= flags;
+		return var;
+	}
+
+	if (!var_value)
+		return NULL;
+
+	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
+	{
+		if (!Cvar_InfoValidate (var_value))
+		{
+			Com_Printf("invalid info cvar value\n");
+			return NULL;
+		}
+	}
+
+	var = Z_Malloc (sizeof(*var));
+	var->name = CopyString (var_name);
+	var->string = CopyString (var_value);
+	var->modified = true;
+	var->value = atof (var->string);
+
+	// link the variable in
+	var->next = cvar_vars;
+	cvar_vars = var;
+
+	var->flags = flags;
+
+	return var;
+}
+
+/*
+============
+Cvar_Set2
+============
+*/
+cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force)
+{
+	cvar_t	*var;
+
+	var = Cvar_FindVar (var_name);
+	if (!var)
+	{	// create it
+		return Cvar_Get (var_name, value, 0);
+	}
+
+	if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO))
+	{
+		if (!Cvar_InfoValidate (value))
+		{
+			Com_Printf("invalid info cvar value\n");
+			return var;
+		}
+	}
+
+	if (!force)
+	{
+		if (var->flags & CVAR_NOSET)
+		{
+			Com_Printf ("%s is write protected.\n", var_name);
+			return var;
+		}
+
+		if (var->flags & CVAR_LATCH)
+		{
+			if (var->latched_string)
+			{
+				if (strcmp(value, var->latched_string) == 0)
+					return var;
+				Z_Free (var->latched_string);
+			}
+			else
+			{
+				if (strcmp(value, var->string) == 0)
+					return var;
+			}
+
+			if (Com_ServerState())
+			{
+				Com_Printf ("%s will be changed for next game.\n", var_name);
+				var->latched_string = CopyString(value);
+			}
+			else
+			{
+				var->string = CopyString(value);
+				var->value = atof (var->string);
+				if (!strcmp(var->name, "game"))
+				{
+					FS_SetGamedir (var->string);
+					FS_ExecAutoexec ();
+				}
+			}
+			return var;
+		}
+	}
+	else
+	{
+		if (var->latched_string)
+		{
+			Z_Free (var->latched_string);
+			var->latched_string = NULL;
+		}
+	}
+
+	if (!strcmp(value, var->string))
+		return var;		// not changed
+
+	var->modified = true;
+
+	if (var->flags & CVAR_USERINFO)
+		userinfo_modified = true;	// transmit at next oportunity
+	
+	Z_Free (var->string);	// free the old value string
+	
+	var->string = CopyString(value);
+	var->value = atof (var->string);
+
+	return var;
+}
+
+/*
+============
+Cvar_ForceSet
+============
+*/
+cvar_t *Cvar_ForceSet (char *var_name, char *value)
+{
+	return Cvar_Set2 (var_name, value, true);
+}
+
+/*
+============
+Cvar_Set
+============
+*/
+cvar_t *Cvar_Set (char *var_name, char *value)
+{
+	return Cvar_Set2 (var_name, value, false);
+}
+
+/*
+============
+Cvar_FullSet
+============
+*/
+cvar_t *Cvar_FullSet (char *var_name, char *value, int flags)
+{
+	cvar_t	*var;
+	
+	var = Cvar_FindVar (var_name);
+	if (!var)
+	{	// create it
+		return Cvar_Get (var_name, value, flags);
+	}
+
+	var->modified = true;
+
+	if (var->flags & CVAR_USERINFO)
+		userinfo_modified = true;	// transmit at next oportunity
+	
+	Z_Free (var->string);	// free the old value string
+	
+	var->string = CopyString(value);
+	var->value = atof (var->string);
+	var->flags = flags;
+
+	return var;
+}
+
+/*
+============
+Cvar_SetValue
+============
+*/
+void Cvar_SetValue (char *var_name, float value)
+{
+	char	val[32];
+
+	if (value == (int)value)
+		Com_sprintf (val, sizeof(val), "%i",(int)value);
+	else
+		Com_sprintf (val, sizeof(val), "%f",value);
+	Cvar_Set (var_name, val);
+}
+
+
+/*
+============
+Cvar_GetLatchedVars
+
+Any variables with latched values will now be updated
+============
+*/
+void Cvar_GetLatchedVars (void)
+{
+	cvar_t	*var;
+
+	for (var = cvar_vars ; var ; var = var->next)
+	{
+		if (!var->latched_string)
+			continue;
+		Z_Free (var->string);
+		var->string = var->latched_string;
+		var->latched_string = NULL;
+		var->value = atof(var->string);
+		if (!strcmp(var->name, "game"))
+		{
+			FS_SetGamedir (var->string);
+			FS_ExecAutoexec ();
+		}
+	}
+}
+
+/*
+============
+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)
+	{
+		Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
+		return true;
+	}
+
+	Cvar_Set (v->name, Cmd_Argv(1));
+	return true;
+}
+
+
+/*
+============
+Cvar_Set_f
+
+Allows setting and defining of arbitrary cvars from console
+============
+*/
+void Cvar_Set_f (void)
+{
+	int		c;
+	int		flags;
+
+	c = Cmd_Argc();
+	if (c != 3 && c != 4)
+	{
+		Com_Printf ("usage: set <variable> <value> [u / s]\n");
+		return;
+	}
+
+	if (c == 4)
+	{
+		if (!strcmp(Cmd_Argv(3), "u"))
+			flags = CVAR_USERINFO;
+		else if (!strcmp(Cmd_Argv(3), "s"))
+			flags = CVAR_SERVERINFO;
+		else
+		{
+			Com_Printf ("flags can only be 'u' or 's'\n");
+			return;
+		}
+		Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags);
+	}
+	else
+		Cvar_Set (Cmd_Argv(1), Cmd_Argv(2));
+}
+
+
+/*
+============
+Cvar_WriteVariables
+
+Appends lines containing "set variable value" for all variables
+with the archive flag set to true.
+============
+*/
+void Cvar_WriteVariables (char *path)
+{
+	cvar_t	*var;
+	char	buffer[1024];
+	FILE	*f;
+
+	f = fopen (path, "a");
+	for (var = cvar_vars ; var ; var = var->next)
+	{
+		if (var->flags & CVAR_ARCHIVE)
+		{
+			Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
+			fprintf (f, "%s", buffer);
+		}
+	}
+	fclose (f);
+}
+
+/*
+============
+Cvar_List_f
+
+============
+*/
+void Cvar_List_f (void)
+{
+	cvar_t	*var;
+	int		i;
+
+	i = 0;
+	for (var = cvar_vars ; var ; var = var->next, i++)
+	{
+		if (var->flags & CVAR_ARCHIVE)
+			Com_Printf ("*");
+		else
+			Com_Printf (" ");
+		if (var->flags & CVAR_USERINFO)
+			Com_Printf ("U");
+		else
+			Com_Printf (" ");
+		if (var->flags & CVAR_SERVERINFO)
+			Com_Printf ("S");
+		else
+			Com_Printf (" ");
+		if (var->flags & CVAR_NOSET)
+			Com_Printf ("-");
+		else if (var->flags & CVAR_LATCH)
+			Com_Printf ("L");
+		else
+			Com_Printf (" ");
+		Com_Printf (" %s \"%s\"\n", var->name, var->string);
+	}
+	Com_Printf ("%i cvars\n", i);
+}
+
+
+qboolean userinfo_modified;
+
+
+char	*Cvar_BitInfo (int bit)
+{
+	static char	info[MAX_INFO_STRING];
+	cvar_t	*var;
+
+	info[0] = 0;
+
+	for (var = cvar_vars ; var ; var = var->next)
+	{
+		if (var->flags & bit)
+			Info_SetValueForKey (info, var->name, var->string);
+	}
+	return info;
+}
+
+// returns an info string containing all the CVAR_USERINFO cvars
+char	*Cvar_Userinfo (void)
+{
+	return Cvar_BitInfo (CVAR_USERINFO);
+}
+
+// returns an info string containing all the CVAR_SERVERINFO cvars
+char	*Cvar_Serverinfo (void)
+{
+	return Cvar_BitInfo (CVAR_SERVERINFO);
+}
+
+/*
+============
+Cvar_Init
+
+Reads in all archived cvars
+============
+*/
+void Cvar_Init (void)
+{
+	Cmd_AddCommand ("set", Cvar_Set_f);
+	Cmd_AddCommand ("cvarlist", Cvar_List_f);
+
+}
--- /dev/null
+++ b/qcommon/files.c
@@ -1,0 +1,877 @@
+/*
+Copyright (C) 1997-2001 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 "qcommon.h"
+
+// define this to dissalow any data but the demo pak file
+//#define	NO_ADDONS
+
+// if a packfile directory differs from this, it is assumed to be hacked
+// Full version
+#define	PAK0_CHECKSUM	0x40e614e0
+// Demo
+//#define	PAK0_CHECKSUM	0xb2c6d7ea
+// OEM
+//#define	PAK0_CHECKSUM	0x78e135c
+
+/*
+=============================================================================
+
+QUAKE FILESYSTEM
+
+=============================================================================
+*/
+
+
+//
+// in memory
+//
+
+typedef struct
+{
+	char	name[MAX_QPATH];
+	int		filepos, filelen;
+} packfile_t;
+
+typedef struct pack_s
+{
+	char	filename[MAX_OSPATH];
+	FILE	*handle;
+	int		numfiles;
+	packfile_t	*files;
+} pack_t;
+
+char	fs_gamedir[MAX_OSPATH];
+cvar_t	*fs_basedir;
+cvar_t	*fs_cddir;
+cvar_t	*fs_gamedirvar;
+
+typedef struct filelink_s
+{
+	struct filelink_s	*next;
+	char	*from;
+	int		fromlength;
+	char	*to;
+} filelink_t;
+
+filelink_t	*fs_links;
+
+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	*fs_searchpaths;
+searchpath_t	*fs_base_searchpaths;	// without gamedirs
+
+
+/*
+
+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.
+
+*/
+
+
+/*
+================
+FS_filelength
+================
+*/
+int FS_filelength (FILE *f)
+{
+	int		pos;
+	int		end;
+
+	pos = ftell (f);
+	fseek (f, 0, SEEK_END);
+	end = ftell (f);
+	fseek (f, pos, SEEK_SET);
+
+	return end;
+}
+
+
+/*
+============
+FS_CreatePath
+
+Creates any directories needed to store the given filename
+============
+*/
+void	FS_CreatePath (char *path)
+{
+	char	*ofs;
+	
+	for (ofs = path+1 ; *ofs ; ofs++)
+	{
+		if (*ofs == '/')
+		{	// create the directory
+			*ofs = 0;
+			Sys_Mkdir (path);
+			*ofs = '/';
+		}
+	}
+}
+
+
+/*
+==============
+FS_FCloseFile
+
+For some reason, other dll's can't just cal fclose()
+on files returned by FS_FOpenFile...
+==============
+*/
+void FS_FCloseFile (FILE *f)
+{
+	fclose (f);
+}
+
+
+// RAFAEL
+/*
+	Developer_searchpath
+*/
+int	Developer_searchpath (int who)
+{
+	
+	int		ch;
+	// PMM - warning removal
+//	char	*start;
+	searchpath_t	*search;
+	
+	if (who == 1) // xatrix
+		ch = 'x';
+	else if (who == 2)
+		ch = 'r';
+
+	for (search = fs_searchpaths ; search ; search = search->next)
+	{
+		if (strstr (search->filename, "xatrix"))
+			return 1;
+
+		if (strstr (search->filename, "rogue"))
+			return 2;
+/*
+		start = strchr (search->filename, ch);
+
+		if (start == NULL)
+			continue;
+
+		if (strcmp (start ,"xatrix") == 0)
+			return (1);
+*/
+	}
+	return (0);
+
+}
+
+
+/*
+===========
+FS_FOpenFile
+
+Finds the file in the search path.
+returns filesize and an open FILE *
+Used for streaming data out of either a pak file or
+a seperate file.
+===========
+*/
+int file_from_pak = 0;
+#ifndef NO_ADDONS
+int FS_FOpenFile (char *filename, FILE **file)
+{
+	searchpath_t	*search;
+	char			netpath[MAX_OSPATH];
+	pack_t			*pak;
+	int				i;
+	filelink_t		*link;
+
+	file_from_pak = 0;
+
+	// check for links first
+	for (link = fs_links ; link ; link=link->next)
+	{
+		if (!strncmp (filename, link->from, link->fromlength))
+		{
+			Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
+			*file = fopen (netpath, "rb");
+			if (*file)
+			{		
+				Com_DPrintf ("link file: %s\n",netpath);
+				return FS_filelength (*file);
+			}
+			return -1;
+		}
+	}
+
+//
+// search through the path, one element at a time
+//
+	for (search = fs_searchpaths ; 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 (!Q_strcasecmp (pak->files[i].name, filename))
+				{	// found it!
+					file_from_pak = 1;
+					Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+				// open a new file on the pakfile
+					*file = fopen (pak->filename, "rb");
+					if (!*file)
+						Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);	
+					fseek (*file, pak->files[i].filepos, SEEK_SET);
+					return pak->files[i].filelen;
+				}
+		}
+		else
+		{		
+	// check a file in the directory tree
+			
+			Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
+			
+			*file = fopen (netpath, "rb");
+			if (!*file)
+				continue;
+			
+			Com_DPrintf ("FindFile: %s\n",netpath);
+
+			return FS_filelength (*file);
+		}
+		
+	}
+	
+	Com_DPrintf ("FindFile: can't find %s\n", filename);
+	
+	*file = NULL;
+	return -1;
+}
+
+#else
+
+// this is just for demos to prevent add on hacking
+
+int FS_FOpenFile (char *filename, FILE **file)
+{
+	searchpath_t	*search;
+	char			netpath[MAX_OSPATH];
+	pack_t			*pak;
+	int				i;
+
+	file_from_pak = 0;
+
+	// get config from directory, everything else from pak
+	if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
+	{
+		Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
+		
+		*file = fopen (netpath, "rb");
+		if (!*file)
+			return -1;
+		
+		Com_DPrintf ("FindFile: %s\n",netpath);
+
+		return FS_filelength (*file);
+	}
+
+	for (search = fs_searchpaths ; search ; search = search->next)
+		if (search->pack)
+			break;
+	if (!search)
+	{
+		*file = NULL;
+		return -1;
+	}
+
+	pak = search->pack;
+	for (i=0 ; i<pak->numfiles ; i++)
+		if (!Q_strcasecmp (pak->files[i].name, filename))
+		{	// found it!
+			file_from_pak = 1;
+			Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+		// open a new file on the pakfile
+			*file = fopen (pak->filename, "rb");
+			if (!*file)
+				Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);	
+			fseek (*file, pak->files[i].filepos, SEEK_SET);
+			return pak->files[i].filelen;
+		}
+	
+	Com_DPrintf ("FindFile: can't find %s\n", filename);
+	
+	*file = NULL;
+	return -1;
+}
+
+#endif
+
+
+/*
+=================
+FS_ReadFile
+
+Properly handles partial reads
+=================
+*/
+void CDAudio_Stop(void);
+#define	MAX_READ	0x10000		// read in blocks of 64k
+void FS_Read (void *buffer, int len, FILE *f)
+{
+	int		block, remaining;
+	int		read;
+	byte	*buf;
+	int		tries;
+
+	buf = (byte *)buffer;
+
+	// read in chunks for progress bar
+	remaining = len;
+	tries = 0;
+	while (remaining)
+	{
+		block = remaining;
+		if (block > MAX_READ)
+			block = MAX_READ;
+		read = fread (buf, 1, block, f);
+		if (read == 0)
+		{
+			// we might have been trying to read from a CD
+			if (!tries)
+			{
+				tries = 1;
+				CDAudio_Stop();
+			}
+			else
+				Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
+		}
+
+		if (read == -1)
+			Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
+
+		// do some progress bar thing here...
+
+		remaining -= read;
+		buf += read;
+	}
+}
+
+/*
+============
+FS_LoadFile
+
+Filename are reletive to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+int FS_LoadFile (char *path, void **buffer)
+{
+	FILE	*h;
+	byte	*buf;
+	int		len;
+
+	buf = NULL;	// quiet compiler warning
+
+// look for it in the filesystem or pack files
+	len = FS_FOpenFile (path, &h);
+	if (!h)
+	{
+		if (buffer)
+			*buffer = NULL;
+		return -1;
+	}
+	
+	if (!buffer)
+	{
+		fclose (h);
+		return len;
+	}
+
+	buf = Z_Malloc(len);
+	*buffer = buf;
+
+	FS_Read (buf, len, h);
+
+	fclose (h);
+
+	return len;
+}
+
+
+/*
+=============
+FS_FreeFile
+=============
+*/
+void FS_FreeFile (void *buffer)
+{
+	Z_Free (buffer);
+}
+
+/*
+=================
+FS_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 *FS_LoadPackFile (char *packfile)
+{
+	dpackheader_t	header;
+	int				i;
+	packfile_t		*newfiles;
+	int				numpackfiles;
+	pack_t			*pack;
+	FILE			*packhandle;
+	dpackfile_t		info[MAX_FILES_IN_PACK];
+	unsigned		checksum;
+
+	packhandle = fopen(packfile, "rb");
+	if (!packhandle)
+		return NULL;
+
+	fread (&header, 1, sizeof(header), packhandle);
+	if (LittleLong(header.ident) != IDPAKHEADER)
+		Com_Error (ERR_FATAL, "%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)
+		Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
+
+	newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
+
+	fseek (packhandle, header.dirofs, SEEK_SET);
+	fread (info, 1, header.dirlen, packhandle);
+
+// crc the directory to check for modifications
+	checksum = Com_BlockChecksum ((void *)info, header.dirlen);
+
+#ifdef NO_ADDONS
+	if (checksum != PAK0_CHECKSUM)
+		return NULL;
+#endif
+// 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 = Z_Malloc (sizeof (pack_t));
+	strcpy (pack->filename, packfile);
+	pack->handle = packhandle;
+	pack->numfiles = numpackfiles;
+	pack->files = newfiles;
+	
+	Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
+	return pack;
+}
+
+
+/*
+================
+FS_AddGameDirectory
+
+Sets fs_gamedir, adds the directory to the head of the path,
+then loads and adds pak1.pak pak2.pak ... 
+================
+*/
+void FS_AddGameDirectory (char *dir)
+{
+	int				i;
+	searchpath_t	*search;
+	pack_t			*pak;
+	char			pakfile[MAX_OSPATH];
+
+	strcpy (fs_gamedir, dir);
+
+	//
+	// add the directory to the search path
+	//
+	search = Z_Malloc (sizeof(searchpath_t));
+	strcpy (search->filename, dir);
+	search->next = fs_searchpaths;
+	fs_searchpaths = search;
+
+	//
+	// add any pak files in the format pak0.pak pak1.pak, ...
+	//
+	for (i=0; i<10; i++)
+	{
+		Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
+		pak = FS_LoadPackFile (pakfile);
+		if (!pak)
+			continue;
+		search = Z_Malloc (sizeof(searchpath_t));
+		search->pack = pak;
+		search->next = fs_searchpaths;
+		fs_searchpaths = search;		
+	}
+
+
+}
+
+/*
+============
+FS_Gamedir
+
+Called to find where to write a file (demos, savegames, etc)
+============
+*/
+char *FS_Gamedir (void)
+{
+	return fs_gamedir;
+}
+
+/*
+=============
+FS_ExecAutoexec
+=============
+*/
+void FS_ExecAutoexec (void)
+{
+	char *dir;
+	char name [MAX_QPATH];
+
+	dir = Cvar_VariableString("gamedir");
+	if (*dir)
+		Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir); 
+	else
+		Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME); 
+	if (Sys_FindFirst(name, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM))
+		Cbuf_AddText ("exec autoexec.cfg\n");
+	Sys_FindClose();
+}
+
+
+/*
+================
+FS_SetGamedir
+
+Sets the gamedir and path to a different directory.
+================
+*/
+void FS_SetGamedir (char *dir)
+{
+	searchpath_t	*next;
+
+	if (strstr(dir, "..") || strstr(dir, "/")
+		|| strstr(dir, "\\") || strstr(dir, ":") )
+	{
+		Com_Printf ("Gamedir should be a single filename, not a path\n");
+		return;
+	}
+
+	//
+	// free up any current game dir info
+	//
+	while (fs_searchpaths != fs_base_searchpaths)
+	{
+		if (fs_searchpaths->pack)
+		{
+			fclose (fs_searchpaths->pack->handle);
+			Z_Free (fs_searchpaths->pack->files);
+			Z_Free (fs_searchpaths->pack);
+		}
+		next = fs_searchpaths->next;
+		Z_Free (fs_searchpaths);
+		fs_searchpaths = next;
+	}
+
+	//
+	// flush all data, so it will be forced to reload
+	//
+	if (dedicated && !dedicated->value)
+		Cbuf_AddText ("vid_restart\nsnd_restart\n");
+
+	Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
+
+	if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
+	{
+		Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
+		Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+	}
+	else
+	{
+		Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
+		if (fs_cddir->string[0])
+			FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
+		FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
+	}
+}
+
+
+/*
+================
+FS_Link_f
+
+Creates a filelink_t
+================
+*/
+void FS_Link_f (void)
+{
+	filelink_t	*l, **prev;
+
+	if (Cmd_Argc() != 3)
+	{
+		Com_Printf ("USAGE: link <from> <to>\n");
+		return;
+	}
+
+	// see if the link already exists
+	prev = &fs_links;
+	for (l=fs_links ; l ; l=l->next)
+	{
+		if (!strcmp (l->from, Cmd_Argv(1)))
+		{
+			Z_Free (l->to);
+			if (!strlen(Cmd_Argv(2)))
+			{	// delete it
+				*prev = l->next;
+				Z_Free (l->from);
+				Z_Free (l);
+				return;
+			}
+			l->to = CopyString (Cmd_Argv(2));
+			return;
+		}
+		prev = &l->next;
+	}
+
+	// create a new link
+	l = Z_Malloc(sizeof(*l));
+	l->next = fs_links;
+	fs_links = l;
+	l->from = CopyString(Cmd_Argv(1));
+	l->fromlength = strlen(l->from);
+	l->to = CopyString(Cmd_Argv(2));
+}
+
+/*
+** FS_ListFiles
+*/
+char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
+{
+	char *s;
+	int nfiles = 0;
+	char **list = 0;
+
+	s = Sys_FindFirst( findname, musthave, canthave );
+	while ( s )
+	{
+		if ( s[strlen(s)-1] != '.' )
+			nfiles++;
+		s = Sys_FindNext( musthave, canthave );
+	}
+	Sys_FindClose ();
+
+	if ( !nfiles )
+		return NULL;
+
+	nfiles++; // add space for a guard
+	*numfiles = nfiles;
+
+	list = malloc( sizeof( char * ) * nfiles );
+	memset( list, 0, sizeof( char * ) * nfiles );
+
+	s = Sys_FindFirst( findname, musthave, canthave );
+	nfiles = 0;
+	while ( s )
+	{
+		if ( s[strlen(s)-1] != '.' )
+		{
+			list[nfiles] = strdup( s );
+#ifdef _WIN32
+			strlwr( list[nfiles] );
+#endif
+			nfiles++;
+		}
+		s = Sys_FindNext( musthave, canthave );
+	}
+	Sys_FindClose ();
+
+	return list;
+}
+
+/*
+** FS_Dir_f
+*/
+void FS_Dir_f( void )
+{
+	char	*path = NULL;
+	char	findname[1024];
+	char	wildcard[1024] = "*.*";
+	char	**dirnames;
+	int		ndirs;
+
+	if ( Cmd_Argc() != 1 )
+	{
+		strcpy( wildcard, Cmd_Argv( 1 ) );
+	}
+
+	while ( ( path = FS_NextPath( path ) ) != NULL )
+	{
+		char *tmp = findname;
+
+		Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
+
+		while ( *tmp != 0 )
+		{
+			if ( *tmp == '\\' ) 
+				*tmp = '/';
+			tmp++;
+		}
+		Com_Printf( "Directory of %s\n", findname );
+		Com_Printf( "----\n" );
+
+		if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
+		{
+			int i;
+
+			for ( i = 0; i < ndirs-1; i++ )
+			{
+				if ( strrchr( dirnames[i], '/' ) )
+					Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
+				else
+					Com_Printf( "%s\n", dirnames[i] );
+
+				free( dirnames[i] );
+			}
+			free( dirnames );
+		}
+		Com_Printf( "\n" );
+	};
+}
+
+/*
+============
+FS_Path_f
+
+============
+*/
+void FS_Path_f (void)
+{
+	searchpath_t	*s;
+	filelink_t		*l;
+
+	Com_Printf ("Current search path:\n");
+	for (s=fs_searchpaths ; s ; s=s->next)
+	{
+		if (s == fs_base_searchpaths)
+			Com_Printf ("----------\n");
+		if (s->pack)
+			Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
+		else
+			Com_Printf ("%s\n", s->filename);
+	}
+
+	Com_Printf ("\nLinks:\n");
+	for (l=fs_links ; l ; l=l->next)
+		Com_Printf ("%s : %s\n", l->from, l->to);
+}
+
+/*
+================
+FS_NextPath
+
+Allows enumerating all of the directories in the search path
+================
+*/
+char *FS_NextPath (char *prevpath)
+{
+	searchpath_t	*s;
+	char			*prev;
+
+	if (!prevpath)
+		return fs_gamedir;
+
+	prev = fs_gamedir;
+	for (s=fs_searchpaths ; s ; s=s->next)
+	{
+		if (s->pack)
+			continue;
+		if (prevpath == prev)
+			return s->filename;
+		prev = s->filename;
+	}
+
+	return NULL;
+}
+
+
+/*
+================
+FS_InitFilesystem
+================
+*/
+void FS_InitFilesystem (void)
+{
+	Cmd_AddCommand ("path", FS_Path_f);
+	Cmd_AddCommand ("link", FS_Link_f);
+	Cmd_AddCommand ("dir", FS_Dir_f );
+
+	//
+	// basedir <path>
+	// allows the game to run from outside the data tree
+	//
+	fs_basedir = Cvar_Get ("basedir", ".", CVAR_NOSET);
+
+	//
+	// cddir <path>
+	// Logically concatenates the cddir after the basedir for 
+	// allows the game to run from outside the data tree
+	//
+	fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
+	if (fs_cddir->string[0])
+		FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
+
+	//
+	// start up with baseq2 by default
+	//
+	FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
+
+	// any set gamedirs will be freed up to here
+	fs_base_searchpaths = fs_searchpaths;
+
+	// check for game override
+	fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+	if (fs_gamedirvar->string[0])
+		FS_SetGamedir (fs_gamedirvar->string);
+}
+
+
+
--- /dev/null
+++ b/qcommon/md4.c
@@ -1,0 +1,278 @@
+/* GLOBAL.H - RSAREF types and constants */
+
+#include <string.h>
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+#ifdef __alpha__
+typedef unsigned int UINT4;
+#else
+typedef unsigned long int UINT4;
+#endif
+
+  
+/* MD4.H - header file for MD4C.C */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. 
+
+All rights reserved.
+  
+License to copy and use this software is granted provided that it is identified as the �RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as �derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided �as is� without express or implied warranty of any kind.
+  
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* MD4 context. */
+typedef struct {
+	UINT4 state[4];				/* state (ABCD) */
+	UINT4 count[2];				/* number of bits, modulo 2^64 (lsb first) */
+	unsigned char buffer[64]; 			/* input buffer */
+} MD4_CTX;
+
+void MD4Init (MD4_CTX *);
+void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
+void MD4Final (unsigned char [16], MD4_CTX *);
+  
+
+  
+/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
+/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+  
+License to copy and use this software is granted provided that it is identified as the
+RSA Data Security, Inc. MD4 Message-Digest Algorithm
+ in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as 
+derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
+in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
+as is without express or implied warranty of any kind.
+  
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* Constants for MD4Transform routine.  */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform (UINT4 [4], unsigned char [64]);
+static void Encode (unsigned char *, UINT4 *, unsigned int);
+static void Decode (UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+0x80, 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, 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
+};
+
+/* F, G and H are basic MD4 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
+
+#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
+
+#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
+
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context. */
+void MD4Init (MD4_CTX *context)
+{
+	context->count[0] = context->count[1] = 0;
+
+/* Load magic initialization constants.*/
+context->state[0] = 0x67452301;
+context->state[1] = 0xefcdab89;
+context->state[2] = 0x98badcfe;
+context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
+void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
+{
+	unsigned int i, index, partLen;
+
+	/* Compute number of bytes mod 64 */
+	index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+	/* Update number of bits */
+	if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
+		context->count[1]++;
+
+	context->count[1] += ((UINT4)inputLen >> 29);
+
+	partLen = 64 - index;
+
+	/* Transform as many times as possible.*/
+	if (inputLen >= partLen)
+	{
+ 		memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ 		MD4Transform (context->state, context->buffer);
+
+ 		for (i = partLen; i + 63 < inputLen; i += 64)
+ 			MD4Transform (context->state, &input[i]);
+
+ 		index = 0;
+	}
+	else
+ 		i = 0;
+
+	/* Buffer remaining input */
+	memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
+void MD4Final (unsigned char digest[16], MD4_CTX *context)
+{
+	unsigned char bits[8];
+	unsigned int index, padLen;
+
+	/* Save number of bits */
+	Encode (bits, context->count, 8);
+
+	/* Pad out to 56 mod 64.*/
+	index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+	padLen = (index < 56) ? (56 - index) : (120 - index);
+	MD4Update (context, PADDING, padLen);
+
+	/* Append length (before padding) */
+	MD4Update (context, bits, 8);
+	
+	/* Store state in digest */
+	Encode (digest, context->state, 16);
+
+	/* Zeroize sensitive information.*/
+	memset ((POINTER)context, 0, sizeof (*context));
+}
+
+
+/* MD4 basic transformation. Transforms state based on block. */
+static void MD4Transform (UINT4 state[4], unsigned char block[64])
+{
+	UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+	Decode (x, block, 64);
+
+/* Round 1 */
+FF (a, b, c, d, x[ 0], S11); 				/* 1 */
+FF (d, a, b, c, x[ 1], S12); 				/* 2 */
+FF (c, d, a, b, x[ 2], S13); 				/* 3 */
+FF (b, c, d, a, x[ 3], S14); 				/* 4 */
+FF (a, b, c, d, x[ 4], S11); 				/* 5 */
+FF (d, a, b, c, x[ 5], S12); 				/* 6 */
+FF (c, d, a, b, x[ 6], S13); 				/* 7 */
+FF (b, c, d, a, x[ 7], S14); 				/* 8 */
+FF (a, b, c, d, x[ 8], S11); 				/* 9 */
+FF (d, a, b, c, x[ 9], S12); 				/* 10 */
+FF (c, d, a, b, x[10], S13); 			/* 11 */
+FF (b, c, d, a, x[11], S14); 			/* 12 */
+FF (a, b, c, d, x[12], S11); 			/* 13 */
+FF (d, a, b, c, x[13], S12); 			/* 14 */
+FF (c, d, a, b, x[14], S13); 			/* 15 */
+FF (b, c, d, a, x[15], S14); 			/* 16 */
+
+/* Round 2 */
+GG (a, b, c, d, x[ 0], S21); 			/* 17 */
+GG (d, a, b, c, x[ 4], S22); 			/* 18 */
+GG (c, d, a, b, x[ 8], S23); 			/* 19 */
+GG (b, c, d, a, x[12], S24); 			/* 20 */
+GG (a, b, c, d, x[ 1], S21); 			/* 21 */
+GG (d, a, b, c, x[ 5], S22); 			/* 22 */
+GG (c, d, a, b, x[ 9], S23); 			/* 23 */
+GG (b, c, d, a, x[13], S24); 			/* 24 */
+GG (a, b, c, d, x[ 2], S21); 			/* 25 */
+GG (d, a, b, c, x[ 6], S22); 			/* 26 */
+GG (c, d, a, b, x[10], S23); 			/* 27 */
+GG (b, c, d, a, x[14], S24); 			/* 28 */
+GG (a, b, c, d, x[ 3], S21); 			/* 29 */
+GG (d, a, b, c, x[ 7], S22); 			/* 30 */
+GG (c, d, a, b, x[11], S23); 			/* 31 */
+GG (b, c, d, a, x[15], S24); 			/* 32 */
+
+/* Round 3 */
+HH (a, b, c, d, x[ 0], S31);				/* 33 */
+HH (d, a, b, c, x[ 8], S32); 			/* 34 */
+HH (c, d, a, b, x[ 4], S33); 			/* 35 */
+HH (b, c, d, a, x[12], S34); 			/* 36 */
+HH (a, b, c, d, x[ 2], S31); 			/* 37 */
+HH (d, a, b, c, x[10], S32); 			/* 38 */
+HH (c, d, a, b, x[ 6], S33); 			/* 39 */
+HH (b, c, d, a, x[14], S34); 			/* 40 */
+HH (a, b, c, d, x[ 1], S31); 			/* 41 */
+HH (d, a, b, c, x[ 9], S32); 			/* 42 */
+HH (c, d, a, b, x[ 5], S33); 			/* 43 */
+HH (b, c, d, a, x[13], S34); 			/* 44 */
+HH (a, b, c, d, x[ 3], S31); 			/* 45 */
+HH (d, a, b, c, x[11], S32); 			/* 46 */
+HH (c, d, a, b, x[ 7], S33); 			/* 47 */
+HH (b, c, d, a, x[15], S34);			/* 48 */
+
+state[0] += a;
+state[1] += b;
+state[2] += c;
+state[3] += d;
+
+	/* Zeroize sensitive information.*/
+	memset ((POINTER)x, 0, sizeof (x));
+}
+
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+{
+	unsigned int i, j;
+
+	for (i = 0, j = 0; j < len; i++, j += 4) {
+ 		output[j] = (unsigned char)(input[i] & 0xff);
+ 		output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ 		output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ 		output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+	}
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
+static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
+{
+unsigned int i, j;
+
+for (i = 0, j = 0; j < len; i++, j += 4)
+ 	output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+//===================================================================
+
+unsigned Com_BlockChecksum (void *buffer, int length)
+{
+	int			digest[4];
+	unsigned	val;
+	MD4_CTX		ctx;
+
+	MD4Init (&ctx);
+	MD4Update (&ctx, (unsigned char *)buffer, length);
+	MD4Final ( (unsigned char *)digest, &ctx);
+	
+	val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+
+	return val;
+}
--- /dev/null
+++ b/qcommon/net_chan.c
@@ -1,0 +1,387 @@
+/*
+Copyright (C) 1997-2001 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 "qcommon.h"
+
+/*
+
+packet header
+-------------
+31	sequence
+1	does this message contain a reliable payload
+31	acknowledge sequence
+1	acknowledge receipt of even/odd message
+16	qport
+
+The remote connection never knows if it missed a reliable message, the
+local side detects that it has been dropped by seeing a sequence acknowledge
+higher thatn the last reliable sequence, but without the correct evon/odd
+bit for the reliable set.
+
+If the sender notices that a reliable message has been dropped, it will be
+retransmitted.  It will not be retransmitted again until a message after
+the retransmit has been acknowledged and the reliable still failed to get there.
+
+if the sequence number is -1, the packet should be handled without a netcon
+
+The reliable message can be added to at any time by doing
+MSG_Write* (&netchan->message, <data>).
+
+If the message buffer is overflowed, either by a single message, or by
+multiple frames worth piling up while the last reliable transmit goes
+unacknowledged, the netchan signals a fatal error.
+
+Reliable messages are always placed first in a packet, then the unreliable
+message is included if there is sufficient room.
+
+To the receiver, there is no distinction between the reliable and unreliable
+parts of the message, they are just processed out as a single larger message.
+
+Illogical packet sequence numbers cause the packet to be dropped, but do
+not kill the connection.  This, combined with the tight window of valid
+reliable acknowledgement numbers provides protection against malicious
+address spoofing.
+
+
+The qport field is a workaround for bad address translating routers that
+sometimes remap the client's source port on a packet during gameplay.
+
+If the base part of the net address matches and the qport matches, then the
+channel matches even if the IP port differs.  The IP port should be updated
+to the new value before sending out any replies.
+
+
+If there is no information that needs to be transfered on a given frame,
+such as during the connection stage while waiting for the client to load,
+then a packet only needs to be delivered if there is something in the
+unacknowledged reliable
+*/
+
+cvar_t		*showpackets;
+cvar_t		*showdrop;
+cvar_t		*qport;
+
+netadr_t	net_from;
+sizebuf_t	net_message;
+byte		net_message_buffer[MAX_MSGLEN];
+
+/*
+===============
+Netchan_Init
+
+===============
+*/
+void Netchan_Init (void)
+{
+	int		port;
+
+	// pick a port value that should be nice and random
+	port = Sys_Milliseconds() & 0xffff;
+
+	showpackets = Cvar_Get ("showpackets", "0", 0);
+	showdrop = Cvar_Get ("showdrop", "0", 0);
+	qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
+}
+
+/*
+===============
+Netchan_OutOfBand
+
+Sends an out-of-band datagram
+================
+*/
+void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
+{
+	sizebuf_t	send;
+	byte		send_buf[MAX_MSGLEN];
+
+// write the packet header
+	SZ_Init (&send, send_buf, sizeof(send_buf));
+	
+	MSG_WriteLong (&send, -1);	// -1 sequence means out of band
+	SZ_Write (&send, data, length);
+
+// send the datagram
+	NET_SendPacket (net_socket, send.cursize, send.data, adr);
+}
+
+/*
+===============
+Netchan_OutOfBandPrint
+
+Sends a text message in an out-of-band datagram
+================
+*/
+void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
+{
+	va_list		argptr;
+	static char		string[MAX_MSGLEN - 4];
+	
+	va_start (argptr, format);
+	vsprintf (string, format,argptr);
+	va_end (argptr);
+
+	Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
+}
+
+
+/*
+==============
+Netchan_Setup
+
+called to open a channel to a remote system
+==============
+*/
+void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
+{
+	memset (chan, 0, sizeof(*chan));
+	
+	chan->sock = sock;
+	chan->remote_address = adr;
+	chan->qport = qport;
+	chan->last_received = curtime;
+	chan->incoming_sequence = 0;
+	chan->outgoing_sequence = 1;
+
+	SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
+	chan->message.allowoverflow = true;
+}
+
+
+/*
+===============
+Netchan_CanReliable
+
+Returns true if the last reliable message has acked
+================
+*/
+qboolean Netchan_CanReliable (netchan_t *chan)
+{
+	if (chan->reliable_length)
+		return false;			// waiting for ack
+	return true;
+}
+
+
+qboolean Netchan_NeedReliable (netchan_t *chan)
+{
+	qboolean	send_reliable;
+
+// if the remote side dropped the last reliable message, resend it
+	send_reliable = false;
+
+	if (chan->incoming_acknowledged > chan->last_reliable_sequence
+	&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
+		send_reliable = true;
+
+// if the reliable transmit buffer is empty, copy the current message out
+	if (!chan->reliable_length && chan->message.cursize)
+	{
+		send_reliable = true;
+	}
+
+	return send_reliable;
+}
+
+/*
+===============
+Netchan_Transmit
+
+tries to send an unreliable message to a connection, and handles the
+transmition / retransmition of the reliable messages.
+
+A 0 length will still generate a packet and deal with the reliable messages.
+================
+*/
+void Netchan_Transmit (netchan_t *chan, int length, byte *data)
+{
+	sizebuf_t	send;
+	byte		send_buf[MAX_MSGLEN];
+	qboolean	send_reliable;
+	unsigned	w1, w2;
+
+// check for message overflow
+	if (chan->message.overflowed)
+	{
+		chan->fatal_error = true;
+		Com_Printf ("%s:Outgoing message overflow\n"
+			, NET_AdrToString (chan->remote_address));
+		return;
+	}
+
+	send_reliable = Netchan_NeedReliable (chan);
+
+	if (!chan->reliable_length && chan->message.cursize)
+	{
+		memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
+		chan->reliable_length = chan->message.cursize;
+		chan->message.cursize = 0;
+		chan->reliable_sequence ^= 1;
+	}
+
+
+// write the packet header
+	SZ_Init (&send, send_buf, sizeof(send_buf));
+
+	w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
+	w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
+
+	chan->outgoing_sequence++;
+	chan->last_sent = curtime;
+
+	MSG_WriteLong (&send, w1);
+	MSG_WriteLong (&send, w2);
+
+	// send the qport if we are a client
+	if (chan->sock == NS_CLIENT)
+		MSG_WriteShort (&send, qport->value);
+
+// copy the reliable message to the packet first
+	if (send_reliable)
+	{
+		SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
+		chan->last_reliable_sequence = chan->outgoing_sequence;
+	}
+	
+// add the unreliable part if space is available
+	if (send.maxsize - send.cursize >= length)
+		SZ_Write (&send, data, length);
+	else
+		Com_Printf ("Netchan_Transmit: dumped unreliable\n");
+
+// send the datagram
+	NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
+
+	if (showpackets->value)
+	{
+		if (send_reliable)
+			Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
+				, send.cursize
+				, chan->outgoing_sequence - 1
+				, chan->reliable_sequence
+				, chan->incoming_sequence
+				, chan->incoming_reliable_sequence);
+		else
+			Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
+				, send.cursize
+				, chan->outgoing_sequence - 1
+				, chan->incoming_sequence
+				, chan->incoming_reliable_sequence);
+	}
+}
+
+/*
+=================
+Netchan_Process
+
+called when the current net_message is from remote_address
+modifies net_message so that it points to the packet payload
+=================
+*/
+qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
+{
+	unsigned	sequence, sequence_ack;
+	unsigned	reliable_ack, reliable_message;
+	int			qport;
+
+// get sequence numbers		
+	MSG_BeginReading (msg);
+	sequence = MSG_ReadLong (msg);
+	sequence_ack = MSG_ReadLong (msg);
+
+	// read the qport if we are a server
+	if (chan->sock == NS_SERVER)
+		qport = MSG_ReadShort (msg);
+
+	reliable_message = sequence >> 31;
+	reliable_ack = sequence_ack >> 31;
+
+	sequence &= ~(1<<31);
+	sequence_ack &= ~(1<<31);	
+
+	if (showpackets->value)
+	{
+		if (reliable_message)
+			Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
+				, msg->cursize
+				, sequence
+				, chan->incoming_reliable_sequence ^ 1
+				, sequence_ack
+				, reliable_ack);
+		else
+			Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
+				, msg->cursize
+				, sequence
+				, sequence_ack
+				, reliable_ack);
+	}
+
+//
+// discard stale or duplicated packets
+//
+	if (sequence <= chan->incoming_sequence)
+	{
+		if (showdrop->value)
+			Com_Printf ("%s:Out of order packet %i at %i\n"
+				, NET_AdrToString (chan->remote_address)
+				,  sequence
+				, chan->incoming_sequence);
+		return false;
+	}
+
+//
+// dropped packets don't keep the message from being used
+//
+	chan->dropped = sequence - (chan->incoming_sequence+1);
+	if (chan->dropped > 0)
+	{
+		if (showdrop->value)
+			Com_Printf ("%s:Dropped %i packets at %i\n"
+			, NET_AdrToString (chan->remote_address)
+			, chan->dropped
+			, sequence);
+	}
+
+//
+// if the current outgoing reliable message has been acknowledged
+// clear the buffer to make way for the next
+//
+	if (reliable_ack == chan->reliable_sequence)
+		chan->reliable_length = 0;	// it has been received
+	
+//
+// if this message contains a reliable message, bump incoming_reliable_sequence 
+//
+	chan->incoming_sequence = sequence;
+	chan->incoming_acknowledged = sequence_ack;
+	chan->incoming_reliable_acknowledged = reliable_ack;
+	if (reliable_message)
+	{
+		chan->incoming_reliable_sequence ^= 1;
+	}
+
+//
+// the message can now be read from the current message pointer
+//
+	chan->last_received = curtime;
+
+	return true;
+}
+
--- /dev/null
+++ b/qcommon/pmove.c
@@ -1,0 +1,1360 @@
+/*
+Copyright (C) 1997-2001 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 "qcommon.h"
+
+
+
+#define	STEPSIZE	18
+
+// all of the locals will be zeroed before each
+// pmove, just to make damn sure we don't have
+// any differences when running on client or server
+
+typedef struct
+{
+	vec3_t		origin;			// full float precision
+	vec3_t		velocity;		// full float precision
+
+	vec3_t		forward, right, up;
+	float		frametime;
+
+
+	csurface_t	*groundsurface;
+	cplane_t	groundplane;
+	int			groundcontents;
+
+	vec3_t		previous_origin;
+	qboolean	ladder;
+} pml_t;
+
+pmove_t		*pm;
+pml_t		pml;
+
+
+// movement parameters
+float	pm_stopspeed = 100;
+float	pm_maxspeed = 300;
+float	pm_duckspeed = 100;
+float	pm_accelerate = 10;
+float	pm_airaccelerate = 0;
+float	pm_wateraccelerate = 10;
+float	pm_friction = 6;
+float	pm_waterfriction = 1;
+float	pm_waterspeed = 400;
+
+/*
+
+  walking up a step should kill some velocity
+
+*/
+
+
+/*
+==================
+PM_ClipVelocity
+
+Slide off of the impacting object
+returns the blocked flags (1 = floor, 2 = step / wall)
+==================
+*/
+#define	STOP_EPSILON	0.1
+
+void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+{
+	float	backoff;
+	float	change;
+	int		i;
+	
+	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;
+	}
+}
+
+
+
+
+/*
+==================
+PM_StepSlideMove
+
+Each intersection will try to step over the obstruction instead of
+sliding along it.
+
+Returns a new origin, velocity, and contact entity
+Does not modify any world state?
+==================
+*/
+#define	MIN_STEP_NORMAL	0.7		// can't step up onto very steep slopes
+#define	MAX_CLIP_PLANES	5
+void PM_StepSlideMove_ (void)
+{
+	int			bumpcount, numbumps;
+	vec3_t		dir;
+	float		d;
+	int			numplanes;
+	vec3_t		planes[MAX_CLIP_PLANES];
+	vec3_t		primal_velocity;
+	int			i, j;
+	trace_t	trace;
+	vec3_t		end;
+	float		time_left;
+	
+	numbumps = 4;
+	
+	VectorCopy (pml.velocity, primal_velocity);
+	numplanes = 0;
+	
+	time_left = pml.frametime;
+
+	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+	{
+		for (i=0 ; i<3 ; i++)
+			end[i] = pml.origin[i] + time_left * pml.velocity[i];
+
+		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+		if (trace.allsolid)
+		{	// entity is trapped in another solid
+			pml.velocity[2] = 0;	// don't build up falling damage
+			return;
+		}
+
+		if (trace.fraction > 0)
+		{	// actually covered some distance
+			VectorCopy (trace.endpos, pml.origin);
+			numplanes = 0;
+		}
+
+		if (trace.fraction == 1)
+			 break;		// moved the entire distance
+
+		// save entity for contact
+		if (pm->numtouch < MAXTOUCH && trace.ent)
+		{
+			pm->touchents[pm->numtouch] = trace.ent;
+			pm->numtouch++;
+		}
+		
+		time_left -= time_left * trace.fraction;
+
+		// slide along this plane
+		if (numplanes >= MAX_CLIP_PLANES)
+		{	// this shouldn't really happen
+			VectorCopy (vec3_origin, pml.velocity);
+			break;
+		}
+
+		VectorCopy (trace.plane.normal, planes[numplanes]);
+		numplanes++;
+
+#if 0
+	float		rub;
+
+		//
+		// modify velocity so it parallels all of the clip planes
+		//
+		if (numplanes == 1)
+		{	// go along this plane
+			VectorCopy (pml.velocity, dir);
+			VectorNormalize (dir);
+			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+			// slide along the plane
+			PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
+			// rub some extra speed off on xy axis
+			// not on Z, or you can scrub down walls
+			pml.velocity[0] *= rub;
+			pml.velocity[1] *= rub;
+			pml.velocity[2] *= rub;
+		}
+		else if (numplanes == 2)
+		{	// go along the crease
+			VectorCopy (pml.velocity, dir);
+			VectorNormalize (dir);
+			rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+			// slide along the plane
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, pml.velocity);
+			VectorScale (dir, d, pml.velocity);
+
+			// rub some extra speed off
+			VectorScale (pml.velocity, rub, pml.velocity);
+		}
+		else
+		{
+//			Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+			VectorCopy (vec3_origin, pml.velocity);
+			break;
+		}
+
+#else
+//
+// modify original_velocity so it parallels all of the clip planes
+//
+		for (i=0 ; i<numplanes ; i++)
+		{
+			PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
+			for (j=0 ; j<numplanes ; j++)
+				if (j != i)
+				{
+					if (DotProduct (pml.velocity, planes[j]) < 0)
+						break;	// not ok
+				}
+			if (j == numplanes)
+				break;
+		}
+		
+		if (i != numplanes)
+		{	// go along this plane
+		}
+		else
+		{	// go along the crease
+			if (numplanes != 2)
+			{
+//				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+				VectorCopy (vec3_origin, pml.velocity);
+				break;
+			}
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, pml.velocity);
+			VectorScale (dir, d, pml.velocity);
+		}
+#endif
+		//
+		// if velocity is against the original velocity, stop dead
+		// to avoid tiny occilations in sloping corners
+		//
+		if (DotProduct (pml.velocity, primal_velocity) <= 0)
+		{
+			VectorCopy (vec3_origin, pml.velocity);
+			break;
+		}
+	}
+
+	if (pm->s.pm_time)
+	{
+		VectorCopy (primal_velocity, pml.velocity);
+	}
+}
+
+/*
+==================
+PM_StepSlideMove
+
+==================
+*/
+void PM_StepSlideMove (void)
+{
+	vec3_t		start_o, start_v;
+	vec3_t		down_o, down_v;
+	trace_t		trace;
+	float		down_dist, up_dist;
+//	vec3_t		delta;
+	vec3_t		up, down;
+
+	VectorCopy (pml.origin, start_o);
+	VectorCopy (pml.velocity, start_v);
+
+	PM_StepSlideMove_ ();
+
+	VectorCopy (pml.origin, down_o);
+	VectorCopy (pml.velocity, down_v);
+
+	VectorCopy (start_o, up);
+	up[2] += STEPSIZE;
+
+	trace = pm->trace (up, pm->mins, pm->maxs, up);
+	if (trace.allsolid)
+		return;		// can't step up
+
+	// try sliding above
+	VectorCopy (up, pml.origin);
+	VectorCopy (start_v, pml.velocity);
+
+	PM_StepSlideMove_ ();
+
+	// push down the final amount
+	VectorCopy (pml.origin, down);
+	down[2] -= STEPSIZE;
+	trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
+	if (!trace.allsolid)
+	{
+		VectorCopy (trace.endpos, pml.origin);
+	}
+
+#if 0
+	VectorSubtract (pml.origin, up, delta);
+	up_dist = DotProduct (delta, start_v);
+
+	VectorSubtract (down_o, start_o, delta);
+	down_dist = DotProduct (delta, start_v);
+#else
+	VectorCopy(pml.origin, up);
+
+	// decide which one went farther
+    down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
+        + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
+    up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
+        + (up[1] - start_o[1])*(up[1] - start_o[1]);
+#endif
+
+	if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
+	{
+		VectorCopy (down_o, pml.origin);
+		VectorCopy (down_v, pml.velocity);
+		return;
+	}
+	//!! Special case
+	// if we were walking along a plane, then we need to copy the Z over
+	pml.velocity[2] = down_v[2];
+}
+
+
+/*
+==================
+PM_Friction
+
+Handles both ground friction and water friction
+==================
+*/
+void PM_Friction (void)
+{
+	float	*vel;
+	float	speed, newspeed, control;
+	float	friction;
+	float	drop;
+	
+	vel = pml.velocity;
+	
+	speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
+	if (speed < 1)
+	{
+		vel[0] = 0;
+		vel[1] = 0;
+		return;
+	}
+
+	drop = 0;
+
+// apply ground friction
+	if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
+	{
+		friction = pm_friction;
+		control = speed < pm_stopspeed ? pm_stopspeed : speed;
+		drop += control*friction*pml.frametime;
+	}
+
+// apply water friction
+	if (pm->waterlevel && !pml.ladder)
+		drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
+
+// scale the velocity
+	newspeed = speed - drop;
+	if (newspeed < 0)
+	{
+		newspeed = 0;
+	}
+	newspeed /= speed;
+
+	vel[0] = vel[0] * newspeed;
+	vel[1] = vel[1] * newspeed;
+	vel[2] = vel[2] * newspeed;
+}
+
+
+/*
+==============
+PM_Accelerate
+
+Handles user intended acceleration
+==============
+*/
+void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+	int			i;
+	float		addspeed, accelspeed, currentspeed;
+
+	currentspeed = DotProduct (pml.velocity, wishdir);
+	addspeed = wishspeed - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = accel*pml.frametime*wishspeed;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		pml.velocity[i] += accelspeed*wishdir[i];	
+}
+
+void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+	int			i;
+	float		addspeed, accelspeed, currentspeed, wishspd = wishspeed;
+		
+	if (wishspd > 30)
+		wishspd = 30;
+	currentspeed = DotProduct (pml.velocity, wishdir);
+	addspeed = wishspd - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = accel * wishspeed * pml.frametime;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		pml.velocity[i] += accelspeed*wishdir[i];	
+}
+
+/*
+=============
+PM_AddCurrents
+=============
+*/
+void PM_AddCurrents (vec3_t	wishvel)
+{
+	vec3_t	v;
+	float	s;
+
+	//
+	// account for ladders
+	//
+
+	if (pml.ladder && fabs(pml.velocity[2]) <= 200)
+	{
+		if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
+			wishvel[2] = 200;
+		else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
+			wishvel[2] = -200;
+		else if (pm->cmd.upmove > 0)
+			wishvel[2] = 200;
+		else if (pm->cmd.upmove < 0)
+			wishvel[2] = -200;
+		else
+			wishvel[2] = 0;
+
+		// limit horizontal speed when on a ladder
+		if (wishvel[0] < -25)
+			wishvel[0] = -25;
+		else if (wishvel[0] > 25)
+			wishvel[0] = 25;
+
+		if (wishvel[1] < -25)
+			wishvel[1] = -25;
+		else if (wishvel[1] > 25)
+			wishvel[1] = 25;
+	}
+
+
+	//
+	// add water currents
+	//
+
+	if (pm->watertype & MASK_CURRENT)
+	{
+		VectorClear (v);
+
+		if (pm->watertype & CONTENTS_CURRENT_0)
+			v[0] += 1;
+		if (pm->watertype & CONTENTS_CURRENT_90)
+			v[1] += 1;
+		if (pm->watertype & CONTENTS_CURRENT_180)
+			v[0] -= 1;
+		if (pm->watertype & CONTENTS_CURRENT_270)
+			v[1] -= 1;
+		if (pm->watertype & CONTENTS_CURRENT_UP)
+			v[2] += 1;
+		if (pm->watertype & CONTENTS_CURRENT_DOWN)
+			v[2] -= 1;
+
+		s = pm_waterspeed;
+		if ((pm->waterlevel == 1) && (pm->groundentity))
+			s /= 2;
+
+		VectorMA (wishvel, s, v, wishvel);
+	}
+
+	//
+	// add conveyor belt velocities
+	//
+
+	if (pm->groundentity)
+	{
+		VectorClear (v);
+
+		if (pml.groundcontents & CONTENTS_CURRENT_0)
+			v[0] += 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_90)
+			v[1] += 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_180)
+			v[0] -= 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_270)
+			v[1] -= 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_UP)
+			v[2] += 1;
+		if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
+			v[2] -= 1;
+
+		VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
+	}
+}
+
+
+/*
+===================
+PM_WaterMove
+
+===================
+*/
+void PM_WaterMove (void)
+{
+	int		i;
+	vec3_t	wishvel;
+	float	wishspeed;
+	vec3_t	wishdir;
+
+//
+// user intentions
+//
+	for (i=0 ; i<3 ; i++)
+		wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
+
+	if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
+		wishvel[2] -= 60;		// drift towards bottom
+	else
+		wishvel[2] += pm->cmd.upmove;
+
+	PM_AddCurrents (wishvel);
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+
+	if (wishspeed > pm_maxspeed)
+	{
+		VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+		wishspeed = pm_maxspeed;
+	}
+	wishspeed *= 0.5;
+
+	PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
+
+	PM_StepSlideMove ();
+}
+
+
+/*
+===================
+PM_AirMove
+
+===================
+*/
+void PM_AirMove (void)
+{
+	int			i;
+	vec3_t		wishvel;
+	float		fmove, smove;
+	vec3_t		wishdir;
+	float		wishspeed;
+	float		maxspeed;
+
+	fmove = pm->cmd.forwardmove;
+	smove = pm->cmd.sidemove;
+	
+//!!!!! pitch should be 1/3 so this isn't needed??!
+#if 0
+	pml.forward[2] = 0;
+	pml.right[2] = 0;
+	VectorNormalize (pml.forward);
+	VectorNormalize (pml.right);
+#endif
+
+	for (i=0 ; i<2 ; i++)
+		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+	wishvel[2] = 0;
+
+	PM_AddCurrents (wishvel);
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+
+//
+// clamp to server defined max speed
+//
+	maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
+
+	if (wishspeed > maxspeed)
+	{
+		VectorScale (wishvel, maxspeed/wishspeed, wishvel);
+		wishspeed = maxspeed;
+	}
+	
+	if ( pml.ladder )
+	{
+		PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+		if (!wishvel[2])
+		{
+			if (pml.velocity[2] > 0)
+			{
+				pml.velocity[2] -= pm->s.gravity * pml.frametime;
+				if (pml.velocity[2] < 0)
+					pml.velocity[2]  = 0;
+			}
+			else
+			{
+				pml.velocity[2] += pm->s.gravity * pml.frametime;
+				if (pml.velocity[2] > 0)
+					pml.velocity[2]  = 0;
+			}
+		}
+		PM_StepSlideMove ();
+	}
+	else if ( pm->groundentity )
+	{	// walking on ground
+		pml.velocity[2] = 0; //!!! this is before the accel
+		PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+
+// PGM	-- fix for negative trigger_gravity fields
+//		pml.velocity[2] = 0;
+		if(pm->s.gravity > 0)
+			pml.velocity[2] = 0;
+		else
+			pml.velocity[2] -= pm->s.gravity * pml.frametime;
+// PGM
+
+		if (!pml.velocity[0] && !pml.velocity[1])
+			return;
+		PM_StepSlideMove ();
+	}
+	else
+	{	// not on ground, so little effect on velocity
+		if (pm_airaccelerate)
+			PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
+		else
+			PM_Accelerate (wishdir, wishspeed, 1);
+		// add gravity
+		pml.velocity[2] -= pm->s.gravity * pml.frametime;
+		PM_StepSlideMove ();
+	}
+}
+
+
+
+/*
+=============
+PM_CatagorizePosition
+=============
+*/
+void PM_CatagorizePosition (void)
+{
+	vec3_t		point;
+	int			cont;
+	trace_t		trace;
+	int			sample1;
+	int			sample2;
+
+// if the player hull point one unit down is solid, the player
+// is on ground
+
+// see if standing on something solid	
+	point[0] = pml.origin[0];
+	point[1] = pml.origin[1];
+	point[2] = pml.origin[2] - 0.25;
+	if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
+	{
+		pm->s.pm_flags &= ~PMF_ON_GROUND;
+		pm->groundentity = NULL;
+	}
+	else
+	{
+		trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
+		pml.groundplane = trace.plane;
+		pml.groundsurface = trace.surface;
+		pml.groundcontents = trace.contents;
+
+		if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
+		{
+			pm->groundentity = NULL;
+			pm->s.pm_flags &= ~PMF_ON_GROUND;
+		}
+		else
+		{
+			pm->groundentity = trace.ent;
+
+			// hitting solid ground will end a waterjump
+			if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+			{
+				pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+				pm->s.pm_time = 0;
+			}
+
+			if (! (pm->s.pm_flags & PMF_ON_GROUND) )
+			{	// just hit the ground
+				pm->s.pm_flags |= PMF_ON_GROUND;
+				// don't do landing time if we were just going down a slope
+				if (pml.velocity[2] < -200)
+				{
+					pm->s.pm_flags |= PMF_TIME_LAND;
+					// don't allow another jump for a little while
+					if (pml.velocity[2] < -400)
+						pm->s.pm_time = 25;	
+					else
+						pm->s.pm_time = 18;
+				}
+			}
+		}
+
+#if 0
+		if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
+			pml.velocity[2] = 0;
+#endif
+
+		if (pm->numtouch < MAXTOUCH && trace.ent)
+		{
+			pm->touchents[pm->numtouch] = trace.ent;
+			pm->numtouch++;
+		}
+	}
+
+//
+// get waterlevel, accounting for ducking
+//
+	pm->waterlevel = 0;
+	pm->watertype = 0;
+
+	sample2 = pm->viewheight - pm->mins[2];
+	sample1 = sample2 / 2;
+
+	point[2] = pml.origin[2] + pm->mins[2] + 1;	
+	cont = pm->pointcontents (point);
+
+	if (cont & MASK_WATER)
+	{
+		pm->watertype = cont;
+		pm->waterlevel = 1;
+		point[2] = pml.origin[2] + pm->mins[2] + sample1;
+		cont = pm->pointcontents (point);
+		if (cont & MASK_WATER)
+		{
+			pm->waterlevel = 2;
+			point[2] = pml.origin[2] + pm->mins[2] + sample2;
+			cont = pm->pointcontents (point);
+			if (cont & MASK_WATER)
+				pm->waterlevel = 3;
+		}
+	}
+
+}
+
+
+/*
+=============
+PM_CheckJump
+=============
+*/
+void PM_CheckJump (void)
+{
+	if (pm->s.pm_flags & PMF_TIME_LAND)
+	{	// hasn't been long enough since landing to jump again
+		return;
+	}
+
+	if (pm->cmd.upmove < 10)
+	{	// not holding jump
+		pm->s.pm_flags &= ~PMF_JUMP_HELD;
+		return;
+	}
+
+	// must wait for jump to be released
+	if (pm->s.pm_flags & PMF_JUMP_HELD)
+		return;
+
+	if (pm->s.pm_type == PM_DEAD)
+		return;
+
+	if (pm->waterlevel >= 2)
+	{	// swimming, not jumping
+		pm->groundentity = NULL;
+
+		if (pml.velocity[2] <= -300)
+			return;
+
+		if (pm->watertype == CONTENTS_WATER)
+			pml.velocity[2] = 100;
+		else if (pm->watertype == CONTENTS_SLIME)
+			pml.velocity[2] = 80;
+		else
+			pml.velocity[2] = 50;
+		return;
+	}
+
+	if (pm->groundentity == NULL)
+		return;		// in air, so no effect
+
+	pm->s.pm_flags |= PMF_JUMP_HELD;
+
+	pm->groundentity = NULL;
+	pml.velocity[2] += 270;
+	if (pml.velocity[2] < 270)
+		pml.velocity[2] = 270;
+}
+
+
+/*
+=============
+PM_CheckSpecialMovement
+=============
+*/
+void PM_CheckSpecialMovement (void)
+{
+	vec3_t	spot;
+	int		cont;
+	vec3_t	flatforward;
+	trace_t	trace;
+
+	if (pm->s.pm_time)
+		return;
+
+	pml.ladder = false;
+
+	// check for ladder
+	flatforward[0] = pml.forward[0];
+	flatforward[1] = pml.forward[1];
+	flatforward[2] = 0;
+	VectorNormalize (flatforward);
+
+	VectorMA (pml.origin, 1, flatforward, spot);
+	trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
+	if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
+		pml.ladder = true;
+
+	// check for water jump
+	if (pm->waterlevel != 2)
+		return;
+
+	VectorMA (pml.origin, 30, flatforward, spot);
+	spot[2] += 4;
+	cont = pm->pointcontents (spot);
+	if (!(cont & CONTENTS_SOLID))
+		return;
+
+	spot[2] += 16;
+	cont = pm->pointcontents (spot);
+	if (cont)
+		return;
+	// jump out of water
+	VectorScale (flatforward, 50, pml.velocity);
+	pml.velocity[2] = 350;
+
+	pm->s.pm_flags |= PMF_TIME_WATERJUMP;
+	pm->s.pm_time = 255;
+}
+
+
+/*
+===============
+PM_FlyMove
+===============
+*/
+void PM_FlyMove (qboolean doclip)
+{
+	float	speed, drop, friction, control, newspeed;
+	float	currentspeed, addspeed, accelspeed;
+	int			i;
+	vec3_t		wishvel;
+	float		fmove, smove;
+	vec3_t		wishdir;
+	float		wishspeed;
+	vec3_t		end;
+	trace_t	trace;
+
+	pm->viewheight = 22;
+
+	// friction
+
+	speed = VectorLength (pml.velocity);
+	if (speed < 1)
+	{
+		VectorCopy (vec3_origin, pml.velocity);
+	}
+	else
+	{
+		drop = 0;
+
+		friction = pm_friction*1.5;	// extra friction
+		control = speed < pm_stopspeed ? pm_stopspeed : speed;
+		drop += control*friction*pml.frametime;
+
+		// scale the velocity
+		newspeed = speed - drop;
+		if (newspeed < 0)
+			newspeed = 0;
+		newspeed /= speed;
+
+		VectorScale (pml.velocity, newspeed, pml.velocity);
+	}
+
+	// accelerate
+	fmove = pm->cmd.forwardmove;
+	smove = pm->cmd.sidemove;
+	
+	VectorNormalize (pml.forward);
+	VectorNormalize (pml.right);
+
+	for (i=0 ; i<3 ; i++)
+		wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+	wishvel[2] += pm->cmd.upmove;
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+
+	//
+	// clamp to server defined max speed
+	//
+	if (wishspeed > pm_maxspeed)
+	{
+		VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+		wishspeed = pm_maxspeed;
+	}
+
+
+	currentspeed = DotProduct(pml.velocity, wishdir);
+	addspeed = wishspeed - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = pm_accelerate*pml.frametime*wishspeed;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		pml.velocity[i] += accelspeed*wishdir[i];	
+
+	if (doclip) {
+		for (i=0 ; i<3 ; i++)
+			end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
+
+		trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+		VectorCopy (trace.endpos, pml.origin);
+	} else {
+		// move
+		VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
+	}
+}
+
+
+/*
+==============
+PM_CheckDuck
+
+Sets mins, maxs, and pm->viewheight
+==============
+*/
+void PM_CheckDuck (void)
+{
+	trace_t	trace;
+
+	pm->mins[0] = -16;
+	pm->mins[1] = -16;
+
+	pm->maxs[0] = 16;
+	pm->maxs[1] = 16;
+
+	if (pm->s.pm_type == PM_GIB)
+	{
+		pm->mins[2] = 0;
+		pm->maxs[2] = 16;
+		pm->viewheight = 8;
+		return;
+	}
+
+	pm->mins[2] = -24;
+
+	if (pm->s.pm_type == PM_DEAD)
+	{
+		pm->s.pm_flags |= PMF_DUCKED;
+	}
+	else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
+	{	// duck
+		pm->s.pm_flags |= PMF_DUCKED;
+	}
+	else
+	{	// stand up if possible
+		if (pm->s.pm_flags & PMF_DUCKED)
+		{
+			// try to stand up
+			pm->maxs[2] = 32;
+			trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
+			if (!trace.allsolid)
+				pm->s.pm_flags &= ~PMF_DUCKED;
+		}
+	}
+
+	if (pm->s.pm_flags & PMF_DUCKED)
+	{
+		pm->maxs[2] = 4;
+		pm->viewheight = -2;
+	}
+	else
+	{
+		pm->maxs[2] = 32;
+		pm->viewheight = 22;
+	}
+}
+
+
+/*
+==============
+PM_DeadMove
+==============
+*/
+void PM_DeadMove (void)
+{
+	float	forward;
+
+	if (!pm->groundentity)
+		return;
+
+	// extra friction
+
+	forward = VectorLength (pml.velocity);
+	forward -= 20;
+	if (forward <= 0)
+	{
+		VectorClear (pml.velocity);
+	}
+	else
+	{
+		VectorNormalize (pml.velocity);
+		VectorScale (pml.velocity, forward, pml.velocity);
+	}
+}
+
+
+qboolean	PM_GoodPosition (void)
+{
+	trace_t	trace;
+	vec3_t	origin, end;
+	int		i;
+
+	if (pm->s.pm_type == PM_SPECTATOR)
+		return true;
+
+	for (i=0 ; i<3 ; i++)
+		origin[i] = end[i] = pm->s.origin[i]*0.125;
+	trace = pm->trace (origin, pm->mins, pm->maxs, end);
+
+	return !trace.allsolid;
+}
+
+/*
+================
+PM_SnapPosition
+
+On exit, the origin will have a value that is pre-quantized to the 0.125
+precision of the network channel and in a valid position.
+================
+*/
+void PM_SnapPosition (void)
+{
+	int		sign[3];
+	int		i, j, bits;
+	short	base[3];
+	// try all single bits first
+	static int jitterbits[8] = {0,4,1,2,3,5,6,7};
+
+	// snap velocity to eigths
+	for (i=0 ; i<3 ; i++)
+		pm->s.velocity[i] = (int)(pml.velocity[i]*8);
+
+	for (i=0 ; i<3 ; i++)
+	{
+		if (pml.origin[i] >= 0)
+			sign[i] = 1;
+		else 
+			sign[i] = -1;
+		pm->s.origin[i] = (int)(pml.origin[i]*8);
+		if (pm->s.origin[i]*0.125 == pml.origin[i])
+			sign[i] = 0;
+	}
+	VectorCopy (pm->s.origin, base);
+
+	// try all combinations
+	for (j=0 ; j<8 ; j++)
+	{
+		bits = jitterbits[j];
+		VectorCopy (base, pm->s.origin);
+		for (i=0 ; i<3 ; i++)
+			if (bits & (1<<i) )
+				pm->s.origin[i] += sign[i];
+
+		if (PM_GoodPosition ())
+			return;
+	}
+
+	// go back to the last position
+	VectorCopy (pml.previous_origin, pm->s.origin);
+//	Com_DPrintf ("using previous_origin\n");
+}
+
+#if 0
+//NO LONGER USED
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+void PM_InitialSnapPosition (void)
+{
+	int		x, y, z;
+	short	base[3];
+
+	VectorCopy (pm->s.origin, base);
+
+	for (z=1 ; z>=-1 ; z--)
+	{
+		pm->s.origin[2] = base[2] + z;
+		for (y=1 ; y>=-1 ; y--)
+		{
+			pm->s.origin[1] = base[1] + y;
+			for (x=1 ; x>=-1 ; x--)
+			{
+				pm->s.origin[0] = base[0] + x;
+				if (PM_GoodPosition ())
+				{
+					pml.origin[0] = pm->s.origin[0]*0.125;
+					pml.origin[1] = pm->s.origin[1]*0.125;
+					pml.origin[2] = pm->s.origin[2]*0.125;
+					VectorCopy (pm->s.origin, pml.previous_origin);
+					return;
+				}
+			}
+		}
+	}
+
+	Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+#else
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+void PM_InitialSnapPosition(void)
+{
+	int        x, y, z;
+	short      base[3];
+	static int offset[3] = { 0, -1, 1 };
+
+	VectorCopy (pm->s.origin, base);
+
+	for ( z = 0; z < 3; z++ ) {
+		pm->s.origin[2] = base[2] + offset[ z ];
+		for ( y = 0; y < 3; y++ ) {
+			pm->s.origin[1] = base[1] + offset[ y ];
+			for ( x = 0; x < 3; x++ ) {
+				pm->s.origin[0] = base[0] + offset[ x ];
+				if (PM_GoodPosition ()) {
+					pml.origin[0] = pm->s.origin[0]*0.125;
+					pml.origin[1] = pm->s.origin[1]*0.125;
+					pml.origin[2] = pm->s.origin[2]*0.125;
+					VectorCopy (pm->s.origin, pml.previous_origin);
+					return;
+				}
+			}
+		}
+	}
+
+	Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+
+#endif
+
+/*
+================
+PM_ClampAngles
+
+================
+*/
+void PM_ClampAngles (void)
+{
+	short	temp;
+	int		i;
+
+	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+	{
+		pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
+		pm->viewangles[PITCH] = 0;
+		pm->viewangles[ROLL] = 0;
+	}
+	else
+	{
+		// circularly clamp the angles with deltas
+		for (i=0 ; i<3 ; i++)
+		{
+			temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
+			pm->viewangles[i] = SHORT2ANGLE(temp);
+		}
+
+		// don't let the player look up or down more than 90 degrees
+		if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
+			pm->viewangles[PITCH] = 89;
+		else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
+			pm->viewangles[PITCH] = 271;
+	}
+	AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
+}
+
+/*
+================
+Pmove
+
+Can be called by either the server or the client
+================
+*/
+void Pmove (pmove_t *pmove)
+{
+	pm = pmove;
+
+	// clear results
+	pm->numtouch = 0;
+	VectorClear (pm->viewangles);
+	pm->viewheight = 0;
+	pm->groundentity = 0;
+	pm->watertype = 0;
+	pm->waterlevel = 0;
+
+	// clear all pmove local vars
+	memset (&pml, 0, sizeof(pml));
+
+	// convert origin and velocity to float values
+	pml.origin[0] = pm->s.origin[0]*0.125;
+	pml.origin[1] = pm->s.origin[1]*0.125;
+	pml.origin[2] = pm->s.origin[2]*0.125;
+
+	pml.velocity[0] = pm->s.velocity[0]*0.125;
+	pml.velocity[1] = pm->s.velocity[1]*0.125;
+	pml.velocity[2] = pm->s.velocity[2]*0.125;
+
+	// save old org in case we get stuck
+	VectorCopy (pm->s.origin, pml.previous_origin);
+
+	pml.frametime = pm->cmd.msec * 0.001;
+
+	PM_ClampAngles ();
+
+	if (pm->s.pm_type == PM_SPECTATOR)
+	{
+		PM_FlyMove (false);
+		PM_SnapPosition ();
+		return;
+	}
+
+	if (pm->s.pm_type >= PM_DEAD)
+	{
+		pm->cmd.forwardmove = 0;
+		pm->cmd.sidemove = 0;
+		pm->cmd.upmove = 0;
+	}
+
+	if (pm->s.pm_type == PM_FREEZE)
+		return;		// no movement at all
+
+	// set mins, maxs, and viewheight
+	PM_CheckDuck ();
+
+	if (pm->snapinitial)
+		PM_InitialSnapPosition ();
+
+	// set groundentity, watertype, and waterlevel
+	PM_CatagorizePosition ();
+
+	if (pm->s.pm_type == PM_DEAD)
+		PM_DeadMove ();
+
+	PM_CheckSpecialMovement ();
+
+	// drop timing counter
+	if (pm->s.pm_time)
+	{
+		int		msec;
+
+		msec = pm->cmd.msec >> 3;
+		if (!msec)
+			msec = 1;
+		if ( msec >= pm->s.pm_time) 
+		{
+			pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+			pm->s.pm_time = 0;
+		}
+		else
+			pm->s.pm_time -= msec;
+	}
+
+	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+	{	// teleport pause stays exactly in place
+	}
+	else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+	{	// waterjump has no control, but falls
+		pml.velocity[2] -= pm->s.gravity * pml.frametime;
+		if (pml.velocity[2] < 0)
+		{	// cancel as soon as we are falling down again
+			pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+			pm->s.pm_time = 0;
+		}
+
+		PM_StepSlideMove ();
+	}
+	else
+	{
+		PM_CheckJump ();
+
+		PM_Friction ();
+
+		if (pm->waterlevel >= 2)
+			PM_WaterMove ();
+		else {
+			vec3_t	angles;
+
+			VectorCopy(pm->viewangles, angles);
+			if (angles[PITCH] > 180)
+				angles[PITCH] = angles[PITCH] - 360;
+			angles[PITCH] /= 3;
+
+			AngleVectors (angles, pml.forward, pml.right, pml.up);
+
+			PM_AirMove ();
+		}
+	}
+
+	// set groundentity, watertype, and waterlevel for final spot
+	PM_CatagorizePosition ();
+
+	PM_SnapPosition ();
+}
+
--- /dev/null
+++ b/qcommon/qcommon.h
@@ -1,0 +1,826 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+// qcommon.h -- definitions common between client and server, but not game.dll
+
+#include "../game/q_shared.h"
+
+
+#define	VERSION		3.19
+
+#define	BASEDIRNAME	"baseq2"
+
+#ifdef WIN32
+
+#ifdef NDEBUG
+#define BUILDSTRING "Win32 RELEASE"
+#else
+#define BUILDSTRING "Win32 DEBUG"
+#endif
+
+#ifdef _M_IX86
+#define	CPUSTRING	"x86"
+#elif defined _M_ALPHA
+#define	CPUSTRING	"AXP"
+#endif
+
+#elif defined __linux__
+
+#define BUILDSTRING "Linux"
+
+#ifdef __i386__
+#define CPUSTRING "i386"
+#elif defined __alpha__
+#define CPUSTRING "axp"
+#else
+#define CPUSTRING "Unknown"
+#endif
+
+#elif defined __sun__
+
+#define BUILDSTRING "Solaris"
+
+#ifdef __i386__
+#define CPUSTRING "i386"
+#else
+#define CPUSTRING "sparc"
+#endif
+
+#else	// !WIN32
+
+#define BUILDSTRING "NON-WIN32"
+#define	CPUSTRING	"NON-WIN32"
+
+#endif
+
+//============================================================================
+
+typedef struct sizebuf_s
+{
+	qboolean	allowoverflow;	// if false, do a Com_Error
+	qboolean	overflowed;		// set to true if the buffer size failed
+	byte	*data;
+	int		maxsize;
+	int		cursize;
+	int		readcount;
+} sizebuf_t;
+
+void SZ_Init (sizebuf_t *buf, byte *data, int length);
+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
+
+//============================================================================
+
+struct usercmd_s;
+struct entity_state_s;
+
+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_WritePos (sizebuf_t *sb, vec3_t pos);
+void MSG_WriteAngle (sizebuf_t *sb, float f);
+void MSG_WriteAngle16 (sizebuf_t *sb, float f);
+void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
+void MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, qboolean newentity);
+void MSG_WriteDir (sizebuf_t *sb, vec3_t vector);
+
+
+void	MSG_BeginReading (sizebuf_t *sb);
+
+int		MSG_ReadChar (sizebuf_t *sb);
+int		MSG_ReadByte (sizebuf_t *sb);
+int		MSG_ReadShort (sizebuf_t *sb);
+int		MSG_ReadLong (sizebuf_t *sb);
+float	MSG_ReadFloat (sizebuf_t *sb);
+char	*MSG_ReadString (sizebuf_t *sb);
+char	*MSG_ReadStringLine (sizebuf_t *sb);
+
+float	MSG_ReadCoord (sizebuf_t *sb);
+void	MSG_ReadPos (sizebuf_t *sb, vec3_t pos);
+float	MSG_ReadAngle (sizebuf_t *sb);
+float	MSG_ReadAngle16 (sizebuf_t *sb);
+void	MSG_ReadDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
+
+void	MSG_ReadDir (sizebuf_t *sb, vec3_t vector);
+
+void	MSG_ReadData (sizebuf_t *sb, void *buffer, int size);
+
+//============================================================================
+
+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);
+
+//============================================================================
+
+
+int	COM_Argc (void);
+char *COM_Argv (int arg);	// range and null checked
+void COM_ClearArgv (int arg);
+int COM_CheckParm (char *parm);
+void COM_AddParm (char *parm);
+
+void COM_Init (void);
+void COM_InitArgv (int argc, char **argv);
+
+char *CopyString (char *in);
+
+//============================================================================
+
+void Info_Print (char *s);
+
+
+/* crc.h */
+
+void CRC_Init(unsigned short *crcvalue);
+void CRC_ProcessByte(unsigned short *crcvalue, byte data);
+unsigned short CRC_Value(unsigned short crcvalue);
+unsigned short CRC_Block (byte *start, int count);
+
+
+
+/*
+==============================================================
+
+PROTOCOL
+
+==============================================================
+*/
+
+// protocol.h -- communications protocols
+
+#define	PROTOCOL_VERSION	34
+
+//=========================================
+
+#define	PORT_MASTER	27900
+#define	PORT_CLIENT	27901
+#define	PORT_SERVER	27910
+
+//=========================================
+
+#define	UPDATE_BACKUP	16	// copies of entity_state_t to keep buffered
+							// must be power of two
+#define	UPDATE_MASK		(UPDATE_BACKUP-1)
+
+
+
+//==================
+// the svc_strings[] array in cl_parse.c should mirror this
+//==================
+
+//
+// server to client
+//
+enum svc_ops_e
+{
+	svc_bad,
+
+	// these ops are known to the game dll
+	svc_muzzleflash,
+	svc_muzzleflash2,
+	svc_temp_entity,
+	svc_layout,
+	svc_inventory,
+
+	// the rest are private to the client and server
+	svc_nop,
+	svc_disconnect,
+	svc_reconnect,
+	svc_sound,					// <see code>
+	svc_print,					// [byte] id [string] null terminated string
+	svc_stufftext,				// [string] stuffed into client's console buffer, should be \n terminated
+	svc_serverdata,				// [long] protocol ...
+	svc_configstring,			// [short] [string]
+	svc_spawnbaseline,		
+	svc_centerprint,			// [string] to put in center of the screen
+	svc_download,				// [short] size [size bytes]
+	svc_playerinfo,				// variable
+	svc_packetentities,			// [...]
+	svc_deltapacketentities,	// [...]
+	svc_frame
+};
+
+//==============================================
+
+//
+// client to server
+//
+enum clc_ops_e
+{
+	clc_bad,
+	clc_nop, 		
+	clc_move,				// [[usercmd_t]
+	clc_userinfo,			// [[userinfo string]
+	clc_stringcmd			// [string] message
+};
+
+//==============================================
+
+// plyer_state_t communication
+
+#define	PS_M_TYPE			(1<<0)
+#define	PS_M_ORIGIN			(1<<1)
+#define	PS_M_VELOCITY		(1<<2)
+#define	PS_M_TIME			(1<<3)
+#define	PS_M_FLAGS			(1<<4)
+#define	PS_M_GRAVITY		(1<<5)
+#define	PS_M_DELTA_ANGLES	(1<<6)
+
+#define	PS_VIEWOFFSET		(1<<7)
+#define	PS_VIEWANGLES		(1<<8)
+#define	PS_KICKANGLES		(1<<9)
+#define	PS_BLEND			(1<<10)
+#define	PS_FOV				(1<<11)
+#define	PS_WEAPONINDEX		(1<<12)
+#define	PS_WEAPONFRAME		(1<<13)
+#define	PS_RDFLAGS			(1<<14)
+
+//==============================================
+
+// user_cmd_t communication
+
+// ms and light always sent, the others are optional
+#define	CM_ANGLE1 	(1<<0)
+#define	CM_ANGLE2 	(1<<1)
+#define	CM_ANGLE3 	(1<<2)
+#define	CM_FORWARD	(1<<3)
+#define	CM_SIDE		(1<<4)
+#define	CM_UP		(1<<5)
+#define	CM_BUTTONS	(1<<6)
+#define	CM_IMPULSE	(1<<7)
+
+//==============================================
+
+// a sound without an ent or pos will be a local only sound
+#define	SND_VOLUME		(1<<0)		// a byte
+#define	SND_ATTENUATION	(1<<1)		// a byte
+#define	SND_POS			(1<<2)		// three coordinates
+#define	SND_ENT			(1<<3)		// a short 0-2: channel, 3-12: entity
+#define	SND_OFFSET		(1<<4)		// a byte, msec offset from frame start
+
+#define DEFAULT_SOUND_PACKET_VOLUME	1.0
+#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
+
+//==============================================
+
+// entity_state_t communication
+
+// try to pack the common update flags into the first byte
+#define	U_ORIGIN1	(1<<0)
+#define	U_ORIGIN2	(1<<1)
+#define	U_ANGLE2	(1<<2)
+#define	U_ANGLE3	(1<<3)
+#define	U_FRAME8	(1<<4)		// frame is a byte
+#define	U_EVENT		(1<<5)
+#define	U_REMOVE	(1<<6)		// REMOVE this entity, don't add it
+#define	U_MOREBITS1	(1<<7)		// read one additional byte
+
+// second byte
+#define	U_NUMBER16	(1<<8)		// NUMBER8 is implicit if not set
+#define	U_ORIGIN3	(1<<9)
+#define	U_ANGLE1	(1<<10)
+#define	U_MODEL		(1<<11)
+#define U_RENDERFX8	(1<<12)		// fullbright, etc
+#define	U_EFFECTS8	(1<<14)		// autorotate, trails, etc
+#define	U_MOREBITS2	(1<<15)		// read one additional byte
+
+// third byte
+#define	U_SKIN8		(1<<16)
+#define	U_FRAME16	(1<<17)		// frame is a short
+#define	U_RENDERFX16 (1<<18)	// 8 + 16 = 32
+#define	U_EFFECTS16	(1<<19)		// 8 + 16 = 32
+#define	U_MODEL2	(1<<20)		// weapons, flags, etc
+#define	U_MODEL3	(1<<21)
+#define	U_MODEL4	(1<<22)
+#define	U_MOREBITS3	(1<<23)		// read one additional byte
+
+// fourth byte
+#define	U_OLDORIGIN	(1<<24)		// FIXME: get rid of this
+#define	U_SKIN16	(1<<25)
+#define	U_SOUND		(1<<26)
+#define	U_SOLID		(1<<27)
+
+
+/*
+==============================================================
+
+CMD
+
+Command text buffering 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 ();
+
+*/
+
+#define	EXEC_NOW	0		// don't return until completed
+#define	EXEC_INSERT	1		// insert at current position, but don't run yet
+#define	EXEC_APPEND	2		// add to end of the command buffer
+
+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_ExecuteText (int exec_when, char *text);
+// this can be used in place of either Cbuf_AddText or Cbuf_InsertText
+
+void Cbuf_AddEarlyCommands (qboolean clear);
+// adds all the +set commands from the command line
+
+qboolean Cbuf_AddLateCommands (void);
+// adds all the remaining + commands from the command line
+// Returns true if any late commands were added, which
+// will keep the demoloop from immediately starting
+
+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!
+
+void Cbuf_CopyToDefer (void);
+void Cbuf_InsertFromDefer (void);
+// These two functions are used to defer any pending commands while a map
+// is being loaded
+
+//===========================================================================
+
+/*
+
+Command execution takes a null terminated string, breaks it into tokens,
+then searches for a command or variable that matches the first token.
+
+*/
+
+typedef void (*xcommand_t) (void);
+
+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
+// if function is NULL, the command will be forwarded to the server
+// as a clc_stringcmd instead of executed locally
+void	Cmd_RemoveCommand (char *cmd_name);
+
+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 always safe.
+
+void	Cmd_TokenizeString (char *text, qboolean macroExpand);
+// Takes a null terminated string.  Does not need to be /n terminated.
+// breaks the string up into arg tokens.
+
+void	Cmd_ExecuteString (char *text);
+// Parses a single line of text into arguments and tries to execute it
+// as if it was typed at the console
+
+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.
+
+
+/*
+==============================================================
+
+CVAR
+
+==============================================================
+*/
+
+/*
+
+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.
+
+The user can access cvars from the console in three ways:
+r_draworder			prints the current value
+r_draworder 0		sets the current value to 0
+set r_draworder 0	as above, but creates the cvar if not present
+Cvars are restricted from having the same names as commands to keep this
+interface from being ambiguous.
+*/
+
+extern	cvar_t	*cvar_vars;
+
+cvar_t *Cvar_Get (char *var_name, char *value, int flags);
+// creates the variable if it doesn't exist, or returns the existing one
+// if it exists, the value will not be changed, but flags will be ORed in
+// that allows variables to be unarchived without needing bitflags
+
+cvar_t 	*Cvar_Set (char *var_name, char *value);
+// will create the variable if it doesn't exist
+
+cvar_t *Cvar_ForceSet (char *var_name, char *value);
+// will set the variable even if NOSET or LATCH
+
+cvar_t 	*Cvar_FullSet (char *var_name, char *value, int flags);
+
+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
+
+void	Cvar_GetLatchedVars (void);
+// any CVAR_LATCHED variables that have been set will now take effect
+
+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 (char *path);
+// appends lines containing "set variable value" for all variables
+// with the archive flag set to true.
+
+void	Cvar_Init (void);
+
+char	*Cvar_Userinfo (void);
+// returns an info string containing all the CVAR_USERINFO cvars
+
+char	*Cvar_Serverinfo (void);
+// returns an info string containing all the CVAR_SERVERINFO cvars
+
+extern	qboolean	userinfo_modified;
+// this is set each time a CVAR_USERINFO variable is changed
+// so that the client knows to send it to the server
+
+/*
+==============================================================
+
+NET
+
+==============================================================
+*/
+
+// net.h -- quake's interface to the networking layer
+
+#define	PORT_ANY	-1
+
+#define	MAX_MSGLEN		1400		// max length of a message
+#define	PACKET_HEADER	10			// two ints and a short
+
+typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t;
+
+typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
+
+typedef struct
+{
+	netadrtype_t	type;
+
+	byte	ip[4];
+	byte	ipx[10];
+
+	unsigned short	port;
+} netadr_t;
+
+void		NET_Init (void);
+void		NET_Shutdown (void);
+
+void		NET_Config (qboolean multiplayer);
+
+qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message);
+void		NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to);
+
+qboolean	NET_CompareAdr (netadr_t a, netadr_t b);
+qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b);
+qboolean	NET_IsLocalAddress (netadr_t adr);
+char		*NET_AdrToString (netadr_t a);
+qboolean	NET_StringToAdr (char *s, netadr_t *a);
+void		NET_Sleep(int msec);
+
+//============================================================================
+
+#define	OLD_AVG		0.99		// total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
+
+#define	MAX_LATENT	32
+
+typedef struct
+{
+	qboolean	fatal_error;
+
+	netsrc_t	sock;
+
+	int			dropped;			// between last packet and previous
+
+	int			last_received;		// for timeouts
+	int			last_sent;			// for retransmits
+
+	netadr_t	remote_address;
+	int			qport;				// qport value to write when transmitting
+
+// sequencing variables
+	int			incoming_sequence;
+	int			incoming_acknowledged;
+	int			incoming_reliable_acknowledged;	// single bit
+
+	int			incoming_reliable_sequence;		// single bit, maintained local
+
+	int			outgoing_sequence;
+	int			reliable_sequence;			// single bit
+	int			last_reliable_sequence;		// sequence number of last send
+
+// reliable staging and holding areas
+	sizebuf_t	message;		// writing buffer to send to server
+	byte		message_buf[MAX_MSGLEN-16];		// leave space for header
+
+// message is copied to this buffer when it is first transfered
+	int			reliable_length;
+	byte		reliable_buf[MAX_MSGLEN-16];	// unacked reliable message
+} netchan_t;
+
+extern	netadr_t	net_from;
+extern	sizebuf_t	net_message;
+extern	byte		net_message_buffer[MAX_MSGLEN];
+
+
+void Netchan_Init (void);
+void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport);
+
+qboolean Netchan_NeedReliable (netchan_t *chan);
+void Netchan_Transmit (netchan_t *chan, int length, byte *data);
+void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data);
+void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...);
+qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg);
+
+qboolean Netchan_CanReliable (netchan_t *chan);
+
+
+/*
+==============================================================
+
+CMODEL
+
+==============================================================
+*/
+
+
+#include "../qcommon/qfiles.h"
+
+cmodel_t	*CM_LoadMap (char *name, qboolean clientload, unsigned *checksum);
+cmodel_t	*CM_InlineModel (char *name);	// *1, *2, etc
+
+int			CM_NumClusters (void);
+int			CM_NumInlineModels (void);
+char		*CM_EntityString (void);
+
+// creates a clipping hull for an arbitrary box
+int			CM_HeadnodeForBox (vec3_t mins, vec3_t maxs);
+
+
+// returns an ORed contents mask
+int			CM_PointContents (vec3_t p, int headnode);
+int			CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles);
+
+trace_t		CM_BoxTrace (vec3_t start, vec3_t end,
+						  vec3_t mins, vec3_t maxs,
+						  int headnode, int brushmask);
+trace_t		CM_TransformedBoxTrace (vec3_t start, vec3_t end,
+						  vec3_t mins, vec3_t maxs,
+						  int headnode, int brushmask,
+						  vec3_t origin, vec3_t angles);
+
+byte		*CM_ClusterPVS (int cluster);
+byte		*CM_ClusterPHS (int cluster);
+
+int			CM_PointLeafnum (vec3_t p);
+
+// call with topnode set to the headnode, returns with topnode
+// set to the first node that splits the box
+int			CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list,
+							int listsize, int *topnode);
+
+int			CM_LeafContents (int leafnum);
+int			CM_LeafCluster (int leafnum);
+int			CM_LeafArea (int leafnum);
+
+void		CM_SetAreaPortalState (int portalnum, qboolean open);
+qboolean	CM_AreasConnected (int area1, int area2);
+
+int			CM_WriteAreaBits (byte *buffer, int area);
+qboolean	CM_HeadnodeVisible (int headnode, byte *visbits);
+
+void		CM_WritePortalState (FILE *f);
+void		CM_ReadPortalState (FILE *f);
+
+/*
+==============================================================
+
+PLAYER MOVEMENT CODE
+
+Common between server and client so prediction matches
+
+==============================================================
+*/
+
+extern float pm_airaccelerate;
+
+void Pmove (pmove_t *pmove);
+
+/*
+==============================================================
+
+FILESYSTEM
+
+==============================================================
+*/
+
+void	FS_InitFilesystem (void);
+void	FS_SetGamedir (char *dir);
+char	*FS_Gamedir (void);
+char	*FS_NextPath (char *prevpath);
+void	FS_ExecAutoexec (void);
+
+int		FS_FOpenFile (char *filename, FILE **file);
+void	FS_FCloseFile (FILE *f);
+// note: this can't be called from another DLL, due to MS libc issues
+
+int		FS_LoadFile (char *path, void **buffer);
+// a null buffer will just return the file length without loading
+// a -1 length is not present
+
+void	FS_Read (void *buffer, int len, FILE *f);
+// properly handles partial reads
+
+void	FS_FreeFile (void *buffer);
+
+void	FS_CreatePath (char *path);
+
+
+/*
+==============================================================
+
+MISC
+
+==============================================================
+*/
+
+
+#define	ERR_FATAL	0		// exit the entire game with a popup window
+#define	ERR_DROP	1		// print to console and disconnect from game
+#define	ERR_QUIT	2		// not an error, just a normal exit
+
+#define	EXEC_NOW	0		// don't return until completed
+#define	EXEC_INSERT	1		// insert at current position, but don't run yet
+#define	EXEC_APPEND	2		// add to end of the command buffer
+
+#define	PRINT_ALL		0
+#define PRINT_DEVELOPER	1	// only print when "developer 1"
+
+void		Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush));
+void		Com_EndRedirect (void);
+void 		Com_Printf (char *fmt, ...);
+void 		Com_DPrintf (char *fmt, ...);
+void 		Com_Error (int code, char *fmt, ...);
+void 		Com_Quit (void);
+
+int			Com_ServerState (void);		// this should have just been a cvar...
+void		Com_SetServerState (int state);
+
+unsigned	Com_BlockChecksum (void *buffer, int length);
+byte		COM_BlockSequenceCRCByte (byte *base, int length, int sequence);
+
+float	frand(void);	// 0 ti 1
+float	crand(void);	// -1 to 1
+
+extern	cvar_t	*developer;
+extern	cvar_t	*dedicated;
+extern	cvar_t	*host_speeds;
+extern	cvar_t	*log_stats;
+
+extern	FILE *log_stats_file;
+
+// host_speeds times
+extern	int		time_before_game;
+extern	int		time_after_game;
+extern	int		time_before_ref;
+extern	int		time_after_ref;
+
+void Z_Free (void *ptr);
+void *Z_Malloc (int size);			// returns 0 filled memory
+void *Z_TagMalloc (int size, int tag);
+void Z_FreeTags (int tag);
+
+void Qcommon_Init (int argc, char **argv);
+void Qcommon_Frame (int msec);
+void Qcommon_Shutdown (void);
+
+#define NUMVERTEXNORMALS	162
+extern	vec3_t	bytedirs[NUMVERTEXNORMALS];
+
+// this is in the client code, but can be used for debugging from server
+void SCR_DebugGraph (float value, int color);
+
+
+/*
+==============================================================
+
+NON-PORTABLE SYSTEM SERVICES
+
+==============================================================
+*/
+
+void	Sys_Init (void);
+
+void	Sys_AppActivate (void);
+
+void	Sys_UnloadGame (void);
+void	*Sys_GetGameAPI (void *parms);
+// loads the game dll and calls the api init function
+
+char	*Sys_ConsoleInput (void);
+void	Sys_ConsoleOutput (char *string);
+void	Sys_SendKeyEvents (void);
+void	Sys_Error (char *error, ...);
+void	Sys_Quit (void);
+char	*Sys_GetClipboardData( void );
+void	Sys_CopyProtect (void);
+
+/*
+==============================================================
+
+CLIENT / SERVER SYSTEMS
+
+==============================================================
+*/
+
+void CL_Init (void);
+void CL_Drop (void);
+void CL_Shutdown (void);
+void CL_Frame (int msec);
+void Con_Print (char *text);
+void SCR_BeginLoadingPlaque (void);
+
+void SV_Init (void);
+void SV_Shutdown (char *finalmsg, qboolean reconnect);
+void SV_Frame (int msec);
+
+
+
--- /dev/null
+++ b/qcommon/qfiles.h
@@ -1,0 +1,482 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+//
+// qfiles.h: quake file formats
+// This file must be identical in the quake and utils directories
+//
+
+/*
+========================================================================
+
+The .pak files are just a linear collapse of a directory tree
+
+========================================================================
+*/
+
+#define IDPAKHEADER		(('K'<<24)+('C'<<16)+('A'<<8)+'P')
+
+typedef struct
+{
+	char	name[56];
+	int		filepos, filelen;
+} dpackfile_t;
+
+typedef struct
+{
+	int		ident;		// == IDPAKHEADER
+	int		dirofs;
+	int		dirlen;
+} dpackheader_t;
+
+#define	MAX_FILES_IN_PACK	4096
+
+
+/*
+========================================================================
+
+PCX files are used for as many images as possible
+
+========================================================================
+*/
+
+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;
+
+
+/*
+========================================================================
+
+.MD2 triangle model file format
+
+========================================================================
+*/
+
+#define IDALIASHEADER		(('2'<<24)+('P'<<16)+('D'<<8)+'I')
+#define ALIAS_VERSION	8
+
+#define	MAX_TRIANGLES	4096
+#define MAX_VERTS		2048
+#define MAX_FRAMES		512
+#define MAX_MD2SKINS	32
+#define	MAX_SKINNAME	64
+
+typedef struct
+{
+	short	s;
+	short	t;
+} dstvert_t;
+
+typedef struct 
+{
+	short	index_xyz[3];
+	short	index_st[3];
+} dtriangle_t;
+
+typedef struct
+{
+	byte	v[3];			// scaled byte to fit in frame mins/maxs
+	byte	lightnormalindex;
+} dtrivertx_t;
+
+#define DTRIVERTX_V0   0
+#define DTRIVERTX_V1   1
+#define DTRIVERTX_V2   2
+#define DTRIVERTX_LNI  3
+#define DTRIVERTX_SIZE 4
+
+typedef struct
+{
+	float		scale[3];	// multiply byte verts by this
+	float		translate[3];	// then add this
+	char		name[16];	// frame name from grabbing
+	dtrivertx_t	verts[1];	// variable sized
+} daliasframe_t;
+
+
+// the glcmd format:
+// a positive integer starts a tristrip command, followed by that many
+// vertex structures.
+// a negative integer starts a trifan command, followed by -x vertexes
+// a zero indicates the end of the command list.
+// a vertex consists of a floating point s, a floating point t,
+// and an integer vertex index.
+
+
+typedef struct
+{
+	int			ident;
+	int			version;
+
+	int			skinwidth;
+	int			skinheight;
+	int			framesize;		// byte size of each frame
+
+	int			num_skins;
+	int			num_xyz;
+	int			num_st;			// greater than num_xyz for seams
+	int			num_tris;
+	int			num_glcmds;		// dwords in strip/fan command list
+	int			num_frames;
+
+	int			ofs_skins;		// each skin is a MAX_SKINNAME string
+	int			ofs_st;			// byte offset from start for stverts
+	int			ofs_tris;		// offset for dtriangles
+	int			ofs_frames;		// offset for first frame
+	int			ofs_glcmds;	
+	int			ofs_end;		// end of file
+
+} dmdl_t;
+
+/*
+========================================================================
+
+.SP2 sprite file format
+
+========================================================================
+*/
+
+#define IDSPRITEHEADER	(('2'<<24)+('S'<<16)+('D'<<8)+'I')
+		// little-endian "IDS2"
+#define SPRITE_VERSION	2
+
+typedef struct
+{
+	int		width, height;
+	int		origin_x, origin_y;		// raster coordinates inside pic
+	char	name[MAX_SKINNAME];		// name of pcx file
+} dsprframe_t;
+
+typedef struct {
+	int			ident;
+	int			version;
+	int			numframes;
+	dsprframe_t	frames[1];			// variable sized
+} dsprite_t;
+
+/*
+==============================================================================
+
+  .WAL texture file format
+
+==============================================================================
+*/
+
+
+#define	MIPLEVELS	4
+typedef struct miptex_s
+{
+	char		name[32];
+	unsigned	width, height;
+	unsigned	offsets[MIPLEVELS];		// four mip maps stored
+	char		animname[32];			// next frame in animation chain
+	int			flags;
+	int			contents;
+	int			value;
+} miptex_t;
+
+
+
+/*
+==============================================================================
+
+  .BSP file format
+
+==============================================================================
+*/
+
+#define IDBSPHEADER	(('P'<<24)+('S'<<16)+('B'<<8)+'I')
+		// little-endian "IBSP"
+
+#define BSPVERSION	38
+
+
+// upper design bounds
+// leaffaces, leafbrushes, planes, and verts are still bounded by
+// 16 bit short limits
+#define	MAX_MAP_MODELS		1024
+#define	MAX_MAP_BRUSHES		8192
+#define	MAX_MAP_ENTITIES	2048
+#define	MAX_MAP_ENTSTRING	0x40000
+#define	MAX_MAP_TEXINFO		8192
+
+#define	MAX_MAP_AREAS		256
+#define	MAX_MAP_AREAPORTALS	1024
+#define	MAX_MAP_PLANES		65536
+#define	MAX_MAP_NODES		65536
+#define	MAX_MAP_BRUSHSIDES	65536
+#define	MAX_MAP_LEAFS		65536
+#define	MAX_MAP_VERTS		65536
+#define	MAX_MAP_FACES		65536
+#define	MAX_MAP_LEAFFACES	65536
+#define	MAX_MAP_LEAFBRUSHES 65536
+#define	MAX_MAP_PORTALS		65536
+#define	MAX_MAP_EDGES		128000
+#define	MAX_MAP_SURFEDGES	256000
+#define	MAX_MAP_LIGHTING	0x200000
+#define	MAX_MAP_VISIBILITY	0x100000
+
+// key / value pair sizes
+
+#define	MAX_KEY		32
+#define	MAX_VALUE	1024
+
+//=============================================================================
+
+typedef struct
+{
+	int		fileofs, filelen;
+} lump_t;
+
+#define	LUMP_ENTITIES		0
+#define	LUMP_PLANES			1
+#define	LUMP_VERTEXES		2
+#define	LUMP_VISIBILITY		3
+#define	LUMP_NODES			4
+#define	LUMP_TEXINFO		5
+#define	LUMP_FACES			6
+#define	LUMP_LIGHTING		7
+#define	LUMP_LEAFS			8
+#define	LUMP_LEAFFACES		9
+#define	LUMP_LEAFBRUSHES	10
+#define	LUMP_EDGES			11
+#define	LUMP_SURFEDGES		12
+#define	LUMP_MODELS			13
+#define	LUMP_BRUSHES		14
+#define	LUMP_BRUSHSIDES		15
+#define	LUMP_POP			16
+#define	LUMP_AREAS			17
+#define	LUMP_AREAPORTALS	18
+#define	HEADER_LUMPS		19
+
+typedef struct
+{
+	int			ident;
+	int			version;	
+	lump_t		lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct
+{
+	float		mins[3], maxs[3];
+	float		origin[3];		// for sounds or lights
+	int			headnode;
+	int			firstface, numfaces;	// submodels just draw faces
+										// without walking the bsp tree
+} dmodel_t;
+
+
+typedef struct
+{
+	float	point[3];
+} dvertex_t;
+
+
+// 0-2 are axial planes
+#define	PLANE_X			0
+#define	PLANE_Y			1
+#define	PLANE_Z			2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define	PLANE_ANYX		3
+#define	PLANE_ANYY		4
+#define	PLANE_ANYZ		5
+
+// planes (x&~1) and (x&~1)+1 are always opposites
+
+typedef struct
+{
+	float	normal[3];
+	float	dist;
+	int		type;		// PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} dplane_t;
+
+
+// contents flags are seperate bits
+// a given brush can contribute multiple content bits
+// multiple brushes can be in a single leaf
+
+// these definitions also need to be in q_shared.h!
+
+// lower bits are stronger, and will eat weaker brushes completely
+#define	CONTENTS_SOLID			1		// an eye is never valid in a solid
+#define	CONTENTS_WINDOW			2		// translucent, but not watery
+#define	CONTENTS_AUX			4
+#define	CONTENTS_LAVA			8
+#define	CONTENTS_SLIME			16
+#define	CONTENTS_WATER			32
+#define	CONTENTS_MIST			64
+#define	LAST_VISIBLE_CONTENTS	64
+
+// remaining contents are non-visible, and don't eat brushes
+
+#define	CONTENTS_AREAPORTAL		0x8000
+
+#define	CONTENTS_PLAYERCLIP		0x10000
+#define	CONTENTS_MONSTERCLIP	0x20000
+
+// currents can be added to any other contents, and may be mixed
+#define	CONTENTS_CURRENT_0		0x40000
+#define	CONTENTS_CURRENT_90		0x80000
+#define	CONTENTS_CURRENT_180	0x100000
+#define	CONTENTS_CURRENT_270	0x200000
+#define	CONTENTS_CURRENT_UP		0x400000
+#define	CONTENTS_CURRENT_DOWN	0x800000
+
+#define	CONTENTS_ORIGIN			0x1000000	// removed before bsping an entity
+
+#define	CONTENTS_MONSTER		0x2000000	// should never be on a brush, only in game
+#define	CONTENTS_DEADMONSTER	0x4000000
+#define	CONTENTS_DETAIL			0x8000000	// brushes to be added after vis leafs
+#define	CONTENTS_TRANSLUCENT	0x10000000	// auto set if any surface has trans
+#define	CONTENTS_LADDER			0x20000000
+
+
+
+#define	SURF_LIGHT		0x1		// value will hold the light strength
+
+#define	SURF_SLICK		0x2		// effects game physics
+
+#define	SURF_SKY		0x4		// don't draw, but add to skybox
+#define	SURF_WARP		0x8		// turbulent water warp
+#define	SURF_TRANS33	0x10
+#define	SURF_TRANS66	0x20
+#define	SURF_FLOWING	0x40	// scroll towards angle
+#define	SURF_NODRAW		0x80	// don't bother referencing the texture
+
+
+
+
+typedef struct
+{
+	int			planenum;
+	int			children[2];	// negative numbers are -(leafs+1), not nodes
+	short		mins[3];		// for frustom culling
+	short		maxs[3];
+	unsigned short	firstface;
+	unsigned short	numfaces;	// counting both sides
+} dnode_t;
+
+
+typedef struct texinfo_s
+{
+	float		vecs[2][4];		// [s/t][xyz offset]
+	int			flags;			// miptex flags + overrides
+	int			value;			// light emission, etc
+	char		texture[32];	// texture name (textures/*.wal)
+	int			nexttexinfo;	// for animations, -1 = end of chain
+} texinfo_t;
+
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+	unsigned short	v[2];		// vertex numbers
+} dedge_t;
+
+#define	MAXLIGHTMAPS	4
+typedef struct
+{
+	unsigned short	planenum;
+	short		side;
+
+	int			firstedge;		// we must support > 64k edges
+	short		numedges;	
+	short		texinfo;
+
+// lighting info
+	byte		styles[MAXLIGHTMAPS];
+	int			lightofs;		// start of [numstyles*surfsize] samples
+} dface_t;
+
+typedef struct
+{
+	int				contents;			// OR of all brushes (not needed?)
+
+	short			cluster;
+	short			area;
+
+	short			mins[3];			// for frustum culling
+	short			maxs[3];
+
+	unsigned short	firstleafface;
+	unsigned short	numleaffaces;
+
+	unsigned short	firstleafbrush;
+	unsigned short	numleafbrushes;
+} dleaf_t;
+
+typedef struct
+{
+	unsigned short	planenum;		// facing out of the leaf
+	short	texinfo;
+} dbrushside_t;
+
+typedef struct
+{
+	int			firstside;
+	int			numsides;
+	int			contents;
+} dbrush_t;
+
+#define	ANGLE_UP	-1
+#define	ANGLE_DOWN	-2
+
+
+// the visibility lump consists of a header with a count, then
+// byte offsets for the PVS and PHS of each cluster, then the raw
+// compressed bit vectors
+#define	DVIS_PVS	0
+#define	DVIS_PHS	1
+typedef struct
+{
+	int			numclusters;
+	int			bitofs[8][2];	// bitofs[numclusters][2]
+} dvis_t;
+
+// each area has a list of portals that lead into other areas
+// when portals are closed, other areas may not be visible or
+// hearable even if the vis info says that it should be
+typedef struct
+{
+	int		portalnum;
+	int		otherarea;
+} dareaportal_t;
+
+typedef struct
+{
+	int		numareaportals;
+	int		firstareaportal;
+} darea_t;
--- /dev/null
+++ b/quake2.001
@@ -1,0 +1,2061 @@
+# Microsoft Developer Studio Project File - Name="quake2" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+# TARGTYPE "Win32 (ALPHA) Application" 0x0601
+
+CFG=quake2 - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "quake2.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "quake2.mak" CFG="quake2 - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "quake2 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "quake2 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "quake2 - Win32 Debug Alpha" (based on "Win32 (ALPHA) Application")
+!MESSAGE "quake2 - Win32 Release Alpha" (based on "Win32 (ALPHA) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /machine:I386
+# SUBTRACT LINK32 /incremental:yes /debug /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# SUBTRACT CPP /Gy
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /incremental:no /map /debug /machine:I386
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "quake2__"
+# PROP BASE Intermediate_Dir "quake2__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# SUBTRACT BASE CPP /Gy
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Fr
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:ALPHA
+# SUBTRACT BASE LINK32 /nodefaultlib
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /debug /machine:ALPHA
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "quake2__"
+# PROP BASE Intermediate_Dir "quake2__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Z<none> /Fr
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:ALPHA
+# SUBTRACT BASE LINK32 /debug /nodefaultlib
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /machine:ALPHA
+# SUBTRACT LINK32 /debug /nodefaultlib
+
+!ENDIF 
+
+# Begin Target
+
+# Name "quake2 - Win32 Release"
+# Name "quake2 - Win32 Debug"
+# Name "quake2 - Win32 Debug Alpha"
+# Name "quake2 - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\win32\cd_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CD_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CD_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_cin.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_CI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_CI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_ents.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_EN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_EN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_fx.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_FX=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_FX=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_input.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_IN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_IN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_inv.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_INV=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_INV=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_main.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_MA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_MA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_newfx.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_NE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_NE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_parse.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_PA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_PA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_pred.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_PR=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_PR=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_scrn.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_SC=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_SC=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_tent.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_TE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_TE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_view.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_VI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_VI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\cmd.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CMD_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CMD_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\cmodel.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CMODE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CMODE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\common.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_COMMO=\
+	".\client\anorms.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_COMMO=\
+	".\client\anorms.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\conproc.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CONPR=\
+	".\win32\conproc.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CONPR=\
+	".\win32\conproc.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\console.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CONSO=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CONSO=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\crc.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CRC_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CRC_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\cvar.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CVAR_=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CVAR_=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\files.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_FILES=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_FILES=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\in_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_IN_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_IN_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\keys.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_KEYS_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_KEYS_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\m_flash.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_M_FLA=\
+	".\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_M_FLA=\
+	".\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\md4.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\menu.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_MENU_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_MENU_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\net_chan.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_NET_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_NET_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\net_wins.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_NET_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_NET_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\pmove.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_PMOVE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_PMOVE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\q_shared.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\q_shwin.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHW=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_Q_SHW=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\qmenu.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_QMENU=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_QMENU=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_dma.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_mem.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_mix.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_MI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_MI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\snd_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_W=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_W=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_ccmds.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_CC=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_CC=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_ents.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_EN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_EN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_game.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_GA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_GA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_init.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_IN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_IN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_main.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_MA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_MA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_send.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_SE=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_SE=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_user.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_US=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_US=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_world.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_WO=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_WO=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\sys_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SYS_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\conproc.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SYS_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\conproc.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\vid_dll.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_VID_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_VID_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\vid_menu.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_VID_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_VID_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\x86.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_X86_C=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_X86_C=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\client\anorms.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\bspfile.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cdaudio.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\client.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\conproc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\console.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\game.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\input.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\keys.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\q_shared.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\qcommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\qfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\qmenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\ref.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\screen.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\server.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_loc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\sound.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\vid.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\winquake.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\win32\q2.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\q2.rc
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+!ENDIF 
+
+# End Source File
+# End Group
+# End Target
+# End Project
binary files /dev/null b/quake2.bce differ
binary files /dev/null b/quake2.bcp differ
--- /dev/null
+++ b/quake2.dsp
@@ -1,0 +1,2050 @@
+# Microsoft Developer Studio Project File - Name="quake2" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+# TARGTYPE "Win32 (ALPHA) Application" 0x0601
+
+CFG=quake2 - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "quake2.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "quake2.mak" CFG="quake2 - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "quake2 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "quake2 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "quake2 - Win32 Debug Alpha" (based on "Win32 (ALPHA) Application")
+!MESSAGE "quake2 - Win32 Release Alpha" (based on "Win32 (ALPHA) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /machine:I386
+# SUBTRACT LINK32 /incremental:yes /debug /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /incremental:no /map /debug /machine:I386
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "quake2__"
+# PROP BASE Intermediate_Dir "quake2__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# SUBTRACT BASE CPP /Gy
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Fr
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /debug /machine:ALPHA
+# SUBTRACT BASE LINK32 /nodefaultlib
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /debug /machine:ALPHA
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "quake2__"
+# PROP BASE Intermediate_Dir "quake2__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zd /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Z<none> /Fr
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:ALPHA
+# SUBTRACT BASE LINK32 /debug /nodefaultlib
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /machine:ALPHA
+# SUBTRACT LINK32 /debug /nodefaultlib
+
+!ENDIF 
+
+# Begin Target
+
+# Name "quake2 - Win32 Release"
+# Name "quake2 - Win32 Debug"
+# Name "quake2 - Win32 Debug Alpha"
+# Name "quake2 - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\win32\cd_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CD_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CD_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_cin.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_CI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_CI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_ents.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_EN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_EN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_fx.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_FX=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_FX=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_input.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_IN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_IN=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_inv.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_INV=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_INV=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_main.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_MA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_MA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_newfx.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_NE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_NE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_parse.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_PA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_PA=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_pred.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_PR=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_PR=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_scrn.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_SC=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_SC=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_tent.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_TE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_TE=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cl_view.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CL_VI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CL_VI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\cmd.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CMD_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CMD_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\cmodel.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CMODE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CMODE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\common.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_COMMO=\
+	".\client\anorms.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_COMMO=\
+	".\client\anorms.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\conproc.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CONPR=\
+	".\win32\conproc.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CONPR=\
+	".\win32\conproc.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\console.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CONSO=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CONSO=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\crc.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CRC_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CRC_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\cvar.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_CVAR_=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_CVAR_=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\files.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_FILES=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_FILES=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\in_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_IN_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_IN_WI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\keys.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_KEYS_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_KEYS_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\m_flash.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_M_FLA=\
+	".\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_M_FLA=\
+	".\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\md4.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\menu.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_MENU_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_MENU_=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\net_chan.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_NET_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_NET_C=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\net_wins.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_NET_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_NET_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\pmove.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_PMOVE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_PMOVE=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\q_shared.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	".\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\q_shwin.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHW=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_Q_SHW=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\qmenu.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_QMENU=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_QMENU=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_dma.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_mem.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_mix.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_MI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_MI=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\snd_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SND_W=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SND_W=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_ccmds.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_CC=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_CC=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_ents.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_EN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_EN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_game.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_GA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_GA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_init.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_IN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_IN=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_main.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_MA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_MA=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_send.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_SE=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_SE=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_user.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_US=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_US=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\sv_world.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SV_WO=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SV_WO=\
+	".\game\game.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\sys_win.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_SYS_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\conproc.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_SYS_W=\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\conproc.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\vid_dll.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_VID_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_VID_D=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\vid_menu.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_VID_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_VID_M=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\qmenu.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\x86.c
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug Alpha"
+
+DEP_CPP_X86_C=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Release Alpha"
+
+DEP_CPP_X86_C=\
+	".\client\cdaudio.h"\
+	".\client\client.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\game\q_shared.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\client\anorms.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\bspfile.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\cdaudio.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\client.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\conproc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\console.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\game.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\input.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\keys.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\game\q_shared.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\qcommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qcommon\qfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\qmenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\ref.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\screen.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\server\server.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\snd_loc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\sound.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client\vid.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\winquake.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\win32\q2.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32\q2.rc
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/quake2.dsw
@@ -1,0 +1,77 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "ctf"=.\ctf\ctf.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "game"=.\game\game.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "quake2"=.\quake2.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "ref_gl"=.\ref_gl\ref_gl.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "ref_soft"=.\ref_soft\ref_soft.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
--- /dev/null
+++ b/quake2.mak
@@ -1,0 +1,4593 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=ref_soft - Win32 Debug
+!MESSAGE No configuration specified.  Defaulting to ref_soft - Win32 Debug.
+!ENDIF 
+
+!IF "$(CFG)" != "quake2 - Win32 Release" && "$(CFG)" != "quake2 - Win32 Debug"\
+ && "$(CFG)" != "ref_soft - Win32 Release" && "$(CFG)" !=\
+ "ref_soft - Win32 Debug" && "$(CFG)" != "ref_gl - Win32 Release" && "$(CFG)" !=\
+ "ref_gl - Win32 Debug" && "$(CFG)" != "game - Win32 Release" && "$(CFG)" !=\
+ "game - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line.  For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "quake2.mak" CFG="ref_soft - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "quake2 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "quake2 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "ref_soft - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "game - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "game - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "ref_soft - Win32 Debug"
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\quake2.exe"
+
+CLEAN : 
+	-@erase "$(INTDIR)\cd_win.obj"
+	-@erase "$(INTDIR)\cl_demo.obj"
+	-@erase "$(INTDIR)\cl_ents.obj"
+	-@erase "$(INTDIR)\cl_fx.obj"
+	-@erase "$(INTDIR)\cl_input.obj"
+	-@erase "$(INTDIR)\cl_main.obj"
+	-@erase "$(INTDIR)\cl_parse.obj"
+	-@erase "$(INTDIR)\cl_tent.obj"
+	-@erase "$(INTDIR)\cmd.obj"
+	-@erase "$(INTDIR)\cmodel.obj"
+	-@erase "$(INTDIR)\common.obj"
+	-@erase "$(INTDIR)\console.obj"
+	-@erase "$(INTDIR)\crc.obj"
+	-@erase "$(INTDIR)\cvar.obj"
+	-@erase "$(INTDIR)\files.obj"
+	-@erase "$(INTDIR)\in_win.obj"
+	-@erase "$(INTDIR)\keys.obj"
+	-@erase "$(INTDIR)\menu.obj"
+	-@erase "$(INTDIR)\net_chan.obj"
+	-@erase "$(INTDIR)\net_wins.obj"
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\sbar2.obj"
+	-@erase "$(INTDIR)\scr_cin.obj"
+	-@erase "$(INTDIR)\screen.obj"
+	-@erase "$(INTDIR)\snd_dma.obj"
+	-@erase "$(INTDIR)\snd_mem.obj"
+	-@erase "$(INTDIR)\snd_mix.obj"
+	-@erase "$(INTDIR)\snd_win.obj"
+	-@erase "$(INTDIR)\sv_ccmds.obj"
+	-@erase "$(INTDIR)\sv_ents.obj"
+	-@erase "$(INTDIR)\sv_game.obj"
+	-@erase "$(INTDIR)\sv_init.obj"
+	-@erase "$(INTDIR)\sv_main.obj"
+	-@erase "$(INTDIR)\sv_move.obj"
+	-@erase "$(INTDIR)\sv_phys.obj"
+	-@erase "$(INTDIR)\sv_send.obj"
+	-@erase "$(INTDIR)\sv_user.obj"
+	-@erase "$(INTDIR)\sv_world.obj"
+	-@erase "$(INTDIR)\sys_win.obj"
+	-@erase "$(INTDIR)\vid_dll.obj"
+	-@erase "$(INTDIR)\view.obj"
+	-@erase "$(OUTDIR)\quake2.exe"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /G5 /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/quake2.pch" /YX /Fo"$(INTDIR)/" /c 
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/quake2.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# SUBTRACT LINK32 /incremental:yes /nodefaultlib
+LINK32_FLAGS=winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib\
+ winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\
+ uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no\
+ /pdb:"$(OUTDIR)/quake2.pdb" /machine:I386 /out:"$(OUTDIR)/quake2.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\cd_win.obj" \
+	"$(INTDIR)\cl_demo.obj" \
+	"$(INTDIR)\cl_ents.obj" \
+	"$(INTDIR)\cl_fx.obj" \
+	"$(INTDIR)\cl_input.obj" \
+	"$(INTDIR)\cl_main.obj" \
+	"$(INTDIR)\cl_parse.obj" \
+	"$(INTDIR)\cl_tent.obj" \
+	"$(INTDIR)\cmd.obj" \
+	"$(INTDIR)\cmodel.obj" \
+	"$(INTDIR)\common.obj" \
+	"$(INTDIR)\console.obj" \
+	"$(INTDIR)\crc.obj" \
+	"$(INTDIR)\cvar.obj" \
+	"$(INTDIR)\files.obj" \
+	"$(INTDIR)\in_win.obj" \
+	"$(INTDIR)\keys.obj" \
+	"$(INTDIR)\menu.obj" \
+	"$(INTDIR)\net_chan.obj" \
+	"$(INTDIR)\net_wins.obj" \
+	"$(INTDIR)\q_shared.obj" \
+	"$(INTDIR)\sbar2.obj" \
+	"$(INTDIR)\scr_cin.obj" \
+	"$(INTDIR)\screen.obj" \
+	"$(INTDIR)\snd_dma.obj" \
+	"$(INTDIR)\snd_mem.obj" \
+	"$(INTDIR)\snd_mix.obj" \
+	"$(INTDIR)\snd_win.obj" \
+	"$(INTDIR)\sv_ccmds.obj" \
+	"$(INTDIR)\sv_ents.obj" \
+	"$(INTDIR)\sv_game.obj" \
+	"$(INTDIR)\sv_init.obj" \
+	"$(INTDIR)\sv_main.obj" \
+	"$(INTDIR)\sv_move.obj" \
+	"$(INTDIR)\sv_phys.obj" \
+	"$(INTDIR)\sv_send.obj" \
+	"$(INTDIR)\sv_user.obj" \
+	"$(INTDIR)\sv_world.obj" \
+	"$(INTDIR)\sys_win.obj" \
+	"$(INTDIR)\vid_dll.obj" \
+	"$(INTDIR)\view.obj"
+
+"$(OUTDIR)\quake2.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\quake2.exe" "$(OUTDIR)\quake2.bsc"
+
+CLEAN : 
+	-@erase "$(INTDIR)\cd_win.obj"
+	-@erase "$(INTDIR)\cd_win.sbr"
+	-@erase "$(INTDIR)\cl_demo.obj"
+	-@erase "$(INTDIR)\cl_demo.sbr"
+	-@erase "$(INTDIR)\cl_ents.obj"
+	-@erase "$(INTDIR)\cl_ents.sbr"
+	-@erase "$(INTDIR)\cl_fx.obj"
+	-@erase "$(INTDIR)\cl_fx.sbr"
+	-@erase "$(INTDIR)\cl_input.obj"
+	-@erase "$(INTDIR)\cl_input.sbr"
+	-@erase "$(INTDIR)\cl_main.obj"
+	-@erase "$(INTDIR)\cl_main.sbr"
+	-@erase "$(INTDIR)\cl_parse.obj"
+	-@erase "$(INTDIR)\cl_parse.sbr"
+	-@erase "$(INTDIR)\cl_tent.obj"
+	-@erase "$(INTDIR)\cl_tent.sbr"
+	-@erase "$(INTDIR)\cmd.obj"
+	-@erase "$(INTDIR)\cmd.sbr"
+	-@erase "$(INTDIR)\cmodel.obj"
+	-@erase "$(INTDIR)\cmodel.sbr"
+	-@erase "$(INTDIR)\common.obj"
+	-@erase "$(INTDIR)\common.sbr"
+	-@erase "$(INTDIR)\console.obj"
+	-@erase "$(INTDIR)\console.sbr"
+	-@erase "$(INTDIR)\crc.obj"
+	-@erase "$(INTDIR)\crc.sbr"
+	-@erase "$(INTDIR)\cvar.obj"
+	-@erase "$(INTDIR)\cvar.sbr"
+	-@erase "$(INTDIR)\files.obj"
+	-@erase "$(INTDIR)\files.sbr"
+	-@erase "$(INTDIR)\in_win.obj"
+	-@erase "$(INTDIR)\in_win.sbr"
+	-@erase "$(INTDIR)\keys.obj"
+	-@erase "$(INTDIR)\keys.sbr"
+	-@erase "$(INTDIR)\menu.obj"
+	-@erase "$(INTDIR)\menu.sbr"
+	-@erase "$(INTDIR)\net_chan.obj"
+	-@erase "$(INTDIR)\net_chan.sbr"
+	-@erase "$(INTDIR)\net_wins.obj"
+	-@erase "$(INTDIR)\net_wins.sbr"
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\q_shared.sbr"
+	-@erase "$(INTDIR)\sbar2.obj"
+	-@erase "$(INTDIR)\sbar2.sbr"
+	-@erase "$(INTDIR)\scr_cin.obj"
+	-@erase "$(INTDIR)\scr_cin.sbr"
+	-@erase "$(INTDIR)\screen.obj"
+	-@erase "$(INTDIR)\screen.sbr"
+	-@erase "$(INTDIR)\snd_dma.obj"
+	-@erase "$(INTDIR)\snd_dma.sbr"
+	-@erase "$(INTDIR)\snd_mem.obj"
+	-@erase "$(INTDIR)\snd_mem.sbr"
+	-@erase "$(INTDIR)\snd_mix.obj"
+	-@erase "$(INTDIR)\snd_mix.sbr"
+	-@erase "$(INTDIR)\snd_win.obj"
+	-@erase "$(INTDIR)\snd_win.sbr"
+	-@erase "$(INTDIR)\sv_ccmds.obj"
+	-@erase "$(INTDIR)\sv_ccmds.sbr"
+	-@erase "$(INTDIR)\sv_ents.obj"
+	-@erase "$(INTDIR)\sv_ents.sbr"
+	-@erase "$(INTDIR)\sv_game.obj"
+	-@erase "$(INTDIR)\sv_game.sbr"
+	-@erase "$(INTDIR)\sv_init.obj"
+	-@erase "$(INTDIR)\sv_init.sbr"
+	-@erase "$(INTDIR)\sv_main.obj"
+	-@erase "$(INTDIR)\sv_main.sbr"
+	-@erase "$(INTDIR)\sv_move.obj"
+	-@erase "$(INTDIR)\sv_move.sbr"
+	-@erase "$(INTDIR)\sv_phys.obj"
+	-@erase "$(INTDIR)\sv_phys.sbr"
+	-@erase "$(INTDIR)\sv_send.obj"
+	-@erase "$(INTDIR)\sv_send.sbr"
+	-@erase "$(INTDIR)\sv_user.obj"
+	-@erase "$(INTDIR)\sv_user.sbr"
+	-@erase "$(INTDIR)\sv_world.obj"
+	-@erase "$(INTDIR)\sv_world.sbr"
+	-@erase "$(INTDIR)\sys_win.obj"
+	-@erase "$(INTDIR)\sys_win.sbr"
+	-@erase "$(INTDIR)\vc40.pdb"
+	-@erase "$(INTDIR)\vid_dll.obj"
+	-@erase "$(INTDIR)\vid_dll.sbr"
+	-@erase "$(INTDIR)\view.obj"
+	-@erase "$(INTDIR)\view.sbr"
+	-@erase "$(OUTDIR)\quake2.bsc"
+	-@erase "$(OUTDIR)\quake2.exe"
+	-@erase "$(OUTDIR)\quake2.pdb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /c
+# SUBTRACT CPP /Gy
+CPP_PROJ=/nologo /G5 /MLd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /FR"$(INTDIR)/" /Fp"$(INTDIR)/quake2.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/"\
+ /c 
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\Debug/
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/quake2.bsc" 
+BSC32_SBRS= \
+	"$(INTDIR)\cd_win.sbr" \
+	"$(INTDIR)\cl_demo.sbr" \
+	"$(INTDIR)\cl_ents.sbr" \
+	"$(INTDIR)\cl_fx.sbr" \
+	"$(INTDIR)\cl_input.sbr" \
+	"$(INTDIR)\cl_main.sbr" \
+	"$(INTDIR)\cl_parse.sbr" \
+	"$(INTDIR)\cl_tent.sbr" \
+	"$(INTDIR)\cmd.sbr" \
+	"$(INTDIR)\cmodel.sbr" \
+	"$(INTDIR)\common.sbr" \
+	"$(INTDIR)\console.sbr" \
+	"$(INTDIR)\crc.sbr" \
+	"$(INTDIR)\cvar.sbr" \
+	"$(INTDIR)\files.sbr" \
+	"$(INTDIR)\in_win.sbr" \
+	"$(INTDIR)\keys.sbr" \
+	"$(INTDIR)\menu.sbr" \
+	"$(INTDIR)\net_chan.sbr" \
+	"$(INTDIR)\net_wins.sbr" \
+	"$(INTDIR)\q_shared.sbr" \
+	"$(INTDIR)\sbar2.sbr" \
+	"$(INTDIR)\scr_cin.sbr" \
+	"$(INTDIR)\screen.sbr" \
+	"$(INTDIR)\snd_dma.sbr" \
+	"$(INTDIR)\snd_mem.sbr" \
+	"$(INTDIR)\snd_mix.sbr" \
+	"$(INTDIR)\snd_win.sbr" \
+	"$(INTDIR)\sv_ccmds.sbr" \
+	"$(INTDIR)\sv_ents.sbr" \
+	"$(INTDIR)\sv_game.sbr" \
+	"$(INTDIR)\sv_init.sbr" \
+	"$(INTDIR)\sv_main.sbr" \
+	"$(INTDIR)\sv_move.sbr" \
+	"$(INTDIR)\sv_phys.sbr" \
+	"$(INTDIR)\sv_send.sbr" \
+	"$(INTDIR)\sv_user.sbr" \
+	"$(INTDIR)\sv_world.sbr" \
+	"$(INTDIR)\sys_win.sbr" \
+	"$(INTDIR)\vid_dll.sbr" \
+	"$(INTDIR)\view.sbr"
+
+"$(OUTDIR)\quake2.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+    $(BSC32) @<<
+  $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386
+# SUBTRACT LINK32 /nodefaultlib
+LINK32_FLAGS=winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib\
+ winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\
+ uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no\
+ /pdb:"$(OUTDIR)/quake2.pdb" /debug /machine:I386 /out:"$(OUTDIR)/quake2.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\cd_win.obj" \
+	"$(INTDIR)\cl_demo.obj" \
+	"$(INTDIR)\cl_ents.obj" \
+	"$(INTDIR)\cl_fx.obj" \
+	"$(INTDIR)\cl_input.obj" \
+	"$(INTDIR)\cl_main.obj" \
+	"$(INTDIR)\cl_parse.obj" \
+	"$(INTDIR)\cl_tent.obj" \
+	"$(INTDIR)\cmd.obj" \
+	"$(INTDIR)\cmodel.obj" \
+	"$(INTDIR)\common.obj" \
+	"$(INTDIR)\console.obj" \
+	"$(INTDIR)\crc.obj" \
+	"$(INTDIR)\cvar.obj" \
+	"$(INTDIR)\files.obj" \
+	"$(INTDIR)\in_win.obj" \
+	"$(INTDIR)\keys.obj" \
+	"$(INTDIR)\menu.obj" \
+	"$(INTDIR)\net_chan.obj" \
+	"$(INTDIR)\net_wins.obj" \
+	"$(INTDIR)\q_shared.obj" \
+	"$(INTDIR)\sbar2.obj" \
+	"$(INTDIR)\scr_cin.obj" \
+	"$(INTDIR)\screen.obj" \
+	"$(INTDIR)\snd_dma.obj" \
+	"$(INTDIR)\snd_mem.obj" \
+	"$(INTDIR)\snd_mix.obj" \
+	"$(INTDIR)\snd_win.obj" \
+	"$(INTDIR)\sv_ccmds.obj" \
+	"$(INTDIR)\sv_ents.obj" \
+	"$(INTDIR)\sv_game.obj" \
+	"$(INTDIR)\sv_init.obj" \
+	"$(INTDIR)\sv_main.obj" \
+	"$(INTDIR)\sv_move.obj" \
+	"$(INTDIR)\sv_phys.obj" \
+	"$(INTDIR)\sv_send.obj" \
+	"$(INTDIR)\sv_user.obj" \
+	"$(INTDIR)\sv_world.obj" \
+	"$(INTDIR)\sys_win.obj" \
+	"$(INTDIR)\vid_dll.obj" \
+	"$(INTDIR)\view.obj"
+
+"$(OUTDIR)\quake2.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ref_soft\ref_soft"
+# PROP BASE Intermediate_Dir "ref_soft\ref_soft"
+# PROP BASE Target_Dir "ref_soft"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "ref_soft\Release"
+# PROP Target_Dir "ref_soft"
+OUTDIR=.\Release
+INTDIR=.\ref_soft\Release
+
+ALL : "$(OUTDIR)\ref_soft.dll"
+
+CLEAN : 
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\r_aclip.obj"
+	-@erase "$(INTDIR)\r_alias.obj"
+	-@erase "$(INTDIR)\r_bsp.obj"
+	-@erase "$(INTDIR)\r_draw.obj"
+	-@erase "$(INTDIR)\r_edge.obj"
+	-@erase "$(INTDIR)\r_image.obj"
+	-@erase "$(INTDIR)\r_inter.obj"
+	-@erase "$(INTDIR)\r_light.obj"
+	-@erase "$(INTDIR)\r_main.obj"
+	-@erase "$(INTDIR)\r_misc.obj"
+	-@erase "$(INTDIR)\r_model.obj"
+	-@erase "$(INTDIR)\r_part.obj"
+	-@erase "$(INTDIR)\r_poly.obj"
+	-@erase "$(INTDIR)\r_polyse.obj"
+	-@erase "$(INTDIR)\r_rast.obj"
+	-@erase "$(INTDIR)\r_scan.obj"
+	-@erase "$(INTDIR)\r_sprite.obj"
+	-@erase "$(INTDIR)\r_surf.obj"
+	-@erase "$(INTDIR)\rw_ddraw.obj"
+	-@erase "$(INTDIR)\rw_dib.obj"
+	-@erase "$(INTDIR)\rw_imp.obj"
+	-@erase "$(OUTDIR)\ref_soft.dll"
+	-@erase "$(OUTDIR)\ref_soft.exp"
+	-@erase "$(OUTDIR)\ref_soft.lib"
+	-@erase ".\Release\r_aclipa.obj"
+	-@erase ".\Release\r_draw16.obj"
+	-@erase ".\Release\r_drawa.obj"
+	-@erase ".\Release\r_edgea.obj"
+	-@erase ".\Release\r_scana.obj"
+	-@erase ".\Release\r_spr8.obj"
+	-@erase ".\Release\r_surf8.obj"
+	-@erase ".\Release\r_varsa.obj"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /G5 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/ref_soft.pch" /YX /Fo"$(INTDIR)/" /c 
+CPP_OBJS=.\ref_soft\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ref_soft.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc"
+# SUBTRACT LINK32 /nodefaultlib
+LINK32_FLAGS=winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib\
+ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\
+ odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/ref_soft.pdb" /machine:I386 /nodefaultlib:"libc"\
+ /def:".\ref_soft\ref_soft.def" /out:"$(OUTDIR)/ref_soft.dll"\
+ /implib:"$(OUTDIR)/ref_soft.lib" 
+DEF_FILE= \
+	".\ref_soft\ref_soft.def"
+LINK32_OBJS= \
+	"$(INTDIR)\q_shared.obj" \
+	"$(INTDIR)\r_aclip.obj" \
+	"$(INTDIR)\r_alias.obj" \
+	"$(INTDIR)\r_bsp.obj" \
+	"$(INTDIR)\r_draw.obj" \
+	"$(INTDIR)\r_edge.obj" \
+	"$(INTDIR)\r_image.obj" \
+	"$(INTDIR)\r_inter.obj" \
+	"$(INTDIR)\r_light.obj" \
+	"$(INTDIR)\r_main.obj" \
+	"$(INTDIR)\r_misc.obj" \
+	"$(INTDIR)\r_model.obj" \
+	"$(INTDIR)\r_part.obj" \
+	"$(INTDIR)\r_poly.obj" \
+	"$(INTDIR)\r_polyse.obj" \
+	"$(INTDIR)\r_rast.obj" \
+	"$(INTDIR)\r_scan.obj" \
+	"$(INTDIR)\r_sprite.obj" \
+	"$(INTDIR)\r_surf.obj" \
+	"$(INTDIR)\rw_ddraw.obj" \
+	"$(INTDIR)\rw_dib.obj" \
+	"$(INTDIR)\rw_imp.obj" \
+	".\Release\r_aclipa.obj" \
+	".\Release\r_draw16.obj" \
+	".\Release\r_drawa.obj" \
+	".\Release\r_edgea.obj" \
+	".\Release\r_scana.obj" \
+	".\Release\r_spr8.obj" \
+	".\Release\r_surf8.obj" \
+	".\Release\r_varsa.obj"
+
+"$(OUTDIR)\ref_soft.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ref_soft\ref_soft"
+# PROP BASE Intermediate_Dir "ref_soft\ref_soft"
+# PROP BASE Target_Dir "ref_soft"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "ref_soft\Debug"
+# PROP Target_Dir "ref_soft"
+OUTDIR=.\Debug
+INTDIR=.\ref_soft\Debug
+
+ALL : "$(OUTDIR)\ref_soft.dll"
+
+CLEAN : 
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\r_aclip.obj"
+	-@erase "$(INTDIR)\r_alias.obj"
+	-@erase "$(INTDIR)\r_bsp.obj"
+	-@erase "$(INTDIR)\r_draw.obj"
+	-@erase "$(INTDIR)\r_edge.obj"
+	-@erase "$(INTDIR)\r_image.obj"
+	-@erase "$(INTDIR)\r_inter.obj"
+	-@erase "$(INTDIR)\r_light.obj"
+	-@erase "$(INTDIR)\r_main.obj"
+	-@erase "$(INTDIR)\r_misc.obj"
+	-@erase "$(INTDIR)\r_model.obj"
+	-@erase "$(INTDIR)\r_part.obj"
+	-@erase "$(INTDIR)\r_poly.obj"
+	-@erase "$(INTDIR)\r_polyse.obj"
+	-@erase "$(INTDIR)\r_rast.obj"
+	-@erase "$(INTDIR)\r_scan.obj"
+	-@erase "$(INTDIR)\r_sprite.obj"
+	-@erase "$(INTDIR)\r_surf.obj"
+	-@erase "$(INTDIR)\rw_ddraw.obj"
+	-@erase "$(INTDIR)\rw_dib.obj"
+	-@erase "$(INTDIR)\rw_imp.obj"
+	-@erase "$(INTDIR)\vc40.idb"
+	-@erase "$(INTDIR)\vc40.pdb"
+	-@erase "$(OUTDIR)\ref_soft.dll"
+	-@erase "$(OUTDIR)\ref_soft.exp"
+	-@erase "$(OUTDIR)\ref_soft.lib"
+	-@erase "$(OUTDIR)\ref_soft.pdb"
+	-@erase ".\Debug\r_aclipa.obj"
+	-@erase ".\Debug\r_draw16.obj"
+	-@erase ".\Debug\r_drawa.obj"
+	-@erase ".\Debug\r_edgea.obj"
+	-@erase ".\Debug\r_scana.obj"
+	-@erase ".\Debug\r_spr8.obj"
+	-@erase ".\Debug\r_surf8.obj"
+	-@erase ".\Debug\r_varsa.obj"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D\
+ "_WINDOWS" /Fp"$(INTDIR)/ref_soft.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+CPP_OBJS=.\ref_soft\Debug/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ref_soft.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /nodefaultlib:"libc"
+# SUBTRACT LINK32 /nodefaultlib
+LINK32_FLAGS=winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib\
+ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\
+ odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/ref_soft.pdb" /debug /machine:I386 /nodefaultlib:"libc"\
+ /def:".\ref_soft\ref_soft.def" /out:"$(OUTDIR)/ref_soft.dll"\
+ /implib:"$(OUTDIR)/ref_soft.lib" 
+DEF_FILE= \
+	".\ref_soft\ref_soft.def"
+LINK32_OBJS= \
+	"$(INTDIR)\q_shared.obj" \
+	"$(INTDIR)\r_aclip.obj" \
+	"$(INTDIR)\r_alias.obj" \
+	"$(INTDIR)\r_bsp.obj" \
+	"$(INTDIR)\r_draw.obj" \
+	"$(INTDIR)\r_edge.obj" \
+	"$(INTDIR)\r_image.obj" \
+	"$(INTDIR)\r_inter.obj" \
+	"$(INTDIR)\r_light.obj" \
+	"$(INTDIR)\r_main.obj" \
+	"$(INTDIR)\r_misc.obj" \
+	"$(INTDIR)\r_model.obj" \
+	"$(INTDIR)\r_part.obj" \
+	"$(INTDIR)\r_poly.obj" \
+	"$(INTDIR)\r_polyse.obj" \
+	"$(INTDIR)\r_rast.obj" \
+	"$(INTDIR)\r_scan.obj" \
+	"$(INTDIR)\r_sprite.obj" \
+	"$(INTDIR)\r_surf.obj" \
+	"$(INTDIR)\rw_ddraw.obj" \
+	"$(INTDIR)\rw_dib.obj" \
+	"$(INTDIR)\rw_imp.obj" \
+	".\Debug\r_aclipa.obj" \
+	".\Debug\r_draw16.obj" \
+	".\Debug\r_drawa.obj" \
+	".\Debug\r_edgea.obj" \
+	".\Debug\r_scana.obj" \
+	".\Debug\r_spr8.obj" \
+	".\Debug\r_surf8.obj" \
+	".\Debug\r_varsa.obj"
+
+"$(OUTDIR)\ref_soft.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ref_gl\ref_gl__"
+# PROP BASE Intermediate_Dir "ref_gl\ref_gl__"
+# PROP BASE Target_Dir "ref_gl"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "ref_gl\Release"
+# PROP Target_Dir "ref_gl"
+OUTDIR=.\Release
+INTDIR=.\ref_gl\Release
+
+ALL : "$(OUTDIR)\ref_gl.dll"
+
+CLEAN : 
+	-@erase "$(INTDIR)\gl_draw.obj"
+	-@erase "$(INTDIR)\gl_inter.obj"
+	-@erase "$(INTDIR)\gl_light.obj"
+	-@erase "$(INTDIR)\gl_mesh.obj"
+	-@erase "$(INTDIR)\gl_model.obj"
+	-@erase "$(INTDIR)\gl_rmain.obj"
+	-@erase "$(INTDIR)\gl_rmisc.obj"
+	-@erase "$(INTDIR)\gl_rsurf.obj"
+	-@erase "$(INTDIR)\gl_textr.obj"
+	-@erase "$(INTDIR)\gl_warp.obj"
+	-@erase "$(INTDIR)\glw_imp.obj"
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\qgl_win.obj"
+	-@erase "$(OUTDIR)\ref_gl.dll"
+	-@erase "$(OUTDIR)\ref_gl.exp"
+	-@erase "$(OUTDIR)\ref_gl.lib"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /G5 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/ref_gl.pch" /YX /Fo"$(INTDIR)/" /c 
+CPP_OBJS=.\ref_gl\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ref_gl.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+LINK32_FLAGS=winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib\
+ winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\
+ uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll\
+ /incremental:no /pdb:"$(OUTDIR)/ref_gl.pdb" /machine:I386\
+ /def:".\ref_gl\ref_gl.def" /out:"$(OUTDIR)/ref_gl.dll"\
+ /implib:"$(OUTDIR)/ref_gl.lib" 
+DEF_FILE= \
+	".\ref_gl\ref_gl.def"
+LINK32_OBJS= \
+	"$(INTDIR)\gl_draw.obj" \
+	"$(INTDIR)\gl_inter.obj" \
+	"$(INTDIR)\gl_light.obj" \
+	"$(INTDIR)\gl_mesh.obj" \
+	"$(INTDIR)\gl_model.obj" \
+	"$(INTDIR)\gl_rmain.obj" \
+	"$(INTDIR)\gl_rmisc.obj" \
+	"$(INTDIR)\gl_rsurf.obj" \
+	"$(INTDIR)\gl_textr.obj" \
+	"$(INTDIR)\gl_warp.obj" \
+	"$(INTDIR)\glw_imp.obj" \
+	"$(INTDIR)\q_shared.obj" \
+	"$(INTDIR)\qgl_win.obj"
+
+"$(OUTDIR)\ref_gl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "ref_gl\ref_gl__"
+# PROP BASE Intermediate_Dir "ref_gl\ref_gl__"
+# PROP BASE Target_Dir "ref_gl"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "ref_gl\Debug"
+# PROP Target_Dir "ref_gl"
+OUTDIR=.\Debug
+INTDIR=.\ref_gl\Debug
+
+ALL : "$(OUTDIR)\ref_gl.dll"
+
+CLEAN : 
+	-@erase "$(INTDIR)\gl_draw.obj"
+	-@erase "$(INTDIR)\gl_inter.obj"
+	-@erase "$(INTDIR)\gl_light.obj"
+	-@erase "$(INTDIR)\gl_mesh.obj"
+	-@erase "$(INTDIR)\gl_model.obj"
+	-@erase "$(INTDIR)\gl_rmain.obj"
+	-@erase "$(INTDIR)\gl_rmisc.obj"
+	-@erase "$(INTDIR)\gl_rsurf.obj"
+	-@erase "$(INTDIR)\gl_textr.obj"
+	-@erase "$(INTDIR)\gl_warp.obj"
+	-@erase "$(INTDIR)\glw_imp.obj"
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\qgl_win.obj"
+	-@erase "$(INTDIR)\vc40.idb"
+	-@erase "$(INTDIR)\vc40.pdb"
+	-@erase "$(OUTDIR)\ref_gl.dll"
+	-@erase "$(OUTDIR)\ref_gl.exp"
+	-@erase "$(OUTDIR)\ref_gl.lib"
+	-@erase "$(OUTDIR)\ref_gl.pdb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D\
+ "_WINDOWS" /Fp"$(INTDIR)/ref_gl.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+CPP_OBJS=.\ref_gl\Debug/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/ref_gl.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386
+LINK32_FLAGS=winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib\
+ winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\
+ uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll\
+ /incremental:no /pdb:"$(OUTDIR)/ref_gl.pdb" /debug /machine:I386\
+ /def:".\ref_gl\ref_gl.def" /out:"$(OUTDIR)/ref_gl.dll"\
+ /implib:"$(OUTDIR)/ref_gl.lib" 
+DEF_FILE= \
+	".\ref_gl\ref_gl.def"
+LINK32_OBJS= \
+	"$(INTDIR)\gl_draw.obj" \
+	"$(INTDIR)\gl_inter.obj" \
+	"$(INTDIR)\gl_light.obj" \
+	"$(INTDIR)\gl_mesh.obj" \
+	"$(INTDIR)\gl_model.obj" \
+	"$(INTDIR)\gl_rmain.obj" \
+	"$(INTDIR)\gl_rmisc.obj" \
+	"$(INTDIR)\gl_rsurf.obj" \
+	"$(INTDIR)\gl_textr.obj" \
+	"$(INTDIR)\gl_warp.obj" \
+	"$(INTDIR)\glw_imp.obj" \
+	"$(INTDIR)\q_shared.obj" \
+	"$(INTDIR)\qgl_win.obj"
+
+"$(OUTDIR)\ref_gl.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "game - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "game\Release"
+# PROP BASE Intermediate_Dir "game\Release"
+# PROP BASE Target_Dir "game"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "game\Release"
+# PROP Target_Dir "game"
+OUTDIR=.\Release
+INTDIR=.\game\Release
+
+ALL : "$(OUTDIR)\game.dll"
+
+CLEAN : 
+	-@erase "$(INTDIR)\g_ai.obj"
+	-@erase "$(INTDIR)\g_bersrk.obj"
+	-@erase "$(INTDIR)\g_brain.obj"
+	-@erase "$(INTDIR)\g_chick.obj"
+	-@erase "$(INTDIR)\g_client.obj"
+	-@erase "$(INTDIR)\g_cmds.obj"
+	-@erase "$(INTDIR)\g_combat.obj"
+	-@erase "$(INTDIR)\g_flipper.obj"
+	-@erase "$(INTDIR)\g_float.obj"
+	-@erase "$(INTDIR)\g_flyer.obj"
+	-@erase "$(INTDIR)\g_func.obj"
+	-@erase "$(INTDIR)\g_gladtr.obj"
+	-@erase "$(INTDIR)\g_gunner.obj"
+	-@erase "$(INTDIR)\g_hover.obj"
+	-@erase "$(INTDIR)\g_inftry.obj"
+	-@erase "$(INTDIR)\g_items.obj"
+	-@erase "$(INTDIR)\g_main.obj"
+	-@erase "$(INTDIR)\g_medic.obj"
+	-@erase "$(INTDIR)\g_misc.obj"
+	-@erase "$(INTDIR)\g_monster.obj"
+	-@erase "$(INTDIR)\g_parasite.obj"
+	-@erase "$(INTDIR)\g_player.obj"
+	-@erase "$(INTDIR)\g_pmove.obj"
+	-@erase "$(INTDIR)\g_ptrail.obj"
+	-@erase "$(INTDIR)\g_pview.obj"
+	-@erase "$(INTDIR)\g_pweapon.obj"
+	-@erase "$(INTDIR)\g_soldier.obj"
+	-@erase "$(INTDIR)\g_tank.obj"
+	-@erase "$(INTDIR)\g_target.obj"
+	-@erase "$(INTDIR)\g_trigger.obj"
+	-@erase "$(INTDIR)\g_utils.obj"
+	-@erase "$(INTDIR)\g_weapon.obj"
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(OUTDIR)\game.dll"
+	-@erase "$(OUTDIR)\game.exp"
+	-@erase "$(OUTDIR)\game.lib"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/game.pch" /YX /Fo"$(INTDIR)/" /c 
+CPP_OBJS=.\game\Release/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/game.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:0x20000000 /subsystem:windows /dll /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /base:0x20000000 /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/game.pdb" /machine:I386 /def:".\game\game.def"\
+ /out:"$(OUTDIR)/game.dll" /implib:"$(OUTDIR)/game.lib" 
+DEF_FILE= \
+	".\game\game.def"
+LINK32_OBJS= \
+	"$(INTDIR)\g_ai.obj" \
+	"$(INTDIR)\g_bersrk.obj" \
+	"$(INTDIR)\g_brain.obj" \
+	"$(INTDIR)\g_chick.obj" \
+	"$(INTDIR)\g_client.obj" \
+	"$(INTDIR)\g_cmds.obj" \
+	"$(INTDIR)\g_combat.obj" \
+	"$(INTDIR)\g_flipper.obj" \
+	"$(INTDIR)\g_float.obj" \
+	"$(INTDIR)\g_flyer.obj" \
+	"$(INTDIR)\g_func.obj" \
+	"$(INTDIR)\g_gladtr.obj" \
+	"$(INTDIR)\g_gunner.obj" \
+	"$(INTDIR)\g_hover.obj" \
+	"$(INTDIR)\g_inftry.obj" \
+	"$(INTDIR)\g_items.obj" \
+	"$(INTDIR)\g_main.obj" \
+	"$(INTDIR)\g_medic.obj" \
+	"$(INTDIR)\g_misc.obj" \
+	"$(INTDIR)\g_monster.obj" \
+	"$(INTDIR)\g_parasite.obj" \
+	"$(INTDIR)\g_player.obj" \
+	"$(INTDIR)\g_pmove.obj" \
+	"$(INTDIR)\g_ptrail.obj" \
+	"$(INTDIR)\g_pview.obj" \
+	"$(INTDIR)\g_pweapon.obj" \
+	"$(INTDIR)\g_soldier.obj" \
+	"$(INTDIR)\g_tank.obj" \
+	"$(INTDIR)\g_target.obj" \
+	"$(INTDIR)\g_trigger.obj" \
+	"$(INTDIR)\g_utils.obj" \
+	"$(INTDIR)\g_weapon.obj" \
+	"$(INTDIR)\q_shared.obj"
+
+"$(OUTDIR)\game.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "game\Debug"
+# PROP BASE Intermediate_Dir "game\Debug"
+# PROP BASE Target_Dir "game"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "game\Debug"
+# PROP Target_Dir "game"
+OUTDIR=.\Debug
+INTDIR=.\game\Debug
+
+ALL : "$(OUTDIR)\game.dll"
+
+CLEAN : 
+	-@erase "$(INTDIR)\g_ai.obj"
+	-@erase "$(INTDIR)\g_bersrk.obj"
+	-@erase "$(INTDIR)\g_brain.obj"
+	-@erase "$(INTDIR)\g_chick.obj"
+	-@erase "$(INTDIR)\g_client.obj"
+	-@erase "$(INTDIR)\g_cmds.obj"
+	-@erase "$(INTDIR)\g_combat.obj"
+	-@erase "$(INTDIR)\g_flipper.obj"
+	-@erase "$(INTDIR)\g_float.obj"
+	-@erase "$(INTDIR)\g_flyer.obj"
+	-@erase "$(INTDIR)\g_func.obj"
+	-@erase "$(INTDIR)\g_gladtr.obj"
+	-@erase "$(INTDIR)\g_gunner.obj"
+	-@erase "$(INTDIR)\g_hover.obj"
+	-@erase "$(INTDIR)\g_inftry.obj"
+	-@erase "$(INTDIR)\g_items.obj"
+	-@erase "$(INTDIR)\g_main.obj"
+	-@erase "$(INTDIR)\g_medic.obj"
+	-@erase "$(INTDIR)\g_misc.obj"
+	-@erase "$(INTDIR)\g_monster.obj"
+	-@erase "$(INTDIR)\g_parasite.obj"
+	-@erase "$(INTDIR)\g_player.obj"
+	-@erase "$(INTDIR)\g_pmove.obj"
+	-@erase "$(INTDIR)\g_ptrail.obj"
+	-@erase "$(INTDIR)\g_pview.obj"
+	-@erase "$(INTDIR)\g_pweapon.obj"
+	-@erase "$(INTDIR)\g_soldier.obj"
+	-@erase "$(INTDIR)\g_tank.obj"
+	-@erase "$(INTDIR)\g_target.obj"
+	-@erase "$(INTDIR)\g_trigger.obj"
+	-@erase "$(INTDIR)\g_utils.obj"
+	-@erase "$(INTDIR)\g_weapon.obj"
+	-@erase "$(INTDIR)\q_shared.obj"
+	-@erase "$(INTDIR)\vc40.idb"
+	-@erase "$(INTDIR)\vc40.pdb"
+	-@erase "$(OUTDIR)\game.dll"
+	-@erase "$(OUTDIR)\game.exp"
+	-@erase "$(OUTDIR)\game.lib"
+	-@erase "$(OUTDIR)\game.pdb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/game.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+CPP_OBJS=.\game\Debug/
+CPP_SBRS=.\.
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+MTL=mktyplib.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32 
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/game.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:0x20000000 /subsystem:windows /dll /incremental:no /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /base:0x20000000 /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/game.pdb" /debug /machine:I386 /def:".\game\game.def"\
+ /out:"$(OUTDIR)/game.dll" /implib:"$(OUTDIR)/game.lib" 
+DEF_FILE= \
+	".\game\game.def"
+LINK32_OBJS= \
+	"$(INTDIR)\g_ai.obj" \
+	"$(INTDIR)\g_bersrk.obj" \
+	"$(INTDIR)\g_brain.obj" \
+	"$(INTDIR)\g_chick.obj" \
+	"$(INTDIR)\g_client.obj" \
+	"$(INTDIR)\g_cmds.obj" \
+	"$(INTDIR)\g_combat.obj" \
+	"$(INTDIR)\g_flipper.obj" \
+	"$(INTDIR)\g_float.obj" \
+	"$(INTDIR)\g_flyer.obj" \
+	"$(INTDIR)\g_func.obj" \
+	"$(INTDIR)\g_gladtr.obj" \
+	"$(INTDIR)\g_gunner.obj" \
+	"$(INTDIR)\g_hover.obj" \
+	"$(INTDIR)\g_inftry.obj" \
+	"$(INTDIR)\g_items.obj" \
+	"$(INTDIR)\g_main.obj" \
+	"$(INTDIR)\g_medic.obj" \
+	"$(INTDIR)\g_misc.obj" \
+	"$(INTDIR)\g_monster.obj" \
+	"$(INTDIR)\g_parasite.obj" \
+	"$(INTDIR)\g_player.obj" \
+	"$(INTDIR)\g_pmove.obj" \
+	"$(INTDIR)\g_ptrail.obj" \
+	"$(INTDIR)\g_pview.obj" \
+	"$(INTDIR)\g_pweapon.obj" \
+	"$(INTDIR)\g_soldier.obj" \
+	"$(INTDIR)\g_tank.obj" \
+	"$(INTDIR)\g_target.obj" \
+	"$(INTDIR)\g_trigger.obj" \
+	"$(INTDIR)\g_utils.obj" \
+	"$(INTDIR)\g_weapon.obj" \
+	"$(INTDIR)\q_shared.obj"
+
+"$(OUTDIR)\game.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF 
+
+################################################################################
+# Begin Target
+
+# Name "quake2 - Win32 Release"
+# Name "quake2 - Win32 Debug"
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\cmodel.c
+DEP_CPP_CMODE=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cmodel.obj" : $(SOURCE) $(DEP_CPP_CMODE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cmodel.obj" : $(SOURCE) $(DEP_CPP_CMODE) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cmodel.sbr" : $(SOURCE) $(DEP_CPP_CMODE) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\common.c
+DEP_CPP_COMMO=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\common.obj" : $(SOURCE) $(DEP_CPP_COMMO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\common.obj" : $(SOURCE) $(DEP_CPP_COMMO) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\common.sbr" : $(SOURCE) $(DEP_CPP_COMMO) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\cvar.c
+DEP_CPP_CVAR_=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cvar.obj" : $(SOURCE) $(DEP_CPP_CVAR_) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cvar.obj" : $(SOURCE) $(DEP_CPP_CVAR_) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cvar.sbr" : $(SOURCE) $(DEP_CPP_CVAR_) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\files.c
+DEP_CPP_FILES=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\files.obj" : $(SOURCE) $(DEP_CPP_FILES) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\files.obj" : $(SOURCE) $(DEP_CPP_FILES) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\files.sbr" : $(SOURCE) $(DEP_CPP_FILES) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\net_chan.c
+DEP_CPP_NET_C=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\net_chan.obj" : $(SOURCE) $(DEP_CPP_NET_C) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\net_chan.obj" : $(SOURCE) $(DEP_CPP_NET_C) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\net_chan.sbr" : $(SOURCE) $(DEP_CPP_NET_C) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\cmd.c
+DEP_CPP_CMD_C=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cmd.obj" : $(SOURCE) $(DEP_CPP_CMD_C) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cmd.obj" : $(SOURCE) $(DEP_CPP_CMD_C) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cmd.sbr" : $(SOURCE) $(DEP_CPP_CMD_C) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\view.c
+DEP_CPP_VIEW_=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\view.obj" : $(SOURCE) $(DEP_CPP_VIEW_) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\view.obj" : $(SOURCE) $(DEP_CPP_VIEW_) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\view.sbr" : $(SOURCE) $(DEP_CPP_VIEW_) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_demo.c
+DEP_CPP_CL_DE=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_demo.obj" : $(SOURCE) $(DEP_CPP_CL_DE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_demo.obj" : $(SOURCE) $(DEP_CPP_CL_DE) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_demo.sbr" : $(SOURCE) $(DEP_CPP_CL_DE) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_ents.c
+DEP_CPP_CL_EN=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_ents.obj" : $(SOURCE) $(DEP_CPP_CL_EN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_ents.obj" : $(SOURCE) $(DEP_CPP_CL_EN) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_ents.sbr" : $(SOURCE) $(DEP_CPP_CL_EN) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_input.c
+DEP_CPP_CL_IN=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_input.obj" : $(SOURCE) $(DEP_CPP_CL_IN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_input.obj" : $(SOURCE) $(DEP_CPP_CL_IN) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_input.sbr" : $(SOURCE) $(DEP_CPP_CL_IN) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_main.c
+DEP_CPP_CL_MA=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_main.obj" : $(SOURCE) $(DEP_CPP_CL_MA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_main.obj" : $(SOURCE) $(DEP_CPP_CL_MA) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_main.sbr" : $(SOURCE) $(DEP_CPP_CL_MA) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_parse.c
+DEP_CPP_CL_PA=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_parse.obj" : $(SOURCE) $(DEP_CPP_CL_PA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_parse.obj" : $(SOURCE) $(DEP_CPP_CL_PA) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_parse.sbr" : $(SOURCE) $(DEP_CPP_CL_PA) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_tent.c
+DEP_CPP_CL_TE=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_tent.obj" : $(SOURCE) $(DEP_CPP_CL_TE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_tent.obj" : $(SOURCE) $(DEP_CPP_CL_TE) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_tent.sbr" : $(SOURCE) $(DEP_CPP_CL_TE) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\console.c
+DEP_CPP_CONSO=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\console.obj" : $(SOURCE) $(DEP_CPP_CONSO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\console.obj" : $(SOURCE) $(DEP_CPP_CONSO) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\console.sbr" : $(SOURCE) $(DEP_CPP_CONSO) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\keys.c
+DEP_CPP_KEYS_=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\keys.obj" : $(SOURCE) $(DEP_CPP_KEYS_) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\keys.obj" : $(SOURCE) $(DEP_CPP_KEYS_) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\keys.sbr" : $(SOURCE) $(DEP_CPP_KEYS_) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\menu.c
+DEP_CPP_MENU_=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\menu.obj" : $(SOURCE) $(DEP_CPP_MENU_) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\menu.obj" : $(SOURCE) $(DEP_CPP_MENU_) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\menu.sbr" : $(SOURCE) $(DEP_CPP_MENU_) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\screen.c
+DEP_CPP_SCREE=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\screen.obj" : $(SOURCE) $(DEP_CPP_SCREE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\screen.obj" : $(SOURCE) $(DEP_CPP_SCREE) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\screen.sbr" : $(SOURCE) $(DEP_CPP_SCREE) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\snd_dma.c
+DEP_CPP_SND_D=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	".\win32\winquake.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\snd_dma.obj" : $(SOURCE) $(DEP_CPP_SND_D) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\snd_dma.obj" : $(SOURCE) $(DEP_CPP_SND_D) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\snd_dma.sbr" : $(SOURCE) $(DEP_CPP_SND_D) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\snd_mem.c
+DEP_CPP_SND_M=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\snd_mem.obj" : $(SOURCE) $(DEP_CPP_SND_M) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\snd_mem.obj" : $(SOURCE) $(DEP_CPP_SND_M) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\snd_mem.sbr" : $(SOURCE) $(DEP_CPP_SND_M) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\snd_mix.c
+DEP_CPP_SND_MI=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	".\win32\winquake.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\snd_mix.obj" : $(SOURCE) $(DEP_CPP_SND_MI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\snd_mix.obj" : $(SOURCE) $(DEP_CPP_SND_MI) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\snd_mix.sbr" : $(SOURCE) $(DEP_CPP_SND_MI) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_ccmds.c
+DEP_CPP_SV_CC=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_ccmds.obj" : $(SOURCE) $(DEP_CPP_SV_CC) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_ccmds.obj" : $(SOURCE) $(DEP_CPP_SV_CC) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_ccmds.sbr" : $(SOURCE) $(DEP_CPP_SV_CC) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_ents.c
+DEP_CPP_SV_EN=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_ents.obj" : $(SOURCE) $(DEP_CPP_SV_EN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_ents.obj" : $(SOURCE) $(DEP_CPP_SV_EN) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_ents.sbr" : $(SOURCE) $(DEP_CPP_SV_EN) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_init.c
+DEP_CPP_SV_IN=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_init.obj" : $(SOURCE) $(DEP_CPP_SV_IN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_init.obj" : $(SOURCE) $(DEP_CPP_SV_IN) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_init.sbr" : $(SOURCE) $(DEP_CPP_SV_IN) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_main.c
+DEP_CPP_SV_MA=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_main.obj" : $(SOURCE) $(DEP_CPP_SV_MA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_main.obj" : $(SOURCE) $(DEP_CPP_SV_MA) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_main.sbr" : $(SOURCE) $(DEP_CPP_SV_MA) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_phys.c
+DEP_CPP_SV_PH=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_phys.obj" : $(SOURCE) $(DEP_CPP_SV_PH) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_phys.obj" : $(SOURCE) $(DEP_CPP_SV_PH) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_phys.sbr" : $(SOURCE) $(DEP_CPP_SV_PH) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_send.c
+DEP_CPP_SV_SE=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_send.obj" : $(SOURCE) $(DEP_CPP_SV_SE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_send.obj" : $(SOURCE) $(DEP_CPP_SV_SE) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_send.sbr" : $(SOURCE) $(DEP_CPP_SV_SE) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_user.c
+DEP_CPP_SV_US=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_user.obj" : $(SOURCE) $(DEP_CPP_SV_US) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_user.obj" : $(SOURCE) $(DEP_CPP_SV_US) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_user.sbr" : $(SOURCE) $(DEP_CPP_SV_US) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\qcommon.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\client.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\server.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\vid_dll.c
+DEP_CPP_VID_D=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	".\win32\winquake.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\vid_dll.obj" : $(SOURCE) $(DEP_CPP_VID_D) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\vid_dll.obj" : $(SOURCE) $(DEP_CPP_VID_D) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\vid_dll.sbr" : $(SOURCE) $(DEP_CPP_VID_D) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\in_win.c
+DEP_CPP_IN_WI=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	".\win32\winquake.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\in_win.obj" : $(SOURCE) $(DEP_CPP_IN_WI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\in_win.obj" : $(SOURCE) $(DEP_CPP_IN_WI) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\in_win.sbr" : $(SOURCE) $(DEP_CPP_IN_WI) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\net_wins.c
+DEP_CPP_NET_W=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\net_wins.obj" : $(SOURCE) $(DEP_CPP_NET_W) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\net_wins.obj" : $(SOURCE) $(DEP_CPP_NET_W) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\net_wins.sbr" : $(SOURCE) $(DEP_CPP_NET_W) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\snd_win.c
+DEP_CPP_SND_W=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\snd_loc.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	".\win32\winquake.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\snd_win.obj" : $(SOURCE) $(DEP_CPP_SND_W) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\snd_win.obj" : $(SOURCE) $(DEP_CPP_SND_W) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\snd_win.sbr" : $(SOURCE) $(DEP_CPP_SND_W) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\sys_win.c
+DEP_CPP_SYS_W=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\winquake.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sys_win.obj" : $(SOURCE) $(DEP_CPP_SYS_W) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sys_win.obj" : $(SOURCE) $(DEP_CPP_SYS_W) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sys_win.sbr" : $(SOURCE) $(DEP_CPP_SYS_W) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\cd_win.c
+DEP_CPP_CD_WI=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cd_win.obj" : $(SOURCE) $(DEP_CPP_CD_WI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cd_win.obj" : $(SOURCE) $(DEP_CPP_CD_WI) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cd_win.sbr" : $(SOURCE) $(DEP_CPP_CD_WI) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\bspfile.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\sbar2.c
+DEP_CPP_SBAR2=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sbar2.obj" : $(SOURCE) $(DEP_CPP_SBAR2) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sbar2.obj" : $(SOURCE) $(DEP_CPP_SBAR2) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sbar2.sbr" : $(SOURCE) $(DEP_CPP_SBAR2) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\ref.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_game.c
+DEP_CPP_SV_GA=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_game.obj" : $(SOURCE) $(DEP_CPP_SV_GA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_game.obj" : $(SOURCE) $(DEP_CPP_SV_GA) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_game.sbr" : $(SOURCE) $(DEP_CPP_SV_GA) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\snd_loc.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_move.c
+DEP_CPP_SV_MO=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_move.obj" : $(SOURCE) $(DEP_CPP_SV_MO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_move.obj" : $(SOURCE) $(DEP_CPP_SV_MO) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_move.sbr" : $(SOURCE) $(DEP_CPP_SV_MO) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\crc.c
+DEP_CPP_CRC_C=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\crc.obj" : $(SOURCE) $(DEP_CPP_CRC_C) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\crc.obj" : $(SOURCE) $(DEP_CPP_CRC_C) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\crc.sbr" : $(SOURCE) $(DEP_CPP_CRC_C) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\cl_fx.c
+DEP_CPP_CL_FX=\
+	".\client\anorms.h"\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\cl_fx.obj" : $(SOURCE) $(DEP_CPP_CL_FX) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\cl_fx.obj" : $(SOURCE) $(DEP_CPP_CL_FX) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\cl_fx.sbr" : $(SOURCE) $(DEP_CPP_CL_FX) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\client\scr_cin.c
+DEP_CPP_SCR_C=\
+	".\client\cdaudio.h"\
+	".\client\console.h"\
+	".\client\input.h"\
+	".\client\keys.h"\
+	".\client\ref.h"\
+	".\client\sbar.h"\
+	".\client\screen.h"\
+	".\client\sound.h"\
+	".\client\vid.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\win32\..\client\client.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\scr_cin.obj" : $(SOURCE) $(DEP_CPP_SCR_C) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\scr_cin.obj" : $(SOURCE) $(DEP_CPP_SCR_C) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\scr_cin.sbr" : $(SOURCE) $(DEP_CPP_SCR_C) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\qfiles.h
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\server\sv_world.c
+DEP_CPP_SV_WO=\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\sv_world.obj" : $(SOURCE) $(DEP_CPP_SV_WO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\sv_world.obj" : $(SOURCE) $(DEP_CPP_SV_WO) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\sv_world.sbr" : $(SOURCE) $(DEP_CPP_SV_WO) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\q_shared.c
+DEP_CPP_Q_SHA=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+!IF  "$(CFG)" == "quake2 - Win32 Release"
+
+
+"$(INTDIR)\q_shared.obj" : $(SOURCE) $(DEP_CPP_Q_SHA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "quake2 - Win32 Debug"
+
+
+BuildCmds= \
+	$(CPP) $(CPP_PROJ) $(SOURCE) \
+	
+
+"$(INTDIR)\q_shared.obj" : $(SOURCE) $(DEP_CPP_Q_SHA) "$(INTDIR)"
+   $(BuildCmds)
+
+"$(INTDIR)\q_shared.sbr" : $(SOURCE) $(DEP_CPP_Q_SHA) "$(INTDIR)"
+   $(BuildCmds)
+
+!ENDIF 
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "ref_soft - Win32 Release"
+# Name "ref_soft - Win32 Debug"
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ENDIF 
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_aclip.c
+DEP_CPP_R_ACL=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_aclip.obj" : $(SOURCE) $(DEP_CPP_R_ACL) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_alias.c
+DEP_CPP_R_ALI=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\anorms.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_alias.obj" : $(SOURCE) $(DEP_CPP_R_ALI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_bsp.c
+DEP_CPP_R_BSP=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_bsp.obj" : $(SOURCE) $(DEP_CPP_R_BSP) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_draw.c
+DEP_CPP_R_DRA=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_draw.obj" : $(SOURCE) $(DEP_CPP_R_DRA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_edge.c
+DEP_CPP_R_EDG=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_edge.obj" : $(SOURCE) $(DEP_CPP_R_EDG) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_inter.c
+DEP_CPP_R_INT=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_inter.obj" : $(SOURCE) $(DEP_CPP_R_INT) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_light.c
+DEP_CPP_R_LIG=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_light.obj" : $(SOURCE) $(DEP_CPP_R_LIG) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_main.c
+DEP_CPP_R_MAI=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_main.obj" : $(SOURCE) $(DEP_CPP_R_MAI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_misc.c
+DEP_CPP_R_MIS=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_misc.obj" : $(SOURCE) $(DEP_CPP_R_MIS) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_part.c
+DEP_CPP_R_PAR=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_part.obj" : $(SOURCE) $(DEP_CPP_R_PAR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_sprite.c
+DEP_CPP_R_SPR=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_sprite.obj" : $(SOURCE) $(DEP_CPP_R_SPR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_surf.c
+DEP_CPP_R_SUR=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_surf.obj" : $(SOURCE) $(DEP_CPP_R_SUR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_aclipa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_aclipa.asm
+InputName=r_aclipa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_aclipa.asm
+InputName=r_aclipa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_drawa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_drawa.asm
+InputName=r_drawa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_drawa.asm
+InputName=r_drawa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_edgea.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_edgea.asm
+InputName=r_edgea
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_edgea.asm
+InputName=r_edgea
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_varsa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_varsa.asm
+InputName=r_varsa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_varsa.asm
+InputName=r_varsa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\ref_soft.def
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_local.h
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_image.c
+DEP_CPP_R_IMA=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_image.obj" : $(SOURCE) $(DEP_CPP_R_IMA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_poly.c
+DEP_CPP_R_POL=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_poly.obj" : $(SOURCE) $(DEP_CPP_R_POL) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_polyse.c
+DEP_CPP_R_POLY=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\adivtab.h"\
+	".\ref_soft\r_model.h"\
+	".\ref_soft\rand1k.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_polyse.obj" : $(SOURCE) $(DEP_CPP_R_POLY) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_model.c
+DEP_CPP_R_MOD=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_model.obj" : $(SOURCE) $(DEP_CPP_R_MOD) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_rast.c
+DEP_CPP_R_RAS=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_rast.obj" : $(SOURCE) $(DEP_CPP_R_RAS) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_surf8.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_surf8.asm
+InputName=r_surf8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_surf8.asm
+InputName=r_surf8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_spr8.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_spr8.asm
+InputName=r_spr8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_spr8.asm
+InputName=r_spr8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_scana.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_scana.asm
+InputName=r_scana
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_scana.asm
+InputName=r_scana
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_scan.c
+DEP_CPP_R_SCA=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	
+
+"$(INTDIR)\r_scan.obj" : $(SOURCE) $(DEP_CPP_R_SCA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_soft\r_draw16.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=.\ref_soft\r_draw16.asm
+InputName=r_draw16
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=.\ref_soft\r_draw16.asm
+InputName=r_draw16
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+   ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\rw_dib.c
+DEP_CPP_RW_DI=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	".\win32\rw_win.h"\
+	
+
+"$(INTDIR)\rw_dib.obj" : $(SOURCE) $(DEP_CPP_RW_DI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\rw_imp.c
+DEP_CPP_RW_IM=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	".\win32\rw_win.h"\
+	
+
+"$(INTDIR)\rw_imp.obj" : $(SOURCE) $(DEP_CPP_RW_IM) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\q_shared.c
+DEP_CPP_Q_SHA=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+"$(INTDIR)\q_shared.obj" : $(SOURCE) $(DEP_CPP_Q_SHA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\rw_ddraw.c
+DEP_CPP_RW_DD=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_soft\r_model.h"\
+	".\win32\..\ref_soft\r_local.h"\
+	".\win32\rw_win.h"\
+	
+
+"$(INTDIR)\rw_ddraw.obj" : $(SOURCE) $(DEP_CPP_RW_DD) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "ref_gl - Win32 Release"
+# Name "ref_gl - Win32 Debug"
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ENDIF 
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_inter.c
+DEP_CPP_GL_IN=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_inter.obj" : $(SOURCE) $(DEP_CPP_GL_IN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_light.c
+DEP_CPP_GL_LI=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_light.obj" : $(SOURCE) $(DEP_CPP_GL_LI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_mesh.c
+DEP_CPP_GL_ME=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\anorms.h"\
+	".\ref_gl\anormtab.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_mesh.obj" : $(SOURCE) $(DEP_CPP_GL_ME) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_model.c
+DEP_CPP_GL_MO=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_model.obj" : $(SOURCE) $(DEP_CPP_GL_MO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_rmain.c
+DEP_CPP_GL_RM=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_rmain.obj" : $(SOURCE) $(DEP_CPP_GL_RM) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_rmisc.c
+DEP_CPP_GL_RMI=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_rmisc.obj" : $(SOURCE) $(DEP_CPP_GL_RMI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_rsurf.c
+DEP_CPP_GL_RS=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_rsurf.obj" : $(SOURCE) $(DEP_CPP_GL_RS) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_textr.c
+DEP_CPP_GL_TE=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_textr.obj" : $(SOURCE) $(DEP_CPP_GL_TE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_warp.c
+DEP_CPP_GL_WA=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	".\ref_gl\warpsin.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_warp.obj" : $(SOURCE) $(DEP_CPP_GL_WA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_draw.c
+DEP_CPP_GL_DR=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\gl_draw.obj" : $(SOURCE) $(DEP_CPP_GL_DR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\ref_gl.def
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\ref_gl.h
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\gl_model.h
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\ref_gl\qgl.h
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\qgl_win.c
+DEP_CPP_QGL_W=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	".\win32\glw_win.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\qgl_win.obj" : $(SOURCE) $(DEP_CPP_QGL_W) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\win32\glw_imp.c
+DEP_CPP_GLW_I=\
+	".\client\ref.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\ref_gl\gl_local.h"\
+	".\ref_gl\gl_model.h"\
+	".\ref_gl\qgl.h"\
+	".\win32\glw_win.h"\
+	".\win32\winquake.h"\
+	{$(INCLUDE)}"\gl\gl.h"\
+	
+
+"$(INTDIR)\glw_imp.obj" : $(SOURCE) $(DEP_CPP_GLW_I) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\q_shared.c
+DEP_CPP_Q_SHA=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+"$(INTDIR)\q_shared.obj" : $(SOURCE) $(DEP_CPP_Q_SHA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+################################################################################
+# Begin Target
+
+# Name "game - Win32 Release"
+# Name "game - Win32 Debug"
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_ai.c
+DEP_CPP_G_AI_=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_ai.obj" : $(SOURCE) $(DEP_CPP_G_AI_) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_bersrk.c
+DEP_CPP_G_BER=\
+	".\game\g_bersrk.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_bersrk.obj" : $(SOURCE) $(DEP_CPP_G_BER) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_bersrk.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_client.c
+DEP_CPP_G_CLI=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_client.obj" : $(SOURCE) $(DEP_CPP_G_CLI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_combat.c
+DEP_CPP_G_COM=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_combat.obj" : $(SOURCE) $(DEP_CPP_G_COM) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_func.c
+DEP_CPP_G_FUN=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_func.obj" : $(SOURCE) $(DEP_CPP_G_FUN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_gladtr.c
+DEP_CPP_G_GLA=\
+	".\game\g_gladtr.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_gladtr.obj" : $(SOURCE) $(DEP_CPP_G_GLA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_gladtr.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_gunner.c
+DEP_CPP_G_GUN=\
+	".\game\g_gunner.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_gunner.obj" : $(SOURCE) $(DEP_CPP_G_GUN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_gunner.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_inftry.c
+DEP_CPP_G_INF=\
+	".\game\g_inftry.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_inftry.obj" : $(SOURCE) $(DEP_CPP_G_INF) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_inftry.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_items.c
+DEP_CPP_G_ITE=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_items.obj" : $(SOURCE) $(DEP_CPP_G_ITE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_local.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_main.c
+DEP_CPP_G_MAI=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_main.obj" : $(SOURCE) $(DEP_CPP_G_MAI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_misc.c
+DEP_CPP_G_MIS=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_misc.obj" : $(SOURCE) $(DEP_CPP_G_MIS) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_monster.c
+DEP_CPP_G_MON=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_monster.obj" : $(SOURCE) $(DEP_CPP_G_MON) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_pmove.c
+DEP_CPP_G_PMO=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_pmove.obj" : $(SOURCE) $(DEP_CPP_G_PMO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_pweapon.c
+DEP_CPP_G_PWE=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_pweapon.obj" : $(SOURCE) $(DEP_CPP_G_PWE) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_soldier.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_utils.c
+DEP_CPP_G_UTI=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_utils.obj" : $(SOURCE) $(DEP_CPP_G_UTI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_weapon.c
+DEP_CPP_G_WEA=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_weapon.obj" : $(SOURCE) $(DEP_CPP_G_WEA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_target.c
+DEP_CPP_G_TAR=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_target.obj" : $(SOURCE) $(DEP_CPP_G_TAR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_trigger.c
+DEP_CPP_G_TRI=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_trigger.obj" : $(SOURCE) $(DEP_CPP_G_TRI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_tank.c
+DEP_CPP_G_TAN=\
+	".\game\g_local.h"\
+	".\game\g_tank.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_tank.obj" : $(SOURCE) $(DEP_CPP_G_TAN) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_soldier.c
+DEP_CPP_G_SOL=\
+	".\game\g_local.h"\
+	".\game\g_soldier.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_soldier.obj" : $(SOURCE) $(DEP_CPP_G_SOL) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\game.def
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\game.h
+
+!IF  "$(CFG)" == "game - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "game - Win32 Debug"
+
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_medic.c
+DEP_CPP_G_MED=\
+	".\game\g_local.h"\
+	".\game\g_medic.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_medic.obj" : $(SOURCE) $(DEP_CPP_G_MED) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_flipper.c
+DEP_CPP_G_FLI=\
+	".\game\g_flipper.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_flipper.obj" : $(SOURCE) $(DEP_CPP_G_FLI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_chick.c
+DEP_CPP_G_CHI=\
+	".\game\g_chick.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_chick.obj" : $(SOURCE) $(DEP_CPP_G_CHI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_parasite.c
+DEP_CPP_G_PAR=\
+	".\game\g_local.h"\
+	".\game\g_parasite.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_parasite.obj" : $(SOURCE) $(DEP_CPP_G_PAR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_flyer.c
+DEP_CPP_G_FLY=\
+	".\game\g_flyer.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_flyer.obj" : $(SOURCE) $(DEP_CPP_G_FLY) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_ptrail.c
+DEP_CPP_G_PTR=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_ptrail.obj" : $(SOURCE) $(DEP_CPP_G_PTR) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_hover.c
+DEP_CPP_G_HOV=\
+	".\game\g_hover.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_hover.obj" : $(SOURCE) $(DEP_CPP_G_HOV) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_float.c
+DEP_CPP_G_FLO=\
+	".\game\g_float.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_float.obj" : $(SOURCE) $(DEP_CPP_G_FLO) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_brain.c
+DEP_CPP_G_BRA=\
+	".\game\g_brain.h"\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_brain.obj" : $(SOURCE) $(DEP_CPP_G_BRA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_cmds.c
+DEP_CPP_G_CMD=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_cmds.obj" : $(SOURCE) $(DEP_CPP_G_CMD) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_player.c
+DEP_CPP_G_PLA=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_player.obj" : $(SOURCE) $(DEP_CPP_G_PLA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\game\g_pview.c
+DEP_CPP_G_PVI=\
+	".\game\g_local.h"\
+	".\game\game.h"\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	".\server\server.h"\
+	
+
+"$(INTDIR)\g_pview.obj" : $(SOURCE) $(DEP_CPP_G_PVI) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\qcommon\q_shared.c
+DEP_CPP_Q_SHA=\
+	".\qcommon\qcommon.h"\
+	".\qcommon\qfiles.h"\
+	
+
+"$(INTDIR)\q_shared.obj" : $(SOURCE) $(DEP_CPP_Q_SHA) "$(INTDIR)"
+   $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
binary files /dev/null b/quake2.opt differ
--- /dev/null
+++ b/quake2.plg
@@ -1,0 +1,715 @@
+<html>
+<body>
+<pre>
+<h1>Build Log</h1>
+<h3>
+--------------------Configuration: ctf - Win32 Debug--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB38.tmp" with contents
+[
+/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR".\debug/" /Fp".\debug/ctf.pch" /YX /Fo".\debug/" /Fd".\debug/" /FD /c 
+"D:\quake2\code\ctf\g_ai.c"
+"D:\quake2\code\ctf\g_chase.c"
+"D:\quake2\code\ctf\g_cmds.c"
+"D:\quake2\code\ctf\g_combat.c"
+"D:\quake2\code\ctf\g_ctf.c"
+"D:\quake2\code\ctf\g_func.c"
+"D:\quake2\code\ctf\g_items.c"
+"D:\quake2\code\ctf\g_main.c"
+"D:\quake2\code\ctf\g_misc.c"
+"D:\quake2\code\ctf\g_monster.c"
+"D:\quake2\code\ctf\g_phys.c"
+"D:\quake2\code\ctf\g_save.c"
+"D:\quake2\code\ctf\g_spawn.c"
+"D:\quake2\code\ctf\g_svcmds.c"
+"D:\quake2\code\ctf\g_target.c"
+"D:\quake2\code\ctf\g_trigger.c"
+"D:\quake2\code\ctf\g_utils.c"
+"D:\quake2\code\ctf\g_weapon.c"
+"D:\quake2\code\ctf\m_move.c"
+"D:\quake2\code\ctf\p_client.c"
+"D:\quake2\code\ctf\p_hud.c"
+"D:\quake2\code\ctf\p_menu.c"
+"D:\quake2\code\ctf\p_trail.c"
+"D:\quake2\code\ctf\p_view.c"
+"D:\quake2\code\ctf\p_weapon.c"
+"D:\quake2\code\ctf\q_shared.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB38.tmp" 
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB39.tmp" with contents
+[
+kernel32.lib user32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:".\debug/gamex86.pdb" /map:".\debug/gamex86.map" /debug /machine:I386 /def:".\ctf.def" /out:".\debug\gamex86.dll" /implib:".\debug/gamex86.lib" /pdbtype:sept 
+.\debug\g_ai.obj
+.\debug\g_chase.obj
+.\debug\g_cmds.obj
+.\debug\g_combat.obj
+.\debug\g_ctf.obj
+.\debug\g_func.obj
+.\debug\g_items.obj
+.\debug\g_main.obj
+.\debug\g_misc.obj
+.\debug\g_monster.obj
+.\debug\g_phys.obj
+.\debug\g_save.obj
+.\debug\g_spawn.obj
+.\debug\g_svcmds.obj
+.\debug\g_target.obj
+.\debug\g_trigger.obj
+.\debug\g_utils.obj
+.\debug\g_weapon.obj
+.\debug\m_move.obj
+.\debug\p_client.obj
+.\debug\p_hud.obj
+.\debug\p_menu.obj
+.\debug\p_trail.obj
+.\debug\p_view.obj
+.\debug\p_weapon.obj
+.\debug\q_shared.obj
+]
+Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB39.tmp"
+<h3>Output Window</h3>
+Compiling...
+g_ai.c
+g_chase.c
+g_cmds.c
+g_combat.c
+g_ctf.c
+g_func.c
+g_items.c
+g_main.c
+g_misc.c
+g_monster.c
+g_phys.c
+g_save.c
+g_spawn.c
+g_svcmds.c
+g_target.c
+g_trigger.c
+g_utils.c
+g_weapon.c
+m_move.c
+p_client.c
+p_hud.c
+p_menu.c
+p_trail.c
+p_view.c
+p_weapon.c
+q_shared.c
+Linking...
+LINK : warning LNK4075: ignoring /EDITANDCONTINUE due to /INCREMENTAL:NO specification
+   Creating library .\debug/gamex86.lib and object .\debug/gamex86.exp
+
+
+
+<h3>Results</h3>
+gamex86.dll - 0 error(s), 1 warning(s)
+<h3>
+--------------------Configuration: game - Win32 Debug--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB3E.tmp" with contents
+[
+/nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "BUILDING_REF_GL" /FR".\debug/" /Fp".\debug/game.pch" /YX /Fo".\debug/" /Fd".\debug/" /FD /c 
+"D:\quake2\code\game\g_ai.c"
+"D:\quake2\code\game\g_chase.c"
+"D:\quake2\code\game\g_cmds.c"
+"D:\quake2\code\game\g_combat.c"
+"D:\quake2\code\game\g_func.c"
+"D:\quake2\code\game\g_items.c"
+"D:\quake2\code\game\g_main.c"
+"D:\quake2\code\game\g_misc.c"
+"D:\quake2\code\game\g_monster.c"
+"D:\quake2\code\game\g_phys.c"
+"D:\quake2\code\game\g_save.c"
+"D:\quake2\code\game\g_spawn.c"
+"D:\quake2\code\game\g_svcmds.c"
+"D:\quake2\code\game\g_target.c"
+"D:\quake2\code\game\g_trigger.c"
+"D:\quake2\code\game\g_turret.c"
+"D:\quake2\code\game\g_utils.c"
+"D:\quake2\code\game\g_weapon.c"
+"D:\quake2\code\game\m_actor.c"
+"D:\quake2\code\game\m_berserk.c"
+"D:\quake2\code\game\m_boss2.c"
+"D:\quake2\code\game\m_boss3.c"
+"D:\quake2\code\game\m_boss31.c"
+"D:\quake2\code\game\m_boss32.c"
+"D:\quake2\code\game\m_brain.c"
+"D:\quake2\code\game\m_chick.c"
+"D:\quake2\code\game\m_flash.c"
+"D:\quake2\code\game\m_flipper.c"
+"D:\quake2\code\game\m_float.c"
+"D:\quake2\code\game\m_flyer.c"
+"D:\quake2\code\game\m_gladiator.c"
+"D:\quake2\code\game\m_gunner.c"
+"D:\quake2\code\game\m_hover.c"
+"D:\quake2\code\game\m_infantry.c"
+"D:\quake2\code\game\m_insane.c"
+"D:\quake2\code\game\m_medic.c"
+"D:\quake2\code\game\m_move.c"
+"D:\quake2\code\game\m_mutant.c"
+"D:\quake2\code\game\m_parasite.c"
+"D:\quake2\code\game\m_soldier.c"
+"D:\quake2\code\game\m_supertank.c"
+"D:\quake2\code\game\m_tank.c"
+"D:\quake2\code\game\p_client.c"
+"D:\quake2\code\game\p_hud.c"
+"D:\quake2\code\game\p_trail.c"
+"D:\quake2\code\game\p_view.c"
+"D:\quake2\code\game\p_weapon.c"
+"D:\quake2\code\game\q_shared.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB3E.tmp" 
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB3F.tmp" with contents
+[
+kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:no /pdb:"..\debug/gamex86.pdb" /map:".\debug/gamex86.map" /debug /machine:I386 /def:".\game.def" /out:"..\debug\gamex86.dll" /implib:"..\debug/gamex86.lib" 
+.\debug\g_ai.obj
+.\debug\g_chase.obj
+.\debug\g_cmds.obj
+.\debug\g_combat.obj
+.\debug\g_func.obj
+.\debug\g_items.obj
+.\debug\g_main.obj
+.\debug\g_misc.obj
+.\debug\g_monster.obj
+.\debug\g_phys.obj
+.\debug\g_save.obj
+.\debug\g_spawn.obj
+.\debug\g_svcmds.obj
+.\debug\g_target.obj
+.\debug\g_trigger.obj
+.\debug\g_turret.obj
+.\debug\g_utils.obj
+.\debug\g_weapon.obj
+.\debug\m_actor.obj
+.\debug\m_berserk.obj
+.\debug\m_boss2.obj
+.\debug\m_boss3.obj
+.\debug\m_boss31.obj
+.\debug\m_boss32.obj
+.\debug\m_brain.obj
+.\debug\m_chick.obj
+.\debug\m_flash.obj
+.\debug\m_flipper.obj
+.\debug\m_float.obj
+.\debug\m_flyer.obj
+.\debug\m_gladiator.obj
+.\debug\m_gunner.obj
+.\debug\m_hover.obj
+.\debug\m_infantry.obj
+.\debug\m_insane.obj
+.\debug\m_medic.obj
+.\debug\m_move.obj
+.\debug\m_mutant.obj
+.\debug\m_parasite.obj
+.\debug\m_soldier.obj
+.\debug\m_supertank.obj
+.\debug\m_tank.obj
+.\debug\p_client.obj
+.\debug\p_hud.obj
+.\debug\p_trail.obj
+.\debug\p_view.obj
+.\debug\p_weapon.obj
+.\debug\q_shared.obj
+]
+Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB3F.tmp"
+<h3>Output Window</h3>
+Compiling...
+g_ai.c
+g_chase.c
+g_cmds.c
+g_combat.c
+g_func.c
+g_items.c
+g_main.c
+g_misc.c
+g_monster.c
+g_phys.c
+g_save.c
+g_spawn.c
+g_svcmds.c
+g_target.c
+g_trigger.c
+g_turret.c
+g_utils.c
+g_weapon.c
+m_actor.c
+m_berserk.c
+m_boss2.c
+m_boss3.c
+m_boss31.c
+m_boss32.c
+m_brain.c
+m_chick.c
+m_flash.c
+m_flipper.c
+m_float.c
+m_flyer.c
+m_gladiator.c
+m_gunner.c
+m_hover.c
+m_infantry.c
+m_insane.c
+m_medic.c
+m_move.c
+m_mutant.c
+m_parasite.c
+m_soldier.c
+m_supertank.c
+m_tank.c
+p_client.c
+p_hud.c
+p_trail.c
+p_view.c
+p_weapon.c
+q_shared.c
+Linking...
+LINK : warning LNK4075: ignoring /EDITANDCONTINUE due to /INCREMENTAL:NO specification
+   Creating library ..\debug/gamex86.lib and object ..\debug/gamex86.exp
+
+
+
+<h3>Results</h3>
+gamex86.dll - 0 error(s), 1 warning(s)
+<h3>
+--------------------Configuration: quake2 - Win32 Debug--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating command line "rc.exe /l 0x409 /fo".\debug/q2.res" /i "win32" /d "_DEBUG" "D:\quake2\code\win32\q2.rc"" 
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB44.tmp" with contents
+[
+/nologo /G5 /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR".\debug/" /Fp".\debug/quake2.pch" /YX /Fo".\debug/" /Fd".\debug/" /FD /c 
+"D:\quake2\code\win32\cd_win.c"
+"D:\quake2\code\client\cl_cin.c"
+"D:\quake2\code\client\cl_ents.c"
+"D:\quake2\code\client\cl_fx.c"
+"D:\quake2\code\client\cl_input.c"
+"D:\quake2\code\client\cl_inv.c"
+"D:\quake2\code\client\cl_main.c"
+"D:\quake2\code\client\cl_newfx.c"
+"D:\quake2\code\client\cl_parse.c"
+"D:\quake2\code\client\cl_pred.c"
+"D:\quake2\code\client\cl_scrn.c"
+"D:\quake2\code\client\cl_tent.c"
+"D:\quake2\code\client\cl_view.c"
+"D:\quake2\code\qcommon\cmd.c"
+"D:\quake2\code\qcommon\cmodel.c"
+"D:\quake2\code\qcommon\common.c"
+"D:\quake2\code\win32\conproc.c"
+"D:\quake2\code\client\console.c"
+"D:\quake2\code\qcommon\crc.c"
+"D:\quake2\code\qcommon\cvar.c"
+"D:\quake2\code\qcommon\files.c"
+"D:\quake2\code\win32\in_win.c"
+"D:\quake2\code\client\keys.c"
+"D:\quake2\code\game\m_flash.c"
+"D:\quake2\code\qcommon\md4.c"
+"D:\quake2\code\client\menu.c"
+"D:\quake2\code\qcommon\net_chan.c"
+"D:\quake2\code\win32\net_wins.c"
+"D:\quake2\code\qcommon\pmove.c"
+"D:\quake2\code\game\q_shared.c"
+"D:\quake2\code\win32\q_shwin.c"
+"D:\quake2\code\client\qmenu.c"
+"D:\quake2\code\client\snd_dma.c"
+"D:\quake2\code\client\snd_mem.c"
+"D:\quake2\code\client\snd_mix.c"
+"D:\quake2\code\win32\snd_win.c"
+"D:\quake2\code\server\sv_ccmds.c"
+"D:\quake2\code\server\sv_ents.c"
+"D:\quake2\code\server\sv_game.c"
+"D:\quake2\code\server\sv_init.c"
+"D:\quake2\code\server\sv_main.c"
+"D:\quake2\code\server\sv_send.c"
+"D:\quake2\code\server\sv_user.c"
+"D:\quake2\code\server\sv_world.c"
+"D:\quake2\code\win32\sys_win.c"
+"D:\quake2\code\win32\vid_dll.c"
+"D:\quake2\code\win32\vid_menu.c"
+"D:\quake2\code\client\x86.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB44.tmp" 
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB45.tmp" with contents
+[
+winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /incremental:no /pdb:".\debug/quake2.pdb" /map:".\debug/quake2.map" /debug /machine:I386 /out:".\debug/quake2.exe" 
+.\debug\cd_win.obj
+.\debug\cl_cin.obj
+.\debug\cl_ents.obj
+.\debug\cl_fx.obj
+.\debug\cl_input.obj
+.\debug\cl_inv.obj
+.\debug\cl_main.obj
+.\debug\cl_newfx.obj
+.\debug\cl_parse.obj
+.\debug\cl_pred.obj
+.\debug\cl_scrn.obj
+.\debug\cl_tent.obj
+.\debug\cl_view.obj
+.\debug\cmd.obj
+.\debug\cmodel.obj
+.\debug\common.obj
+.\debug\conproc.obj
+.\debug\console.obj
+.\debug\crc.obj
+.\debug\cvar.obj
+.\debug\files.obj
+.\debug\in_win.obj
+.\debug\keys.obj
+.\debug\m_flash.obj
+.\debug\md4.obj
+.\debug\menu.obj
+.\debug\net_chan.obj
+.\debug\net_wins.obj
+.\debug\pmove.obj
+.\debug\q_shared.obj
+.\debug\q_shwin.obj
+.\debug\qmenu.obj
+.\debug\snd_dma.obj
+.\debug\snd_mem.obj
+.\debug\snd_mix.obj
+.\debug\snd_win.obj
+.\debug\sv_ccmds.obj
+.\debug\sv_ents.obj
+.\debug\sv_game.obj
+.\debug\sv_init.obj
+.\debug\sv_main.obj
+.\debug\sv_send.obj
+.\debug\sv_user.obj
+.\debug\sv_world.obj
+.\debug\sys_win.obj
+.\debug\vid_dll.obj
+.\debug\vid_menu.obj
+.\debug\x86.obj
+.\debug\q2.res
+]
+Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB45.tmp"
+<h3>Output Window</h3>
+Compiling resources...
+Compiling...
+cd_win.c
+cl_cin.c
+cl_ents.c
+cl_fx.c
+cl_input.c
+D:\quake2\code\client\cl_input.c(460) : warning C4700: local variable 'buf' used without having been initialized
+cl_inv.c
+cl_main.c
+cl_newfx.c
+cl_parse.c
+cl_pred.c
+cl_scrn.c
+cl_tent.c
+cl_view.c
+cmd.c
+cmodel.c
+common.c
+conproc.c
+console.c
+crc.c
+cvar.c
+files.c
+in_win.c
+d:\quake2\code\win32\in_win.c(555) : warning C4715: 'RawValuePointer' : not all control paths return a value
+keys.c
+m_flash.c
+md4.c
+menu.c
+d:\quake2\code\client\menu.c(3561) : warning C4715: 'PlayerConfig_ScanDirectories' : not all control paths return a value
+net_chan.c
+net_wins.c
+d:\quake2\code\win32\net_wins.c(105) : warning C4715: 'NET_CompareAdr' : not all control paths return a value
+d:\quake2\code\win32\net_wins.c(135) : warning C4715: 'NET_CompareBaseAdr' : not all control paths return a value
+pmove.c
+q_shared.c
+q_shwin.c
+qmenu.c
+snd_dma.c
+snd_mem.c
+snd_mix.c
+snd_win.c
+sv_ccmds.c
+sv_ents.c
+sv_game.c
+sv_init.c
+sv_main.c
+sv_send.c
+sv_user.c
+sv_world.c
+sys_win.c
+vid_dll.c
+vid_menu.c
+x86.c
+Linking...
+LINK : warning LNK4075: ignoring /EDITANDCONTINUE due to /INCREMENTAL:NO specification
+
+
+
+<h3>Results</h3>
+quake2.exe - 0 error(s), 6 warning(s)
+<h3>
+--------------------Configuration: ref_gl - Win32 Debug--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB48.tmp" with contents
+[
+/nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR".\debug/" /Fp".\debug/ref_gl.pch" /YX /Fo".\debug/" /Fd".\debug/" /FD /c 
+"D:\quake2\code\ref_gl\gl_draw.c"
+"D:\quake2\code\ref_gl\gl_image.c"
+"D:\quake2\code\ref_gl\gl_light.c"
+"D:\quake2\code\ref_gl\gl_mesh.c"
+"D:\quake2\code\ref_gl\gl_model.c"
+"D:\quake2\code\ref_gl\gl_rmain.c"
+"D:\quake2\code\ref_gl\gl_rmisc.c"
+"D:\quake2\code\ref_gl\gl_rsurf.c"
+"D:\quake2\code\ref_gl\gl_warp.c"
+"D:\quake2\code\win32\glw_imp.c"
+"D:\quake2\code\game\q_shared.c"
+"D:\quake2\code\win32\q_shwin.c"
+"D:\quake2\code\win32\qgl_win.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB48.tmp" 
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB49.tmp" with contents
+[
+kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\debug/ref_gl.pdb" /map:".\debug/ref_gl.map" /debug /machine:I386 /def:".\ref_gl.def" /out:"..\debug/ref_gl.dll" /implib:"..\debug/ref_gl.lib" 
+.\debug\gl_draw.obj
+.\debug\gl_image.obj
+.\debug\gl_light.obj
+.\debug\gl_mesh.obj
+.\debug\gl_model.obj
+.\debug\gl_rmain.obj
+.\debug\gl_rmisc.obj
+.\debug\gl_rsurf.obj
+.\debug\gl_warp.obj
+.\debug\glw_imp.obj
+.\debug\q_shared.obj
+.\debug\q_shwin.obj
+.\debug\qgl_win.obj
+]
+Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB49.tmp"
+<h3>Output Window</h3>
+Compiling...
+gl_draw.c
+gl_image.c
+D:\quake2\code\ref_gl\gl_image.c(1204) : warning C4715: 'GL_Upload8' : not all control paths return a value
+gl_light.c
+gl_mesh.c
+gl_model.c
+gl_rmain.c
+D:\quake2\code\ref_gl\gl_rmain.c(1322) : warning C4715: 'R_Init' : not all control paths return a value
+gl_rmisc.c
+gl_rsurf.c
+gl_warp.c
+glw_imp.c
+q_shared.c
+q_shwin.c
+qgl_win.c
+Linking...
+LINK : warning LNK4075: ignoring /EDITANDCONTINUE due to /INCREMENTAL:NO specification
+   Creating library ..\debug/ref_gl.lib and object ..\debug/ref_gl.exp
+
+
+
+<h3>Results</h3>
+ref_gl.dll - 0 error(s), 3 warning(s)
+<h3>
+--------------------Configuration: ref_soft - Win32 Debug--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB4E.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_varsa.obj /Zm /Zi .\r_varsa.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB4E.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB4F.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_surf8.obj /Zm /Zi .\r_surf8.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB4F.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB50.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_spr8.obj /Zm /Zi .\r_spr8.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB50.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB51.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_scana.obj /Zm /Zi .\r_scana.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB51.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB52.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_polysa.obj /Zm /Zi .\r_polysa.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB52.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB53.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_edgea.obj /Zm /Zi .\r_edgea.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB53.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB54.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_drawa.obj /Zm /Zi .\r_drawa.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB54.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB55.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_draw16.obj /Zm /Zi .\r_draw16.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB55.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB56.bat" with contents
+[
+@echo off
+ml /c /Cp /coff /Fo.\..\debug\r_aclipa.obj /Zm /Zi .\r_aclipa.asm
+]
+Creating command line "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB56.bat"
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB57.tmp" with contents
+[
+/nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR".\debug/" /Fp".\debug/ref_soft.pch" /YX /Fo".\debug/" /Fd".\debug/" /FD /c 
+"D:\quake2\code\game\q_shared.c"
+"D:\quake2\code\win32\q_shwin.c"
+"D:\quake2\code\ref_soft\r_aclip.c"
+"D:\quake2\code\ref_soft\r_alias.c"
+"D:\quake2\code\ref_soft\r_bsp.c"
+"D:\quake2\code\ref_soft\r_draw.c"
+"D:\quake2\code\ref_soft\r_edge.c"
+"D:\quake2\code\ref_soft\r_image.c"
+"D:\quake2\code\ref_soft\r_light.c"
+"D:\quake2\code\ref_soft\r_main.c"
+"D:\quake2\code\ref_soft\r_misc.c"
+"D:\quake2\code\ref_soft\r_model.c"
+"D:\quake2\code\ref_soft\r_part.c"
+"D:\quake2\code\ref_soft\r_poly.c"
+"D:\quake2\code\ref_soft\r_polyse.c"
+"D:\quake2\code\ref_soft\r_rast.c"
+"D:\quake2\code\ref_soft\r_scan.c"
+"D:\quake2\code\ref_soft\r_sprite.c"
+"D:\quake2\code\ref_soft\r_surf.c"
+"D:\quake2\code\win32\rw_ddraw.c"
+"D:\quake2\code\win32\rw_dib.c"
+"D:\quake2\code\win32\rw_imp.c"
+]
+Creating command line "cl.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB57.tmp" 
+Performing Custom Build Step on .\r_varsa.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_varsa.asm
+Performing Custom Build Step on .\r_surf8.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_surf8.asm
+Performing Custom Build Step on .\r_spr8.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_spr8.asm
+Performing Custom Build Step on .\r_scana.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_scana.asm
+Performing Custom Build Step on .\r_polysa.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_polysa.asm
+Performing Custom Build Step on .\r_edgea.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_edgea.asm
+Performing Custom Build Step on .\r_drawa.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_drawa.asm
+Performing Custom Build Step on .\r_draw16.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_draw16.asm
+Performing Custom Build Step on .\r_aclipa.asm
+Microsoft (R) Macro Assembler Version 6.15.8803
+Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.
+
+ Assembling: .\r_aclipa.asm
+Creating temporary file "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB58.tmp" with contents
+[
+kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\debug/ref_soft.pdb" /map:".\debug/ref_soft.map" /debug /machine:I386 /nodefaultlib:"libc" /def:".\ref_soft.def" /out:"..\debug/ref_soft.dll" /implib:"..\debug/ref_soft.lib" 
+.\debug\q_shared.obj
+.\debug\q_shwin.obj
+.\debug\r_aclip.obj
+.\debug\r_alias.obj
+.\debug\r_bsp.obj
+.\debug\r_draw.obj
+.\debug\r_edge.obj
+.\debug\r_image.obj
+.\debug\r_light.obj
+.\debug\r_main.obj
+.\debug\r_misc.obj
+.\debug\r_model.obj
+.\debug\r_part.obj
+.\debug\r_poly.obj
+.\debug\r_polyse.obj
+.\debug\r_rast.obj
+.\debug\r_scan.obj
+.\debug\r_sprite.obj
+.\debug\r_surf.obj
+.\debug\rw_ddraw.obj
+.\debug\rw_dib.obj
+.\debug\rw_imp.obj
+\quake2\code\debug\r_aclipa.obj
+\quake2\code\debug\r_draw16.obj
+\quake2\code\debug\r_drawa.obj
+\quake2\code\debug\r_edgea.obj
+\quake2\code\debug\r_polysa.obj
+\quake2\code\debug\r_scana.obj
+\quake2\code\debug\r_spr8.obj
+\quake2\code\debug\r_surf8.obj
+\quake2\code\debug\r_varsa.obj
+]
+Creating command line "link.exe @C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\RSPB58.tmp"
+<h3>Output Window</h3>
+Compiling...
+q_shared.c
+q_shwin.c
+r_aclip.c
+r_alias.c
+r_bsp.c
+r_draw.c
+r_edge.c
+r_image.c
+r_light.c
+r_main.c
+r_misc.c
+r_model.c
+r_part.c
+r_poly.c
+r_polyse.c
+r_rast.c
+r_scan.c
+r_sprite.c
+r_surf.c
+rw_ddraw.c
+rw_dib.c
+rw_imp.c
+Linking...
+LINK : warning LNK4075: ignoring /EDITANDCONTINUE due to /INCREMENTAL:NO specification
+   Creating library ..\debug/ref_soft.lib and object ..\debug/ref_soft.exp
+
+
+
+<h3>Results</h3>
+ref_soft.dll - 0 error(s), 1 warning(s)
+</pre>
+</body>
+</html>
--- /dev/null
+++ b/readme.txt
@@ -1,0 +1,29 @@
+
+This is the complete source code for Quake 2, version 3.19, buildable with
+visual C++ 6.0.  The linux version should be buildable, but we haven't
+tested it for the release.
+
+The code is all licensed under the terms of the GPL (gnu public license).  
+You should read the entire license, but the gist of it is that you can do 
+anything you want with the code, including sell your new version.  The catch 
+is that if you distribute new binary versions, you are required to make the 
+entire source code available for free to everyone.
+
+The primary intent of this release is for entertainment and educational 
+purposes, but the GPL does allow commercial exploitation if you obey the 
+full license.  If you want to do something commercial and you just can't bear 
+to have your source changes released, we could still negotiate a separate 
+license agreement (for $$$), but I would encourage you to just live with the 
+GPL.
+
+All of the Q2 data files remain copyrighted and licensed under the 
+original terms, so you cannot redistribute data from the original game, but if 
+you do a true total conversion, you can create a standalone game based on 
+this code.
+
+Thanks to Robert Duffy for doing the grunt work of building this release.
+
+John Carmack
+Id Software
+
+
--- /dev/null
+++ b/ref_gl/anorms.h
@@ -1,0 +1,181 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+{-0.525731, 0.000000, 0.850651}, 
+{-0.442863, 0.238856, 0.864188}, 
+{-0.295242, 0.000000, 0.955423}, 
+{-0.309017, 0.500000, 0.809017}, 
+{-0.162460, 0.262866, 0.951056}, 
+{0.000000, 0.000000, 1.000000}, 
+{0.000000, 0.850651, 0.525731}, 
+{-0.147621, 0.716567, 0.681718}, 
+{0.147621, 0.716567, 0.681718}, 
+{0.000000, 0.525731, 0.850651}, 
+{0.309017, 0.500000, 0.809017}, 
+{0.525731, 0.000000, 0.850651}, 
+{0.295242, 0.000000, 0.955423}, 
+{0.442863, 0.238856, 0.864188}, 
+{0.162460, 0.262866, 0.951056}, 
+{-0.681718, 0.147621, 0.716567}, 
+{-0.809017, 0.309017, 0.500000}, 
+{-0.587785, 0.425325, 0.688191}, 
+{-0.850651, 0.525731, 0.000000}, 
+{-0.864188, 0.442863, 0.238856}, 
+{-0.716567, 0.681718, 0.147621}, 
+{-0.688191, 0.587785, 0.425325}, 
+{-0.500000, 0.809017, 0.309017}, 
+{-0.238856, 0.864188, 0.442863}, 
+{-0.425325, 0.688191, 0.587785}, 
+{-0.716567, 0.681718, -0.147621}, 
+{-0.500000, 0.809017, -0.309017}, 
+{-0.525731, 0.850651, 0.000000}, 
+{0.000000, 0.850651, -0.525731}, 
+{-0.238856, 0.864188, -0.442863}, 
+{0.000000, 0.955423, -0.295242}, 
+{-0.262866, 0.951056, -0.162460}, 
+{0.000000, 1.000000, 0.000000}, 
+{0.000000, 0.955423, 0.295242}, 
+{-0.262866, 0.951056, 0.162460}, 
+{0.238856, 0.864188, 0.442863}, 
+{0.262866, 0.951056, 0.162460}, 
+{0.500000, 0.809017, 0.309017}, 
+{0.238856, 0.864188, -0.442863}, 
+{0.262866, 0.951056, -0.162460}, 
+{0.500000, 0.809017, -0.309017}, 
+{0.850651, 0.525731, 0.000000}, 
+{0.716567, 0.681718, 0.147621}, 
+{0.716567, 0.681718, -0.147621}, 
+{0.525731, 0.850651, 0.000000}, 
+{0.425325, 0.688191, 0.587785}, 
+{0.864188, 0.442863, 0.238856}, 
+{0.688191, 0.587785, 0.425325}, 
+{0.809017, 0.309017, 0.500000}, 
+{0.681718, 0.147621, 0.716567}, 
+{0.587785, 0.425325, 0.688191}, 
+{0.955423, 0.295242, 0.000000}, 
+{1.000000, 0.000000, 0.000000}, 
+{0.951056, 0.162460, 0.262866}, 
+{0.850651, -0.525731, 0.000000}, 
+{0.955423, -0.295242, 0.000000}, 
+{0.864188, -0.442863, 0.238856}, 
+{0.951056, -0.162460, 0.262866}, 
+{0.809017, -0.309017, 0.500000}, 
+{0.681718, -0.147621, 0.716567}, 
+{0.850651, 0.000000, 0.525731}, 
+{0.864188, 0.442863, -0.238856}, 
+{0.809017, 0.309017, -0.500000}, 
+{0.951056, 0.162460, -0.262866}, 
+{0.525731, 0.000000, -0.850651}, 
+{0.681718, 0.147621, -0.716567}, 
+{0.681718, -0.147621, -0.716567}, 
+{0.850651, 0.000000, -0.525731}, 
+{0.809017, -0.309017, -0.500000}, 
+{0.864188, -0.442863, -0.238856}, 
+{0.951056, -0.162460, -0.262866}, 
+{0.147621, 0.716567, -0.681718}, 
+{0.309017, 0.500000, -0.809017}, 
+{0.425325, 0.688191, -0.587785}, 
+{0.442863, 0.238856, -0.864188}, 
+{0.587785, 0.425325, -0.688191}, 
+{0.688191, 0.587785, -0.425325}, 
+{-0.147621, 0.716567, -0.681718}, 
+{-0.309017, 0.500000, -0.809017}, 
+{0.000000, 0.525731, -0.850651}, 
+{-0.525731, 0.000000, -0.850651}, 
+{-0.442863, 0.238856, -0.864188}, 
+{-0.295242, 0.000000, -0.955423}, 
+{-0.162460, 0.262866, -0.951056}, 
+{0.000000, 0.000000, -1.000000}, 
+{0.295242, 0.000000, -0.955423}, 
+{0.162460, 0.262866, -0.951056}, 
+{-0.442863, -0.238856, -0.864188}, 
+{-0.309017, -0.500000, -0.809017}, 
+{-0.162460, -0.262866, -0.951056}, 
+{0.000000, -0.850651, -0.525731}, 
+{-0.147621, -0.716567, -0.681718}, 
+{0.147621, -0.716567, -0.681718}, 
+{0.000000, -0.525731, -0.850651}, 
+{0.309017, -0.500000, -0.809017}, 
+{0.442863, -0.238856, -0.864188}, 
+{0.162460, -0.262866, -0.951056}, 
+{0.238856, -0.864188, -0.442863}, 
+{0.500000, -0.809017, -0.309017}, 
+{0.425325, -0.688191, -0.587785}, 
+{0.716567, -0.681718, -0.147621}, 
+{0.688191, -0.587785, -0.425325}, 
+{0.587785, -0.425325, -0.688191}, 
+{0.000000, -0.955423, -0.295242}, 
+{0.000000, -1.000000, 0.000000}, 
+{0.262866, -0.951056, -0.162460}, 
+{0.000000, -0.850651, 0.525731}, 
+{0.000000, -0.955423, 0.295242}, 
+{0.238856, -0.864188, 0.442863}, 
+{0.262866, -0.951056, 0.162460}, 
+{0.500000, -0.809017, 0.309017}, 
+{0.716567, -0.681718, 0.147621}, 
+{0.525731, -0.850651, 0.000000}, 
+{-0.238856, -0.864188, -0.442863}, 
+{-0.500000, -0.809017, -0.309017}, 
+{-0.262866, -0.951056, -0.162460}, 
+{-0.850651, -0.525731, 0.000000}, 
+{-0.716567, -0.681718, -0.147621}, 
+{-0.716567, -0.681718, 0.147621}, 
+{-0.525731, -0.850651, 0.000000}, 
+{-0.500000, -0.809017, 0.309017}, 
+{-0.238856, -0.864188, 0.442863}, 
+{-0.262866, -0.951056, 0.162460}, 
+{-0.864188, -0.442863, 0.238856}, 
+{-0.809017, -0.309017, 0.500000}, 
+{-0.688191, -0.587785, 0.425325}, 
+{-0.681718, -0.147621, 0.716567}, 
+{-0.442863, -0.238856, 0.864188}, 
+{-0.587785, -0.425325, 0.688191}, 
+{-0.309017, -0.500000, 0.809017}, 
+{-0.147621, -0.716567, 0.681718}, 
+{-0.425325, -0.688191, 0.587785}, 
+{-0.162460, -0.262866, 0.951056}, 
+{0.442863, -0.238856, 0.864188}, 
+{0.162460, -0.262866, 0.951056}, 
+{0.309017, -0.500000, 0.809017}, 
+{0.147621, -0.716567, 0.681718}, 
+{0.000000, -0.525731, 0.850651}, 
+{0.425325, -0.688191, 0.587785}, 
+{0.587785, -0.425325, 0.688191}, 
+{0.688191, -0.587785, 0.425325}, 
+{-0.955423, 0.295242, 0.000000}, 
+{-0.951056, 0.162460, 0.262866}, 
+{-1.000000, 0.000000, 0.000000}, 
+{-0.850651, 0.000000, 0.525731}, 
+{-0.955423, -0.295242, 0.000000}, 
+{-0.951056, -0.162460, 0.262866}, 
+{-0.864188, 0.442863, -0.238856}, 
+{-0.951056, 0.162460, -0.262866}, 
+{-0.809017, 0.309017, -0.500000}, 
+{-0.864188, -0.442863, -0.238856}, 
+{-0.951056, -0.162460, -0.262866}, 
+{-0.809017, -0.309017, -0.500000}, 
+{-0.681718, 0.147621, -0.716567}, 
+{-0.681718, -0.147621, -0.716567}, 
+{-0.850651, 0.000000, -0.525731}, 
+{-0.688191, 0.587785, -0.425325}, 
+{-0.587785, 0.425325, -0.688191}, 
+{-0.425325, 0.688191, -0.587785}, 
+{-0.425325, -0.688191, -0.587785}, 
+{-0.587785, -0.425325, -0.688191}, 
+{-0.688191, -0.587785, -0.425325}, 
--- /dev/null
+++ b/ref_gl/anormtab.h
@@ -1,0 +1,37 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+{
+{1.23,1.30,1.47,1.35,1.56,1.71,1.37,1.38,1.59,1.60,1.79,1.97,1.88,1.92,1.79,1.02,0.93,1.07,0.82,0.87,0.88,0.94,0.96,1.14,1.11,0.82,0.83,0.89,0.89,0.86,0.94,0.91,1.00,1.21,0.98,1.48,1.30,1.57,0.96,1.07,1.14,1.60,1.61,1.40,1.37,1.72,1.78,1.79,1.93,1.99,1.90,1.68,1.71,1.86,1.60,1.68,1.78,1.86,1.93,1.99,1.97,1.44,1.22,1.49,0.93,0.99,0.99,1.23,1.22,1.44,1.49,0.89,0.89,0.97,0.91,0.98,1.19,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.19,0.98,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.87,0.93,0.94,1.02,1.30,1.07,1.35,1.38,1.11,1.56,1.92,1.79,1.79,1.59,1.60,1.72,1.90,1.79,0.80,0.85,0.79,0.93,0.80,0.85,0.77,0.74,0.72,0.77,0.74,0.72,0.70,0.70,0.71,0.76,0.73,0.79,0.79,0.73,0.76,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.26,1.26,1.48,1.23,1.50,1.71,1.14,1.19,1.38,1.46,1.64,1.94,1.87,1.84,1.71,1.02,0.92,1.00,0.79,0.85,0.84,0.91,0.90,0.98,0.99,0.77,0.77,0.83,0.82,0.79,0.86,0.84,0.92,0.99,0.91,1.24,1.03,1.33,0.88,0.94,0.97,1.41,1.39,1.18,1.11,1.51,1.61,1.59,1.80,1.91,1.76,1.54,1.65,1.76,1.70,1.70,1.85,1.85,1.97,1.99,1.93,1.28,1.09,1.39,0.92,0.97,0.99,1.18,1.26,1.52,1.48,0.83,0.85,0.90,0.88,0.93,1.00,0.77,0.73,0.78,0.72,0.71,0.74,0.75,0.79,0.86,0.81,0.75,0.81,0.79,0.96,0.88,0.94,0.86,0.93,0.92,0.85,1.08,1.33,1.05,1.55,1.31,1.01,1.05,1.27,1.31,1.60,1.47,1.70,1.54,1.76,1.76,1.57,0.93,0.90,0.99,0.88,0.88,0.95,0.97,1.11,1.39,1.20,0.92,0.97,1.01,1.10,1.39,1.22,1.51,1.58,1.32,1.64,1.97,1.85,1.91,1.77,1.74,1.88,1.99,1.91,0.79,0.86,0.80,0.94,0.84,0.88,0.74,0.74,0.71,0.82,0.77,0.76,0.70,0.73,0.72,0.73,0.70,0.74,0.85,0.77,0.82,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.34,1.27,1.53,1.17,1.46,1.71,0.98,1.05,1.20,1.34,1.48,1.86,1.82,1.71,1.62,1.09,0.94,0.99,0.79,0.85,0.82,0.90,0.87,0.93,0.96,0.76,0.74,0.79,0.76,0.74,0.79,0.78,0.85,0.92,0.85,1.00,0.93,1.06,0.81,0.86,0.89,1.16,1.12,0.97,0.95,1.28,1.38,1.35,1.60,1.77,1.57,1.33,1.50,1.58,1.69,1.63,1.82,1.74,1.91,1.92,1.80,1.04,0.97,1.21,0.90,0.93,0.97,1.05,1.21,1.48,1.37,0.77,0.80,0.84,0.85,0.88,0.92,0.73,0.71,0.74,0.74,0.71,0.75,0.73,0.79,0.84,0.78,0.79,0.86,0.81,1.05,0.94,0.99,0.90,0.95,0.92,0.86,1.24,1.44,1.14,1.59,1.34,1.02,1.27,1.50,1.49,1.80,1.69,1.86,1.72,1.87,1.80,1.69,1.00,0.98,1.23,0.95,0.96,1.09,1.16,1.37,1.63,1.46,0.99,1.10,1.25,1.24,1.51,1.41,1.67,1.77,1.55,1.72,1.95,1.89,1.98,1.91,1.86,1.97,1.99,1.94,0.81,0.89,0.85,0.98,0.90,0.94,0.75,0.78,0.73,0.89,0.83,0.82,0.72,0.77,0.76,0.72,0.70,0.71,0.91,0.83,0.89,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.46,1.34,1.60,1.16,1.46,1.71,0.94,0.99,1.05,1.26,1.33,1.74,1.76,1.57,1.54,1.23,0.98,1.05,0.83,0.89,0.84,0.92,0.87,0.91,0.96,0.78,0.74,0.79,0.72,0.72,0.75,0.76,0.80,0.88,0.83,0.94,0.87,0.95,0.76,0.80,0.82,0.97,0.96,0.89,0.88,1.08,1.11,1.10,1.37,1.59,1.37,1.07,1.27,1.34,1.57,1.45,1.69,1.55,1.77,1.79,1.60,0.93,0.90,0.99,0.86,0.87,0.93,0.96,1.07,1.35,1.18,0.73,0.76,0.77,0.81,0.82,0.85,0.70,0.71,0.72,0.78,0.73,0.77,0.73,0.79,0.82,0.76,0.83,0.90,0.84,1.18,0.98,1.03,0.92,0.95,0.90,0.86,1.32,1.45,1.15,1.53,1.27,0.99,1.42,1.65,1.58,1.93,1.83,1.94,1.81,1.88,1.74,1.70,1.19,1.17,1.44,1.11,1.15,1.36,1.41,1.61,1.81,1.67,1.22,1.34,1.50,1.42,1.65,1.61,1.82,1.91,1.75,1.80,1.89,1.89,1.98,1.99,1.94,1.98,1.92,1.87,0.86,0.95,0.92,1.14,0.98,1.03,0.79,0.84,0.77,0.97,0.90,0.89,0.76,0.82,0.82,0.74,0.72,0.71,0.98,0.89,0.97,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.60,1.44,1.68,1.22,1.49,1.71,0.93,0.99,0.99,1.23,1.22,1.60,1.68,1.44,1.49,1.40,1.14,1.19,0.89,0.96,0.89,0.97,0.89,0.91,0.98,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.91,0.83,0.89,0.72,0.76,0.76,0.89,0.89,0.82,0.82,0.98,0.96,0.97,1.14,1.40,1.19,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.70,0.72,0.73,0.77,0.76,0.79,0.70,0.72,0.71,0.82,0.77,0.80,0.74,0.79,0.80,0.74,0.87,0.93,0.85,1.23,1.02,1.02,0.93,0.93,0.87,0.85,1.30,1.35,1.07,1.38,1.11,0.94,1.47,1.71,1.56,1.97,1.88,1.92,1.79,1.79,1.59,1.60,1.30,1.35,1.56,1.37,1.38,1.59,1.60,1.79,1.92,1.79,1.48,1.57,1.72,1.61,1.78,1.79,1.93,1.99,1.90,1.86,1.78,1.86,1.93,1.99,1.97,1.90,1.79,1.72,0.94,1.07,1.00,1.37,1.21,1.30,0.86,0.91,0.83,1.14,0.98,0.96,0.82,0.88,0.89,0.79,0.76,0.73,1.07,0.94,1.11,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.74,1.57,1.76,1.33,1.54,1.71,0.94,1.05,0.99,1.26,1.16,1.46,1.60,1.34,1.46,1.59,1.37,1.37,0.97,1.11,0.96,1.10,0.95,0.94,1.08,0.89,0.82,0.88,0.72,0.76,0.75,0.80,0.80,0.88,0.87,0.91,0.83,0.87,0.72,0.76,0.74,0.83,0.84,0.78,0.79,0.96,0.89,0.92,0.98,1.23,1.05,0.86,0.92,0.95,1.11,0.98,1.22,1.03,1.34,1.42,1.14,0.79,0.77,0.84,0.78,0.76,0.82,0.82,0.89,0.97,0.90,0.70,0.71,0.71,0.73,0.72,0.74,0.73,0.76,0.72,0.86,0.81,0.82,0.76,0.79,0.77,0.73,0.90,0.95,0.86,1.18,1.03,0.98,0.92,0.90,0.83,0.84,1.19,1.17,0.98,1.15,0.97,0.89,1.42,1.65,1.44,1.93,1.83,1.81,1.67,1.61,1.36,1.41,1.32,1.45,1.58,1.57,1.53,1.74,1.70,1.88,1.94,1.81,1.69,1.77,1.87,1.79,1.89,1.92,1.98,1.99,1.98,1.89,1.65,1.80,1.82,1.91,1.94,1.75,1.61,1.50,1.07,1.34,1.27,1.60,1.45,1.55,0.93,0.99,0.90,1.35,1.18,1.07,0.87,0.93,0.96,0.85,0.82,0.77,1.15,0.99,1.27,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.86,1.71,1.82,1.48,1.62,1.71,0.98,1.20,1.05,1.34,1.17,1.34,1.53,1.27,1.46,1.77,1.60,1.57,1.16,1.38,1.12,1.35,1.06,1.00,1.28,0.97,0.89,0.95,0.76,0.81,0.79,0.86,0.85,0.92,0.93,0.93,0.85,0.87,0.74,0.78,0.74,0.79,0.82,0.76,0.79,0.96,0.85,0.90,0.94,1.09,0.99,0.81,0.85,0.89,0.95,0.90,0.99,0.94,1.10,1.24,0.98,0.75,0.73,0.78,0.74,0.72,0.77,0.76,0.82,0.89,0.83,0.73,0.71,0.71,0.71,0.70,0.72,0.77,0.80,0.74,0.90,0.85,0.84,0.78,0.79,0.75,0.73,0.92,0.95,0.86,1.05,0.99,0.94,0.90,0.86,0.79,0.81,1.00,0.98,0.91,0.96,0.89,0.83,1.27,1.50,1.23,1.80,1.69,1.63,1.46,1.37,1.09,1.16,1.24,1.44,1.49,1.69,1.59,1.80,1.69,1.87,1.86,1.72,1.82,1.91,1.94,1.92,1.95,1.99,1.98,1.91,1.97,1.89,1.51,1.72,1.67,1.77,1.86,1.55,1.41,1.25,1.33,1.58,1.50,1.80,1.63,1.74,1.04,1.21,0.97,1.48,1.37,1.21,0.93,0.97,1.05,0.92,0.88,0.84,1.14,1.02,1.34,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.94,1.84,1.87,1.64,1.71,1.71,1.14,1.38,1.19,1.46,1.23,1.26,1.48,1.26,1.50,1.91,1.80,1.76,1.41,1.61,1.39,1.59,1.33,1.24,1.51,1.18,0.97,1.11,0.82,0.88,0.86,0.94,0.92,0.99,1.03,0.98,0.91,0.90,0.79,0.84,0.77,0.79,0.84,0.77,0.83,0.99,0.85,0.91,0.92,1.02,1.00,0.79,0.80,0.86,0.88,0.84,0.92,0.88,0.97,1.10,0.94,0.74,0.71,0.74,0.72,0.70,0.73,0.72,0.76,0.82,0.77,0.77,0.73,0.74,0.71,0.70,0.73,0.83,0.85,0.78,0.92,0.88,0.86,0.81,0.79,0.74,0.75,0.92,0.93,0.85,0.96,0.94,0.88,0.86,0.81,0.75,0.79,0.93,0.90,0.85,0.88,0.82,0.77,1.05,1.27,0.99,1.60,1.47,1.39,1.20,1.11,0.95,0.97,1.08,1.33,1.31,1.70,1.55,1.76,1.57,1.76,1.70,1.54,1.85,1.97,1.91,1.99,1.97,1.99,1.91,1.77,1.88,1.85,1.39,1.64,1.51,1.58,1.74,1.32,1.22,1.01,1.54,1.76,1.65,1.93,1.70,1.85,1.28,1.39,1.09,1.52,1.48,1.26,0.97,0.99,1.18,1.00,0.93,0.90,1.05,1.01,1.31,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.97,1.92,1.88,1.79,1.79,1.71,1.37,1.59,1.38,1.60,1.35,1.23,1.47,1.30,1.56,1.99,1.93,1.90,1.60,1.78,1.61,1.79,1.57,1.48,1.72,1.40,1.14,1.37,0.89,0.96,0.94,1.07,1.00,1.21,1.30,1.14,0.98,0.96,0.86,0.91,0.83,0.82,0.88,0.82,0.89,1.11,0.87,0.94,0.93,1.02,1.07,0.80,0.79,0.85,0.82,0.80,0.87,0.85,0.93,1.02,0.93,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.82,0.76,0.79,0.72,0.73,0.76,0.89,0.89,0.82,0.93,0.91,0.86,0.83,0.79,0.73,0.76,0.91,0.89,0.83,0.89,0.89,0.82,0.82,0.76,0.72,0.76,0.86,0.83,0.79,0.82,0.76,0.73,0.94,1.00,0.91,1.37,1.21,1.14,0.98,0.96,0.88,0.89,0.96,1.14,1.07,1.60,1.40,1.61,1.37,1.57,1.48,1.30,1.78,1.93,1.79,1.99,1.92,1.90,1.79,1.59,1.72,1.79,1.30,1.56,1.35,1.38,1.60,1.11,1.07,0.94,1.68,1.86,1.71,1.97,1.68,1.86,1.44,1.49,1.22,1.44,1.49,1.22,0.99,0.99,1.23,1.19,0.98,0.97,0.97,0.98,1.19,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.94,1.97,1.87,1.91,1.85,1.71,1.60,1.77,1.58,1.74,1.51,1.26,1.48,1.39,1.64,1.99,1.97,1.99,1.70,1.85,1.76,1.91,1.76,1.70,1.88,1.55,1.33,1.57,0.96,1.08,1.05,1.31,1.27,1.47,1.54,1.39,1.20,1.11,0.93,0.99,0.90,0.88,0.95,0.88,0.97,1.32,0.92,1.01,0.97,1.10,1.22,0.84,0.80,0.88,0.79,0.79,0.85,0.86,0.92,1.02,0.94,0.82,0.76,0.77,0.72,0.73,0.70,0.72,0.71,0.74,0.74,0.88,0.81,0.85,0.75,0.77,0.82,0.94,0.93,0.86,0.92,0.92,0.86,0.85,0.79,0.74,0.79,0.88,0.85,0.81,0.82,0.83,0.77,0.78,0.73,0.71,0.75,0.79,0.77,0.74,0.77,0.73,0.70,0.86,0.92,0.84,1.14,0.99,0.98,0.91,0.90,0.84,0.83,0.88,0.97,0.94,1.41,1.18,1.39,1.11,1.33,1.24,1.03,1.61,1.80,1.59,1.91,1.84,1.76,1.64,1.38,1.51,1.71,1.26,1.50,1.23,1.19,1.46,0.99,1.00,0.91,1.70,1.85,1.65,1.93,1.54,1.76,1.52,1.48,1.26,1.28,1.39,1.09,0.99,0.97,1.18,1.31,1.01,1.05,0.90,0.93,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.86,1.95,1.82,1.98,1.89,1.71,1.80,1.91,1.77,1.86,1.67,1.34,1.53,1.51,1.72,1.92,1.91,1.99,1.69,1.82,1.80,1.94,1.87,1.86,1.97,1.59,1.44,1.69,1.05,1.24,1.27,1.49,1.50,1.69,1.72,1.63,1.46,1.37,1.00,1.23,0.98,0.95,1.09,0.96,1.16,1.55,0.99,1.25,1.10,1.24,1.41,0.90,0.85,0.94,0.79,0.81,0.85,0.89,0.94,1.09,0.98,0.89,0.82,0.83,0.74,0.77,0.72,0.76,0.73,0.75,0.78,0.94,0.86,0.91,0.79,0.83,0.89,0.99,0.95,0.90,0.90,0.92,0.84,0.86,0.79,0.75,0.81,0.85,0.80,0.78,0.76,0.77,0.73,0.74,0.71,0.71,0.73,0.74,0.74,0.71,0.76,0.72,0.70,0.79,0.85,0.78,0.98,0.92,0.93,0.85,0.87,0.82,0.79,0.81,0.89,0.86,1.16,0.97,1.12,0.95,1.06,1.00,0.93,1.38,1.60,1.35,1.77,1.71,1.57,1.48,1.20,1.28,1.62,1.27,1.46,1.17,1.05,1.34,0.96,0.99,0.90,1.63,1.74,1.50,1.80,1.33,1.58,1.48,1.37,1.21,1.04,1.21,0.97,0.97,0.93,1.05,1.34,1.02,1.14,0.84,0.88,0.92,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.74,1.89,1.76,1.98,1.89,1.71,1.93,1.99,1.91,1.94,1.82,1.46,1.60,1.65,1.80,1.79,1.77,1.92,1.57,1.69,1.74,1.87,1.88,1.94,1.98,1.53,1.45,1.70,1.18,1.32,1.42,1.58,1.65,1.83,1.81,1.81,1.67,1.61,1.19,1.44,1.17,1.11,1.36,1.15,1.41,1.75,1.22,1.50,1.34,1.42,1.61,0.98,0.92,1.03,0.83,0.86,0.89,0.95,0.98,1.23,1.14,0.97,0.89,0.90,0.78,0.82,0.76,0.82,0.77,0.79,0.84,0.98,0.90,0.98,0.83,0.89,0.97,1.03,0.95,0.92,0.86,0.90,0.82,0.86,0.79,0.77,0.84,0.81,0.76,0.76,0.72,0.73,0.70,0.72,0.71,0.73,0.73,0.72,0.74,0.71,0.78,0.74,0.72,0.75,0.80,0.76,0.94,0.88,0.91,0.83,0.87,0.84,0.79,0.76,0.82,0.80,0.97,0.89,0.96,0.88,0.95,0.94,0.87,1.11,1.37,1.10,1.59,1.57,1.37,1.33,1.05,1.08,1.54,1.34,1.46,1.16,0.99,1.26,0.96,1.05,0.92,1.45,1.55,1.27,1.60,1.07,1.34,1.35,1.18,1.07,0.93,0.99,0.90,0.93,0.87,0.96,1.27,0.99,1.15,0.77,0.82,0.85,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.60,1.78,1.68,1.93,1.86,1.71,1.97,1.99,1.99,1.97,1.93,1.60,1.68,1.78,1.86,1.61,1.57,1.79,1.37,1.48,1.59,1.72,1.79,1.92,1.90,1.38,1.35,1.60,1.23,1.30,1.47,1.56,1.71,1.88,1.79,1.92,1.79,1.79,1.30,1.56,1.35,1.37,1.59,1.38,1.60,1.90,1.48,1.72,1.57,1.61,1.79,1.21,1.00,1.30,0.89,0.94,0.96,1.07,1.14,1.40,1.37,1.14,0.96,0.98,0.82,0.88,0.82,0.89,0.83,0.86,0.91,1.02,0.93,1.07,0.87,0.94,1.11,1.02,0.93,0.93,0.82,0.87,0.80,0.85,0.79,0.80,0.85,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.72,0.76,0.73,0.82,0.79,0.76,0.73,0.79,0.76,0.93,0.86,0.91,0.83,0.89,0.89,0.82,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.44,1.19,1.22,0.99,0.98,1.49,1.44,1.49,1.22,0.99,1.23,0.98,1.19,0.97,1.21,1.30,1.00,1.37,0.94,1.07,1.14,0.98,0.96,0.86,0.91,0.83,0.88,0.82,0.89,1.11,0.94,1.07,0.73,0.76,0.79,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.46,1.65,1.60,1.82,1.80,1.71,1.93,1.91,1.99,1.94,1.98,1.74,1.76,1.89,1.89,1.42,1.34,1.61,1.11,1.22,1.36,1.50,1.61,1.81,1.75,1.15,1.17,1.41,1.18,1.19,1.42,1.44,1.65,1.83,1.67,1.94,1.81,1.88,1.32,1.58,1.45,1.57,1.74,1.53,1.70,1.98,1.69,1.87,1.77,1.79,1.92,1.45,1.27,1.55,0.97,1.07,1.11,1.34,1.37,1.59,1.60,1.35,1.07,1.18,0.86,0.93,0.87,0.96,0.90,0.93,0.99,1.03,0.95,1.15,0.90,0.99,1.27,0.98,0.90,0.92,0.78,0.83,0.77,0.84,0.79,0.82,0.86,0.73,0.71,0.73,0.72,0.70,0.73,0.72,0.76,0.81,0.76,0.76,0.82,0.77,0.89,0.85,0.82,0.75,0.80,0.80,0.94,0.88,0.94,0.87,0.95,0.96,0.88,0.72,0.74,0.76,0.83,0.78,0.84,0.79,0.87,0.91,0.83,0.89,0.98,0.92,1.23,1.34,1.05,1.16,0.99,0.96,1.46,1.57,1.54,1.33,1.05,1.26,1.08,1.37,1.10,0.98,1.03,0.92,1.14,0.86,0.95,0.97,0.90,0.89,0.79,0.84,0.77,0.82,0.76,0.82,0.97,0.89,0.98,0.71,0.72,0.74,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.34,1.51,1.53,1.67,1.72,1.71,1.80,1.77,1.91,1.86,1.98,1.86,1.82,1.95,1.89,1.24,1.10,1.41,0.95,0.99,1.09,1.25,1.37,1.63,1.55,0.96,0.98,1.16,1.05,1.00,1.27,1.23,1.50,1.69,1.46,1.86,1.72,1.87,1.24,1.49,1.44,1.69,1.80,1.59,1.69,1.97,1.82,1.94,1.91,1.92,1.99,1.63,1.50,1.74,1.16,1.33,1.38,1.58,1.60,1.77,1.80,1.48,1.21,1.37,0.90,0.97,0.93,1.05,0.97,1.04,1.21,0.99,0.95,1.14,0.92,1.02,1.34,0.94,0.86,0.90,0.74,0.79,0.75,0.81,0.79,0.84,0.86,0.71,0.71,0.73,0.76,0.73,0.77,0.74,0.80,0.85,0.78,0.81,0.89,0.84,0.97,0.92,0.88,0.79,0.85,0.86,0.98,0.92,1.00,0.93,1.06,1.12,0.95,0.74,0.74,0.78,0.79,0.76,0.82,0.79,0.87,0.93,0.85,0.85,0.94,0.90,1.09,1.27,0.99,1.17,1.05,0.96,1.46,1.71,1.62,1.48,1.20,1.34,1.28,1.57,1.35,0.90,0.94,0.85,0.98,0.81,0.89,0.89,0.83,0.82,0.75,0.78,0.73,0.77,0.72,0.76,0.89,0.83,0.91,0.71,0.70,0.72,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
+{1.26,1.39,1.48,1.51,1.64,1.71,1.60,1.58,1.77,1.74,1.91,1.94,1.87,1.97,1.85,1.10,0.97,1.22,0.88,0.92,0.95,1.01,1.11,1.39,1.32,0.88,0.90,0.97,0.96,0.93,1.05,0.99,1.27,1.47,1.20,1.70,1.54,1.76,1.08,1.31,1.33,1.70,1.76,1.55,1.57,1.88,1.85,1.91,1.97,1.99,1.99,1.70,1.65,1.85,1.41,1.54,1.61,1.76,1.80,1.91,1.93,1.52,1.26,1.48,0.92,0.99,0.97,1.18,1.09,1.28,1.39,0.94,0.93,1.05,0.92,1.01,1.31,0.88,0.81,0.86,0.72,0.75,0.74,0.79,0.79,0.86,0.85,0.71,0.73,0.75,0.82,0.77,0.83,0.78,0.85,0.88,0.81,0.88,0.97,0.90,1.18,1.00,0.93,0.86,0.92,0.94,1.14,0.99,1.24,1.03,1.33,1.39,1.11,0.79,0.77,0.84,0.79,0.77,0.84,0.83,0.90,0.98,0.91,0.85,0.92,0.91,1.02,1.26,1.00,1.23,1.19,0.99,1.50,1.84,1.71,1.64,1.38,1.46,1.51,1.76,1.59,0.84,0.88,0.80,0.94,0.79,0.86,0.82,0.77,0.76,0.74,0.74,0.71,0.73,0.70,0.72,0.82,0.77,0.85,0.74,0.70,0.73,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}
+}
--- /dev/null
+++ b/ref_gl/gl_draw.c
@@ -1,0 +1,415 @@
+/*
+Copyright (C) 1997-2001 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
+
+#include "gl_local.h"
+
+image_t		*draw_chars;
+
+extern	qboolean	scrap_dirty;
+void Scrap_Upload (void);
+
+
+/*
+===============
+Draw_InitLocal
+===============
+*/
+void Draw_InitLocal (void)
+{
+	// load console characters (don't bilerp characters)
+	draw_chars = GL_FindImage ("pics/conchars.pcx", it_pic);
+	GL_Bind( draw_chars->texnum );
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+}
+
+
+
+/*
+================
+Draw_Char
+
+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_Char (int x, int y, int num)
+{
+	int				row, col;
+	float			frow, fcol, size;
+
+	num &= 255;
+	
+	if ( (num&127) == 32 )
+		return;		// space
+
+	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 (draw_chars->texnum);
+
+	qglBegin (GL_QUADS);
+	qglTexCoord2f (fcol, frow);
+	qglVertex2f (x, y);
+	qglTexCoord2f (fcol + size, frow);
+	qglVertex2f (x+8, y);
+	qglTexCoord2f (fcol + size, frow + size);
+	qglVertex2f (x+8, y+8);
+	qglTexCoord2f (fcol, frow + size);
+	qglVertex2f (x, y+8);
+	qglEnd ();
+}
+
+/*
+=============
+Draw_FindPic
+=============
+*/
+image_t	*Draw_FindPic (char *name)
+{
+	image_t *gl;
+	char	fullname[MAX_QPATH];
+
+	if (name[0] != '/' && name[0] != '\\')
+	{
+		Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
+		gl = GL_FindImage (fullname, it_pic);
+	}
+	else
+		gl = GL_FindImage (name+1, it_pic);
+
+	return gl;
+}
+
+/*
+=============
+Draw_GetPicSize
+=============
+*/
+void Draw_GetPicSize (int *w, int *h, char *pic)
+{
+	image_t *gl;
+
+	gl = Draw_FindPic (pic);
+	if (!gl)
+	{
+		*w = *h = -1;
+		return;
+	}
+	*w = gl->width;
+	*h = gl->height;
+}
+
+/*
+=============
+Draw_StretchPic
+=============
+*/
+void Draw_StretchPic (int x, int y, int w, int h, char *pic)
+{
+	image_t *gl;
+
+	gl = Draw_FindPic (pic);
+	if (!gl)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
+		return;
+	}
+
+	if (scrap_dirty)
+		Scrap_Upload ();
+
+	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
+		qglDisable (GL_ALPHA_TEST);
+
+	GL_Bind (gl->texnum);
+	qglBegin (GL_QUADS);
+	qglTexCoord2f (gl->sl, gl->tl);
+	qglVertex2f (x, y);
+	qglTexCoord2f (gl->sh, gl->tl);
+	qglVertex2f (x+w, y);
+	qglTexCoord2f (gl->sh, gl->th);
+	qglVertex2f (x+w, y+h);
+	qglTexCoord2f (gl->sl, gl->th);
+	qglVertex2f (x, y+h);
+	qglEnd ();
+
+	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
+		qglEnable (GL_ALPHA_TEST);
+}
+
+
+/*
+=============
+Draw_Pic
+=============
+*/
+void Draw_Pic (int x, int y, char *pic)
+{
+	image_t *gl;
+
+	gl = Draw_FindPic (pic);
+	if (!gl)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
+		return;
+	}
+	if (scrap_dirty)
+		Scrap_Upload ();
+
+	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
+		qglDisable (GL_ALPHA_TEST);
+
+	GL_Bind (gl->texnum);
+	qglBegin (GL_QUADS);
+	qglTexCoord2f (gl->sl, gl->tl);
+	qglVertex2f (x, y);
+	qglTexCoord2f (gl->sh, gl->tl);
+	qglVertex2f (x+gl->width, y);
+	qglTexCoord2f (gl->sh, gl->th);
+	qglVertex2f (x+gl->width, y+gl->height);
+	qglTexCoord2f (gl->sl, gl->th);
+	qglVertex2f (x, y+gl->height);
+	qglEnd ();
+
+	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha)
+		qglEnable (GL_ALPHA_TEST);
+}
+
+/*
+=============
+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, char *pic)
+{
+	image_t	*image;
+
+	image = Draw_FindPic (pic);
+	if (!image)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
+		return;
+	}
+
+	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !image->has_alpha)
+		qglDisable (GL_ALPHA_TEST);
+
+	GL_Bind (image->texnum);
+	qglBegin (GL_QUADS);
+	qglTexCoord2f (x/64.0, y/64.0);
+	qglVertex2f (x, y);
+	qglTexCoord2f ( (x+w)/64.0, y/64.0);
+	qglVertex2f (x+w, y);
+	qglTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
+	qglVertex2f (x+w, y+h);
+	qglTexCoord2f ( x/64.0, (y+h)/64.0 );
+	qglVertex2f (x, y+h);
+	qglEnd ();
+
+	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !image->has_alpha)
+		qglEnable (GL_ALPHA_TEST);
+}
+
+
+/*
+=============
+Draw_Fill
+
+Fills a box of pixels with a single color
+=============
+*/
+void Draw_Fill (int x, int y, int w, int h, int c)
+{
+	union
+	{
+		unsigned	c;
+		byte		v[4];
+	} color;
+
+	if ( (unsigned)c > 255)
+		ri.Sys_Error (ERR_FATAL, "Draw_Fill: bad color");
+
+	qglDisable (GL_TEXTURE_2D);
+
+	color.c = d_8to24table[c];
+	qglColor3f (color.v[0]/255.0,
+		color.v[1]/255.0,
+		color.v[2]/255.0);
+
+	qglBegin (GL_QUADS);
+
+	qglVertex2f (x,y);
+	qglVertex2f (x+w, y);
+	qglVertex2f (x+w, y+h);
+	qglVertex2f (x, y+h);
+
+	qglEnd ();
+	qglColor3f (1,1,1);
+	qglEnable (GL_TEXTURE_2D);
+}
+
+//=============================================================================
+
+/*
+================
+Draw_FadeScreen
+
+================
+*/
+void Draw_FadeScreen (void)
+{
+	qglEnable (GL_BLEND);
+	qglDisable (GL_TEXTURE_2D);
+	qglColor4f (0, 0, 0, 0.8);
+	qglBegin (GL_QUADS);
+
+	qglVertex2f (0,0);
+	qglVertex2f (vid.width, 0);
+	qglVertex2f (vid.width, vid.height);
+	qglVertex2f (0, vid.height);
+
+	qglEnd ();
+	qglColor4f (1,1,1,1);
+	qglEnable (GL_TEXTURE_2D);
+	qglDisable (GL_BLEND);
+}
+
+
+//====================================================================
+
+
+/*
+=============
+Draw_StretchRaw
+=============
+*/
+extern unsigned	r_rawpalette[256];
+
+void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
+{
+	unsigned	image32[256*256];
+	unsigned char image8[256*256];
+	int			i, j, trows;
+	byte		*source;
+	int			frac, fracstep;
+	float		hscale;
+	int			row;
+	float		t;
+
+	GL_Bind (0);
+
+	if (rows<=256)
+	{
+		hscale = 1;
+		trows = rows;
+	}
+	else
+	{
+		hscale = rows/256.0;
+		trows = 256;
+	}
+	t = rows*hscale / 256;
+
+	if ( !qglColorTableEXT )
+	{
+		unsigned *dest;
+
+		for (i=0 ; i<trows ; i++)
+		{
+			row = (int)(i*hscale);
+			if (row > rows)
+				break;
+			source = data + cols*row;
+			dest = &image32[i*256];
+			fracstep = cols*0x10000/256;
+			frac = fracstep >> 1;
+			for (j=0 ; j<256 ; j++)
+			{
+				dest[j] = r_rawpalette[source[frac>>16]];
+				frac += fracstep;
+			}
+		}
+
+		qglTexImage2D (GL_TEXTURE_2D, 0, gl_tex_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image32);
+	}
+	else
+	{
+		unsigned char *dest;
+
+		for (i=0 ; i<trows ; i++)
+		{
+			row = (int)(i*hscale);
+			if (row > rows)
+				break;
+			source = data + cols*row;
+			dest = &image8[i*256];
+			fracstep = cols*0x10000/256;
+			frac = fracstep >> 1;
+			for (j=0 ; j<256 ; j++)
+			{
+				dest[j] = source[frac>>16];
+				frac += fracstep;
+			}
+		}
+
+		qglTexImage2D( GL_TEXTURE_2D, 
+			           0, 
+					   GL_COLOR_INDEX8_EXT, 
+					   256, 256, 
+					   0, 
+					   GL_COLOR_INDEX, 
+					   GL_UNSIGNED_BYTE, 
+					   image8 );
+	}
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) 
+		qglDisable (GL_ALPHA_TEST);
+
+	qglBegin (GL_QUADS);
+	qglTexCoord2f (0, 0);
+	qglVertex2f (x, y);
+	qglTexCoord2f (1, 0);
+	qglVertex2f (x+w, y);
+	qglTexCoord2f (1, t);
+	qglVertex2f (x+w, y+h);
+	qglTexCoord2f (0, t);
+	qglVertex2f (x, y+h);
+	qglEnd ();
+
+	if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) 
+		qglEnable (GL_ALPHA_TEST);
+}
+
--- /dev/null
+++ b/ref_gl/gl_image.c
@@ -1,0 +1,1571 @@
+/*
+Copyright (C) 1997-2001 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 "gl_local.h"
+
+image_t		gltextures[MAX_GLTEXTURES];
+int			numgltextures;
+int			base_textureid;		// gltextures[i] = base_textureid+i
+
+static byte			 intensitytable[256];
+static unsigned char gammatable[256];
+
+cvar_t		*intensity;
+
+unsigned	d_8to24table[256];
+
+qboolean GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean is_sky );
+qboolean GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap);
+
+
+int		gl_solid_format = 3;
+int		gl_alpha_format = 4;
+
+int		gl_tex_solid_format = 3;
+int		gl_tex_alpha_format = 4;
+
+int		gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
+int		gl_filter_max = GL_LINEAR;
+
+void GL_SetTexturePalette( unsigned palette[256] )
+{
+	int i;
+	unsigned char temptable[768];
+
+	for ( i = 0; i < 256; i++ )
+	{
+		temptable[i*3+0] = ( palette[i] >> 0 ) & 0xff;
+		temptable[i*3+1] = ( palette[i] >> 8 ) & 0xff;
+		temptable[i*3+2] = ( palette[i] >> 16 ) & 0xff;
+	}
+
+	if ( qglColorTableEXT && gl_ext_palettedtexture->value )
+	{
+		qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT,
+						   GL_RGB,
+						   256,
+						   GL_RGB,
+						   GL_UNSIGNED_BYTE,
+						   temptable );
+	}
+}
+
+void GL_EnableMultitexture( qboolean enable )
+{
+	if ( !qglSelectTextureSGIS )
+		return;
+
+	if ( enable )
+	{
+		GL_SelectTexture( GL_TEXTURE1_SGIS );
+		qglEnable( GL_TEXTURE_2D );
+		GL_TexEnv( GL_REPLACE );
+	}
+	else
+	{
+		GL_SelectTexture( GL_TEXTURE1_SGIS );
+		qglDisable( GL_TEXTURE_2D );
+		GL_TexEnv( GL_REPLACE );
+	}
+	GL_SelectTexture( GL_TEXTURE0_SGIS );
+	GL_TexEnv( GL_REPLACE );
+}
+
+void GL_SelectTexture( GLenum texture )
+{
+	int tmu;
+
+	if ( !qglSelectTextureSGIS )
+		return;
+
+	if ( texture == GL_TEXTURE0_SGIS )
+		tmu = 0;
+	else
+		tmu = 1;
+
+	if ( tmu == gl_state.currenttmu )
+		return;
+
+	gl_state.currenttmu = tmu;
+
+	if ( tmu == 0 )
+		qglSelectTextureSGIS( GL_TEXTURE0_SGIS );
+	else
+		qglSelectTextureSGIS( GL_TEXTURE1_SGIS );
+}
+
+void GL_TexEnv( GLenum mode )
+{
+	static int lastmodes[2] = { -1, -1 };
+
+	if ( mode != lastmodes[gl_state.currenttmu] )
+	{
+		qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode );
+		lastmodes[gl_state.currenttmu] = mode;
+	}
+}
+
+void GL_Bind (int texnum)
+{
+	extern	image_t	*draw_chars;
+
+	if (gl_nobind->value && draw_chars)		// performance evaluation option
+		texnum = draw_chars->texnum;
+	if ( gl_state.currenttextures[gl_state.currenttmu] == texnum)
+		return;
+	gl_state.currenttextures[gl_state.currenttmu] = texnum;
+	qglBindTexture (GL_TEXTURE_2D, texnum);
+}
+
+void GL_MBind( GLenum target, int texnum )
+{
+	GL_SelectTexture( target );
+	if ( target == GL_TEXTURE0_SGIS )
+	{
+		if ( gl_state.currenttextures[0] == texnum )
+			return;
+	}
+	else
+	{
+		if ( gl_state.currenttextures[1] == texnum )
+			return;
+	}
+	GL_Bind( texnum );
+}
+
+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}
+};
+
+#define NUM_GL_MODES (sizeof(modes) / sizeof (glmode_t))
+
+typedef struct
+{
+	char *name;
+	int mode;
+} gltmode_t;
+
+gltmode_t gl_alpha_modes[] = {
+	{"default", 4},
+	{"GL_RGBA", GL_RGBA},
+	{"GL_RGBA8", GL_RGBA8},
+	{"GL_RGB5_A1", GL_RGB5_A1},
+	{"GL_RGBA4", GL_RGBA4},
+	{"GL_RGBA2", GL_RGBA2},
+};
+
+#define NUM_GL_ALPHA_MODES (sizeof(gl_alpha_modes) / sizeof (gltmode_t))
+
+gltmode_t gl_solid_modes[] = {
+	{"default", 3},
+	{"GL_RGB", GL_RGB},
+	{"GL_RGB8", GL_RGB8},
+	{"GL_RGB5", GL_RGB5},
+	{"GL_RGB4", GL_RGB4},
+	{"GL_R3_G3_B2", GL_R3_G3_B2},
+#ifdef GL_RGB2_EXT
+	{"GL_RGB2", GL_RGB2_EXT},
+#endif
+};
+
+#define NUM_GL_SOLID_MODES (sizeof(gl_solid_modes) / sizeof (gltmode_t))
+
+/*
+===============
+GL_TextureMode
+===============
+*/
+void GL_TextureMode( char *string )
+{
+	int		i;
+	image_t	*glt;
+
+	for (i=0 ; i< NUM_GL_MODES ; i++)
+	{
+		if ( !Q_stricmp( modes[i].name, string ) )
+			break;
+	}
+
+	if (i == NUM_GL_MODES)
+	{
+		ri.Con_Printf (PRINT_ALL, "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->type != it_pic && glt->type != it_sky )
+		{
+			GL_Bind (glt->texnum);
+			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+		}
+	}
+}
+
+/*
+===============
+GL_TextureAlphaMode
+===============
+*/
+void GL_TextureAlphaMode( char *string )
+{
+	int		i;
+
+	for (i=0 ; i< NUM_GL_ALPHA_MODES ; i++)
+	{
+		if ( !Q_stricmp( gl_alpha_modes[i].name, string ) )
+			break;
+	}
+
+	if (i == NUM_GL_ALPHA_MODES)
+	{
+		ri.Con_Printf (PRINT_ALL, "bad alpha texture mode name\n");
+		return;
+	}
+
+	gl_tex_alpha_format = gl_alpha_modes[i].mode;
+}
+
+/*
+===============
+GL_TextureSolidMode
+===============
+*/
+void GL_TextureSolidMode( char *string )
+{
+	int		i;
+
+	for (i=0 ; i< NUM_GL_SOLID_MODES ; i++)
+	{
+		if ( !Q_stricmp( gl_solid_modes[i].name, string ) )
+			break;
+	}
+
+	if (i == NUM_GL_SOLID_MODES)
+	{
+		ri.Con_Printf (PRINT_ALL, "bad solid texture mode name\n");
+		return;
+	}
+
+	gl_tex_solid_format = gl_solid_modes[i].mode;
+}
+
+/*
+===============
+GL_ImageList_f
+===============
+*/
+void	GL_ImageList_f (void)
+{
+	int		i;
+	image_t	*image;
+	int		texels;
+	const char *palstrings[2] =
+	{
+		"RGB",
+		"PAL"
+	};
+
+	ri.Con_Printf (PRINT_ALL, "------------------\n");
+	texels = 0;
+
+	for (i=0, image=gltextures ; i<numgltextures ; i++, image++)
+	{
+		if (image->texnum <= 0)
+			continue;
+		texels += image->upload_width*image->upload_height;
+		switch (image->type)
+		{
+		case it_skin:
+			ri.Con_Printf (PRINT_ALL, "M");
+			break;
+		case it_sprite:
+			ri.Con_Printf (PRINT_ALL, "S");
+			break;
+		case it_wall:
+			ri.Con_Printf (PRINT_ALL, "W");
+			break;
+		case it_pic:
+			ri.Con_Printf (PRINT_ALL, "P");
+			break;
+		default:
+			ri.Con_Printf (PRINT_ALL, " ");
+			break;
+		}
+
+		ri.Con_Printf (PRINT_ALL,  " %3i %3i %s: %s\n",
+			image->upload_width, image->upload_height, palstrings[image->paletted], image->name);
+	}
+	ri.Con_Printf (PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels);
+}
+
+
+/*
+=============================================================================
+
+  scrap allocation
+
+  Allocate all the little status bar obejcts into a single texture
+  to crutch up inefficient hardware / drivers
+
+=============================================================================
+*/
+
+#define	MAX_SCRAPS		1
+#define	BLOCK_WIDTH		256
+#define	BLOCK_HEIGHT	256
+
+int			scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
+byte		scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT];
+qboolean	scrap_dirty;
+
+// 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		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;
+	}
+
+	return -1;
+//	Sys_Error ("Scrap_AllocBlock: full");
+}
+
+int	scrap_uploads;
+
+void Scrap_Upload (void)
+{
+	scrap_uploads++;
+	GL_Bind(TEXNUM_SCRAPS);
+	GL_Upload8 (scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false );
+	scrap_dirty = false;
+}
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+
+/*
+==============
+LoadPCX
+==============
+*/
+void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+	byte	*raw;
+	pcx_t	*pcx;
+	int		x, y;
+	int		len;
+	int		dataByte, runLength;
+	byte	*out, *pix;
+
+	*pic = NULL;
+	*palette = NULL;
+
+	//
+	// load the file
+	//
+	len = ri.FS_LoadFile (filename, (void **)&raw);
+	if (!raw)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
+		return;
+	}
+
+	//
+	// parse the PCX file
+	//
+	pcx = (pcx_t *)raw;
+
+    pcx->xmin = LittleShort(pcx->xmin);
+    pcx->ymin = LittleShort(pcx->ymin);
+    pcx->xmax = LittleShort(pcx->xmax);
+    pcx->ymax = LittleShort(pcx->ymax);
+    pcx->hres = LittleShort(pcx->hres);
+    pcx->vres = LittleShort(pcx->vres);
+    pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
+    pcx->palette_type = LittleShort(pcx->palette_type);
+
+	raw = &pcx->data;
+
+	if (pcx->manufacturer != 0x0a
+		|| pcx->version != 5
+		|| pcx->encoding != 1
+		|| pcx->bits_per_pixel != 8
+		|| pcx->xmax >= 640
+		|| pcx->ymax >= 480)
+	{
+		ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
+		return;
+	}
+
+	out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+	*pic = out;
+
+	pix = out;
+
+	if (palette)
+	{
+		*palette = malloc(768);
+		memcpy (*palette, (byte *)pcx + len - 768, 768);
+	}
+
+	if (width)
+		*width = pcx->xmax+1;
+	if (height)
+		*height = pcx->ymax+1;
+
+	for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+	{
+		for (x=0 ; x<=pcx->xmax ; )
+		{
+			dataByte = *raw++;
+
+			if((dataByte & 0xC0) == 0xC0)
+			{
+				runLength = dataByte & 0x3F;
+				dataByte = *raw++;
+			}
+			else
+				runLength = 1;
+
+			while(runLength-- > 0)
+				pix[x++] = dataByte;
+		}
+
+	}
+
+	if ( raw - (byte *)pcx > len)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
+		free (*pic);
+		*pic = NULL;
+	}
+
+	ri.FS_FreeFile (pcx);
+}
+
+/*
+=========================================================
+
+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;
+
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (char *name, byte **pic, int *width, int *height)
+{
+	int		columns, rows, numPixels;
+	byte	*pixbuf;
+	int		row, column;
+	byte	*buf_p;
+	byte	*buffer;
+	int		length;
+	TargaHeader		targa_header;
+	byte			*targa_rgba;
+	byte tmp[2];
+
+	*pic = NULL;
+
+	//
+	// load the file
+	//
+	length = ri.FS_LoadFile (name, (void **)&buffer);
+	if (!buffer)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
+		return;
+	}
+
+	buf_p = buffer;
+
+	targa_header.id_length = *buf_p++;
+	targa_header.colormap_type = *buf_p++;
+	targa_header.image_type = *buf_p++;
+	
+	tmp[0] = buf_p[0];
+	tmp[1] = buf_p[1];
+	targa_header.colormap_index = LittleShort ( *((short *)tmp) );
+	buf_p+=2;
+	tmp[0] = buf_p[0];
+	tmp[1] = buf_p[1];
+	targa_header.colormap_length = LittleShort ( *((short *)tmp) );
+	buf_p+=2;
+	targa_header.colormap_size = *buf_p++;
+	targa_header.x_origin = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.y_origin = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.width = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.height = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.pixel_size = *buf_p++;
+	targa_header.attributes = *buf_p++;
+
+	if (targa_header.image_type!=2 
+		&& targa_header.image_type!=10) 
+		ri.Sys_Error (ERR_DROP, "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))
+		ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+
+	columns = targa_header.width;
+	rows = targa_header.height;
+	numPixels = columns * rows;
+
+	if (width)
+		*width = columns;
+	if (height)
+		*height = rows;
+
+	targa_rgba = malloc (numPixels*4);
+	*pic = targa_rgba;
+
+	if (targa_header.id_length != 0)
+		buf_p += targa_header.id_length;  // 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 = *buf_p++;
+							green = *buf_p++;
+							red = *buf_p++;
+							*pixbuf++ = red;
+							*pixbuf++ = green;
+							*pixbuf++ = blue;
+							*pixbuf++ = 255;
+							break;
+					case 32:
+							blue = *buf_p++;
+							green = *buf_p++;
+							red = *buf_p++;
+							alphabyte = *buf_p++;
+							*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= *buf_p++;
+				packetSize = 1 + (packetHeader & 0x7f);
+				if (packetHeader & 0x80) {        // run-length packet
+					switch (targa_header.pixel_size) {
+						case 24:
+								blue = *buf_p++;
+								green = *buf_p++;
+								red = *buf_p++;
+								alphabyte = 255;
+								break;
+						case 32:
+								blue = *buf_p++;
+								green = *buf_p++;
+								red = *buf_p++;
+								alphabyte = *buf_p++;
+								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 = *buf_p++;
+									green = *buf_p++;
+									red = *buf_p++;
+									*pixbuf++ = red;
+									*pixbuf++ = green;
+									*pixbuf++ = blue;
+									*pixbuf++ = 255;
+									break;
+							case 32:
+									blue = *buf_p++;
+									green = *buf_p++;
+									red = *buf_p++;
+									alphabyte = *buf_p++;
+									*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:;
+		}
+	}
+
+	ri.FS_FreeFile (buffer);
+}
+
+
+/*
+====================================================================
+
+IMAGE FLOOD FILLING
+
+====================================================================
+*/
+
+
+/*
+=================
+Mod_FloodFillSkin
+
+Fill background pixels so mipmapping doesn't have haloes
+=================
+*/
+
+typedef struct
+{
+	short		x, y;
+} floodfill_t;
+
+// must be a power of 2
+#define FLOODFILL_FIFO_SIZE 0x1000
+#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
+
+#define FLOODFILL_STEP( off, dx, dy ) \
+{ \
+	if (pos[off] == fillcolor) \
+	{ \
+		pos[off] = 255; \
+		fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \
+		inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
+	} \
+	else if (pos[off] != 255) fdc = pos[off]; \
+}
+
+void R_FloodFillSkin( byte *skin, int skinwidth, int skinheight )
+{
+	byte				fillcolor = *skin; // assume this is the pixel to fill
+	floodfill_t			fifo[FLOODFILL_FIFO_SIZE];
+	int					inpt = 0, outpt = 0;
+	int					filledcolor = -1;
+	int					i;
+
+	if (filledcolor == -1)
+	{
+		filledcolor = 0;
+		// attempt to find opaque black
+		for (i = 0; i < 256; ++i)
+			if (d_8to24table[i] == (255 << 0)) // alpha 1.0
+			{
+				filledcolor = i;
+				break;
+			}
+	}
+
+	// can't fill to filled color or to transparent color (used as visited marker)
+	if ((fillcolor == filledcolor) || (fillcolor == 255))
+	{
+		//printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
+		return;
+	}
+
+	fifo[inpt].x = 0, fifo[inpt].y = 0;
+	inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
+
+	while (outpt != inpt)
+	{
+		int			x = fifo[outpt].x, y = fifo[outpt].y;
+		int			fdc = filledcolor;
+		byte		*pos = &skin[x + skinwidth * y];
+
+		outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
+
+		if (x > 0)				FLOODFILL_STEP( -1, -1, 0 );
+		if (x < skinwidth - 1)	FLOODFILL_STEP( 1, 1, 0 );
+		if (y > 0)				FLOODFILL_STEP( -skinwidth, 0, -1 );
+		if (y < skinheight - 1)	FLOODFILL_STEP( skinwidth, 0, 1 );
+		skin[x + skinwidth * y] = fdc;
+	}
+}
+
+//=======================================================
+
+
+/*
+================
+GL_ResampleTexture
+================
+*/
+void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)
+{
+	int		i, j;
+	unsigned	*inrow, *inrow2;
+	unsigned	frac, fracstep;
+	unsigned	p1[1024], p2[1024];
+	byte		*pix1, *pix2, *pix3, *pix4;
+
+	fracstep = inwidth*0x10000/outwidth;
+
+	frac = fracstep>>2;
+	for (i=0 ; i<outwidth ; i++)
+	{
+		p1[i] = 4*(frac>>16);
+		frac += fracstep;
+	}
+	frac = 3*(fracstep>>2);
+	for (i=0 ; i<outwidth ; i++)
+	{
+		p2[i] = 4*(frac>>16);
+		frac += fracstep;
+	}
+
+	for (i=0 ; i<outheight ; i++, out += outwidth)
+	{
+		inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
+		inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
+		frac = fracstep >> 1;
+		for (j=0 ; j<outwidth ; j++)
+		{
+			pix1 = (byte *)inrow + p1[j];
+			pix2 = (byte *)inrow + p2[j];
+			pix3 = (byte *)inrow2 + p1[j];
+			pix4 = (byte *)inrow2 + p2[j];
+			((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
+			((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
+			((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
+			((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
+		}
+	}
+}
+
+/*
+================
+GL_LightScaleTexture
+
+Scale up the pixel values in a texture to increase the
+lighting range
+================
+*/
+void GL_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )
+{
+	if ( only_gamma )
+	{
+		int		i, c;
+		byte	*p;
+
+		p = (byte *)in;
+
+		c = inwidth*inheight;
+		for (i=0 ; i<c ; i++, p+=4)
+		{
+			p[0] = gammatable[p[0]];
+			p[1] = gammatable[p[1]];
+			p[2] = gammatable[p[2]];
+		}
+	}
+	else
+	{
+		int		i, c;
+		byte	*p;
+
+		p = (byte *)in;
+
+		c = inwidth*inheight;
+		for (i=0 ; i<c ; i++, p+=4)
+		{
+			p[0] = gammatable[intensitytable[p[0]]];
+			p[1] = gammatable[intensitytable[p[1]]];
+			p[2] = gammatable[intensitytable[p[2]]];
+		}
+	}
+}
+
+/*
+================
+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_Upload32
+
+Returns has_alpha
+===============
+*/
+void GL_BuildPalettedTexture( unsigned char *paletted_texture, unsigned char *scaled, int scaled_width, int scaled_height )
+{
+	int i;
+
+	for ( i = 0; i < scaled_width * scaled_height; i++ )
+	{
+		unsigned int r, g, b, c;
+
+		r = ( scaled[0] >> 3 ) & 31;
+		g = ( scaled[1] >> 2 ) & 63;
+		b = ( scaled[2] >> 3 ) & 31;
+
+		c = r | ( g << 5 ) | ( b << 11 );
+
+		paletted_texture[i] = gl_state.d_16to8table[c];
+
+		scaled += 4;
+	}
+}
+
+int		upload_width, upload_height;
+qboolean uploaded_paletted;
+
+qboolean GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap)
+{
+	int			samples;
+	unsigned	scaled[256*256];
+	unsigned char paletted_texture[256*256];
+	int			scaled_width, scaled_height;
+	int			i, c;
+	byte		*scan;
+	int comp;
+
+	uploaded_paletted = false;
+
+	for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+		;
+	if (gl_round_down->value && scaled_width > width && mipmap)
+		scaled_width >>= 1;
+	for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+		;
+	if (gl_round_down->value && scaled_height > height && mipmap)
+		scaled_height >>= 1;
+
+	// let people sample down the world textures for speed
+	if (mipmap)
+	{
+		scaled_width >>= (int)gl_picmip->value;
+		scaled_height >>= (int)gl_picmip->value;
+	}
+
+	// don't ever bother with >256 textures
+	if (scaled_width > 256)
+		scaled_width = 256;
+	if (scaled_height > 256)
+		scaled_height = 256;
+
+	if (scaled_width < 1)
+		scaled_width = 1;
+	if (scaled_height < 1)
+		scaled_height = 1;
+
+	upload_width = scaled_width;
+	upload_height = scaled_height;
+
+	if (scaled_width * scaled_height > sizeof(scaled)/4)
+		ri.Sys_Error (ERR_DROP, "GL_Upload32: too big");
+
+	// scan the texture for any non-255 alpha
+	c = width*height;
+	scan = ((byte *)data) + 3;
+	samples = gl_solid_format;
+	for (i=0 ; i<c ; i++, scan += 4)
+	{
+		if ( *scan != 255 )
+		{
+			samples = gl_alpha_format;
+			break;
+		}
+	}
+
+	if (samples == gl_solid_format)
+	    comp = gl_tex_solid_format;
+	else if (samples == gl_alpha_format)
+	    comp = gl_tex_alpha_format;
+	else {
+	    ri.Con_Printf (PRINT_ALL,
+			   "Unknown number of texture components %i\n",
+			   samples);
+	    comp = samples;
+	}
+
+#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)
+		qglTexImage2D (GL_TEXTURE_2D, 0, comp, 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);
+		qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+	}
+#else
+
+	if (scaled_width == width && scaled_height == height)
+	{
+		if (!mipmap)
+		{
+			if ( qglColorTableEXT && gl_ext_palettedtexture->value && samples == gl_solid_format )
+			{
+				uploaded_paletted = true;
+				GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) data, scaled_width, scaled_height );
+				qglTexImage2D( GL_TEXTURE_2D,
+							  0,
+							  GL_COLOR_INDEX8_EXT,
+							  scaled_width,
+							  scaled_height,
+							  0,
+							  GL_COLOR_INDEX,
+							  GL_UNSIGNED_BYTE,
+							  paletted_texture );
+			}
+			else
+			{
+				qglTexImage2D (GL_TEXTURE_2D, 0, comp, 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);
+
+	GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap );
+
+	if ( qglColorTableEXT && gl_ext_palettedtexture->value && ( samples == gl_solid_format ) )
+	{
+		uploaded_paletted = true;
+		GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) scaled, scaled_width, scaled_height );
+		qglTexImage2D( GL_TEXTURE_2D,
+					  0,
+					  GL_COLOR_INDEX8_EXT,
+					  scaled_width,
+					  scaled_height,
+					  0,
+					  GL_COLOR_INDEX,
+					  GL_UNSIGNED_BYTE,
+					  paletted_texture );
+	}
+	else
+	{
+		qglTexImage2D( GL_TEXTURE_2D, 0, comp, 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++;
+			if ( qglColorTableEXT && gl_ext_palettedtexture->value && samples == gl_solid_format )
+			{
+				uploaded_paletted = true;
+				GL_BuildPalettedTexture( paletted_texture, ( unsigned char * ) scaled, scaled_width, scaled_height );
+				qglTexImage2D( GL_TEXTURE_2D,
+							  miplevel,
+							  GL_COLOR_INDEX8_EXT,
+							  scaled_width,
+							  scaled_height,
+							  0,
+							  GL_COLOR_INDEX,
+							  GL_UNSIGNED_BYTE,
+							  paletted_texture );
+			}
+			else
+			{
+				qglTexImage2D (GL_TEXTURE_2D, miplevel, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+			}
+		}
+	}
+done: ;
+#endif
+
+
+	if (mipmap)
+	{
+		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+	}
+	else
+	{
+		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+	}
+
+	return (samples == gl_alpha_format);
+}
+
+/*
+===============
+GL_Upload8
+
+Returns has_alpha
+===============
+*/
+/*
+static qboolean IsPowerOf2( int value )
+{
+	int i = 1;
+
+
+	while ( 1 )
+	{
+		if ( value == i )
+			return true;
+		if ( i > value )
+			return false;
+		i <<= 1;
+	}
+}
+*/
+
+qboolean GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean is_sky )
+{
+	unsigned	trans[512*256];
+	int			i, s;
+	int			p;
+
+	s = width*height;
+
+	if (s > sizeof(trans)/4)
+		ri.Sys_Error (ERR_DROP, "GL_Upload8: too large");
+
+	if ( qglColorTableEXT && 
+		 gl_ext_palettedtexture->value && 
+		 is_sky )
+	{
+		qglTexImage2D( GL_TEXTURE_2D,
+					  0,
+					  GL_COLOR_INDEX8_EXT,
+					  width,
+					  height,
+					  0,
+					  GL_COLOR_INDEX,
+					  GL_UNSIGNED_BYTE,
+					  data );
+
+		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+	}
+	else
+	{
+		for (i=0 ; i<s ; i++)
+		{
+			p = data[i];
+			trans[i] = d_8to24table[p];
+
+			if (p == 255)
+			{	// transparent, so scan around for another color
+				// to avoid alpha fringes
+				// FIXME: do a full flood fill so mips work...
+				if (i > width && data[i-width] != 255)
+					p = data[i-width];
+				else if (i < s-width && data[i+width] != 255)
+					p = data[i+width];
+				else if (i > 0 && data[i-1] != 255)
+					p = data[i-1];
+				else if (i < s-1 && data[i+1] != 255)
+					p = data[i+1];
+				else
+					p = 0;
+				// copy rgb components
+				((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0];
+				((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1];
+				((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2];
+			}
+		}
+
+		return GL_Upload32 (trans, width, height, mipmap);
+	}
+}
+
+
+/*
+================
+GL_LoadPic
+
+This is also used as an entry point for the generated r_notexture
+================
+*/
+image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits)
+{
+	image_t		*image;
+	int			i;
+
+	// find a free image_t
+	for (i=0, image=gltextures ; i<numgltextures ; i++,image++)
+	{
+		if (!image->texnum)
+			break;
+	}
+	if (i == numgltextures)
+	{
+		if (numgltextures == MAX_GLTEXTURES)
+			ri.Sys_Error (ERR_DROP, "MAX_GLTEXTURES");
+		numgltextures++;
+	}
+	image = &gltextures[i];
+
+	if (strlen(name) >= sizeof(image->name))
+		ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
+	strcpy (image->name, name);
+	image->registration_sequence = registration_sequence;
+
+	image->width = width;
+	image->height = height;
+	image->type = type;
+
+	if (type == it_skin && bits == 8)
+		R_FloodFillSkin(pic, width, height);
+
+	// load little pics into the scrap
+	if (image->type == it_pic && bits == 8
+		&& image->width < 64 && image->height < 64)
+	{
+		int		x, y;
+		int		i, j, k;
+		int		texnum;
+
+		texnum = Scrap_AllocBlock (image->width, image->height, &x, &y);
+		if (texnum == -1)
+			goto nonscrap;
+		scrap_dirty = true;
+
+		// copy the texels into the scrap block
+		k = 0;
+		for (i=0 ; i<image->height ; i++)
+			for (j=0 ; j<image->width ; j++, k++)
+				scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = pic[k];
+		image->texnum = TEXNUM_SCRAPS + texnum;
+		image->scrap = true;
+		image->has_alpha = true;
+		image->sl = (x+0.01)/(float)BLOCK_WIDTH;
+		image->sh = (x+image->width-0.01)/(float)BLOCK_WIDTH;
+		image->tl = (y+0.01)/(float)BLOCK_WIDTH;
+		image->th = (y+image->height-0.01)/(float)BLOCK_WIDTH;
+	}
+	else
+	{
+nonscrap:
+		image->scrap = false;
+		image->texnum = TEXNUM_IMAGES + (image - gltextures);
+		GL_Bind(image->texnum);
+		if (bits == 8)
+			image->has_alpha = GL_Upload8 (pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky );
+		else
+			image->has_alpha = GL_Upload32 ((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky) );
+		image->upload_width = upload_width;		// after power of 2 and scales
+		image->upload_height = upload_height;
+		image->paletted = uploaded_paletted;
+		image->sl = 0;
+		image->sh = 1;
+		image->tl = 0;
+		image->th = 1;
+	}
+
+	return image;
+}
+
+
+/*
+================
+GL_LoadWal
+================
+*/
+image_t *GL_LoadWal (char *name)
+{
+	miptex_t	*mt;
+	int			width, height, ofs;
+	image_t		*image;
+
+	ri.FS_LoadFile (name, (void **)&mt);
+	if (!mt)
+	{
+		ri.Con_Printf (PRINT_ALL, "GL_FindImage: can't load %s\n", name);
+		return r_notexture;
+	}
+
+	width = LittleLong (mt->width);
+	height = LittleLong (mt->height);
+	ofs = LittleLong (mt->offsets[0]);
+
+	image = GL_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 8);
+
+	ri.FS_FreeFile ((void *)mt);
+
+	return image;
+}
+
+/*
+===============
+GL_FindImage
+
+Finds or loads the given image
+===============
+*/
+image_t	*GL_FindImage (char *name, imagetype_t type)
+{
+	image_t	*image;
+	int		i, len;
+	byte	*pic, *palette;
+	int		width, height;
+
+	if (!name)
+		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: NULL name");
+	len = strlen(name);
+	if (len<5)
+		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: bad name: %s", name);
+
+	// look for it
+	for (i=0, image=gltextures ; i<numgltextures ; i++,image++)
+	{
+		if (!strcmp(name, image->name))
+		{
+			image->registration_sequence = registration_sequence;
+			return image;
+		}
+	}
+
+	//
+	// load the pic from disk
+	//
+	pic = NULL;
+	palette = NULL;
+	if (!strcmp(name+len-4, ".pcx"))
+	{
+		LoadPCX (name, &pic, &palette, &width, &height);
+		if (!pic)
+			return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name);
+		image = GL_LoadPic (name, pic, width, height, type, 8);
+	}
+	else if (!strcmp(name+len-4, ".wal"))
+	{
+		image = GL_LoadWal (name);
+	}
+	else if (!strcmp(name+len-4, ".tga"))
+	{
+		LoadTGA (name, &pic, &width, &height);
+		if (!pic)
+			return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name);
+		image = GL_LoadPic (name, pic, width, height, type, 32);
+	}
+	else
+		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: bad extension on: %s", name);
+
+
+	if (pic)
+		free(pic);
+	if (palette)
+		free(palette);
+
+	return image;
+}
+
+
+
+/*
+===============
+R_RegisterSkin
+===============
+*/
+struct image_s *R_RegisterSkin (char *name)
+{
+	return GL_FindImage (name, it_skin);
+}
+
+
+/*
+================
+GL_FreeUnusedImages
+
+Any image that was not touched on this registration sequence
+will be freed.
+================
+*/
+void GL_FreeUnusedImages (void)
+{
+	int		i;
+	image_t	*image;
+
+	// never free r_notexture or particle texture
+	r_notexture->registration_sequence = registration_sequence;
+	r_particletexture->registration_sequence = registration_sequence;
+
+	for (i=0, image=gltextures ; i<numgltextures ; i++, image++)
+	{
+		if (image->registration_sequence == registration_sequence)
+			continue;		// used this sequence
+		if (!image->registration_sequence)
+			continue;		// free image_t slot
+		if (image->type == it_pic)
+			continue;		// don't free pics
+		// free it
+		qglDeleteTextures (1, &image->texnum);
+		memset (image, 0, sizeof(*image));
+	}
+}
+
+
+/*
+===============
+Draw_GetPalette
+===============
+*/
+int Draw_GetPalette (void)
+{
+	int		i;
+	int		r, g, b;
+	unsigned	v;
+	byte	*pic, *pal;
+	int		width, height;
+
+	// get the palette
+
+	LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height);
+	if (!pal)
+		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
+
+	for (i=0 ; i<256 ; i++)
+	{
+		r = pal[i*3+0];
+		g = pal[i*3+1];
+		b = pal[i*3+2];
+		
+		v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
+		d_8to24table[i] = LittleLong(v);
+	}
+
+	d_8to24table[255] &= LittleLong(0xffffff);	// 255 is transparent
+
+	free (pic);
+	free (pal);
+
+	return 0;
+}
+
+
+/*
+===============
+GL_InitImages
+===============
+*/
+void	GL_InitImages (void)
+{
+	int		i, j;
+	float	g = vid_gamma->value;
+
+	registration_sequence = 1;
+
+	// init intensity conversions
+	intensity = ri.Cvar_Get ("intensity", "2", 0);
+
+	if ( intensity->value <= 1 )
+		ri.Cvar_Set( "intensity", "1" );
+
+	gl_state.inverse_intensity = 1 / intensity->value;
+
+	Draw_GetPalette ();
+
+	if ( qglColorTableEXT )
+	{
+		ri.FS_LoadFile( "pics/16to8.dat", &gl_state.d_16to8table );
+		if ( !gl_state.d_16to8table )
+			ri.Sys_Error( ERR_FATAL, "Couldn't load pics/16to8.pcx");
+	}
+
+	if ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) )
+	{
+		g = 1.0F;
+	}
+
+	for ( i = 0; i < 256; i++ )
+	{
+		if ( g == 1 )
+		{
+			gammatable[i] = i;
+		}
+		else
+		{
+			float inf;
+
+			inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
+			if (inf < 0)
+				inf = 0;
+			if (inf > 255)
+				inf = 255;
+			gammatable[i] = inf;
+		}
+	}
+
+	for (i=0 ; i<256 ; i++)
+	{
+		j = i*intensity->value;
+		if (j > 255)
+			j = 255;
+		intensitytable[i] = j;
+	}
+}
+
+/*
+===============
+GL_ShutdownImages
+===============
+*/
+void	GL_ShutdownImages (void)
+{
+	int		i;
+	image_t	*image;
+
+	for (i=0, image=gltextures ; i<numgltextures ; i++, image++)
+	{
+		if (!image->registration_sequence)
+			continue;		// free image_t slot
+		// free it
+		qglDeleteTextures (1, &image->texnum);
+		memset (image, 0, sizeof(*image));
+	}
+}
+
--- /dev/null
+++ b/ref_gl/gl_light.c
@@ -1,0 +1,729 @@
+/*
+Copyright (C) 1997-2001 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 "gl_local.h"
+
+int	r_dlightframecount;
+
+#define	DLIGHT_CUTOFF	64
+
+/*
+=============================================================================
+
+DYNAMIC LIGHTS BLEND RENDERING
+
+=============================================================================
+*/
+
+void R_RenderDlight (dlight_t *light)
+{
+	int		i, j;
+	float	a;
+	vec3_t	v;
+	float	rad;
+
+	rad = light->intensity * 0.35;
+
+	VectorSubtract (light->origin, r_origin, v);
+#if 0
+	// FIXME?
+	if (VectorLength (v) < rad)
+	{	// view is inside the dlight
+		V_AddBlend (light->color[0], light->color[1], light->color[2], light->intensity * 0.0003, v_blend);
+		return;
+	}
+#endif
+
+	qglBegin (GL_TRIANGLE_FAN);
+	qglColor3f (light->color[0]*0.2, light->color[1]*0.2, light->color[2]*0.2);
+	for (i=0 ; i<3 ; i++)
+		v[i] = light->origin[i] - vpn[i]*rad;
+	qglVertex3fv (v);
+	qglColor3f (0,0,0);
+	for (i=16 ; i>=0 ; i--)
+	{
+		a = i/16.0 * M_PI*2;
+		for (j=0 ; j<3 ; j++)
+			v[j] = light->origin[j] + vright[j]*cos(a)*rad
+				+ vup[j]*sin(a)*rad;
+		qglVertex3fv (v);
+	}
+	qglEnd ();
+}
+
+/*
+=============
+R_RenderDlights
+=============
+*/
+void R_RenderDlights (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
+	qglDepthMask (0);
+	qglDisable (GL_TEXTURE_2D);
+	qglShadeModel (GL_SMOOTH);
+	qglEnable (GL_BLEND);
+	qglBlendFunc (GL_ONE, GL_ONE);
+
+	l = r_newrefdef.dlights;
+	for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++)
+		R_RenderDlight (l);
+
+	qglColor3f (1,1,1);
+	qglDisable (GL_BLEND);
+	qglEnable (GL_TEXTURE_2D);
+	qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	qglDepthMask (1);
+}
+
+
+/*
+=============================================================================
+
+DYNAMIC LIGHTS
+
+=============================================================================
+*/
+
+/*
+=============
+R_MarkLights
+=============
+*/
+void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
+{
+	cplane_t	*splitplane;
+	float		dist;
+	msurface_t	*surf;
+	int			i;
+	
+	if (node->contents != -1)
+		return;
+
+	splitplane = node->plane;
+	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
+	
+	if (dist > light->intensity-DLIGHT_CUTOFF)
+	{
+		R_MarkLights (light, bit, node->children[0]);
+		return;
+	}
+	if (dist < -light->intensity+DLIGHT_CUTOFF)
+	{
+		R_MarkLights (light, bit, node->children[1]);
+		return;
+	}
+		
+// mark the polygons
+	surf = r_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 = r_newrefdef.dlights;
+	for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++)
+		R_MarkLights ( l, 1<<i, r_worldmodel->nodes );
+}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+vec3_t			pointcolor;
+cplane_t		*lightplane;		// used as shadow plane
+vec3_t			lightspot;
+
+int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
+{
+	float		front, back, frac;
+	int			side;
+	cplane_t	*plane;
+	vec3_t		mid;
+	msurface_t	*surf;
+	int			s, t, ds, dt;
+	int			i;
+	mtexinfo_t	*tex;
+	byte		*lightmap;
+	int			maps;
+	int			r;
+
+	if (node->contents != -1)
+		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 = r_worldmodel->surfaces + node->firstsurface;
+	for (i=0 ; i<node->numsurfaces ; i++, surf++)
+	{
+		if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 
+			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;
+		VectorCopy (vec3_origin, pointcolor);
+		if (lightmap)
+		{
+			vec3_t scale;
+
+			lightmap += 3*(dt * ((surf->extents[0]>>4)+1) + ds);
+
+			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+					maps++)
+			{
+				for (i=0 ; i<3 ; i++)
+					scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
+
+				pointcolor[0] += lightmap[0] * scale[0] * (1.0/255);
+				pointcolor[1] += lightmap[1] * scale[1] * (1.0/255);
+				pointcolor[2] += lightmap[2] * scale[2] * (1.0/255);
+				lightmap += 3*((surf->extents[0]>>4)+1) *
+						((surf->extents[1]>>4)+1);
+			}
+		}
+		
+		return 1;
+	}
+
+// go down back side
+	return RecursiveLightPoint (node->children[!side], mid, end);
+}
+
+/*
+===============
+R_LightPoint
+===============
+*/
+void R_LightPoint (vec3_t p, vec3_t color)
+{
+	vec3_t		end;
+	float		r;
+	int			lnum;
+	dlight_t	*dl;
+	float		light;
+	vec3_t		dist;
+	float		add;
+	
+	if (!r_worldmodel->lightdata)
+	{
+		color[0] = color[1] = color[2] = 1.0;
+		return;
+	}
+	
+	end[0] = p[0];
+	end[1] = p[1];
+	end[2] = p[2] - 2048;
+	
+	r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
+	
+	if (r == -1)
+	{
+		VectorCopy (vec3_origin, color);
+	}
+	else
+	{
+		VectorCopy (pointcolor, color);
+	}
+
+	//
+	// add dynamic lights
+	//
+	light = 0;
+	dl = r_newrefdef.dlights;
+	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++, dl++)
+	{
+		VectorSubtract (currententity->origin,
+						dl->origin,
+						dist);
+		add = dl->intensity - VectorLength(dist);
+		add *= (1.0/256);
+		if (add > 0)
+		{
+			VectorMA (color, add, dl->color, color);
+		}
+	}
+
+	VectorScale (color, gl_modulate->value, color);
+}
+
+
+//===================================================================
+
+static float s_blocklights[34*34*3];
+/*
+===============
+R_AddDynamicLights
+===============
+*/
+void R_AddDynamicLights (msurface_t *surf)
+{
+	int			lnum;
+	int			sd, td;
+	float		fdist, frad, fminlight;
+	vec3_t		impact, local;
+	int			s, t;
+	int			i;
+	int			smax, tmax;
+	mtexinfo_t	*tex;
+	dlight_t	*dl;
+	float		*pfBL;
+	float		fsacc, ftacc;
+
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+	tex = surf->texinfo;
+
+	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+	{
+		if ( !(surf->dlightbits & (1<<lnum) ) )
+			continue;		// not lit by this light
+
+		dl = &r_newrefdef.dlights[lnum];
+		frad = dl->intensity;
+		fdist = DotProduct (dl->origin, surf->plane->normal) -
+				surf->plane->dist;
+		frad -= fabs(fdist);
+		// rad is now the highest intensity on the plane
+
+		fminlight = DLIGHT_CUTOFF;	// FIXME: make configurable?
+		if (frad < fminlight)
+			continue;
+		fminlight = frad - fminlight;
+
+		for (i=0 ; i<3 ; i++)
+		{
+			impact[i] = dl->origin[i] -
+					surf->plane->normal[i]*fdist;
+		}
+
+		local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0];
+		local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1];
+
+		pfBL = s_blocklights;
+		for (t = 0, ftacc = 0 ; t<tmax ; t++, ftacc += 16)
+		{
+			td = local[1] - ftacc;
+			if ( td < 0 )
+				td = -td;
+
+			for ( s=0, fsacc = 0 ; s<smax ; s++, fsacc += 16, pfBL += 3)
+			{
+				sd = Q_ftol( local[0] - fsacc );
+
+				if ( sd < 0 )
+					sd = -sd;
+
+				if (sd > td)
+					fdist = sd + (td>>1);
+				else
+					fdist = td + (sd>>1);
+
+				if ( fdist < fminlight )
+				{
+					pfBL[0] += ( frad - fdist ) * dl->color[0];
+					pfBL[1] += ( frad - fdist ) * dl->color[1];
+					pfBL[2] += ( frad - fdist ) * dl->color[2];
+				}
+			}
+		}
+	}
+}
+
+
+/*
+** R_SetCacheState
+*/
+void R_SetCacheState( msurface_t *surf )
+{
+	int maps;
+
+	for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+		 maps++)
+	{
+		surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white;
+	}
+}
+
+/*
+===============
+R_BuildLightMap
+
+Combine and scale multiple lightmaps into the floating format in blocklights
+===============
+*/
+void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
+{
+	int			smax, tmax;
+	int			r, g, b, a, max;
+	int			i, j, size;
+	byte		*lightmap;
+	float		scale[4];
+	int			nummaps;
+	float		*bl;
+	lightstyle_t	*style;
+	int monolightmap;
+
+	if ( surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) )
+		ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface");
+
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+	size = smax*tmax;
+	if (size > (sizeof(s_blocklights)>>4) )
+		ri.Sys_Error (ERR_DROP, "Bad s_blocklights size");
+
+// set to full bright if no light data
+	if (!surf->samples)
+	{
+		int maps;
+
+		for (i=0 ; i<size*3 ; i++)
+			s_blocklights[i] = 255;
+		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+			 maps++)
+		{
+			style = &r_newrefdef.lightstyles[surf->styles[maps]];
+		}
+		goto store;
+	}
+
+	// count the # of maps
+	for ( nummaps = 0 ; nummaps < MAXLIGHTMAPS && surf->styles[nummaps] != 255 ;
+		 nummaps++)
+		;
+
+	lightmap = surf->samples;
+
+	// add all the lightmaps
+	if ( nummaps == 1 )
+	{
+		int maps;
+
+		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+			 maps++)
+		{
+			bl = s_blocklights;
+
+			for (i=0 ; i<3 ; i++)
+				scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
+
+			if ( scale[0] == 1.0F &&
+				 scale[1] == 1.0F &&
+				 scale[2] == 1.0F )
+			{
+				for (i=0 ; i<size ; i++, bl+=3)
+				{
+					bl[0] = lightmap[i*3+0];
+					bl[1] = lightmap[i*3+1];
+					bl[2] = lightmap[i*3+2];
+				}
+			}
+			else
+			{
+				for (i=0 ; i<size ; i++, bl+=3)
+				{
+					bl[0] = lightmap[i*3+0] * scale[0];
+					bl[1] = lightmap[i*3+1] * scale[1];
+					bl[2] = lightmap[i*3+2] * scale[2];
+				}
+			}
+			lightmap += size*3;		// skip to next lightmap
+		}
+	}
+	else
+	{
+		int maps;
+
+		memset( s_blocklights, 0, sizeof( s_blocklights[0] ) * size * 3 );
+
+		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+			 maps++)
+		{
+			bl = s_blocklights;
+
+			for (i=0 ; i<3 ; i++)
+				scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
+
+			if ( scale[0] == 1.0F &&
+				 scale[1] == 1.0F &&
+				 scale[2] == 1.0F )
+			{
+				for (i=0 ; i<size ; i++, bl+=3 )
+				{
+					bl[0] += lightmap[i*3+0];
+					bl[1] += lightmap[i*3+1];
+					bl[2] += lightmap[i*3+2];
+				}
+			}
+			else
+			{
+				for (i=0 ; i<size ; i++, bl+=3)
+				{
+					bl[0] += lightmap[i*3+0] * scale[0];
+					bl[1] += lightmap[i*3+1] * scale[1];
+					bl[2] += lightmap[i*3+2] * scale[2];
+				}
+			}
+			lightmap += size*3;		// skip to next lightmap
+		}
+	}
+
+// add all the dynamic lights
+	if (surf->dlightframe == r_framecount)
+		R_AddDynamicLights (surf);
+
+// put into texture format
+store:
+	stride -= (smax<<2);
+	bl = s_blocklights;
+
+	monolightmap = gl_monolightmap->string[0];
+
+	if ( monolightmap == '0' )
+	{
+		for (i=0 ; i<tmax ; i++, dest += stride)
+		{
+			for (j=0 ; j<smax ; j++)
+			{
+				
+				r = Q_ftol( bl[0] );
+				g = Q_ftol( bl[1] );
+				b = Q_ftol( bl[2] );
+
+				// catch negative lights
+				if (r < 0)
+					r = 0;
+				if (g < 0)
+					g = 0;
+				if (b < 0)
+					b = 0;
+
+				/*
+				** determine the brightest of the three color components
+				*/
+				if (r > g)
+					max = r;
+				else
+					max = g;
+				if (b > max)
+					max = b;
+
+				/*
+				** alpha is ONLY used for the mono lightmap case.  For this reason
+				** we set it to the brightest of the color components so that 
+				** things don't get too dim.
+				*/
+				a = max;
+
+				/*
+				** rescale all the color components if the intensity of the greatest
+				** channel exceeds 1.0
+				*/
+				if (max > 255)
+				{
+					float t = 255.0F / max;
+
+					r = r*t;
+					g = g*t;
+					b = b*t;
+					a = a*t;
+				}
+
+				dest[0] = r;
+				dest[1] = g;
+				dest[2] = b;
+				dest[3] = a;
+
+				bl += 3;
+				dest += 4;
+			}
+		}
+	}
+	else
+	{
+		for (i=0 ; i<tmax ; i++, dest += stride)
+		{
+			for (j=0 ; j<smax ; j++)
+			{
+				
+				r = Q_ftol( bl[0] );
+				g = Q_ftol( bl[1] );
+				b = Q_ftol( bl[2] );
+
+				// catch negative lights
+				if (r < 0)
+					r = 0;
+				if (g < 0)
+					g = 0;
+				if (b < 0)
+					b = 0;
+
+				/*
+				** determine the brightest of the three color components
+				*/
+				if (r > g)
+					max = r;
+				else
+					max = g;
+				if (b > max)
+					max = b;
+
+				/*
+				** alpha is ONLY used for the mono lightmap case.  For this reason
+				** we set it to the brightest of the color components so that 
+				** things don't get too dim.
+				*/
+				a = max;
+
+				/*
+				** rescale all the color components if the intensity of the greatest
+				** channel exceeds 1.0
+				*/
+				if (max > 255)
+				{
+					float t = 255.0F / max;
+
+					r = r*t;
+					g = g*t;
+					b = b*t;
+					a = a*t;
+				}
+
+				/*
+				** So if we are doing alpha lightmaps we need to set the R, G, and B
+				** components to 0 and we need to set alpha to 1-alpha.
+				*/
+				switch ( monolightmap )
+				{
+				case 'L':
+				case 'I':
+					r = a;
+					g = b = 0;
+					break;
+				case 'C':
+					// try faking colored lighting
+					a = 255 - ((r+g+b)/3);
+					r *= a/255.0;
+					g *= a/255.0;
+					b *= a/255.0;
+					break;
+				case 'A':
+				default:
+					r = g = b = 0;
+					a = 255 - a;
+					break;
+				}
+
+				dest[0] = r;
+				dest[1] = g;
+				dest[2] = b;
+				dest[3] = a;
+
+				bl += 3;
+				dest += 4;
+			}
+		}
+	}
+}
+
--- /dev/null
+++ b/ref_gl/gl_local.h
@@ -1,0 +1,460 @@
+/*
+Copyright (C) 1997-2001 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
+
+#if 0
+#pragma warning(disable : 4244)     // MIPS
+#pragma warning(disable : 4136)     // X86
+#pragma warning(disable : 4051)     // ALPHA
+#endif
+
+#ifdef _WIN32
+#  include <windows.h>
+#endif
+
+#include <stdio.h>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <math.h>
+
+#ifndef GL_COLOR_INDEX8_EXT
+#define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX
+#endif
+
+#include "../client/ref.h"
+
+#include "qgl.h"
+
+#define	REF_VERSION	"GL 0.01"
+
+// up / down
+#define	PITCH	0
+
+// left / right
+#define	YAW		1
+
+// fall over
+#define	ROLL	2
+
+
+typedef struct
+{
+	unsigned		width, height;			// coordinates from main game
+} viddef_t;
+
+extern	viddef_t	vid;
+
+
+/*
+
+  skins will be outline flood filled and mip mapped
+  pics and sprites with alpha will be outline flood filled
+  pic won't be mip mapped
+
+  model skin
+  sprite frame
+  wall texture
+  pic
+
+*/
+
+typedef enum 
+{
+	it_skin,
+	it_sprite,
+	it_wall,
+	it_pic,
+	it_sky
+} imagetype_t;
+
+typedef struct image_s
+{
+	char	name[MAX_QPATH];			// game path, including extension
+	imagetype_t	type;
+	int		width, height;				// source image
+	int		upload_width, upload_height;	// after power of two and picmip
+	int		registration_sequence;		// 0 = free
+	struct msurface_s	*texturechain;	// for sort-by-texture world drawing
+	int		texnum;						// gl texture binding
+	float	sl, tl, sh, th;				// 0,0 - 1,1 unless part of the scrap
+	qboolean	scrap;
+	qboolean	has_alpha;
+
+	qboolean paletted;
+} image_t;
+
+#define	TEXNUM_LIGHTMAPS	1024
+#define	TEXNUM_SCRAPS		1152
+#define	TEXNUM_IMAGES		1153
+
+#define		MAX_GLTEXTURES	1024
+
+//===================================================================
+
+typedef enum
+{
+	rserr_ok,
+
+	rserr_invalid_fullscreen,
+	rserr_invalid_mode,
+
+	rserr_unknown
+} rserr_t;
+
+#include "gl_model.h"
+
+void GL_BeginRendering (int *x, int *y, int *width, int *height);
+void GL_EndRendering (void);
+
+void GL_SetDefaultState( void );
+void GL_UpdateSwapInterval( void );
+
+extern	float	gldepthmin, gldepthmax;
+
+typedef struct
+{
+	float	x, y, z;
+	float	s, t;
+	float	r, g, b;
+} glvert_t;
+
+
+#define	MAX_LBM_HEIGHT		480
+
+#define BACKFACE_EPSILON	0.01
+
+
+//====================================================
+
+extern	image_t		gltextures[MAX_GLTEXTURES];
+extern	int			numgltextures;
+
+
+extern	image_t		*r_notexture;
+extern	image_t		*r_particletexture;
+extern	entity_t	*currententity;
+extern	model_t		*currentmodel;
+extern	int			r_visframecount;
+extern	int			r_framecount;
+extern	cplane_t	frustum[4];
+extern	int			c_brush_polys, c_alias_polys;
+
+
+extern	int			gl_filter_min, gl_filter_max;
+
+//
+// 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_newrefdef;
+extern	int		r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
+
+extern	cvar_t	*r_norefresh;
+extern	cvar_t	*r_lefthand;
+extern	cvar_t	*r_drawentities;
+extern	cvar_t	*r_drawworld;
+extern	cvar_t	*r_speeds;
+extern	cvar_t	*r_fullbright;
+extern	cvar_t	*r_novis;
+extern	cvar_t	*r_nocull;
+extern	cvar_t	*r_lerpmodels;
+
+extern	cvar_t	*r_lightlevel;	// FIXME: This is a HACK to get the client's light level
+
+extern cvar_t	*gl_vertex_arrays;
+
+extern cvar_t	*gl_ext_swapinterval;
+extern cvar_t	*gl_ext_palettedtexture;
+extern cvar_t	*gl_ext_multitexture;
+extern cvar_t	*gl_ext_pointparameters;
+extern cvar_t	*gl_ext_compiled_vertex_array;
+
+extern cvar_t	*gl_particle_min_size;
+extern cvar_t	*gl_particle_max_size;
+extern cvar_t	*gl_particle_size;
+extern cvar_t	*gl_particle_att_a;
+extern cvar_t	*gl_particle_att_b;
+extern cvar_t	*gl_particle_att_c;
+
+extern	cvar_t	*gl_nosubimage;
+extern	cvar_t	*gl_bitdepth;
+extern	cvar_t	*gl_mode;
+extern	cvar_t	*gl_log;
+extern	cvar_t	*gl_lightmap;
+extern	cvar_t	*gl_shadows;
+extern	cvar_t	*gl_dynamic;
+extern  cvar_t  *gl_monolightmap;
+extern	cvar_t	*gl_nobind;
+extern	cvar_t	*gl_round_down;
+extern	cvar_t	*gl_picmip;
+extern	cvar_t	*gl_skymip;
+extern	cvar_t	*gl_showtris;
+extern	cvar_t	*gl_finish;
+extern	cvar_t	*gl_ztrick;
+extern	cvar_t	*gl_clear;
+extern	cvar_t	*gl_cull;
+extern	cvar_t	*gl_poly;
+extern	cvar_t	*gl_texsort;
+extern	cvar_t	*gl_polyblend;
+extern	cvar_t	*gl_flashblend;
+extern	cvar_t	*gl_lightmaptype;
+extern	cvar_t	*gl_modulate;
+extern	cvar_t	*gl_playermip;
+extern	cvar_t	*gl_drawbuffer;
+extern	cvar_t	*gl_3dlabs_broken;
+extern  cvar_t  *gl_driver;
+extern	cvar_t	*gl_swapinterval;
+extern	cvar_t	*gl_texturemode;
+extern	cvar_t	*gl_texturealphamode;
+extern	cvar_t	*gl_texturesolidmode;
+extern  cvar_t  *gl_saturatelighting;
+extern  cvar_t  *gl_lockpvs;
+
+extern	cvar_t	*vid_fullscreen;
+extern	cvar_t	*vid_gamma;
+
+extern	cvar_t		*intensity;
+
+extern	int		gl_lightmap_format;
+extern	int		gl_solid_format;
+extern	int		gl_alpha_format;
+extern	int		gl_tex_solid_format;
+extern	int		gl_tex_alpha_format;
+
+extern	int		c_visible_lightmaps;
+extern	int		c_visible_textures;
+
+extern	float	r_world_matrix[16];
+
+void R_TranslatePlayerSkin (int playernum);
+void GL_Bind (int texnum);
+void GL_MBind( GLenum target, int texnum );
+void GL_TexEnv( GLenum value );
+void GL_EnableMultitexture( qboolean enable );
+void GL_SelectTexture( GLenum );
+
+void R_LightPoint (vec3_t p, vec3_t color);
+void R_PushDlights (void);
+
+//====================================================================
+
+extern	model_t	*r_worldmodel;
+
+extern	unsigned	d_8to24table[256];
+
+extern	int		registration_sequence;
+
+
+void V_AddBlend (float r, float g, float b, float a, float *v_blend);
+
+int 	R_Init( void *hinstance, void *hWnd );
+void	R_Shutdown( void );
+
+void R_RenderView (refdef_t *fd);
+void GL_ScreenShot_f (void);
+void R_DrawAliasModel (entity_t *e);
+void R_DrawBrushModel (entity_t *e);
+void R_DrawSpriteModel (entity_t *e);
+void R_DrawBeam( entity_t *e );
+void R_DrawWorld (void);
+void R_RenderDlights (void);
+void R_DrawAlphaSurfaces (void);
+void R_RenderBrushPoly (msurface_t *fa);
+void R_InitParticleTexture (void);
+void Draw_InitLocal (void);
+void GL_SubdivideSurface (msurface_t *fa);
+qboolean R_CullBox (vec3_t mins, vec3_t maxs);
+void R_RotateForEntity (entity_t *e);
+void R_MarkLeaves (void);
+
+glpoly_t *WaterWarpPolyVerts (glpoly_t *p);
+void EmitWaterPolys (msurface_t *fa);
+void R_AddSkySurface (msurface_t *fa);
+void R_ClearSkyBox (void);
+void R_DrawSkyBox (void);
+void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
+
+#if 0
+short LittleShort (short l);
+short BigShort (short l);
+int	LittleLong (int l);
+float LittleFloat (float f);
+
+char	*va(char *format, ...);
+// does a varargs printf into a temp buffer
+#endif
+
+void COM_StripExtension (char *in, char *out);
+
+void	Draw_GetPicSize (int *w, int *h, char *name);
+void	Draw_Pic (int x, int y, char *name);
+void	Draw_StretchPic (int x, int y, int w, int h, char *name);
+void	Draw_Char (int x, int y, int c);
+void	Draw_TileClear (int x, int y, int w, int h, char *name);
+void	Draw_Fill (int x, int y, int w, int h, int c);
+void	Draw_FadeScreen (void);
+void	Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data);
+
+void	R_BeginFrame( float camera_separation );
+void	R_SwapBuffers( int );
+void	R_SetPalette ( const unsigned char *palette);
+
+int		Draw_GetPalette (void);
+
+void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight);
+
+struct image_s *R_RegisterSkin (char *name);
+
+void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height);
+image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits);
+image_t	*GL_FindImage (char *name, imagetype_t type);
+void	GL_TextureMode( char *string );
+void	GL_ImageList_f (void);
+
+void	GL_SetTexturePalette( unsigned palette[256] );
+
+void	GL_InitImages (void);
+void	GL_ShutdownImages (void);
+
+void	GL_FreeUnusedImages (void);
+
+void GL_TextureAlphaMode( char *string );
+void GL_TextureSolidMode( char *string );
+
+/*
+** GL extension emulation functions
+*/
+void GL_DrawParticles( int n, const particle_t particles[], const unsigned colortable[768] );
+
+/*
+** GL config stuff
+*/
+#define GL_RENDERER_VOODOO		0x00000001
+#define GL_RENDERER_VOODOO2   	0x00000002
+#define GL_RENDERER_VOODOO_RUSH	0x00000004
+#define GL_RENDERER_BANSHEE		0x00000008
+#define		GL_RENDERER_3DFX		0x0000000F
+
+#define GL_RENDERER_PCX1		0x00000010
+#define GL_RENDERER_PCX2		0x00000020
+#define GL_RENDERER_PMX			0x00000040
+#define		GL_RENDERER_POWERVR		0x00000070
+
+#define GL_RENDERER_PERMEDIA2	0x00000100
+#define GL_RENDERER_GLINT_MX	0x00000200
+#define GL_RENDERER_GLINT_TX	0x00000400
+#define GL_RENDERER_3DLABS_MISC	0x00000800
+#define		GL_RENDERER_3DLABS	0x00000F00
+
+#define GL_RENDERER_REALIZM		0x00001000
+#define GL_RENDERER_REALIZM2	0x00002000
+#define		GL_RENDERER_INTERGRAPH	0x00003000
+
+#define GL_RENDERER_3DPRO		0x00004000
+#define GL_RENDERER_REAL3D		0x00008000
+#define GL_RENDERER_RIVA128		0x00010000
+#define GL_RENDERER_DYPIC		0x00020000
+
+#define GL_RENDERER_V1000		0x00040000
+#define GL_RENDERER_V2100		0x00080000
+#define GL_RENDERER_V2200		0x00100000
+#define		GL_RENDERER_RENDITION	0x001C0000
+
+#define GL_RENDERER_O2          0x00100000
+#define GL_RENDERER_IMPACT      0x00200000
+#define GL_RENDERER_RE			0x00400000
+#define GL_RENDERER_IR			0x00800000
+#define		GL_RENDERER_SGI			0x00F00000
+
+#define GL_RENDERER_MCD			0x01000000
+#define GL_RENDERER_OTHER		0x80000000
+
+typedef struct
+{
+	int         renderer;
+	const char *renderer_string;
+	const char *vendor_string;
+	const char *version_string;
+	const char *extensions_string;
+
+	qboolean	allow_cds;
+} glconfig_t;
+
+typedef struct
+{
+	float inverse_intensity;
+	qboolean fullscreen;
+
+	int     prev_mode;
+
+	unsigned char *d_16to8table;
+
+	int lightmap_textures;
+
+	int	currenttextures[2];
+	int currenttmu;
+
+	float camera_separation;
+	qboolean stereo_enabled;
+
+	unsigned char originalRedGammaTable[256];
+	unsigned char originalGreenGammaTable[256];
+	unsigned char originalBlueGammaTable[256];
+} glstate_t;
+
+extern glconfig_t  gl_config;
+extern glstate_t   gl_state;
+
+/*
+====================================================================
+
+IMPORTED FUNCTIONS
+
+====================================================================
+*/
+
+extern	refimport_t	ri;
+
+
+/*
+====================================================================
+
+IMPLEMENTATION SPECIFIC FUNCTIONS
+
+====================================================================
+*/
+
+void		GLimp_BeginFrame( float camera_separation );
+void		GLimp_EndFrame( void );
+int 		GLimp_Init( void *hinstance, void *hWnd );
+void		GLimp_Shutdown( void );
+int     	GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen );
+void		GLimp_AppActivate( qboolean active );
+void		GLimp_EnableLogging( qboolean enable );
+void		GLimp_LogNewFrame( void );
+
--- /dev/null
+++ b/ref_gl/gl_mesh.c
@@ -1,0 +1,839 @@
+/*
+Copyright (C) 1997-2001 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 "gl_local.h"
+
+/*
+=============================================================
+
+  ALIAS MODELS
+
+=============================================================
+*/
+
+#define NUMVERTEXNORMALS	162
+
+float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
+#include "anorms.h"
+};
+
+typedef float vec4_t[4];
+
+static	vec4_t	s_lerped[MAX_VERTS];
+//static	vec3_t	lerped[MAX_VERTS];
+
+vec3_t	shadevector;
+float	shadelight[3];
+
+// precalculated dot products for quantized angles
+#define SHADEDOT_QUANT 16
+float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =
+#include "anormtab.h"
+;
+
+float	*shadedots = r_avertexnormal_dots[0];
+
+void GL_LerpVerts( int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3] )
+{
+	int i;
+
+	//PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM
+	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+	{
+		for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4 )
+		{
+			float *normal = r_avertexnormals[verts[i].lightnormalindex];
+
+			lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0] + normal[0] * POWERSUIT_SCALE;
+			lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * POWERSUIT_SCALE;
+			lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * POWERSUIT_SCALE; 
+		}
+	}
+	else
+	{
+		for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4)
+		{
+			lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0];
+			lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1];
+			lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2];
+		}
+	}
+
+}
+
+/*
+=============
+GL_DrawAliasFrameLerp
+
+interpolates between two frames and origins
+FIXME: batch lerp all vertexes
+=============
+*/
+void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp)
+{
+	float 	l;
+	daliasframe_t	*frame, *oldframe;
+	dtrivertx_t	*v, *ov, *verts;
+	int		*order;
+	int		count;
+	float	frontlerp;
+	float	alpha;
+	vec3_t	move, delta, vectors[3];
+	vec3_t	frontv, backv;
+	int		i;
+	int		index_xyz;
+	float	*lerp;
+
+	frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames 
+		+ currententity->frame * paliashdr->framesize);
+	verts = v = frame->verts;
+
+	oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames 
+		+ currententity->oldframe * paliashdr->framesize);
+	ov = oldframe->verts;
+
+	order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
+
+//	glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]);
+//	glScalef (frame->scale[0], frame->scale[1], frame->scale[2]);
+
+	if (currententity->flags & RF_TRANSLUCENT)
+		alpha = currententity->alpha;
+	else
+		alpha = 1.0;
+
+	// PMM - added double shell
+	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+		qglDisable( GL_TEXTURE_2D );
+
+	frontlerp = 1.0 - backlerp;
+
+	// move should be the delta back to the previous frame * backlerp
+	VectorSubtract (currententity->oldorigin, currententity->origin, delta);
+	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
+
+	move[0] = DotProduct (delta, vectors[0]);	// forward
+	move[1] = -DotProduct (delta, vectors[1]);	// left
+	move[2] = DotProduct (delta, vectors[2]);	// up
+
+	VectorAdd (move, oldframe->translate, move);
+
+	for (i=0 ; i<3 ; i++)
+	{
+		move[i] = backlerp*move[i] + frontlerp*frame->translate[i];
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		frontv[i] = frontlerp*frame->scale[i];
+		backv[i] = backlerp*oldframe->scale[i];
+	}
+
+	lerp = s_lerped[0];
+
+	GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv );
+
+	if ( gl_vertex_arrays->value )
+	{
+		float colorArray[MAX_VERTS*4];
+
+		qglEnableClientState( GL_VERTEX_ARRAY );
+		qglVertexPointer( 3, GL_FLOAT, 16, s_lerped );	// padded for SIMD
+
+//		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
+		// PMM - added double damage shell
+		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+		{
+			qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha );
+		}
+		else
+		{
+			qglEnableClientState( GL_COLOR_ARRAY );
+			qglColorPointer( 3, GL_FLOAT, 0, colorArray );
+
+			//
+			// pre light everything
+			//
+			for ( i = 0; i < paliashdr->num_xyz; i++ )
+			{
+				float l = shadedots[verts[i].lightnormalindex];
+
+				colorArray[i*3+0] = l * shadelight[0];
+				colorArray[i*3+1] = l * shadelight[1];
+				colorArray[i*3+2] = l * shadelight[2];
+			}
+		}
+
+		if ( qglLockArraysEXT != 0 )
+			qglLockArraysEXT( 0, paliashdr->num_xyz );
+
+		while (1)
+		{
+			// get the vertex count and primitive type
+			count = *order++;
+			if (!count)
+				break;		// done
+			if (count < 0)
+			{
+				count = -count;
+				qglBegin (GL_TRIANGLE_FAN);
+			}
+			else
+			{
+				qglBegin (GL_TRIANGLE_STRIP);
+			}
+
+			// PMM - added double damage shell
+			if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+			{
+				do
+				{
+					index_xyz = order[2];
+					order += 3;
+
+					qglVertex3fv( s_lerped[index_xyz] );
+
+				} while (--count);
+			}
+			else
+			{
+				do
+				{
+					// texture coordinates come from the draw list
+					qglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
+					index_xyz = order[2];
+
+					order += 3;
+
+					// normals and vertexes come from the frame list
+//					l = shadedots[verts[index_xyz].lightnormalindex];
+					
+//					qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
+					qglArrayElement( index_xyz );
+
+				} while (--count);
+			}
+			qglEnd ();
+		}
+
+		if ( qglUnlockArraysEXT != 0 )
+			qglUnlockArraysEXT();
+	}
+	else
+	{
+		while (1)
+		{
+			// get the vertex count and primitive type
+			count = *order++;
+			if (!count)
+				break;		// done
+			if (count < 0)
+			{
+				count = -count;
+				qglBegin (GL_TRIANGLE_FAN);
+			}
+			else
+			{
+				qglBegin (GL_TRIANGLE_STRIP);
+			}
+
+			if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
+			{
+				do
+				{
+					index_xyz = order[2];
+					order += 3;
+
+					qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha);
+					qglVertex3fv (s_lerped[index_xyz]);
+
+				} while (--count);
+			}
+			else
+			{
+				do
+				{
+					// texture coordinates come from the draw list
+					qglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
+					index_xyz = order[2];
+					order += 3;
+
+					// normals and vertexes come from the frame list
+					l = shadedots[verts[index_xyz].lightnormalindex];
+					
+					qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
+					qglVertex3fv (s_lerped[index_xyz]);
+				} while (--count);
+			}
+
+			qglEnd ();
+		}
+	}
+
+//	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
+	// PMM - added double damage shell
+	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+		qglEnable( GL_TEXTURE_2D );
+}
+
+
+#if 1
+/*
+=============
+GL_DrawAliasShadow
+=============
+*/
+extern	vec3_t			lightspot;
+
+void GL_DrawAliasShadow (dmdl_t *paliashdr, int posenum)
+{
+	dtrivertx_t	*verts;
+	int		*order;
+	vec3_t	point;
+	float	height, lheight;
+	int		count;
+	daliasframe_t	*frame;
+
+	lheight = currententity->origin[2] - lightspot[2];
+
+	frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames 
+		+ currententity->frame * paliashdr->framesize);
+	verts = frame->verts;
+
+	height = 0;
+
+	order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
+
+	height = -lheight + 1.0;
+
+	while (1)
+	{
+		// get the vertex count and primitive type
+		count = *order++;
+		if (!count)
+			break;		// done
+		if (count < 0)
+		{
+			count = -count;
+			qglBegin (GL_TRIANGLE_FAN);
+		}
+		else
+			qglBegin (GL_TRIANGLE_STRIP);
+
+		do
+		{
+			// normals and vertexes come from the frame list
+/*
+			point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0];
+			point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1];
+			point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2];
+*/
+
+			memcpy( point, s_lerped[order[2]], sizeof( point )  );
+
+			point[0] -= shadevector[0]*(point[2]+lheight);
+			point[1] -= shadevector[1]*(point[2]+lheight);
+			point[2] = height;
+//			height -= 0.001;
+			qglVertex3fv (point);
+
+			order += 3;
+
+//			verts++;
+
+		} while (--count);
+
+		qglEnd ();
+	}	
+}
+
+#endif
+
+/*
+** R_CullAliasModel
+*/
+static qboolean R_CullAliasModel( vec3_t bbox[8], entity_t *e )
+{
+	int i;
+	vec3_t		mins, maxs;
+	dmdl_t		*paliashdr;
+	vec3_t		vectors[3];
+	vec3_t		thismins, oldmins, thismaxs, oldmaxs;
+	daliasframe_t *pframe, *poldframe;
+	vec3_t angles;
+
+	paliashdr = (dmdl_t *)currentmodel->extradata;
+
+	if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such frame %d\n", 
+			currentmodel->name, e->frame);
+		e->frame = 0;
+	}
+	if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such oldframe %d\n", 
+			currentmodel->name, e->oldframe);
+		e->oldframe = 0;
+	}
+
+	pframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + 
+		                              paliashdr->ofs_frames +
+									  e->frame * paliashdr->framesize);
+
+	poldframe = ( daliasframe_t * ) ( ( byte * ) paliashdr + 
+		                              paliashdr->ofs_frames +
+									  e->oldframe * paliashdr->framesize);
+
+	/*
+	** compute axially aligned mins and maxs
+	*/
+	if ( pframe == poldframe )
+	{
+		for ( i = 0; i < 3; i++ )
+		{
+			mins[i] = pframe->translate[i];
+			maxs[i] = mins[i] + pframe->scale[i]*255;
+		}
+	}
+	else
+	{
+		for ( i = 0; i < 3; i++ )
+		{
+			thismins[i] = pframe->translate[i];
+			thismaxs[i] = thismins[i] + pframe->scale[i]*255;
+
+			oldmins[i]  = poldframe->translate[i];
+			oldmaxs[i]  = oldmins[i] + poldframe->scale[i]*255;
+
+			if ( thismins[i] < oldmins[i] )
+				mins[i] = thismins[i];
+			else
+				mins[i] = oldmins[i];
+
+			if ( thismaxs[i] > oldmaxs[i] )
+				maxs[i] = thismaxs[i];
+			else
+				maxs[i] = oldmaxs[i];
+		}
+	}
+
+	/*
+	** compute a full bounding box
+	*/
+	for ( i = 0; i < 8; i++ )
+	{
+		vec3_t   tmp;
+
+		if ( i & 1 )
+			tmp[0] = mins[0];
+		else
+			tmp[0] = maxs[0];
+
+		if ( i & 2 )
+			tmp[1] = mins[1];
+		else
+			tmp[1] = maxs[1];
+
+		if ( i & 4 )
+			tmp[2] = mins[2];
+		else
+			tmp[2] = maxs[2];
+
+		VectorCopy( tmp, bbox[i] );
+	}
+
+	/*
+	** rotate the bounding box
+	*/
+	VectorCopy( e->angles, angles );
+	angles[YAW] = -angles[YAW];
+	AngleVectors( angles, vectors[0], vectors[1], vectors[2] );
+
+	for ( i = 0; i < 8; i++ )
+	{
+		vec3_t tmp;
+
+		VectorCopy( bbox[i], tmp );
+
+		bbox[i][0] = DotProduct( vectors[0], tmp );
+		bbox[i][1] = -DotProduct( vectors[1], tmp );
+		bbox[i][2] = DotProduct( vectors[2], tmp );
+
+		VectorAdd( e->origin, bbox[i], bbox[i] );
+	}
+
+	{
+		int p, f, aggregatemask = ~0;
+
+		for ( p = 0; p < 8; p++ )
+		{
+			int mask = 0;
+
+			for ( f = 0; f < 4; f++ )
+			{
+				float dp = DotProduct( frustum[f].normal, bbox[p] );
+
+				if ( ( dp - frustum[f].dist ) < 0 )
+				{
+					mask |= ( 1 << f );
+				}
+			}
+
+			aggregatemask &= mask;
+		}
+
+		if ( aggregatemask )
+		{
+			return true;
+		}
+
+		return false;
+	}
+}
+
+/*
+=================
+R_DrawAliasModel
+
+=================
+*/
+void R_DrawAliasModel (entity_t *e)
+{
+	int			i;
+	dmdl_t		*paliashdr;
+	float		an;
+	vec3_t		bbox[8];
+	image_t		*skin;
+
+	if ( !( e->flags & RF_WEAPONMODEL ) )
+	{
+		if ( R_CullAliasModel( bbox, e ) )
+			return;
+	}
+
+	if ( e->flags & RF_WEAPONMODEL )
+	{
+		if ( r_lefthand->value == 2 )
+			return;
+	}
+
+	paliashdr = (dmdl_t *)currentmodel->extradata;
+
+	//
+	// get lighting information
+	//
+	// PMM - rewrote, reordered to handle new shells & mixing
+	//
+	if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) )
+	{
+		// PMM -special case for godmode
+		if ( (currententity->flags & RF_SHELL_RED) &&
+			(currententity->flags & RF_SHELL_BLUE) &&
+			(currententity->flags & RF_SHELL_GREEN) )
+		{
+			for (i=0 ; i<3 ; i++)
+				shadelight[i] = 1.0;
+		}
+		else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) )
+		{
+			VectorClear (shadelight);
+
+			if ( currententity->flags & RF_SHELL_RED )
+			{
+				shadelight[0] = 1.0;
+				if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) )
+					shadelight[2] = 1.0;
+			}
+			else if ( currententity->flags & RF_SHELL_BLUE )
+			{
+				if ( currententity->flags & RF_SHELL_DOUBLE )
+				{
+					shadelight[1] = 1.0;
+					shadelight[2] = 1.0;
+				}
+				else
+				{
+					shadelight[2] = 1.0;
+				}
+			}
+			else if ( currententity->flags & RF_SHELL_DOUBLE )
+			{
+				shadelight[0] = 0.9;
+				shadelight[1] = 0.7;
+			}
+		}
+		else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) )
+		{
+			VectorClear (shadelight);
+			// PMM - new colors
+			if ( currententity->flags & RF_SHELL_HALF_DAM )
+			{
+				shadelight[0] = 0.56;
+				shadelight[1] = 0.59;
+				shadelight[2] = 0.45;
+			}
+			if ( currententity->flags & RF_SHELL_GREEN )
+			{
+				shadelight[1] = 1.0;
+			}
+		}
+	}
+			//PMM - ok, now flatten these down to range from 0 to 1.0.
+	//		max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2]));
+	//		if (max_shell_val > 0)
+	//		{
+	//			for (i=0; i<3; i++)
+	//			{
+	//				shadelight[i] = shadelight[i] / max_shell_val;
+	//			}
+	//		}
+	// pmm
+	else if ( currententity->flags & RF_FULLBRIGHT )
+	{
+		for (i=0 ; i<3 ; i++)
+			shadelight[i] = 1.0;
+	}
+	else
+	{
+		R_LightPoint (currententity->origin, shadelight);
+
+		// player lighting hack for communication back to server
+		// big hack!
+		if ( currententity->flags & RF_WEAPONMODEL )
+		{
+			// pick the greatest component, which should be the same
+			// as the mono value returned by software
+			if (shadelight[0] > shadelight[1])
+			{
+				if (shadelight[0] > shadelight[2])
+					r_lightlevel->value = 150*shadelight[0];
+				else
+					r_lightlevel->value = 150*shadelight[2];
+			}
+			else
+			{
+				if (shadelight[1] > shadelight[2])
+					r_lightlevel->value = 150*shadelight[1];
+				else
+					r_lightlevel->value = 150*shadelight[2];
+			}
+
+		}
+		
+		if ( gl_monolightmap->string[0] != '0' )
+		{
+			float s = shadelight[0];
+
+			if ( s < shadelight[1] )
+				s = shadelight[1];
+			if ( s < shadelight[2] )
+				s = shadelight[2];
+
+			shadelight[0] = s;
+			shadelight[1] = s;
+			shadelight[2] = s;
+		}
+	}
+
+	if ( currententity->flags & RF_MINLIGHT )
+	{
+		for (i=0 ; i<3 ; i++)
+			if (shadelight[i] > 0.1)
+				break;
+		if (i == 3)
+		{
+			shadelight[0] = 0.1;
+			shadelight[1] = 0.1;
+			shadelight[2] = 0.1;
+		}
+	}
+
+	if ( currententity->flags & RF_GLOW )
+	{	// bonus items will pulse with time
+		float	scale;
+		float	min;
+
+		scale = 0.1 * sin(r_newrefdef.time*7);
+		for (i=0 ; i<3 ; i++)
+		{
+			min = shadelight[i] * 0.8;
+			shadelight[i] += scale;
+			if (shadelight[i] < min)
+				shadelight[i] = min;
+		}
+	}
+
+// =================
+// PGM	ir goggles color override
+	if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+	{
+		shadelight[0] = 1.0;
+		shadelight[1] = 0.0;
+		shadelight[2] = 0.0;
+	}
+// PGM	
+// =================
+
+	shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
+	
+	an = currententity->angles[1]/180*M_PI;
+	shadevector[0] = cos(-an);
+	shadevector[1] = sin(-an);
+	shadevector[2] = 1;
+	VectorNormalize (shadevector);
+
+	//
+	// locate the proper data
+	//
+
+	c_alias_polys += paliashdr->num_tris;
+
+	//
+	// draw all the triangles
+	//
+	if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls
+		qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
+
+	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+	{
+		extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar );
+
+		qglMatrixMode( GL_PROJECTION );
+		qglPushMatrix();
+		qglLoadIdentity();
+		qglScalef( -1, 1, 1 );
+	    MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height,  4,  4096);
+		qglMatrixMode( GL_MODELVIEW );
+
+		qglCullFace( GL_BACK );
+	}
+
+    qglPushMatrix ();
+	e->angles[PITCH] = -e->angles[PITCH];	// sigh.
+	R_RotateForEntity (e);
+	e->angles[PITCH] = -e->angles[PITCH];	// sigh.
+
+	// select skin
+	if (currententity->skin)
+		skin = currententity->skin;	// custom player skin
+	else
+	{
+		if (currententity->skinnum >= MAX_MD2SKINS)
+			skin = currentmodel->skins[0];
+		else
+		{
+			skin = currentmodel->skins[currententity->skinnum];
+			if (!skin)
+				skin = currentmodel->skins[0];
+		}
+	}
+	if (!skin)
+		skin = r_notexture;	// fallback...
+	GL_Bind(skin->texnum);
+
+	// draw it
+
+	qglShadeModel (GL_SMOOTH);
+
+	GL_TexEnv( GL_MODULATE );
+	if ( currententity->flags & RF_TRANSLUCENT )
+	{
+		qglEnable (GL_BLEND);
+	}
+
+
+	if ( (currententity->frame >= paliashdr->num_frames) 
+		|| (currententity->frame < 0) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n",
+			currentmodel->name, currententity->frame);
+		currententity->frame = 0;
+		currententity->oldframe = 0;
+	}
+
+	if ( (currententity->oldframe >= paliashdr->num_frames)
+		|| (currententity->oldframe < 0))
+	{
+		ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n",
+			currentmodel->name, currententity->oldframe);
+		currententity->frame = 0;
+		currententity->oldframe = 0;
+	}
+
+	if ( !r_lerpmodels->value )
+		currententity->backlerp = 0;
+	GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp);
+
+	GL_TexEnv( GL_REPLACE );
+	qglShadeModel (GL_FLAT);
+
+	qglPopMatrix ();
+
+#if 0
+	qglDisable( GL_CULL_FACE );
+	qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+	qglDisable( GL_TEXTURE_2D );
+	qglBegin( GL_TRIANGLE_STRIP );
+	for ( i = 0; i < 8; i++ )
+	{
+		qglVertex3fv( bbox[i] );
+	}
+	qglEnd();
+	qglEnable( GL_TEXTURE_2D );
+	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+	qglEnable( GL_CULL_FACE );
+#endif
+
+	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+	{
+		qglMatrixMode( GL_PROJECTION );
+		qglPopMatrix();
+		qglMatrixMode( GL_MODELVIEW );
+		qglCullFace( GL_FRONT );
+	}
+
+	if ( currententity->flags & RF_TRANSLUCENT )
+	{
+		qglDisable (GL_BLEND);
+	}
+
+	if (currententity->flags & RF_DEPTHHACK)
+		qglDepthRange (gldepthmin, gldepthmax);
+
+#if 1
+	if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL)))
+	{
+		qglPushMatrix ();
+		R_RotateForEntity (e);
+		qglDisable (GL_TEXTURE_2D);
+		qglEnable (GL_BLEND);
+		qglColor4f (0,0,0,0.5);
+		GL_DrawAliasShadow (paliashdr, currententity->frame );
+		qglEnable (GL_TEXTURE_2D);
+		qglDisable (GL_BLEND);
+		qglPopMatrix ();
+	}
+#endif
+	qglColor4f (1,1,1,1);
+}
+
+
--- /dev/null
+++ b/ref_gl/gl_model.c
@@ -1,0 +1,1223 @@
+/*
+Copyright (C) 1997-2001 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
+
+#include "gl_local.h"
+
+model_t	*loadmodel;
+int		modfilelen;
+
+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	512
+model_t	mod_known[MAX_MOD_KNOWN];
+int		mod_numknown;
+
+// the inline * models from the current map are kept seperate
+model_t	mod_inline[MAX_MOD_KNOWN];
+
+int		registration_sequence;
+
+/*
+===============
+Mod_PointInLeaf
+===============
+*/
+mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
+{
+	mnode_t		*node;
+	float		d;
+	cplane_t	*plane;
+	
+	if (!model || !model->nodes)
+		ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
+
+	node = model->nodes;
+	while (1)
+	{
+		if (node->contents != -1)
+			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->vis->numclusters+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;
+}
+
+/*
+==============
+Mod_ClusterPVS
+==============
+*/
+byte *Mod_ClusterPVS (int cluster, model_t *model)
+{
+	if (cluster == -1 || !model->vis)
+		return mod_novis;
+	return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
+		model);
+}
+
+
+//===============================================================================
+
+/*
+================
+Mod_Modellist_f
+================
+*/
+void Mod_Modellist_f (void)
+{
+	int		i;
+	model_t	*mod;
+	int		total;
+
+	total = 0;
+	ri.Con_Printf (PRINT_ALL,"Loaded models:\n");
+	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name);
+		total += mod->extradatasize;
+	}
+	ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total);
+}
+
+/*
+===============
+Mod_Init
+===============
+*/
+void Mod_Init (void)
+{
+	memset (mod_novis, 0xff, sizeof(mod_novis));
+}
+
+
+
+/*
+==================
+Mod_ForName
+
+Loads in a model for the given name
+==================
+*/
+model_t *Mod_ForName (char *name, qboolean crash)
+{
+	model_t	*mod;
+	unsigned *buf;
+	int		i;
+	
+	if (!name[0])
+		ri.Sys_Error (ERR_DROP, "Mod_ForName: NULL name");
+		
+	//
+	// inline models are grabbed only from worldmodel
+	//
+	if (name[0] == '*')
+	{
+		i = atoi(name+1);
+		if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
+			ri.Sys_Error (ERR_DROP, "bad inline model number");
+		return &mod_inline[i];
+	}
+
+	//
+	// search the currently loaded models
+	//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		if (!strcmp (mod->name, name) )
+			return mod;
+	}
+	
+	//
+	// find a free model slot spot
+	//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			break;	// free spot
+	}
+	if (i == mod_numknown)
+	{
+		if (mod_numknown == MAX_MOD_KNOWN)
+			ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
+		mod_numknown++;
+	}
+	strcpy (mod->name, name);
+	
+	//
+	// load the file
+	//
+	modfilelen = ri.FS_LoadFile (mod->name, &buf);
+	if (!buf)
+	{
+		if (crash)
+			ri.Sys_Error (ERR_DROP, "Mod_NumForName: %s not found", mod->name);
+		memset (mod->name, 0, sizeof(mod->name));
+		return NULL;
+	}
+	
+	loadmodel = mod;
+
+	//
+	// fill it in
+	//
+
+
+	// call the apropriate loader
+	
+	switch (LittleLong(*(unsigned *)buf))
+	{
+	case IDALIASHEADER:
+		loadmodel->extradata = Hunk_Begin (0x200000);
+		Mod_LoadAliasModel (mod, buf);
+		break;
+		
+	case IDSPRITEHEADER:
+		loadmodel->extradata = Hunk_Begin (0x10000);
+		Mod_LoadSpriteModel (mod, buf);
+		break;
+	
+	case IDBSPHEADER:
+		loadmodel->extradata = Hunk_Begin (0x1000000);
+		Mod_LoadBrushModel (mod, buf);
+		break;
+
+	default:
+		ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
+		break;
+	}
+
+	loadmodel->extradatasize = Hunk_End ();
+
+	ri.FS_FreeFile (buf);
+
+	return mod;
+}
+
+/*
+===============================================================================
+
+					BRUSHMODEL LOADING
+
+===============================================================================
+*/
+
+byte	*mod_base;
+
+
+/*
+=================
+Mod_LoadLighting
+=================
+*/
+void Mod_LoadLighting (lump_t *l)
+{
+	if (!l->filelen)
+	{
+		loadmodel->lightdata = NULL;
+		return;
+	}
+	loadmodel->lightdata = Hunk_Alloc ( l->filelen);	
+	memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
+}
+
+
+/*
+=================
+Mod_LoadVisibility
+=================
+*/
+void Mod_LoadVisibility (lump_t *l)
+{
+	int		i;
+
+	if (!l->filelen)
+	{
+		loadmodel->vis = NULL;
+		return;
+	}
+	loadmodel->vis = Hunk_Alloc ( l->filelen);	
+	memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
+
+	loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
+	for (i=0 ; i<loadmodel->vis->numclusters ; i++)
+	{
+		loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
+		loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
+	}
+}
+
+
+/*
+=================
+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))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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]);
+	}
+}
+
+/*
+=================
+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 VectorLength (corner);
+}
+
+
+/*
+=================
+Mod_LoadSubmodels
+=================
+*/
+void Mod_LoadSubmodels (lump_t *l)
+{
+	dmodel_t	*in;
+	mmodel_t	*out;
+	int			i, j, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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]);
+		}
+		out->radius = RadiusFromBounds (out->mins, out->maxs);
+		out->headnode = LittleLong (in->headnode);
+		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))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count + 1) * sizeof(*out));	
+
+	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, *step;
+	int 	i, j, count;
+	char	name[MAX_QPATH];
+	int		next;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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]);
+
+		out->flags = LittleLong (in->flags);
+		next = LittleLong (in->nexttexinfo);
+		if (next > 0)
+			out->next = loadmodel->texinfo + next;
+		else
+		    out->next = NULL;
+		Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
+
+		out->image = GL_FindImage (name, it_wall);
+		if (!out->image)
+		{
+			ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name);
+			out->image = r_notexture;
+		}
+	}
+
+	// count animation frames
+	for (i=0 ; i<count ; i++)
+	{
+		out = &loadmodel->texinfo[i];
+		out->numframes = 1;
+		for (step = out->next ; step && step != out ; step=step->next)
+			out->numframes++;
+	}
+}
+
+/*
+================
+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] > 512 /* 256 */ )
+//			ri.Sys_Error (ERR_DROP, "Bad surface extents");
+	}
+}
+
+
+void GL_BuildPolygonFromSurface(msurface_t *fa);
+void GL_CreateSurfaceLightmap (msurface_t *surf);
+void GL_EndBuildingLightmaps (void);
+void GL_BeginBuildingLightmaps (model_t *m);
+
+/*
+=================
+Mod_LoadFaces
+=================
+*/
+void Mod_LoadFaces (lump_t *l)
+{
+	dface_t		*in;
+	msurface_t 	*out;
+	int			i, count, surfnum;
+	int			planenum, side;
+	int			ti;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	loadmodel->surfaces = out;
+	loadmodel->numsurfaces = count;
+
+	currentmodel = loadmodel;
+
+	GL_BeginBuildingLightmaps (loadmodel);
+
+	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+	{
+		out->firstedge = LittleLong(in->firstedge);
+		out->numedges = LittleShort(in->numedges);		
+		out->flags = 0;
+		out->polys = NULL;
+
+		planenum = LittleShort(in->planenum);
+		side = LittleShort(in->side);
+		if (side)
+			out->flags |= SURF_PLANEBACK;			
+
+		out->plane = loadmodel->planes + planenum;
+
+		ti = LittleShort (in->texinfo);
+		if (ti < 0 || ti >= loadmodel->numtexinfo)
+			ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: bad texinfo number");
+		out->texinfo = loadmodel->texinfo + ti;
+
+		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
+		
+		if (out->texinfo->flags & SURF_WARP)
+		{
+			out->flags |= SURF_DRAWTURB;
+			for (i=0 ; i<2 ; i++)
+			{
+				out->extents[i] = 16384;
+				out->texturemins[i] = -8192;
+			}
+			GL_SubdivideSurface (out);	// cut up polygon for warps
+		}
+
+		// create lightmaps and polygons
+		if ( !(out->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) )
+			GL_CreateSurfaceLightmap (out);
+
+		if (! (out->texinfo->flags & SURF_WARP) ) 
+			GL_BuildPolygonFromSurface(out);
+
+	}
+
+	GL_EndBuildingLightmaps ();
+}
+
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+	node->parent = parent;
+	if (node->contents != -1)
+		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))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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);
+		out->contents = -1;	// differentiate from leafs
+
+		for (j=0 ; j<2 ; j++)
+		{
+			p = LittleLong (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;
+//	glpoly_t	*poly;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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->cluster = LittleShort(in->cluster);
+		out->area = LittleShort(in->area);
+
+		out->firstmarksurface = loadmodel->marksurfaces +
+			LittleShort(in->firstleafface);
+		out->nummarksurfaces = LittleShort(in->numleaffaces);
+		
+		// gl underwater warp
+#if 0
+		if (out->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_THINWATER) )
+		{
+			for (j=0 ; j<out->nummarksurfaces ; j++)
+			{
+				out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
+				for (poly = out->firstmarksurface[j]->polys ; poly ; poly=poly->next)
+					poly->flags |= SURF_UNDERWATER;
+			}
+		}
+#endif
+	}	
+}
+
+/*
+=================
+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))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	loadmodel->marksurfaces = out;
+	loadmodel->nummarksurfaces = count;
+
+	for ( i=0 ; i<count ; i++)
+	{
+		j = LittleShort(in[i]);
+		if (j < 0 ||  j >= loadmodel->numsurfaces)
+			ri.Sys_Error (ERR_DROP, "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))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	if (count < 1 || count >= MAX_MAP_SURFEDGES)
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: bad surfedges count in %s: %i",
+		loadmodel->name, count);
+
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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;
+	cplane_t	*out;
+	dplane_t 	*in;
+	int			count;
+	int			bits;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*2*sizeof(*out));	
+	
+	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;
+	}
+}
+
+/*
+=================
+Mod_LoadBrushModel
+=================
+*/
+void Mod_LoadBrushModel (model_t *mod, void *buffer)
+{
+	int			i;
+	dheader_t	*header;
+	mmodel_t 	*bm;
+	
+	loadmodel->type = mod_brush;
+	if (loadmodel != mod_known)
+		ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world");
+
+	header = (dheader_t *)buffer;
+
+	i = LittleLong (header->version);
+	if (i != BSPVERSION)
+		ri.Sys_Error (ERR_DROP, "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_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_LEAFFACES]);
+	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+	mod->numframes = 2;		// regular and alternate animation
+	
+//
+// set up the submodels
+//
+	for (i=0 ; i<mod->numsubmodels ; i++)
+	{
+		model_t	*starmod;
+
+		bm = &mod->submodels[i];
+		starmod = &mod_inline[i];
+
+		*starmod = *loadmodel;
+		
+		starmod->firstmodelsurface = bm->firstface;
+		starmod->nummodelsurfaces = bm->numfaces;
+		starmod->firstnode = bm->headnode;
+		if (starmod->firstnode >= loadmodel->numnodes)
+			ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
+
+		VectorCopy (bm->maxs, starmod->maxs);
+		VectorCopy (bm->mins, starmod->mins);
+		starmod->radius = bm->radius;
+	
+		if (i == 0)
+			*loadmodel = *starmod;
+
+		starmod->numleafs = bm->visleafs;
+	}
+}
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadAliasModel
+=================
+*/
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
+{
+	int					i, j;
+	dmdl_t				*pinmodel, *pheader;
+	dstvert_t			*pinst, *poutst;
+	dtriangle_t			*pintri, *pouttri;
+	daliasframe_t		*pinframe, *poutframe;
+	int					*pincmd, *poutcmd;
+	int					version;
+
+	pinmodel = (dmdl_t *)buffer;
+
+	version = LittleLong (pinmodel->version);
+	if (version != ALIAS_VERSION)
+		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+				 mod->name, version, ALIAS_VERSION);
+
+	pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end));
+	
+	// byte swap the header fields and sanity check
+	for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
+		((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
+
+	if (pheader->skinheight > MAX_LBM_HEIGHT)
+		ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
+				   MAX_LBM_HEIGHT);
+
+	if (pheader->num_xyz <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name);
+
+	if (pheader->num_xyz > MAX_VERTS)
+		ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name);
+
+	if (pheader->num_st <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name);
+
+	if (pheader->num_tris <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name);
+
+	if (pheader->num_frames <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name);
+
+//
+// load base s and t vertices (not used in gl version)
+//
+	pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
+	poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
+
+	for (i=0 ; i<pheader->num_st ; i++)
+	{
+		poutst[i].s = LittleShort (pinst[i].s);
+		poutst[i].t = LittleShort (pinst[i].t);
+	}
+
+//
+// load triangle lists
+//
+	pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
+	pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
+
+	for (i=0 ; i<pheader->num_tris ; i++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
+			pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
+		}
+	}
+
+//
+// load the frames
+//
+	for (i=0 ; i<pheader->num_frames ; i++)
+	{
+		pinframe = (daliasframe_t *) ((byte *)pinmodel 
+			+ pheader->ofs_frames + i * pheader->framesize);
+		poutframe = (daliasframe_t *) ((byte *)pheader 
+			+ pheader->ofs_frames + i * pheader->framesize);
+
+		memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
+		for (j=0 ; j<3 ; j++)
+		{
+			poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
+			poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
+		}
+		// verts are all 8 bit, so no swapping needed
+		memcpy (poutframe->verts, pinframe->verts, 
+			pheader->num_xyz*sizeof(dtrivertx_t));
+
+	}
+
+	mod->type = mod_alias;
+
+	//
+	// load the glcmds
+	//
+	pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
+	poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
+	for (i=0 ; i<pheader->num_glcmds ; i++)
+		poutcmd[i] = LittleLong (pincmd[i]);
+
+
+	// register all skins
+	memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
+		pheader->num_skins*MAX_SKINNAME);
+	for (i=0 ; i<pheader->num_skins ; i++)
+	{
+		mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME
+			, it_skin);
+	}
+
+	mod->mins[0] = -32;
+	mod->mins[1] = -32;
+	mod->mins[2] = -32;
+	mod->maxs[0] = 32;
+	mod->maxs[1] = 32;
+	mod->maxs[2] = 32;
+}
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+	dsprite_t	*sprin, *sprout;
+	int			i;
+
+	sprin = (dsprite_t *)buffer;
+	sprout = Hunk_Alloc (modfilelen);
+
+	sprout->ident = LittleLong (sprin->ident);
+	sprout->version = LittleLong (sprin->version);
+	sprout->numframes = LittleLong (sprin->numframes);
+
+	if (sprout->version != SPRITE_VERSION)
+		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+				 mod->name, sprout->version, SPRITE_VERSION);
+
+	if (sprout->numframes > MAX_MD2SKINS)
+		ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)",
+				 mod->name, sprout->numframes, MAX_MD2SKINS);
+
+	// byte swap everything
+	for (i=0 ; i<sprout->numframes ; i++)
+	{
+		sprout->frames[i].width = LittleLong (sprin->frames[i].width);
+		sprout->frames[i].height = LittleLong (sprin->frames[i].height);
+		sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
+		sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
+		memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
+		mod->skins[i] = GL_FindImage (sprout->frames[i].name,
+			it_sprite);
+	}
+
+	mod->type = mod_sprite;
+}
+
+//=============================================================================
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_BeginRegistration
+
+Specifies the model that will be used as the world
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_BeginRegistration (char *model)
+{
+	char	fullname[MAX_QPATH];
+	cvar_t	*flushmap;
+
+	registration_sequence++;
+	r_oldviewcluster = -1;		// force markleafs
+
+	Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
+
+	// explicitly free the old map if different
+	// this guarantees that mod_known[0] is the world map
+	flushmap = ri.Cvar_Get ("flushmap", "0", 0);
+	if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
+		Mod_Free (&mod_known[0]);
+	r_worldmodel = Mod_ForName(fullname, true);
+
+	r_viewcluster = -1;
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_RegisterModel
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+struct model_s *R_RegisterModel (char *name)
+{
+	model_t	*mod;
+	int		i;
+	dsprite_t	*sprout;
+	dmdl_t		*pheader;
+
+	mod = Mod_ForName (name, false);
+	if (mod)
+	{
+		mod->registration_sequence = registration_sequence;
+
+		// register any images used by the models
+		if (mod->type == mod_sprite)
+		{
+			sprout = (dsprite_t *)mod->extradata;
+			for (i=0 ; i<sprout->numframes ; i++)
+				mod->skins[i] = GL_FindImage (sprout->frames[i].name, it_sprite);
+		}
+		else if (mod->type == mod_alias)
+		{
+			pheader = (dmdl_t *)mod->extradata;
+			for (i=0 ; i<pheader->num_skins ; i++)
+				mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+//PGM
+			mod->numframes = pheader->num_frames;
+//PGM
+		}
+		else if (mod->type == mod_brush)
+		{
+			for (i=0 ; i<mod->numtexinfo ; i++)
+				mod->texinfo[i].image->registration_sequence = registration_sequence;
+		}
+	}
+	return mod;
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_EndRegistration
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_EndRegistration (void)
+{
+	int		i;
+	model_t	*mod;
+
+	for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		if (mod->registration_sequence != registration_sequence)
+		{	// don't need this model
+			Mod_Free (mod);
+		}
+	}
+
+	GL_FreeUnusedImages ();
+}
+
+
+//=============================================================================
+
+
+/*
+================
+Mod_Free
+================
+*/
+void Mod_Free (model_t *mod)
+{
+	Hunk_Free (mod->extradata);
+	memset (mod, 0, sizeof(*mod));
+}
+
+/*
+================
+Mod_FreeAll
+================
+*/
+void Mod_FreeAll (void)
+{
+	int		i;
+
+	for (i=0 ; i<mod_numknown ; i++)
+	{
+		if (mod_known[i].extradatasize)
+			Mod_Free (&mod_known[i]);
+	}
+}
--- /dev/null
+++ b/ref_gl/gl_model.h
@@ -1,0 +1,261 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+
+/*
+
+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;
+
+typedef struct
+{
+	vec3_t		mins, maxs;
+	vec3_t		origin;		// for sounds or lights
+	float		radius;
+	int			headnode;
+	int			visleafs;		// not including the solid leaf 0
+	int			firstface, numfaces;
+} mmodel_t;
+
+
+#define	SIDE_FRONT	0
+#define	SIDE_BACK	1
+#define	SIDE_ON		2
+
+
+#define	SURF_PLANEBACK		2
+#define	SURF_DRAWSKY		4
+#define SURF_DRAWTURB		0x10
+#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 mtexinfo_s
+{
+	float		vecs[2][4];
+	int			flags;
+	int			numframes;
+	struct mtexinfo_s	*next;		// animation chain
+	image_t		*image;
+} mtexinfo_t;
+
+#define	VERTEXSIZE	7
+
+typedef struct glpoly_s
+{
+	struct	glpoly_s	*next;
+	struct	glpoly_s	*chain;
+	int		numverts;
+	int		flags;			// for SURF_UNDERWATER (not needed anymore?)
+	float	verts[4][VERTEXSIZE];	// variable sized (xyz s1t1 s2t2)
+} glpoly_t;
+
+typedef struct msurface_s
+{
+	int			visframe;		// should be drawn when node is crossed
+
+	cplane_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
+	int			dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps
+
+	glpoly_t	*polys;				// multiple if warped
+	struct	msurface_s	*texturechain;
+	struct  msurface_s	*lightmapchain;
+
+	mtexinfo_t	*texinfo;
+	
+// lighting info
+	int			dlightframe;
+	int			dlightbits;
+
+	int			lightmaptexturenum;
+	byte		styles[MAXLIGHTMAPS];
+	float		cached_light[MAXLIGHTMAPS];	// values currently used in lightmap
+	byte		*samples;		// [numstyles*surfsize]
+} msurface_t;
+
+typedef struct mnode_s
+{
+// common with leaf
+	int			contents;		// -1, 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
+	cplane_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
+	int			cluster;
+	int			area;
+
+	msurface_t	**firstmarksurface;
+	int			nummarksurfaces;
+} mleaf_t;
+
+
+//===================================================================
+
+//
+// Whole model
+//
+
+typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t;
+
+typedef struct model_s
+{
+	char		name[MAX_QPATH];
+
+	int			registration_sequence;
+
+	modtype_t	type;
+	int			numframes;
+	
+	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			lightmap;		// only for submodels
+
+	int			numsubmodels;
+	mmodel_t	*submodels;
+
+	int			numplanes;
+	cplane_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;
+	int			firstnode;
+	mnode_t		*nodes;
+
+	int			numtexinfo;
+	mtexinfo_t	*texinfo;
+
+	int			numsurfaces;
+	msurface_t	*surfaces;
+
+	int			numsurfedges;
+	int			*surfedges;
+
+	int			nummarksurfaces;
+	msurface_t	**marksurfaces;
+
+	dvis_t		*vis;
+
+	byte		*lightdata;
+
+	// for alias models and skins
+	image_t		*skins[MAX_MD2SKINS];
+
+	int			extradatasize;
+	void		*extradata;
+} model_t;
+
+//============================================================================
+
+void	Mod_Init (void);
+void	Mod_ClearAll (void);
+model_t *Mod_ForName (char *name, qboolean crash);
+mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
+byte	*Mod_ClusterPVS (int cluster, model_t *model);
+
+void	Mod_Modellist_f (void);
+
+void	*Hunk_Begin (int maxsize);
+void	*Hunk_Alloc (int size);
+int		Hunk_End (void);
+void	Hunk_Free (void *base);
+
+void	Mod_FreeAll (void);
+void	Mod_Free (model_t *mod);
--- /dev/null
+++ b/ref_gl/gl_rmain.c
@@ -1,0 +1,1692 @@
+/*
+Copyright (C) 1997-2001 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 "gl_local.h"
+
+void R_Clear (void);
+
+viddef_t	vid;
+
+refimport_t	ri;
+
+model_t		*r_worldmodel;
+
+float		gldepthmin, gldepthmax;
+
+glconfig_t gl_config;
+glstate_t  gl_state;
+
+image_t		*r_notexture;		// use for bad textures
+image_t		*r_particletexture;	// little dot for particles
+
+entity_t	*currententity;
+model_t		*currentmodel;
+
+cplane_t	frustum[4];
+
+int			r_visframecount;	// bumped when going to a new PVS
+int			r_framecount;		// used for dlight push checking
+
+int			c_brush_polys, c_alias_polys;
+
+float		v_blend[4];			// final blending color
+
+void GL_Strings_f( void );
+
+//
+// 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_newrefdef;
+
+int		r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
+
+cvar_t	*r_norefresh;
+cvar_t	*r_drawentities;
+cvar_t	*r_drawworld;
+cvar_t	*r_speeds;
+cvar_t	*r_fullbright;
+cvar_t	*r_novis;
+cvar_t	*r_nocull;
+cvar_t	*r_lerpmodels;
+cvar_t	*r_lefthand;
+
+cvar_t	*r_lightlevel;	// FIXME: This is a HACK to get the client's light level
+
+cvar_t	*gl_nosubimage;
+cvar_t	*gl_allow_software;
+
+cvar_t	*gl_vertex_arrays;
+
+cvar_t	*gl_particle_min_size;
+cvar_t	*gl_particle_max_size;
+cvar_t	*gl_particle_size;
+cvar_t	*gl_particle_att_a;
+cvar_t	*gl_particle_att_b;
+cvar_t	*gl_particle_att_c;
+
+cvar_t	*gl_ext_swapinterval;
+cvar_t	*gl_ext_palettedtexture;
+cvar_t	*gl_ext_multitexture;
+cvar_t	*gl_ext_pointparameters;
+cvar_t	*gl_ext_compiled_vertex_array;
+
+cvar_t	*gl_log;
+cvar_t	*gl_bitdepth;
+cvar_t	*gl_drawbuffer;
+cvar_t  *gl_driver;
+cvar_t	*gl_lightmap;
+cvar_t	*gl_shadows;
+cvar_t	*gl_mode;
+cvar_t	*gl_dynamic;
+cvar_t  *gl_monolightmap;
+cvar_t	*gl_modulate;
+cvar_t	*gl_nobind;
+cvar_t	*gl_round_down;
+cvar_t	*gl_picmip;
+cvar_t	*gl_skymip;
+cvar_t	*gl_showtris;
+cvar_t	*gl_ztrick;
+cvar_t	*gl_finish;
+cvar_t	*gl_clear;
+cvar_t	*gl_cull;
+cvar_t	*gl_polyblend;
+cvar_t	*gl_flashblend;
+cvar_t	*gl_playermip;
+cvar_t  *gl_saturatelighting;
+cvar_t	*gl_swapinterval;
+cvar_t	*gl_texturemode;
+cvar_t	*gl_texturealphamode;
+cvar_t	*gl_texturesolidmode;
+cvar_t	*gl_lockpvs;
+
+cvar_t	*gl_3dlabs_broken;
+
+cvar_t	*vid_fullscreen;
+cvar_t	*vid_gamma;
+cvar_t	*vid_ref;
+
+/*
+=================
+R_CullBox
+
+Returns true if the box is completely outside the frustom
+=================
+*/
+qboolean R_CullBox (vec3_t mins, vec3_t maxs)
+{
+	int		i;
+
+	if (r_nocull->value)
+		return false;
+
+	for (i=0 ; i<4 ; i++)
+		if ( BOX_ON_PLANE_SIDE(mins, maxs, &frustum[i]) == 2)
+			return true;
+	return false;
+}
+
+
+void R_RotateForEntity (entity_t *e)
+{
+    qglTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);
+
+    qglRotatef (e->angles[1],  0, 0, 1);
+    qglRotatef (-e->angles[0],  0, 1, 0);
+    qglRotatef (-e->angles[2],  1, 0, 0);
+}
+
+/*
+=============================================================
+
+  SPRITE MODELS
+
+=============================================================
+*/
+
+
+/*
+=================
+R_DrawSpriteModel
+
+=================
+*/
+void R_DrawSpriteModel (entity_t *e)
+{
+	float alpha = 1.0F;
+	vec3_t	point;
+	dsprframe_t	*frame;
+	float		*up, *right;
+	dsprite_t		*psprite;
+
+	// don't even bother culling, because it's just a single
+	// polygon without a surface cache
+
+	psprite = (dsprite_t *)currentmodel->extradata;
+
+#if 0
+	if (e->frame < 0 || e->frame >= psprite->numframes)
+	{
+		ri.Con_Printf (PRINT_ALL, "no such sprite frame %i\n", e->frame);
+		e->frame = 0;
+	}
+#endif
+	e->frame %= psprite->numframes;
+
+	frame = &psprite->frames[e->frame];
+
+#if 0
+	if (psprite->type == SPR_ORIENTED)
+	{	// bullet marks on walls
+	vec3_t		v_forward, v_right, v_up;
+
+	AngleVectors (currententity->angles, v_forward, v_right, v_up);
+		up = v_up;
+		right = v_right;
+	}
+	else
+#endif
+	{	// normal sprite
+		up = vup;
+		right = vright;
+	}
+
+	if ( e->flags & RF_TRANSLUCENT )
+		alpha = e->alpha;
+
+	if ( alpha != 1.0F )
+		qglEnable( GL_BLEND );
+
+	qglColor4f( 1, 1, 1, alpha );
+
+    GL_Bind(currentmodel->skins[e->frame]->texnum);
+
+	GL_TexEnv( GL_MODULATE );
+
+	if ( alpha == 1.0 )
+		qglEnable (GL_ALPHA_TEST);
+	else
+		qglDisable( GL_ALPHA_TEST );
+
+	qglBegin (GL_QUADS);
+
+	qglTexCoord2f (0, 1);
+	VectorMA (e->origin, -frame->origin_y, up, point);
+	VectorMA (point, -frame->origin_x, right, point);
+	qglVertex3fv (point);
+
+	qglTexCoord2f (0, 0);
+	VectorMA (e->origin, frame->height - frame->origin_y, up, point);
+	VectorMA (point, -frame->origin_x, right, point);
+	qglVertex3fv (point);
+
+	qglTexCoord2f (1, 0);
+	VectorMA (e->origin, frame->height - frame->origin_y, up, point);
+	VectorMA (point, frame->width - frame->origin_x, right, point);
+	qglVertex3fv (point);
+
+	qglTexCoord2f (1, 1);
+	VectorMA (e->origin, -frame->origin_y, up, point);
+	VectorMA (point, frame->width - frame->origin_x, right, point);
+	qglVertex3fv (point);
+	
+	qglEnd ();
+
+	qglDisable (GL_ALPHA_TEST);
+	GL_TexEnv( GL_REPLACE );
+
+	if ( alpha != 1.0F )
+		qglDisable( GL_BLEND );
+
+	qglColor4f( 1, 1, 1, 1 );
+}
+
+//==================================================================================
+
+/*
+=============
+R_DrawNullModel
+=============
+*/
+void R_DrawNullModel (void)
+{
+	vec3_t	shadelight;
+	int		i;
+
+	if ( currententity->flags & RF_FULLBRIGHT )
+		shadelight[0] = shadelight[1] = shadelight[2] = 1.0F;
+	else
+		R_LightPoint (currententity->origin, shadelight);
+
+    qglPushMatrix ();
+	R_RotateForEntity (currententity);
+
+	qglDisable (GL_TEXTURE_2D);
+	qglColor3fv (shadelight);
+
+	qglBegin (GL_TRIANGLE_FAN);
+	qglVertex3f (0, 0, -16);
+	for (i=0 ; i<=4 ; i++)
+		qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0);
+	qglEnd ();
+
+	qglBegin (GL_TRIANGLE_FAN);
+	qglVertex3f (0, 0, 16);
+	for (i=4 ; i>=0 ; i--)
+		qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0);
+	qglEnd ();
+
+	qglColor3f (1,1,1);
+	qglPopMatrix ();
+	qglEnable (GL_TEXTURE_2D);
+}
+
+/*
+=============
+R_DrawEntitiesOnList
+=============
+*/
+void R_DrawEntitiesOnList (void)
+{
+	int		i;
+
+	if (!r_drawentities->value)
+		return;
+
+	// draw non-transparent first
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+		if (currententity->flags & RF_TRANSLUCENT)
+			continue;	// solid
+
+		if ( currententity->flags & RF_BEAM )
+		{
+			R_DrawBeam( currententity );
+		}
+		else
+		{
+			currentmodel = currententity->model;
+			if (!currentmodel)
+			{
+				R_DrawNullModel ();
+				continue;
+			}
+			switch (currentmodel->type)
+			{
+			case mod_alias:
+				R_DrawAliasModel (currententity);
+				break;
+			case mod_brush:
+				R_DrawBrushModel (currententity);
+				break;
+			case mod_sprite:
+				R_DrawSpriteModel (currententity);
+				break;
+			default:
+				ri.Sys_Error (ERR_DROP, "Bad modeltype");
+				break;
+			}
+		}
+	}
+
+	// draw transparent entities
+	// we could sort these if it ever becomes a problem...
+	qglDepthMask (0);		// no z writes
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+		if (!(currententity->flags & RF_TRANSLUCENT))
+			continue;	// solid
+
+		if ( currententity->flags & RF_BEAM )
+		{
+			R_DrawBeam( currententity );
+		}
+		else
+		{
+			currentmodel = currententity->model;
+
+			if (!currentmodel)
+			{
+				R_DrawNullModel ();
+				continue;
+			}
+			switch (currentmodel->type)
+			{
+			case mod_alias:
+				R_DrawAliasModel (currententity);
+				break;
+			case mod_brush:
+				R_DrawBrushModel (currententity);
+				break;
+			case mod_sprite:
+				R_DrawSpriteModel (currententity);
+				break;
+			default:
+				ri.Sys_Error (ERR_DROP, "Bad modeltype");
+				break;
+			}
+		}
+	}
+	qglDepthMask (1);		// back to writing
+
+}
+
+/*
+** GL_DrawParticles
+**
+*/
+void GL_DrawParticles( int num_particles, const particle_t particles[], const unsigned colortable[768] )
+{
+	const particle_t *p;
+	int				i;
+	vec3_t			up, right;
+	float			scale;
+	byte			color[4];
+
+    GL_Bind(r_particletexture->texnum);
+	qglDepthMask( GL_FALSE );		// no z buffering
+	qglEnable( GL_BLEND );
+	GL_TexEnv( GL_MODULATE );
+	qglBegin( GL_TRIANGLES );
+
+	VectorScale (vup, 1.5, up);
+	VectorScale (vright, 1.5, right);
+
+	for ( p = particles, i=0 ; i < num_particles ; i++,p++)
+	{
+		// hack a scale up to keep particles from disapearing
+		scale = ( p->origin[0] - r_origin[0] ) * vpn[0] + 
+			    ( p->origin[1] - r_origin[1] ) * vpn[1] +
+			    ( p->origin[2] - r_origin[2] ) * vpn[2];
+
+		if (scale < 20)
+			scale = 1;
+		else
+			scale = 1 + scale * 0.004;
+
+		*(int *)color = colortable[p->color];
+		color[3] = p->alpha*255;
+
+		qglColor4ubv( color );
+
+		qglTexCoord2f( 0.0625, 0.0625 );
+		qglVertex3fv( p->origin );
+
+		qglTexCoord2f( 1.0625, 0.0625 );
+		qglVertex3f( p->origin[0] + up[0]*scale, 
+			         p->origin[1] + up[1]*scale, 
+					 p->origin[2] + up[2]*scale);
+
+		qglTexCoord2f( 0.0625, 1.0625 );
+		qglVertex3f( p->origin[0] + right[0]*scale, 
+			         p->origin[1] + right[1]*scale, 
+					 p->origin[2] + right[2]*scale);
+	}
+
+	qglEnd ();
+	qglDisable( GL_BLEND );
+	qglColor4f( 1,1,1,1 );
+	qglDepthMask( 1 );		// back to normal Z buffering
+	GL_TexEnv( GL_REPLACE );
+}
+
+/*
+===============
+R_DrawParticles
+===============
+*/
+void R_DrawParticles (void)
+{
+	if ( gl_ext_pointparameters->value && qglPointParameterfEXT )
+	{
+		int i;
+		unsigned char color[4];
+		const particle_t *p;
+
+		qglDepthMask( GL_FALSE );
+		qglEnable( GL_BLEND );
+		qglDisable( GL_TEXTURE_2D );
+
+		qglPointSize( gl_particle_size->value );
+
+		qglBegin( GL_POINTS );
+		for ( i = 0, p = r_newrefdef.particles; i < r_newrefdef.num_particles; i++, p++ )
+		{
+			*(int *)color = d_8to24table[p->color];
+			color[3] = p->alpha*255;
+
+			qglColor4ubv( color );
+
+			qglVertex3fv( p->origin );
+		}
+		qglEnd();
+
+		qglDisable( GL_BLEND );
+		qglColor4f( 1.0F, 1.0F, 1.0F, 1.0F );
+		qglDepthMask( GL_TRUE );
+		qglEnable( GL_TEXTURE_2D );
+
+	}
+	else
+	{
+		GL_DrawParticles( r_newrefdef.num_particles, r_newrefdef.particles, d_8to24table );
+	}
+}
+
+/*
+============
+R_PolyBlend
+============
+*/
+void R_PolyBlend (void)
+{
+	if (!gl_polyblend->value)
+		return;
+	if (!v_blend[3])
+		return;
+
+	qglDisable (GL_ALPHA_TEST);
+	qglEnable (GL_BLEND);
+	qglDisable (GL_DEPTH_TEST);
+	qglDisable (GL_TEXTURE_2D);
+
+    qglLoadIdentity ();
+
+	// FIXME: get rid of these
+    qglRotatef (-90,  1, 0, 0);	    // put Z going up
+    qglRotatef (90,  0, 0, 1);	    // put Z going up
+
+	qglColor4fv (v_blend);
+
+	qglBegin (GL_QUADS);
+
+	qglVertex3f (10, 100, 100);
+	qglVertex3f (10, -100, 100);
+	qglVertex3f (10, -100, -100);
+	qglVertex3f (10, 100, -100);
+	qglEnd ();
+
+	qglDisable (GL_BLEND);
+	qglEnable (GL_TEXTURE_2D);
+	qglEnable (GL_ALPHA_TEST);
+
+	qglColor4f(1,1,1,1);
+}
+
+//=======================================================================
+
+int SignbitsForPlane (cplane_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 0
+	/*
+	** this code is wrong, since it presume a 90 degree FOV both in the
+	** horizontal and vertical plane
+	*/
+	// 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);
+
+	// we theoretically don't need to normalize these vectors, but I do it
+	// anyway so that debugging is a little easier
+	VectorNormalize( frustum[0].normal );
+	VectorNormalize( frustum[1].normal );
+	VectorNormalize( frustum[2].normal );
+	VectorNormalize( frustum[3].normal );
+#else
+	// rotate VPN right by FOV_X/2 degrees
+	RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_newrefdef.fov_x / 2 ) );
+	// rotate VPN left by FOV_X/2 degrees
+	RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_newrefdef.fov_x / 2 );
+	// rotate VPN up by FOV_X/2 degrees
+	RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_newrefdef.fov_y / 2 );
+	// rotate VPN down by FOV_X/2 degrees
+	RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_newrefdef.fov_y / 2 ) );
+#endif
+
+	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 i;
+	mleaf_t	*leaf;
+
+	r_framecount++;
+
+// build the transformation matrix for the given view angles
+	VectorCopy (r_newrefdef.vieworg, r_origin);
+
+	AngleVectors (r_newrefdef.viewangles, vpn, vright, vup);
+
+// current viewcluster
+	if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+	{
+		r_oldviewcluster = r_viewcluster;
+		r_oldviewcluster2 = r_viewcluster2;
+		leaf = Mod_PointInLeaf (r_origin, r_worldmodel);
+		r_viewcluster = r_viewcluster2 = leaf->cluster;
+
+		// check above and below so crossing solid water doesn't draw wrong
+		if (!leaf->contents)
+		{	// look down a bit
+			vec3_t	temp;
+
+			VectorCopy (r_origin, temp);
+			temp[2] -= 16;
+			leaf = Mod_PointInLeaf (temp, r_worldmodel);
+			if ( !(leaf->contents & CONTENTS_SOLID) &&
+				(leaf->cluster != r_viewcluster2) )
+				r_viewcluster2 = leaf->cluster;
+		}
+		else
+		{	// look up a bit
+			vec3_t	temp;
+
+			VectorCopy (r_origin, temp);
+			temp[2] += 16;
+			leaf = Mod_PointInLeaf (temp, r_worldmodel);
+			if ( !(leaf->contents & CONTENTS_SOLID) &&
+				(leaf->cluster != r_viewcluster2) )
+				r_viewcluster2 = leaf->cluster;
+		}
+	}
+
+	for (i=0 ; i<4 ; i++)
+		v_blend[i] = r_newrefdef.blend[i];
+
+	c_brush_polys = 0;
+	c_alias_polys = 0;
+
+	// clear out the portion of the screen that the NOWORLDMODEL defines
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+	{
+		qglEnable( GL_SCISSOR_TEST );
+		qglClearColor( 0.3, 0.3, 0.3, 1 );
+		qglScissor( r_newrefdef.x, vid.height - r_newrefdef.height - r_newrefdef.y, r_newrefdef.width, r_newrefdef.height );
+		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+		qglClearColor( 1, 0, 0.5, 0.5 );
+		qglDisable( GL_SCISSOR_TEST );
+	}
+}
+
+
+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;
+
+   xmin += -( 2 * gl_state.camera_separation ) / zNear;
+   xmax += -( 2 * gl_state.camera_separation ) / zNear;
+
+   qglFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
+}
+
+
+/*
+=============
+R_SetupGL
+=============
+*/
+void R_SetupGL (void)
+{
+	float	screenaspect;
+//	float	yfov;
+	int		x, x2, y2, y, w, h;
+
+	//
+	// set up viewport
+	//
+	x = floor(r_newrefdef.x * vid.width / vid.width);
+	x2 = ceil((r_newrefdef.x + r_newrefdef.width) * vid.width / vid.width);
+	y = floor(vid.height - r_newrefdef.y * vid.height / vid.height);
+	y2 = ceil(vid.height - (r_newrefdef.y + r_newrefdef.height) * vid.height / vid.height);
+
+	w = x2 - x;
+	h = y - y2;
+
+	qglViewport (x, y2, w, h);
+
+	//
+	// set up projection matrix
+	//
+    screenaspect = (float)r_newrefdef.width/r_newrefdef.height;
+//	yfov = 2*atan((float)r_newrefdef.height/r_newrefdef.width)*180/M_PI;
+	qglMatrixMode(GL_PROJECTION);
+    qglLoadIdentity ();
+    MYgluPerspective (r_newrefdef.fov_y,  screenaspect,  4,  4096);
+
+	qglCullFace(GL_FRONT);
+
+	qglMatrixMode(GL_MODELVIEW);
+    qglLoadIdentity ();
+
+    qglRotatef (-90,  1, 0, 0);	    // put Z going up
+    qglRotatef (90,  0, 0, 1);	    // put Z going up
+    qglRotatef (-r_newrefdef.viewangles[2],  1, 0, 0);
+    qglRotatef (-r_newrefdef.viewangles[0],  0, 1, 0);
+    qglRotatef (-r_newrefdef.viewangles[1],  0, 0, 1);
+    qglTranslatef (-r_newrefdef.vieworg[0],  -r_newrefdef.vieworg[1],  -r_newrefdef.vieworg[2]);
+
+//	if ( gl_state.camera_separation != 0 && gl_state.stereo_enabled )
+//		qglTranslatef ( gl_state.camera_separation, 0, 0 );
+
+	qglGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
+
+	//
+	// set drawing parms
+	//
+	if (gl_cull->value)
+		qglEnable(GL_CULL_FACE);
+	else
+		qglDisable(GL_CULL_FACE);
+
+	qglDisable(GL_BLEND);
+	qglDisable(GL_ALPHA_TEST);
+	qglEnable(GL_DEPTH_TEST);
+}
+
+/*
+=============
+R_Clear
+=============
+*/
+void R_Clear (void)
+{
+	if (gl_ztrick->value)
+	{
+		static int trickframe;
+
+		if (gl_clear->value)
+			qglClear (GL_COLOR_BUFFER_BIT);
+
+		trickframe++;
+		if (trickframe & 1)
+		{
+			gldepthmin = 0;
+			gldepthmax = 0.49999;
+			qglDepthFunc (GL_LEQUAL);
+		}
+		else
+		{
+			gldepthmin = 1;
+			gldepthmax = 0.5;
+			qglDepthFunc (GL_GEQUAL);
+		}
+	}
+	else
+	{
+		if (gl_clear->value)
+			qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		else
+			qglClear (GL_DEPTH_BUFFER_BIT);
+		gldepthmin = 0;
+		gldepthmax = 1;
+		qglDepthFunc (GL_LEQUAL);
+	}
+
+	qglDepthRange (gldepthmin, gldepthmax);
+
+}
+
+void R_Flash( void )
+{
+	R_PolyBlend ();
+}
+
+/*
+================
+R_RenderView
+
+r_newrefdef must be set before the first call
+================
+*/
+void R_RenderView (refdef_t *fd)
+{
+	if (r_norefresh->value)
+		return;
+
+	r_newrefdef = *fd;
+
+	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+		ri.Sys_Error (ERR_DROP, "R_RenderView: NULL worldmodel");
+
+	if (r_speeds->value)
+	{
+		c_brush_polys = 0;
+		c_alias_polys = 0;
+	}
+
+	R_PushDlights ();
+
+	if (gl_finish->value)
+		qglFinish ();
+
+	R_SetupFrame ();
+
+	R_SetFrustum ();
+
+	R_SetupGL ();
+
+	R_MarkLeaves ();	// done here so we know if we're in water
+
+	R_DrawWorld ();
+
+	R_DrawEntitiesOnList ();
+
+	R_RenderDlights ();
+
+	R_DrawParticles ();
+
+	R_DrawAlphaSurfaces ();
+
+	R_Flash();
+
+	if (r_speeds->value)
+	{
+		ri.Con_Printf (PRINT_ALL, "%4i wpoly %4i epoly %i tex %i lmaps\n",
+			c_brush_polys, 
+			c_alias_polys, 
+			c_visible_textures, 
+			c_visible_lightmaps); 
+	}
+}
+
+
+void	R_SetGL2D (void)
+{
+	// set 2D virtual screen size
+	qglViewport (0,0, vid.width, vid.height);
+	qglMatrixMode(GL_PROJECTION);
+    qglLoadIdentity ();
+	qglOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
+	qglMatrixMode(GL_MODELVIEW);
+    qglLoadIdentity ();
+	qglDisable (GL_DEPTH_TEST);
+	qglDisable (GL_CULL_FACE);
+	qglDisable (GL_BLEND);
+	qglEnable (GL_ALPHA_TEST);
+	qglColor4f (1,1,1,1);
+}
+
+static void GL_DrawColoredStereoLinePair( float r, float g, float b, float y )
+{
+	qglColor3f( r, g, b );
+	qglVertex2f( 0, y );
+	qglVertex2f( vid.width, y );
+	qglColor3f( 0, 0, 0 );
+	qglVertex2f( 0, y + 1 );
+	qglVertex2f( vid.width, y + 1 );
+}
+
+static void GL_DrawStereoPattern( void )
+{
+	int i;
+
+	if ( !( gl_config.renderer & GL_RENDERER_INTERGRAPH ) )
+		return;
+
+	if ( !gl_state.stereo_enabled )
+		return;
+
+	R_SetGL2D();
+
+	qglDrawBuffer( GL_BACK_LEFT );
+
+	for ( i = 0; i < 20; i++ )
+	{
+		qglBegin( GL_LINES );
+			GL_DrawColoredStereoLinePair( 1, 0, 0, 0 );
+			GL_DrawColoredStereoLinePair( 1, 0, 0, 2 );
+			GL_DrawColoredStereoLinePair( 1, 0, 0, 4 );
+			GL_DrawColoredStereoLinePair( 1, 0, 0, 6 );
+			GL_DrawColoredStereoLinePair( 0, 1, 0, 8 );
+			GL_DrawColoredStereoLinePair( 1, 1, 0, 10);
+			GL_DrawColoredStereoLinePair( 1, 1, 0, 12);
+			GL_DrawColoredStereoLinePair( 0, 1, 0, 14);
+		qglEnd();
+		
+		GLimp_EndFrame();
+	}
+}
+
+
+/*
+====================
+R_SetLightLevel
+
+====================
+*/
+void R_SetLightLevel (void)
+{
+	vec3_t		shadelight;
+
+	if (r_newrefdef.rdflags & RDF_NOWORLDMODEL)
+		return;
+
+	// save off light value for server to look at (BIG HACK!)
+
+	R_LightPoint (r_newrefdef.vieworg, shadelight);
+
+	// pick the greatest component, which should be the same
+	// as the mono value returned by software
+	if (shadelight[0] > shadelight[1])
+	{
+		if (shadelight[0] > shadelight[2])
+			r_lightlevel->value = 150*shadelight[0];
+		else
+			r_lightlevel->value = 150*shadelight[2];
+	}
+	else
+	{
+		if (shadelight[1] > shadelight[2])
+			r_lightlevel->value = 150*shadelight[1];
+		else
+			r_lightlevel->value = 150*shadelight[2];
+	}
+
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_RenderFrame
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_RenderFrame (refdef_t *fd)
+{
+	R_RenderView( fd );
+	R_SetLightLevel ();
+	R_SetGL2D ();
+}
+
+
+void R_Register( void )
+{
+	r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+	r_norefresh = ri.Cvar_Get ("r_norefresh", "0", 0);
+	r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
+	r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
+	r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
+	r_novis = ri.Cvar_Get ("r_novis", "0", 0);
+	r_nocull = ri.Cvar_Get ("r_nocull", "0", 0);
+	r_lerpmodels = ri.Cvar_Get ("r_lerpmodels", "1", 0);
+	r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
+
+	r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
+
+	gl_nosubimage = ri.Cvar_Get( "gl_nosubimage", "0", 0 );
+	gl_allow_software = ri.Cvar_Get( "gl_allow_software", "0", 0 );
+
+	gl_particle_min_size = ri.Cvar_Get( "gl_particle_min_size", "2", CVAR_ARCHIVE );
+	gl_particle_max_size = ri.Cvar_Get( "gl_particle_max_size", "40", CVAR_ARCHIVE );
+	gl_particle_size = ri.Cvar_Get( "gl_particle_size", "40", CVAR_ARCHIVE );
+	gl_particle_att_a = ri.Cvar_Get( "gl_particle_att_a", "0.01", CVAR_ARCHIVE );
+	gl_particle_att_b = ri.Cvar_Get( "gl_particle_att_b", "0.0", CVAR_ARCHIVE );
+	gl_particle_att_c = ri.Cvar_Get( "gl_particle_att_c", "0.01", CVAR_ARCHIVE );
+
+	gl_modulate = ri.Cvar_Get ("gl_modulate", "1", CVAR_ARCHIVE );
+	gl_log = ri.Cvar_Get( "gl_log", "0", 0 );
+	gl_bitdepth = ri.Cvar_Get( "gl_bitdepth", "0", 0 );
+	gl_mode = ri.Cvar_Get( "gl_mode", "3", CVAR_ARCHIVE );
+	gl_lightmap = ri.Cvar_Get ("gl_lightmap", "0", 0);
+	gl_shadows = ri.Cvar_Get ("gl_shadows", "0", CVAR_ARCHIVE );
+	gl_dynamic = ri.Cvar_Get ("gl_dynamic", "1", 0);
+	gl_nobind = ri.Cvar_Get ("gl_nobind", "0", 0);
+	gl_round_down = ri.Cvar_Get ("gl_round_down", "1", 0);
+	gl_picmip = ri.Cvar_Get ("gl_picmip", "0", 0);
+	gl_skymip = ri.Cvar_Get ("gl_skymip", "0", 0);
+	gl_showtris = ri.Cvar_Get ("gl_showtris", "0", 0);
+	gl_ztrick = ri.Cvar_Get ("gl_ztrick", "0", 0);
+	gl_finish = ri.Cvar_Get ("gl_finish", "0", CVAR_ARCHIVE);
+	gl_clear = ri.Cvar_Get ("gl_clear", "0", 0);
+	gl_cull = ri.Cvar_Get ("gl_cull", "1", 0);
+	gl_polyblend = ri.Cvar_Get ("gl_polyblend", "1", 0);
+	gl_flashblend = ri.Cvar_Get ("gl_flashblend", "0", 0);
+	gl_playermip = ri.Cvar_Get ("gl_playermip", "0", 0);
+	gl_monolightmap = ri.Cvar_Get( "gl_monolightmap", "0", 0 );
+	gl_driver = ri.Cvar_Get( "gl_driver", "opengl32", CVAR_ARCHIVE );
+	gl_texturemode = ri.Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
+	gl_texturealphamode = ri.Cvar_Get( "gl_texturealphamode", "default", CVAR_ARCHIVE );
+	gl_texturesolidmode = ri.Cvar_Get( "gl_texturesolidmode", "default", CVAR_ARCHIVE );
+	gl_lockpvs = ri.Cvar_Get( "gl_lockpvs", "0", 0 );
+
+	gl_vertex_arrays = ri.Cvar_Get( "gl_vertex_arrays", "0", CVAR_ARCHIVE );
+
+	gl_ext_swapinterval = ri.Cvar_Get( "gl_ext_swapinterval", "1", CVAR_ARCHIVE );
+	gl_ext_palettedtexture = ri.Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
+	gl_ext_multitexture = ri.Cvar_Get( "gl_ext_multitexture", "1", CVAR_ARCHIVE );
+	gl_ext_pointparameters = ri.Cvar_Get( "gl_ext_pointparameters", "1", CVAR_ARCHIVE );
+	gl_ext_compiled_vertex_array = ri.Cvar_Get( "gl_ext_compiled_vertex_array", "1", CVAR_ARCHIVE );
+
+	gl_drawbuffer = ri.Cvar_Get( "gl_drawbuffer", "GL_BACK", 0 );
+	gl_swapinterval = ri.Cvar_Get( "gl_swapinterval", "1", CVAR_ARCHIVE );
+
+	gl_saturatelighting = ri.Cvar_Get( "gl_saturatelighting", "0", 0 );
+
+	gl_3dlabs_broken = ri.Cvar_Get( "gl_3dlabs_broken", "1", CVAR_ARCHIVE );
+
+	vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
+	vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
+	vid_ref = ri.Cvar_Get( "vid_ref", "soft", CVAR_ARCHIVE );
+
+	ri.Cmd_AddCommand( "imagelist", GL_ImageList_f );
+	ri.Cmd_AddCommand( "screenshot", GL_ScreenShot_f );
+	ri.Cmd_AddCommand( "modellist", Mod_Modellist_f );
+	ri.Cmd_AddCommand( "gl_strings", GL_Strings_f );
+}
+
+/*
+==================
+R_SetMode
+==================
+*/
+qboolean R_SetMode (void)
+{
+	rserr_t err;
+	qboolean fullscreen;
+
+	if ( vid_fullscreen->modified && !gl_config.allow_cds )
+	{
+		ri.Con_Printf( PRINT_ALL, "R_SetMode() - CDS not allowed with this driver\n" );
+		ri.Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value );
+		vid_fullscreen->modified = false;
+	}
+
+	fullscreen = vid_fullscreen->value;
+
+	vid_fullscreen->modified = false;
+	gl_mode->modified = false;
+
+	if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, fullscreen ) ) == rserr_ok )
+	{
+		gl_state.prev_mode = gl_mode->value;
+	}
+	else
+	{
+		if ( err == rserr_invalid_fullscreen )
+		{
+			ri.Cvar_SetValue( "vid_fullscreen", 0);
+			vid_fullscreen->modified = false;
+			ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - fullscreen unavailable in this mode\n" );
+			if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, false ) ) == rserr_ok )
+				return true;
+		}
+		else if ( err == rserr_invalid_mode )
+		{
+			ri.Cvar_SetValue( "gl_mode", gl_state.prev_mode );
+			gl_mode->modified = false;
+			ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n" );
+		}
+
+		// try setting it back to something safe
+		if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_state.prev_mode, false ) ) != rserr_ok )
+		{
+			ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - could not revert to safe mode\n" );
+			return false;
+		}
+	}
+	return true;
+}
+
+/*
+===============
+R_Init
+===============
+*/
+int R_Init( void *hinstance, void *hWnd )
+{	
+	char renderer_buffer[1000];
+	char vendor_buffer[1000];
+	int		err;
+	int		j;
+	extern float r_turbsin[256];
+
+	for ( j = 0; j < 256; j++ )
+	{
+		r_turbsin[j] *= 0.5;
+	}
+
+	ri.Con_Printf (PRINT_ALL, "ref_gl version: "REF_VERSION"\n");
+
+	Draw_GetPalette ();
+
+	R_Register();
+
+	// initialize our QGL dynamic bindings
+	if ( !QGL_Init( gl_driver->string ) )
+	{
+		QGL_Shutdown();
+        ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not load \"%s\"\n", gl_driver->string );
+		return -1;
+	}
+
+	// initialize OS-specific parts of OpenGL
+	if ( !GLimp_Init( hinstance, hWnd ) )
+	{
+		QGL_Shutdown();
+		return -1;
+	}
+
+	// set our "safe" modes
+	gl_state.prev_mode = 3;
+
+	// create the window and set up the context
+	if ( !R_SetMode () )
+	{
+		QGL_Shutdown();
+        ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not R_SetMode()\n" );
+		return -1;
+	}
+
+	ri.Vid_MenuInit();
+
+	/*
+	** get our various GL strings
+	*/
+	gl_config.vendor_string = qglGetString (GL_VENDOR);
+	ri.Con_Printf (PRINT_ALL, "GL_VENDOR: %s\n", gl_config.vendor_string );
+	gl_config.renderer_string = qglGetString (GL_RENDERER);
+	ri.Con_Printf (PRINT_ALL, "GL_RENDERER: %s\n", gl_config.renderer_string );
+	gl_config.version_string = qglGetString (GL_VERSION);
+	ri.Con_Printf (PRINT_ALL, "GL_VERSION: %s\n", gl_config.version_string );
+	gl_config.extensions_string = qglGetString (GL_EXTENSIONS);
+	ri.Con_Printf (PRINT_ALL, "GL_EXTENSIONS: %s\n", gl_config.extensions_string );
+
+	strcpy( renderer_buffer, gl_config.renderer_string );
+	strlwr( renderer_buffer );
+
+	strcpy( vendor_buffer, gl_config.vendor_string );
+	strlwr( vendor_buffer );
+
+	if ( strstr( renderer_buffer, "voodoo" ) )
+	{
+		if ( !strstr( renderer_buffer, "rush" ) )
+			gl_config.renderer = GL_RENDERER_VOODOO;
+		else
+			gl_config.renderer = GL_RENDERER_VOODOO_RUSH;
+	}
+	else if ( strstr( vendor_buffer, "sgi" ) )
+		gl_config.renderer = GL_RENDERER_SGI;
+	else if ( strstr( renderer_buffer, "permedia" ) )
+		gl_config.renderer = GL_RENDERER_PERMEDIA2;
+	else if ( strstr( renderer_buffer, "glint" ) )
+		gl_config.renderer = GL_RENDERER_GLINT_MX;
+	else if ( strstr( renderer_buffer, "glzicd" ) )
+		gl_config.renderer = GL_RENDERER_REALIZM;
+	else if ( strstr( renderer_buffer, "gdi" ) )
+		gl_config.renderer = GL_RENDERER_MCD;
+	else if ( strstr( renderer_buffer, "pcx2" ) )
+		gl_config.renderer = GL_RENDERER_PCX2;
+	else if ( strstr( renderer_buffer, "verite" ) )
+		gl_config.renderer = GL_RENDERER_RENDITION;
+	else
+		gl_config.renderer = GL_RENDERER_OTHER;
+
+	if ( toupper( gl_monolightmap->string[1] ) != 'F' )
+	{
+		if ( gl_config.renderer == GL_RENDERER_PERMEDIA2 )
+		{
+			ri.Cvar_Set( "gl_monolightmap", "A" );
+			ri.Con_Printf( PRINT_ALL, "...using gl_monolightmap 'a'\n" );
+		}
+		else if ( gl_config.renderer & GL_RENDERER_POWERVR ) 
+		{
+			ri.Cvar_Set( "gl_monolightmap", "0" );
+		}
+		else
+		{
+			ri.Cvar_Set( "gl_monolightmap", "0" );
+		}
+	}
+
+	// power vr can't have anything stay in the framebuffer, so
+	// the screen needs to redraw the tiled background every frame
+	if ( gl_config.renderer & GL_RENDERER_POWERVR ) 
+	{
+		ri.Cvar_Set( "scr_drawall", "1" );
+	}
+	else
+	{
+		ri.Cvar_Set( "scr_drawall", "0" );
+	}
+
+	// MCD has buffering issues
+	if ( gl_config.renderer == GL_RENDERER_MCD )
+	{
+		ri.Cvar_SetValue( "gl_finish", 1 );
+	}
+
+	if ( gl_config.renderer & GL_RENDERER_3DLABS )
+	{
+		if ( gl_3dlabs_broken->value )
+			gl_config.allow_cds = false;
+		else
+			gl_config.allow_cds = true;
+	}
+	else
+	{
+		gl_config.allow_cds = true;
+	}
+
+	if ( gl_config.allow_cds )
+		ri.Con_Printf( PRINT_ALL, "...allowing CDS\n" );
+	else
+		ri.Con_Printf( PRINT_ALL, "...disabling CDS\n" );
+
+	/*
+	** grab extensions
+	*/
+#ifdef WIN32
+	if ( strstr( gl_config.extensions_string, "GL_EXT_compiled_vertex_array" ) || 
+		 strstr( gl_config.extensions_string, "GL_SGI_compiled_vertex_array" ) )
+	{
+		ri.Con_Printf( PRINT_ALL, "...enabling GL_EXT_compiled_vertex_array\n" );
+		qglLockArraysEXT = ( void * ) qwglGetProcAddress( "glLockArraysEXT" );
+		qglUnlockArraysEXT = ( void * ) qwglGetProcAddress( "glUnlockArraysEXT" );
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
+	}
+
+	if ( strstr( gl_config.extensions_string, "WGL_EXT_swap_control" ) )
+	{
+		qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" );
+		ri.Con_Printf( PRINT_ALL, "...enabling WGL_EXT_swap_control\n" );
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" );
+	}
+
+	if ( strstr( gl_config.extensions_string, "GL_EXT_point_parameters" ) )
+	{
+		if ( gl_ext_pointparameters->value )
+		{
+			qglPointParameterfEXT = ( void (APIENTRY *)( GLenum, GLfloat ) ) qwglGetProcAddress( "glPointParameterfEXT" );
+			qglPointParameterfvEXT = ( void (APIENTRY *)( GLenum, const GLfloat * ) ) qwglGetProcAddress( "glPointParameterfvEXT" );
+			ri.Con_Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" );
+		}
+		else
+		{
+			ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" );
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" );
+	}
+
+	if ( strstr( gl_config.extensions_string, "GL_EXT_paletted_texture" ) && 
+		 strstr( gl_config.extensions_string, "GL_EXT_shared_texture_palette" ) )
+	{
+		if ( gl_ext_palettedtexture->value )
+		{
+			ri.Con_Printf( PRINT_ALL, "...using GL_EXT_shared_texture_palette\n" );
+			qglColorTableEXT = ( void ( APIENTRY * ) ( int, int, int, int, int, const void * ) ) qwglGetProcAddress( "glColorTableEXT" );
+		}
+		else
+		{
+			ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_shared_texture_palette\n" );
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...GL_EXT_shared_texture_palette not found\n" );
+	}
+
+	if ( strstr( gl_config.extensions_string, "GL_SGIS_multitexture" ) )
+	{
+		if ( gl_ext_multitexture->value )
+		{
+			ri.Con_Printf( PRINT_ALL, "...using GL_SGIS_multitexture\n" );
+			qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMTexCoord2fSGIS" );
+			qglSelectTextureSGIS = ( void * ) qwglGetProcAddress( "glSelectTextureSGIS" );
+		}
+		else
+		{
+			ri.Con_Printf( PRINT_ALL, "...ignoring GL_SGIS_multitexture\n" );
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture not found\n" );
+	}
+#endif
+
+	GL_SetDefaultState();
+
+	/*
+	** draw our stereo patterns
+	*/
+#if 0 // commented out until H3D pays us the money they owe us
+	GL_DrawStereoPattern();
+#endif
+
+	GL_InitImages ();
+	Mod_Init ();
+	R_InitParticleTexture ();
+	Draw_InitLocal ();
+
+	err = qglGetError();
+	if ( err != GL_NO_ERROR )
+		ri.Con_Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);
+}
+
+/*
+===============
+R_Shutdown
+===============
+*/
+void R_Shutdown (void)
+{	
+	ri.Cmd_RemoveCommand ("modellist");
+	ri.Cmd_RemoveCommand ("screenshot");
+	ri.Cmd_RemoveCommand ("imagelist");
+	ri.Cmd_RemoveCommand ("gl_strings");
+
+	Mod_FreeAll ();
+
+	GL_ShutdownImages ();
+
+	/*
+	** shut down OS specific OpenGL stuff like contexts, etc.
+	*/
+	GLimp_Shutdown();
+
+	/*
+	** shutdown our QGL subsystem
+	*/
+	QGL_Shutdown();
+}
+
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_BeginFrame
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_BeginFrame( float camera_separation )
+{
+
+	gl_state.camera_separation = camera_separation;
+
+	/*
+	** change modes if necessary
+	*/
+	if ( gl_mode->modified || vid_fullscreen->modified )
+	{	// FIXME: only restart if CDS is required
+		cvar_t	*ref;
+
+		ref = ri.Cvar_Get ("vid_ref", "gl", 0);
+		ref->modified = true;
+	}
+
+	if ( gl_log->modified )
+	{
+		GLimp_EnableLogging( gl_log->value );
+		gl_log->modified = false;
+	}
+
+	if ( gl_log->value )
+	{
+		GLimp_LogNewFrame();
+	}
+
+	/*
+	** update 3Dfx gamma -- it is expected that a user will do a vid_restart
+	** after tweaking this value
+	*/
+	if ( vid_gamma->modified )
+	{
+		vid_gamma->modified = false;
+
+		if ( gl_config.renderer & ( GL_RENDERER_VOODOO ) )
+		{
+			char envbuffer[1024];
+			float g;
+
+			g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
+			Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g );
+			putenv( envbuffer );
+			Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
+			putenv( envbuffer );
+		}
+	}
+
+	GLimp_BeginFrame( camera_separation );
+
+	/*
+	** go into 2D mode
+	*/
+	qglViewport (0,0, vid.width, vid.height);
+	qglMatrixMode(GL_PROJECTION);
+    qglLoadIdentity ();
+	qglOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
+	qglMatrixMode(GL_MODELVIEW);
+    qglLoadIdentity ();
+	qglDisable (GL_DEPTH_TEST);
+	qglDisable (GL_CULL_FACE);
+	qglDisable (GL_BLEND);
+	qglEnable (GL_ALPHA_TEST);
+	qglColor4f (1,1,1,1);
+
+	/*
+	** draw buffer stuff
+	*/
+	if ( gl_drawbuffer->modified )
+	{
+		gl_drawbuffer->modified = false;
+
+		if ( gl_state.camera_separation == 0 || !gl_state.stereo_enabled )
+		{
+			if ( Q_stricmp( gl_drawbuffer->string, "GL_FRONT" ) == 0 )
+				qglDrawBuffer( GL_FRONT );
+			else
+				qglDrawBuffer( GL_BACK );
+		}
+	}
+
+	/*
+	** texturemode stuff
+	*/
+	if ( gl_texturemode->modified )
+	{
+		GL_TextureMode( gl_texturemode->string );
+		gl_texturemode->modified = false;
+	}
+
+	if ( gl_texturealphamode->modified )
+	{
+		GL_TextureAlphaMode( gl_texturealphamode->string );
+		gl_texturealphamode->modified = false;
+	}
+
+	if ( gl_texturesolidmode->modified )
+	{
+		GL_TextureSolidMode( gl_texturesolidmode->string );
+		gl_texturesolidmode->modified = false;
+	}
+
+	/*
+	** swapinterval stuff
+	*/
+	GL_UpdateSwapInterval();
+
+	//
+	// clear screen if desired
+	//
+	R_Clear ();
+}
+
+/*
+=============
+R_SetPalette
+=============
+*/
+unsigned r_rawpalette[256];
+
+void R_SetPalette ( const unsigned char *palette)
+{
+	int		i;
+
+	byte *rp = ( byte * ) r_rawpalette;
+
+	if ( palette )
+	{
+		for ( i = 0; i < 256; i++ )
+		{
+			rp[i*4+0] = palette[i*3+0];
+			rp[i*4+1] = palette[i*3+1];
+			rp[i*4+2] = palette[i*3+2];
+			rp[i*4+3] = 0xff;
+		}
+	}
+	else
+	{
+		for ( i = 0; i < 256; i++ )
+		{
+			rp[i*4+0] = d_8to24table[i] & 0xff;
+			rp[i*4+1] = ( d_8to24table[i] >> 8 ) & 0xff;
+			rp[i*4+2] = ( d_8to24table[i] >> 16 ) & 0xff;
+			rp[i*4+3] = 0xff;
+		}
+	}
+	GL_SetTexturePalette( r_rawpalette );
+
+	qglClearColor (0,0,0,0);
+	qglClear (GL_COLOR_BUFFER_BIT);
+	qglClearColor (1,0, 0.5 , 0.5);
+}
+
+/*
+** R_DrawBeam
+*/
+void R_DrawBeam( entity_t *e )
+{
+#define NUM_BEAM_SEGS 6
+
+	int	i;
+	float r, g, b;
+
+	vec3_t perpvec;
+	vec3_t direction, normalized_direction;
+	vec3_t	start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+	vec3_t oldorigin, origin;
+
+	oldorigin[0] = e->oldorigin[0];
+	oldorigin[1] = e->oldorigin[1];
+	oldorigin[2] = e->oldorigin[2];
+
+	origin[0] = e->origin[0];
+	origin[1] = e->origin[1];
+	origin[2] = e->origin[2];
+
+	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+	if ( VectorNormalize( normalized_direction ) == 0 )
+		return;
+
+	PerpendicularVector( perpvec, normalized_direction );
+	VectorScale( perpvec, e->frame / 2, perpvec );
+
+	for ( i = 0; i < 6; i++ )
+	{
+		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+		VectorAdd( start_points[i], origin, start_points[i] );
+		VectorAdd( start_points[i], direction, end_points[i] );
+	}
+
+	qglDisable( GL_TEXTURE_2D );
+	qglEnable( GL_BLEND );
+	qglDepthMask( GL_FALSE );
+
+	r = ( d_8to24table[e->skinnum & 0xFF] ) & 0xFF;
+	g = ( d_8to24table[e->skinnum & 0xFF] >> 8 ) & 0xFF;
+	b = ( d_8to24table[e->skinnum & 0xFF] >> 16 ) & 0xFF;
+
+	r *= 1/255.0F;
+	g *= 1/255.0F;
+	b *= 1/255.0F;
+
+	qglColor4f( r, g, b, e->alpha );
+
+	qglBegin( GL_TRIANGLE_STRIP );
+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+	{
+		qglVertex3fv( start_points[i] );
+		qglVertex3fv( end_points[i] );
+		qglVertex3fv( start_points[(i+1)%NUM_BEAM_SEGS] );
+		qglVertex3fv( end_points[(i+1)%NUM_BEAM_SEGS] );
+	}
+	qglEnd();
+
+	qglEnable( GL_TEXTURE_2D );
+	qglDisable( GL_BLEND );
+	qglDepthMask( GL_TRUE );
+}
+
+//===================================================================
+
+
+void	R_BeginRegistration (char *map);
+struct model_s	*R_RegisterModel (char *name);
+struct image_s	*R_RegisterSkin (char *name);
+void R_SetSky (char *name, float rotate, vec3_t axis);
+void	R_EndRegistration (void);
+
+void	R_RenderFrame (refdef_t *fd);
+
+struct image_s	*Draw_FindPic (char *name);
+
+void	Draw_Pic (int x, int y, char *name);
+void	Draw_Char (int x, int y, int c);
+void	Draw_TileClear (int x, int y, int w, int h, char *name);
+void	Draw_Fill (int x, int y, int w, int h, int c);
+void	Draw_FadeScreen (void);
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+refexport_t GetRefAPI (refimport_t rimp )
+{
+	refexport_t	re;
+
+	ri = rimp;
+
+	re.api_version = API_VERSION;
+
+	re.BeginRegistration = R_BeginRegistration;
+	re.RegisterModel = R_RegisterModel;
+	re.RegisterSkin = R_RegisterSkin;
+	re.RegisterPic = Draw_FindPic;
+	re.SetSky = R_SetSky;
+	re.EndRegistration = R_EndRegistration;
+
+	re.RenderFrame = R_RenderFrame;
+
+	re.DrawGetPicSize = Draw_GetPicSize;
+	re.DrawPic = Draw_Pic;
+	re.DrawStretchPic = Draw_StretchPic;
+	re.DrawChar = Draw_Char;
+	re.DrawTileClear = Draw_TileClear;
+	re.DrawFill = Draw_Fill;
+	re.DrawFadeScreen= Draw_FadeScreen;
+
+	re.DrawStretchRaw = Draw_StretchRaw;
+
+	re.Init = R_Init;
+	re.Shutdown = R_Shutdown;
+
+	re.CinematicSetPalette = R_SetPalette;
+	re.BeginFrame = R_BeginFrame;
+	re.EndFrame = GLimp_EndFrame;
+
+	re.AppActivate = GLimp_AppActivate;
+
+	Swap_Init ();
+
+	return re;
+}
+
+
+#ifndef REF_HARD_LINKED
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, error);
+	vsprintf (text, error, argptr);
+	va_end (argptr);
+
+	ri.Sys_Error (ERR_FATAL, "%s", text);
+}
+
+void Com_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, fmt);
+	vsprintf (text, fmt, argptr);
+	va_end (argptr);
+
+	ri.Con_Printf (PRINT_ALL, "%s", text);
+}
+
+#endif
--- /dev/null
+++ b/ref_gl/gl_rmisc.c
@@ -1,0 +1,246 @@
+/*
+Copyright (C) 1997-2001 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 "gl_local.h"
+
+/*
+==================
+R_InitParticleTexture
+==================
+*/
+byte	dottexture[8][8] =
+{
+	{0,0,0,0,0,0,0,0},
+	{0,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},
+};
+
+void R_InitParticleTexture (void)
+{
+	int		x,y;
+	byte	data[8][8][4];
+
+	//
+	// particle texture
+	//
+	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;
+		}
+	}
+	r_particletexture = GL_LoadPic ("***particle***", (byte *)data, 8, 8, it_sprite, 32);
+
+	//
+	// also use this for bad textures, but without alpha
+	//
+	for (x=0 ; x<8 ; x++)
+	{
+		for (y=0 ; y<8 ; y++)
+		{
+			data[y][x][0] = dottexture[x&3][y&3]*255;
+			data[y][x][1] = 0; // dottexture[x&3][y&3]*255;
+			data[y][x][2] = 0; //dottexture[x&3][y&3]*255;
+			data[y][x][3] = 255;
+		}
+	}
+	r_notexture = GL_LoadPic ("***r_notexture***", (byte *)data, 8, 8, it_wall, 32);
+}
+
+
+/* 
+============================================================================== 
+ 
+						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;
+
+
+/* 
+================== 
+GL_ScreenShot_f
+================== 
+*/  
+void GL_ScreenShot_f (void) 
+{
+	byte		*buffer;
+	char		picname[80]; 
+	char		checkname[MAX_OSPATH];
+	int			i, c, temp;
+	FILE		*f;
+
+	// create the scrnshots directory if it doesn't exist
+	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
+	Sys_Mkdir (checkname);
+
+// 
+// find a file name to save it to 
+// 
+	strcpy(picname,"quake00.tga");
+
+	for (i=0 ; i<=99 ; i++) 
+	{ 
+		picname[5] = i/10 + '0'; 
+		picname[6] = i%10 + '0'; 
+		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname);
+		f = fopen (checkname, "rb");
+		if (!f)
+			break;	// file doesn't exist
+		fclose (f);
+	} 
+	if (i==100) 
+	{
+		ri.Con_Printf (PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n"); 
+		return;
+ 	}
+
+
+	buffer = malloc(vid.width*vid.height*3 + 18);
+	memset (buffer, 0, 18);
+	buffer[2] = 2;		// uncompressed type
+	buffer[12] = vid.width&255;
+	buffer[13] = vid.width>>8;
+	buffer[14] = vid.height&255;
+	buffer[15] = vid.height>>8;
+	buffer[16] = 24;	// pixel size
+
+	qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 
+
+	// swap rgb to bgr
+	c = 18+vid.width*vid.height*3;
+	for (i=18 ; i<c ; i+=3)
+	{
+		temp = buffer[i];
+		buffer[i] = buffer[i+2];
+		buffer[i+2] = temp;
+	}
+
+	f = fopen (checkname, "wb");
+	fwrite (buffer, 1, c, f);
+	fclose (f);
+
+	free (buffer);
+	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname);
+} 
+
+/*
+** GL_Strings_f
+*/
+void GL_Strings_f( void )
+{
+	ri.Con_Printf (PRINT_ALL, "GL_VENDOR: %s\n", gl_config.vendor_string );
+	ri.Con_Printf (PRINT_ALL, "GL_RENDERER: %s\n", gl_config.renderer_string );
+	ri.Con_Printf (PRINT_ALL, "GL_VERSION: %s\n", gl_config.version_string );
+	ri.Con_Printf (PRINT_ALL, "GL_EXTENSIONS: %s\n", gl_config.extensions_string );
+}
+
+/*
+** GL_SetDefaultState
+*/
+void GL_SetDefaultState( void )
+{
+	qglClearColor (1,0, 0.5 , 0.5);
+	qglCullFace(GL_FRONT);
+	qglEnable(GL_TEXTURE_2D);
+
+	qglEnable(GL_ALPHA_TEST);
+	qglAlphaFunc(GL_GREATER, 0.666);
+
+	qglDisable (GL_DEPTH_TEST);
+	qglDisable (GL_CULL_FACE);
+	qglDisable (GL_BLEND);
+
+	qglColor4f (1,1,1,1);
+
+	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+	qglShadeModel (GL_FLAT);
+
+	GL_TextureMode( gl_texturemode->string );
+	GL_TextureAlphaMode( gl_texturealphamode->string );
+	GL_TextureSolidMode( gl_texturesolidmode->string );
+
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+	qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	GL_TexEnv( GL_REPLACE );
+
+	if ( qglPointParameterfEXT )
+	{
+		float attenuations[3];
+
+		attenuations[0] = gl_particle_att_a->value;
+		attenuations[1] = gl_particle_att_b->value;
+		attenuations[2] = gl_particle_att_c->value;
+
+		qglEnable( GL_POINT_SMOOTH );
+		qglPointParameterfEXT( GL_POINT_SIZE_MIN_EXT, gl_particle_min_size->value );
+		qglPointParameterfEXT( GL_POINT_SIZE_MAX_EXT, gl_particle_max_size->value );
+		qglPointParameterfvEXT( GL_DISTANCE_ATTENUATION_EXT, attenuations );
+	}
+
+	if ( qglColorTableEXT && gl_ext_palettedtexture->value )
+	{
+		qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
+
+		GL_SetTexturePalette( d_8to24table );
+	}
+
+	GL_UpdateSwapInterval();
+}
+
+void GL_UpdateSwapInterval( void )
+{
+	if ( gl_swapinterval->modified )
+	{
+		gl_swapinterval->modified = false;
+
+		if ( !gl_state.stereo_enabled ) 
+		{
+#ifdef _WIN32
+			if ( qwglSwapIntervalEXT )
+				qwglSwapIntervalEXT( gl_swapinterval->value );
+#endif
+		}
+	}
+}
\ No newline at end of file
--- /dev/null
+++ b/ref_gl/gl_rsurf.c
@@ -1,0 +1,1660 @@
+/*
+Copyright (C) 1997-2001 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_RSURF.C: surface-related refresh code
+#include <assert.h>
+
+#include "gl_local.h"
+
+static vec3_t	modelorg;		// relative to viewpoint
+
+msurface_t	*r_alpha_surfaces;
+
+#define DYNAMIC_LIGHT_WIDTH  128
+#define DYNAMIC_LIGHT_HEIGHT 128
+
+#define LIGHTMAP_BYTES 4
+
+#define	BLOCK_WIDTH		128
+#define	BLOCK_HEIGHT	128
+
+#define	MAX_LIGHTMAPS	128
+
+int		c_visible_lightmaps;
+int		c_visible_textures;
+
+#define GL_LIGHTMAP_FORMAT GL_RGBA
+
+typedef struct
+{
+	int internal_format;
+	int	current_lightmap_texture;
+
+	msurface_t	*lightmap_surfaces[MAX_LIGHTMAPS];
+
+	int			allocated[BLOCK_WIDTH];
+
+	// the lightmap texture data needs to be kept in
+	// main memory so texsubimage can update properly
+	byte		lightmap_buffer[4*BLOCK_WIDTH*BLOCK_HEIGHT];
+} gllightmapstate_t;
+
+static gllightmapstate_t gl_lms;
+
+
+static void		LM_InitBlock( void );
+static void		LM_UploadBlock( qboolean dynamic );
+static qboolean	LM_AllocBlock (int w, int h, int *x, int *y);
+
+extern void R_SetCacheState( msurface_t *surf );
+extern void R_BuildLightMap (msurface_t *surf, byte *dest, int stride);
+
+/*
+=============================================================
+
+	BRUSH MODELS
+
+=============================================================
+*/
+
+/*
+===============
+R_TextureAnimation
+
+Returns the proper texture for a given time and base texture
+===============
+*/
+image_t *R_TextureAnimation (mtexinfo_t *tex)
+{
+	int		c;
+
+	if (!tex->next)
+		return tex->image;
+
+	c = currententity->frame % tex->numframes;
+	while (c)
+	{
+		tex = tex->next;
+		c--;
+	}
+
+	return tex->image;
+}
+
+#if 0
+/*
+=================
+WaterWarpPolyVerts
+
+Mangles the x and y coordinates in a copy of the poly
+so that any drawing routine can be water warped
+=================
+*/
+glpoly_t *WaterWarpPolyVerts (glpoly_t *p)
+{
+	int		i;
+	float	*v, *nv;
+	static byte	buffer[1024];
+	glpoly_t *out;
+
+	out = (glpoly_t *)buffer;
+
+	out->numverts = p->numverts;
+	v = p->verts[0];
+	nv = out->verts[0];
+	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE, nv+=VERTEXSIZE)
+	{
+		nv[0] = v[0] + 4*sin(v[1]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time);
+		nv[1] = v[1] + 4*sin(v[0]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time);
+
+		nv[2] = v[2];
+		nv[3] = v[3];
+		nv[4] = v[4];
+		nv[5] = v[5];
+		nv[6] = v[6];
+	}
+
+	return out;
+}
+
+/*
+================
+DrawGLWaterPoly
+
+Warp the vertex coordinates
+================
+*/
+void DrawGLWaterPoly (glpoly_t *p)
+{
+	int		i;
+	float	*v;
+
+	p = WaterWarpPolyVerts (p);
+	qglBegin (GL_TRIANGLE_FAN);
+	v = p->verts[0];
+	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+	{
+		qglTexCoord2f (v[3], v[4]);
+		qglVertex3fv (v);
+	}
+	qglEnd ();
+}
+void DrawGLWaterPolyLightmap (glpoly_t *p)
+{
+	int		i;
+	float	*v;
+
+	p = WaterWarpPolyVerts (p);
+	qglBegin (GL_TRIANGLE_FAN);
+	v = p->verts[0];
+	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+	{
+		qglTexCoord2f (v[5], v[6]);
+		qglVertex3fv (v);
+	}
+	qglEnd ();
+}
+#endif
+
+/*
+================
+DrawGLPoly
+================
+*/
+void DrawGLPoly (glpoly_t *p)
+{
+	int		i;
+	float	*v;
+
+	qglBegin (GL_POLYGON);
+	v = p->verts[0];
+	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+	{
+		qglTexCoord2f (v[3], v[4]);
+		qglVertex3fv (v);
+	}
+	qglEnd ();
+}
+
+//============
+//PGM
+/*
+================
+DrawGLFlowingPoly -- version of DrawGLPoly that handles scrolling texture
+================
+*/
+void DrawGLFlowingPoly (msurface_t *fa)
+{
+	int		i;
+	float	*v;
+	glpoly_t *p;
+	float	scroll;
+
+	p = fa->polys;
+
+	scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) );
+	if(scroll == 0.0)
+		scroll = -64.0;
+
+	qglBegin (GL_POLYGON);
+	v = p->verts[0];
+	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+	{
+		qglTexCoord2f ((v[3] + scroll), v[4]);
+		qglVertex3fv (v);
+	}
+	qglEnd ();
+}
+//PGM
+//============
+
+/*
+** R_DrawTriangleOutlines
+*/
+void R_DrawTriangleOutlines (void)
+{
+	int			i, j;
+	glpoly_t	*p;
+
+	if (!gl_showtris->value)
+		return;
+
+	qglDisable (GL_TEXTURE_2D);
+	qglDisable (GL_DEPTH_TEST);
+	qglColor4f (1,1,1,1);
+
+	for (i=0 ; i<MAX_LIGHTMAPS ; i++)
+	{
+		msurface_t *surf;
+
+		for ( surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain )
+		{
+			p = surf->polys;
+			for ( ; p ; p=p->chain)
+			{
+				for (j=2 ; j<p->numverts ; j++ )
+				{
+					qglBegin (GL_LINE_STRIP);
+					qglVertex3fv (p->verts[0]);
+					qglVertex3fv (p->verts[j-1]);
+					qglVertex3fv (p->verts[j]);
+					qglVertex3fv (p->verts[0]);
+					qglEnd ();
+				}
+			}
+		}
+	}
+
+	qglEnable (GL_DEPTH_TEST);
+	qglEnable (GL_TEXTURE_2D);
+}
+
+/*
+** DrawGLPolyChain
+*/
+void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset )
+{
+	if ( soffset == 0 && toffset == 0 )
+	{
+		for ( ; p != 0; p = p->chain )
+		{
+			float *v;
+			int j;
+
+			qglBegin (GL_POLYGON);
+			v = p->verts[0];
+			for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
+			{
+				qglTexCoord2f (v[5], v[6] );
+				qglVertex3fv (v);
+			}
+			qglEnd ();
+		}
+	}
+	else
+	{
+		for ( ; p != 0; p = p->chain )
+		{
+			float *v;
+			int j;
+
+			qglBegin (GL_POLYGON);
+			v = p->verts[0];
+			for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
+			{
+				qglTexCoord2f (v[5] - soffset, v[6] - toffset );
+				qglVertex3fv (v);
+			}
+			qglEnd ();
+		}
+	}
+}
+
+/*
+** R_BlendLightMaps
+**
+** This routine takes all the given light mapped surfaces in the world and
+** blends them into the framebuffer.
+*/
+void R_BlendLightmaps (void)
+{
+	int			i;
+	msurface_t	*surf, *newdrawsurf = 0;
+
+	// don't bother if we're set to fullbright
+	if (r_fullbright->value)
+		return;
+	if (!r_worldmodel->lightdata)
+		return;
+
+	// don't bother writing Z
+	qglDepthMask( 0 );
+
+	/*
+	** set the appropriate blending mode unless we're only looking at the
+	** lightmaps.
+	*/
+	if (!gl_lightmap->value)
+	{
+		qglEnable (GL_BLEND);
+
+		if ( gl_saturatelighting->value )
+		{
+			qglBlendFunc( GL_ONE, GL_ONE );
+		}
+		else
+		{
+			if ( gl_monolightmap->string[0] != '0' )
+			{
+				switch ( toupper( gl_monolightmap->string[0] ) )
+				{
+				case 'I':
+					qglBlendFunc (GL_ZERO, GL_SRC_COLOR );
+					break;
+				case 'L':
+					qglBlendFunc (GL_ZERO, GL_SRC_COLOR );
+					break;
+				case 'A':
+				default:
+					qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+					break;
+				}
+			}
+			else
+			{
+				qglBlendFunc (GL_ZERO, GL_SRC_COLOR );
+			}
+		}
+	}
+
+	if ( currentmodel == r_worldmodel )
+		c_visible_lightmaps = 0;
+
+	/*
+	** render static lightmaps first
+	*/
+	for ( i = 1; i < MAX_LIGHTMAPS; i++ )
+	{
+		if ( gl_lms.lightmap_surfaces[i] )
+		{
+			if (currentmodel == r_worldmodel)
+				c_visible_lightmaps++;
+			GL_Bind( gl_state.lightmap_textures + i);
+
+			for ( surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain )
+			{
+				if ( surf->polys )
+					DrawGLPolyChain( surf->polys, 0, 0 );
+			}
+		}
+	}
+
+	/*
+	** render dynamic lightmaps
+	*/
+	if ( gl_dynamic->value )
+	{
+		LM_InitBlock();
+
+		GL_Bind( gl_state.lightmap_textures+0 );
+
+		if (currentmodel == r_worldmodel)
+			c_visible_lightmaps++;
+
+		newdrawsurf = gl_lms.lightmap_surfaces[0];
+
+		for ( surf = gl_lms.lightmap_surfaces[0]; surf != 0; surf = surf->lightmapchain )
+		{
+			int		smax, tmax;
+			byte	*base;
+
+			smax = (surf->extents[0]>>4)+1;
+			tmax = (surf->extents[1]>>4)+1;
+
+			if ( LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) )
+			{
+				base = gl_lms.lightmap_buffer;
+				base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES;
+
+				R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES);
+			}
+			else
+			{
+				msurface_t *drawsurf;
+
+				// upload what we have so far
+				LM_UploadBlock( true );
+
+				// draw all surfaces that use this lightmap
+				for ( drawsurf = newdrawsurf; drawsurf != surf; drawsurf = drawsurf->lightmapchain )
+				{
+					if ( drawsurf->polys )
+						DrawGLPolyChain( drawsurf->polys, 
+							              ( drawsurf->light_s - drawsurf->dlight_s ) * ( 1.0 / 128.0 ), 
+										( drawsurf->light_t - drawsurf->dlight_t ) * ( 1.0 / 128.0 ) );
+				}
+
+				newdrawsurf = drawsurf;
+
+				// clear the block
+				LM_InitBlock();
+
+				// try uploading the block now
+				if ( !LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) )
+				{
+					ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed (dynamic)\n", smax, tmax );
+				}
+
+				base = gl_lms.lightmap_buffer;
+				base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES;
+
+				R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES);
+			}
+		}
+
+		/*
+		** draw remainder of dynamic lightmaps that haven't been uploaded yet
+		*/
+		if ( newdrawsurf )
+			LM_UploadBlock( true );
+
+		for ( surf = newdrawsurf; surf != 0; surf = surf->lightmapchain )
+		{
+			if ( surf->polys )
+				DrawGLPolyChain( surf->polys, ( surf->light_s - surf->dlight_s ) * ( 1.0 / 128.0 ), ( surf->light_t - surf->dlight_t ) * ( 1.0 / 128.0 ) );
+		}
+	}
+
+	/*
+	** restore state
+	*/
+	qglDisable (GL_BLEND);
+	qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	qglDepthMask( 1 );
+}
+
+/*
+================
+R_RenderBrushPoly
+================
+*/
+void R_RenderBrushPoly (msurface_t *fa)
+{
+	int			maps;
+	image_t		*image;
+	qboolean is_dynamic = false;
+
+	c_brush_polys++;
+
+	image = R_TextureAnimation (fa->texinfo);
+
+	if (fa->flags & SURF_DRAWTURB)
+	{	
+		GL_Bind( image->texnum );
+
+		// warp texture, no lightmaps
+		GL_TexEnv( GL_MODULATE );
+		qglColor4f( gl_state.inverse_intensity, 
+			        gl_state.inverse_intensity,
+					gl_state.inverse_intensity,
+					1.0F );
+		EmitWaterPolys (fa);
+		GL_TexEnv( GL_REPLACE );
+
+		return;
+	}
+	else
+	{
+		GL_Bind( image->texnum );
+
+		GL_TexEnv( GL_REPLACE );
+	}
+
+//======
+//PGM
+	if(fa->texinfo->flags & SURF_FLOWING)
+		DrawGLFlowingPoly (fa);
+	else
+		DrawGLPoly (fa->polys);
+//PGM
+//======
+
+	/*
+	** check for lightmap modification
+	*/
+	for ( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
+	{
+		if ( r_newrefdef.lightstyles[fa->styles[maps]].white != fa->cached_light[maps] )
+			goto dynamic;
+	}
+
+	// dynamic this frame or dynamic previously
+	if ( ( fa->dlightframe == r_framecount ) )
+	{
+dynamic:
+		if ( gl_dynamic->value )
+		{
+			if (!( fa->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) )
+			{
+				is_dynamic = true;
+			}
+		}
+	}
+
+	if ( is_dynamic )
+	{
+		if ( ( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != r_framecount ) )
+		{
+			unsigned	temp[34*34];
+			int			smax, tmax;
+
+			smax = (fa->extents[0]>>4)+1;
+			tmax = (fa->extents[1]>>4)+1;
+
+			R_BuildLightMap( fa, (void *)temp, smax*4 );
+			R_SetCacheState( fa );
+
+			GL_Bind( gl_state.lightmap_textures + fa->lightmaptexturenum );
+
+			qglTexSubImage2D( GL_TEXTURE_2D, 0,
+							  fa->light_s, fa->light_t, 
+							  smax, tmax, 
+							  GL_LIGHTMAP_FORMAT, 
+							  GL_UNSIGNED_BYTE, temp );
+
+			fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
+			gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
+		}
+		else
+		{
+			fa->lightmapchain = gl_lms.lightmap_surfaces[0];
+			gl_lms.lightmap_surfaces[0] = fa;
+		}
+	}
+	else
+	{
+		fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
+		gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
+	}
+}
+
+
+/*
+================
+R_DrawAlphaSurfaces
+
+Draw water surfaces and windows.
+The BSP tree is waled front to back, so unwinding the chain
+of alpha_surfaces will draw back to front, giving proper ordering.
+================
+*/
+void R_DrawAlphaSurfaces (void)
+{
+	msurface_t	*s;
+	float		intens;
+
+	//
+	// go back to the world matrix
+	//
+    qglLoadMatrixf (r_world_matrix);
+
+	qglEnable (GL_BLEND);
+	GL_TexEnv( GL_MODULATE );
+
+	// the textures are prescaled up for a better lighting range,
+	// so scale it back down
+	intens = gl_state.inverse_intensity;
+
+	for (s=r_alpha_surfaces ; s ; s=s->texturechain)
+	{
+		GL_Bind(s->texinfo->image->texnum);
+		c_brush_polys++;
+		if (s->texinfo->flags & SURF_TRANS33)
+			qglColor4f (intens,intens,intens,0.33);
+		else if (s->texinfo->flags & SURF_TRANS66)
+			qglColor4f (intens,intens,intens,0.66);
+		else
+			qglColor4f (intens,intens,intens,1);
+		if (s->flags & SURF_DRAWTURB)
+			EmitWaterPolys (s);
+		else
+			DrawGLPoly (s->polys);
+	}
+
+	GL_TexEnv( GL_REPLACE );
+	qglColor4f (1,1,1,1);
+	qglDisable (GL_BLEND);
+
+	r_alpha_surfaces = NULL;
+}
+
+/*
+================
+DrawTextureChains
+================
+*/
+void DrawTextureChains (void)
+{
+	int		i;
+	msurface_t	*s;
+	image_t		*image;
+
+	c_visible_textures = 0;
+
+//	GL_TexEnv( GL_REPLACE );
+
+	if ( !qglSelectTextureSGIS )
+	{
+		for ( i = 0, image=gltextures ; i<numgltextures ; i++,image++)
+		{
+			if (!image->registration_sequence)
+				continue;
+			s = image->texturechain;
+			if (!s)
+				continue;
+			c_visible_textures++;
+
+			for ( ; s ; s=s->texturechain)
+				R_RenderBrushPoly (s);
+
+			image->texturechain = NULL;
+		}
+	}
+	else
+	{
+		for ( i = 0, image=gltextures ; i<numgltextures ; i++,image++)
+		{
+			if (!image->registration_sequence)
+				continue;
+			if (!image->texturechain)
+				continue;
+			c_visible_textures++;
+
+			for ( s = image->texturechain; s ; s=s->texturechain)
+			{
+				if ( !( s->flags & SURF_DRAWTURB ) )
+					R_RenderBrushPoly (s);
+			}
+		}
+
+		GL_EnableMultitexture( false );
+		for ( i = 0, image=gltextures ; i<numgltextures ; i++,image++)
+		{
+			if (!image->registration_sequence)
+				continue;
+			s = image->texturechain;
+			if (!s)
+				continue;
+
+			for ( ; s ; s=s->texturechain)
+			{
+				if ( s->flags & SURF_DRAWTURB )
+					R_RenderBrushPoly (s);
+			}
+
+			image->texturechain = NULL;
+		}
+//		GL_EnableMultitexture( true );
+	}
+
+	GL_TexEnv( GL_REPLACE );
+}
+
+
+static void GL_RenderLightmappedPoly( msurface_t *surf )
+{
+	int		i, nv = surf->polys->numverts;
+	int		map;
+	float	*v;
+	image_t *image = R_TextureAnimation( surf->texinfo );
+	qboolean is_dynamic = false;
+	unsigned lmtex = surf->lightmaptexturenum;
+	glpoly_t *p;
+
+	for ( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
+	{
+		if ( r_newrefdef.lightstyles[surf->styles[map]].white != surf->cached_light[map] )
+			goto dynamic;
+	}
+
+	// dynamic this frame or dynamic previously
+	if ( ( surf->dlightframe == r_framecount ) )
+	{
+dynamic:
+		if ( gl_dynamic->value )
+		{
+			if ( !(surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) )
+			{
+				is_dynamic = true;
+			}
+		}
+	}
+
+	if ( is_dynamic )
+	{
+		unsigned	temp[128*128];
+		int			smax, tmax;
+
+		if ( ( surf->styles[map] >= 32 || surf->styles[map] == 0 ) && ( surf->dlightframe != r_framecount ) )
+		{
+			smax = (surf->extents[0]>>4)+1;
+			tmax = (surf->extents[1]>>4)+1;
+
+			R_BuildLightMap( surf, (void *)temp, smax*4 );
+			R_SetCacheState( surf );
+
+			GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + surf->lightmaptexturenum );
+
+			lmtex = surf->lightmaptexturenum;
+
+			qglTexSubImage2D( GL_TEXTURE_2D, 0,
+							  surf->light_s, surf->light_t, 
+							  smax, tmax, 
+							  GL_LIGHTMAP_FORMAT, 
+							  GL_UNSIGNED_BYTE, temp );
+
+		}
+		else
+		{
+			smax = (surf->extents[0]>>4)+1;
+			tmax = (surf->extents[1]>>4)+1;
+
+			R_BuildLightMap( surf, (void *)temp, smax*4 );
+
+			GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + 0 );
+
+			lmtex = 0;
+
+			qglTexSubImage2D( GL_TEXTURE_2D, 0,
+							  surf->light_s, surf->light_t, 
+							  smax, tmax, 
+							  GL_LIGHTMAP_FORMAT, 
+							  GL_UNSIGNED_BYTE, temp );
+
+		}
+
+		c_brush_polys++;
+
+		GL_MBind( GL_TEXTURE0_SGIS, image->texnum );
+		GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + lmtex );
+
+//==========
+//PGM
+		if (surf->texinfo->flags & SURF_FLOWING)
+		{
+			float scroll;
+		
+			scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) );
+			if(scroll == 0.0)
+				scroll = -64.0;
+
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts[0];
+				qglBegin (GL_POLYGON);
+				for (i=0 ; i< nv; i++, v+= VERTEXSIZE)
+				{
+					qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, (v[3]+scroll), v[4]);
+					qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]);
+					qglVertex3fv (v);
+				}
+				qglEnd ();
+			}
+		}
+		else
+		{
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts[0];
+				qglBegin (GL_POLYGON);
+				for (i=0 ; i< nv; i++, v+= VERTEXSIZE)
+				{
+					qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, v[3], v[4]);
+					qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]);
+					qglVertex3fv (v);
+				}
+				qglEnd ();
+			}
+		}
+//PGM
+//==========
+	}
+	else
+	{
+		c_brush_polys++;
+
+		GL_MBind( GL_TEXTURE0_SGIS, image->texnum );
+		GL_MBind( GL_TEXTURE1_SGIS, gl_state.lightmap_textures + lmtex );
+
+//==========
+//PGM
+		if (surf->texinfo->flags & SURF_FLOWING)
+		{
+			float scroll;
+		
+			scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) );
+			if(scroll == 0.0)
+				scroll = -64.0;
+
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts[0];
+				qglBegin (GL_POLYGON);
+				for (i=0 ; i< nv; i++, v+= VERTEXSIZE)
+				{
+					qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, (v[3]+scroll), v[4]);
+					qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]);
+					qglVertex3fv (v);
+				}
+				qglEnd ();
+			}
+		}
+		else
+		{
+//PGM
+//==========
+			for ( p = surf->polys; p; p = p->chain )
+			{
+				v = p->verts[0];
+				qglBegin (GL_POLYGON);
+				for (i=0 ; i< nv; i++, v+= VERTEXSIZE)
+				{
+					qglMTexCoord2fSGIS( GL_TEXTURE0_SGIS, v[3], v[4]);
+					qglMTexCoord2fSGIS( GL_TEXTURE1_SGIS, v[5], v[6]);
+					qglVertex3fv (v);
+				}
+				qglEnd ();
+			}
+//==========
+//PGM
+		}
+//PGM
+//==========
+	}
+}
+
+/*
+=================
+R_DrawInlineBModel
+=================
+*/
+void R_DrawInlineBModel (void)
+{
+	int			i, k;
+	cplane_t	*pplane;
+	float		dot;
+	msurface_t	*psurf;
+	dlight_t	*lt;
+
+	// calculate dynamic lighting for bmodel
+	if ( !gl_flashblend->value )
+	{
+		lt = r_newrefdef.dlights;
+		for (k=0 ; k<r_newrefdef.num_dlights ; k++, lt++)
+		{
+			R_MarkLights (lt, 1<<k, currentmodel->nodes + currentmodel->firstnode);
+		}
+	}
+
+	psurf = &currentmodel->surfaces[currentmodel->firstmodelsurface];
+
+	if ( currententity->flags & RF_TRANSLUCENT )
+	{
+		qglEnable (GL_BLEND);
+		qglColor4f (1,1,1,0.25);
+		GL_TexEnv( GL_MODULATE );
+	}
+
+	//
+	// draw texture
+	//
+	for (i=0 ; i<currentmodel->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 (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66) )
+			{	// add to the translucent chain
+				psurf->texturechain = r_alpha_surfaces;
+				r_alpha_surfaces = psurf;
+			}
+			else if ( qglMTexCoord2fSGIS && !( psurf->flags & SURF_DRAWTURB ) )
+			{
+				GL_RenderLightmappedPoly( psurf );
+			}
+			else
+			{
+				GL_EnableMultitexture( false );
+				R_RenderBrushPoly( psurf );
+				GL_EnableMultitexture( true );
+			}
+		}
+	}
+
+	if ( !(currententity->flags & RF_TRANSLUCENT) )
+	{
+		if ( !qglMTexCoord2fSGIS )
+			R_BlendLightmaps ();
+	}
+	else
+	{
+		qglDisable (GL_BLEND);
+		qglColor4f (1,1,1,1);
+		GL_TexEnv( GL_REPLACE );
+	}
+}
+
+/*
+=================
+R_DrawBrushModel
+=================
+*/
+void R_DrawBrushModel (entity_t *e)
+{
+	vec3_t		mins, maxs;
+	int			i;
+	qboolean	rotated;
+
+	if (currentmodel->nummodelsurfaces == 0)
+		return;
+
+	currententity = e;
+	gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1;
+
+	if (e->angles[0] || e->angles[1] || e->angles[2])
+	{
+		rotated = true;
+		for (i=0 ; i<3 ; i++)
+		{
+			mins[i] = e->origin[i] - currentmodel->radius;
+			maxs[i] = e->origin[i] + currentmodel->radius;
+		}
+	}
+	else
+	{
+		rotated = false;
+		VectorAdd (e->origin, currentmodel->mins, mins);
+		VectorAdd (e->origin, currentmodel->maxs, maxs);
+	}
+
+	if (R_CullBox (mins, maxs))
+		return;
+
+	qglColor3f (1,1,1);
+	memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces));
+
+	VectorSubtract (r_newrefdef.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);
+	}
+
+    qglPushMatrix ();
+e->angles[0] = -e->angles[0];	// stupid quake bug
+e->angles[2] = -e->angles[2];	// stupid quake bug
+	R_RotateForEntity (e);
+e->angles[0] = -e->angles[0];	// stupid quake bug
+e->angles[2] = -e->angles[2];	// stupid quake bug
+
+	GL_EnableMultitexture( true );
+	GL_SelectTexture( GL_TEXTURE0_SGIS );
+	GL_TexEnv( GL_REPLACE );
+	GL_SelectTexture( GL_TEXTURE1_SGIS );
+	GL_TexEnv( GL_MODULATE );
+
+	R_DrawInlineBModel ();
+	GL_EnableMultitexture( false );
+
+	qglPopMatrix ();
+}
+
+/*
+=============================================================
+
+	WORLD MODEL
+
+=============================================================
+*/
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+void R_RecursiveWorldNode (mnode_t *node)
+{
+	int			c, side, sidebit;
+	cplane_t	*plane;
+	msurface_t	*surf, **mark;
+	mleaf_t		*pleaf;
+	float		dot;
+	image_t		*image;
+
+	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 != -1)
+	{
+		pleaf = (mleaf_t *)node;
+
+		// check for door connected areas
+		if (r_newrefdef.areabits)
+		{
+			if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
+				return;		// not visible
+		}
+
+		mark = pleaf->firstmarksurface;
+		c = pleaf->nummarksurfaces;
+
+		if (c)
+		{
+			do
+			{
+				(*mark)->visframe = r_framecount;
+				mark++;
+			} while (--c);
+		}
+
+		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;
+		sidebit = 0;
+	}
+	else
+	{
+		side = 1;
+		sidebit = SURF_PLANEBACK;
+	}
+
+// recurse down the children, front side first
+	R_RecursiveWorldNode (node->children[side]);
+
+	// draw stuff
+	for ( c = node->numsurfaces, surf = r_worldmodel->surfaces + node->firstsurface; c ; c--, surf++)
+	{
+		if (surf->visframe != r_framecount)
+			continue;
+
+		if ( (surf->flags & SURF_PLANEBACK) != sidebit )
+			continue;		// wrong side
+
+		if (surf->texinfo->flags & SURF_SKY)
+		{	// just adds to visible sky bounds
+			R_AddSkySurface (surf);
+		}
+		else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+		{	// add to the translucent chain
+			surf->texturechain = r_alpha_surfaces;
+			r_alpha_surfaces = surf;
+		}
+		else
+		{
+			if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) )
+			{
+				GL_RenderLightmappedPoly( surf );
+			}
+			else
+			{
+				// the polygon is visible, so add it to the texture
+				// sorted chain
+				// FIXME: this is a hack for animation
+				image = R_TextureAnimation (surf->texinfo);
+				surf->texturechain = image->texturechain;
+				image->texturechain = surf;
+			}
+		}
+	}
+
+	// recurse down the back side
+	R_RecursiveWorldNode (node->children[!side]);
+/*
+	for ( ; c ; c--, surf++)
+	{
+		if (surf->visframe != r_framecount)
+			continue;
+
+		if ( (surf->flags & SURF_PLANEBACK) != sidebit )
+			continue;		// wrong side
+
+		if (surf->texinfo->flags & SURF_SKY)
+		{	// just adds to visible sky bounds
+			R_AddSkySurface (surf);
+		}
+		else if (surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+		{	// add to the translucent chain
+//			surf->texturechain = alpha_surfaces;
+//			alpha_surfaces = surf;
+		}
+		else
+		{
+			if ( qglMTexCoord2fSGIS && !( surf->flags & SURF_DRAWTURB ) )
+			{
+				GL_RenderLightmappedPoly( surf );
+			}
+			else
+			{
+				// the polygon is visible, so add it to the texture
+				// sorted chain
+				// FIXME: this is a hack for animation
+				image = R_TextureAnimation (surf->texinfo);
+				surf->texturechain = image->texturechain;
+				image->texturechain = surf;
+			}
+		}
+	}
+*/
+}
+
+
+/*
+=============
+R_DrawWorld
+=============
+*/
+void R_DrawWorld (void)
+{
+	entity_t	ent;
+
+	if (!r_drawworld->value)
+		return;
+
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+		return;
+
+	currentmodel = r_worldmodel;
+
+	VectorCopy (r_newrefdef.vieworg, modelorg);
+
+	// auto cycle the world frame for texture animation
+	memset (&ent, 0, sizeof(ent));
+	ent.frame = (int)(r_newrefdef.time*2);
+	currententity = &ent;
+
+	gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1;
+
+	qglColor3f (1,1,1);
+	memset (gl_lms.lightmap_surfaces, 0, sizeof(gl_lms.lightmap_surfaces));
+	R_ClearSkyBox ();
+
+	if ( qglMTexCoord2fSGIS )
+	{
+		GL_EnableMultitexture( true );
+
+		GL_SelectTexture( GL_TEXTURE0_SGIS );
+		GL_TexEnv( GL_REPLACE );
+		GL_SelectTexture( GL_TEXTURE1_SGIS );
+
+		if ( gl_lightmap->value )
+			GL_TexEnv( GL_REPLACE );
+		else 
+			GL_TexEnv( GL_MODULATE );
+
+		R_RecursiveWorldNode (r_worldmodel->nodes);
+
+		GL_EnableMultitexture( false );
+	}
+	else
+	{
+		R_RecursiveWorldNode (r_worldmodel->nodes);
+	}
+
+	/*
+	** theoretically nothing should happen in the next two functions
+	** if multitexture is enabled
+	*/
+	DrawTextureChains ();
+	R_BlendLightmaps ();
+	
+	R_DrawSkyBox ();
+
+	R_DrawTriangleOutlines ();
+}
+
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+void R_MarkLeaves (void)
+{
+	byte	*vis;
+	byte	fatvis[MAX_MAP_LEAFS/8];
+	mnode_t	*node;
+	int		i, c;
+	mleaf_t	*leaf;
+	int		cluster;
+
+	if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2 && !r_novis->value && r_viewcluster != -1)
+		return;
+
+	// development aid to let you run around and see exactly where
+	// the pvs ends
+	if (gl_lockpvs->value)
+		return;
+
+	r_visframecount++;
+	r_oldviewcluster = r_viewcluster;
+	r_oldviewcluster2 = r_viewcluster2;
+
+	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
+	{
+		// mark everything
+		for (i=0 ; i<r_worldmodel->numleafs ; i++)
+			r_worldmodel->leafs[i].visframe = r_visframecount;
+		for (i=0 ; i<r_worldmodel->numnodes ; i++)
+			r_worldmodel->nodes[i].visframe = r_visframecount;
+		return;
+	}
+
+	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
+	// may have to combine two clusters because of solid water boundaries
+	if (r_viewcluster2 != r_viewcluster)
+	{
+		memcpy (fatvis, vis, (r_worldmodel->numleafs+7)/8);
+		vis = Mod_ClusterPVS (r_viewcluster2, r_worldmodel);
+		c = (r_worldmodel->numleafs+31)/32;
+		for (i=0 ; i<c ; i++)
+			((int *)fatvis)[i] |= ((int *)vis)[i];
+		vis = fatvis;
+	}
+	
+	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
+	{
+		cluster = leaf->cluster;
+		if (cluster == -1)
+			continue;
+		if (vis[cluster>>3] & (1<<(cluster&7)))
+		{
+			node = (mnode_t *)leaf;
+			do
+			{
+				if (node->visframe == r_visframecount)
+					break;
+				node->visframe = r_visframecount;
+				node = node->parent;
+			} while (node);
+		}
+	}
+
+#if 0
+	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
+	{
+		if (vis[i>>3] & (1<<(i&7)))
+		{
+			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
+			do
+			{
+				if (node->visframe == r_visframecount)
+					break;
+				node->visframe = r_visframecount;
+				node = node->parent;
+			} while (node);
+		}
+	}
+#endif
+}
+
+
+
+/*
+=============================================================================
+
+  LIGHTMAP ALLOCATION
+
+=============================================================================
+*/
+
+static void LM_InitBlock( void )
+{
+	memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated ) );
+}
+
+static void LM_UploadBlock( qboolean dynamic )
+{
+	int texture;
+	int height = 0;
+
+	if ( dynamic )
+	{
+		texture = 0;
+	}
+	else
+	{
+		texture = gl_lms.current_lightmap_texture;
+	}
+
+	GL_Bind( gl_state.lightmap_textures + texture );
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	if ( dynamic )
+	{
+		int i;
+
+		for ( i = 0; i < BLOCK_WIDTH; i++ )
+		{
+			if ( gl_lms.allocated[i] > height )
+				height = gl_lms.allocated[i];
+		}
+
+		qglTexSubImage2D( GL_TEXTURE_2D, 
+						  0,
+						  0, 0,
+						  BLOCK_WIDTH, height,
+						  GL_LIGHTMAP_FORMAT,
+						  GL_UNSIGNED_BYTE,
+						  gl_lms.lightmap_buffer );
+	}
+	else
+	{
+		qglTexImage2D( GL_TEXTURE_2D, 
+					   0, 
+					   gl_lms.internal_format,
+					   BLOCK_WIDTH, BLOCK_HEIGHT, 
+					   0, 
+					   GL_LIGHTMAP_FORMAT, 
+					   GL_UNSIGNED_BYTE, 
+					   gl_lms.lightmap_buffer );
+		if ( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
+			ri.Sys_Error( ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n" );
+	}
+}
+
+// returns a texture number and the position inside it
+static qboolean LM_AllocBlock (int w, int h, int *x, int *y)
+{
+	int		i, j;
+	int		best, best2;
+
+	best = BLOCK_HEIGHT;
+
+	for (i=0 ; i<BLOCK_WIDTH-w ; i++)
+	{
+		best2 = 0;
+
+		for (j=0 ; j<w ; j++)
+		{
+			if (gl_lms.allocated[i+j] >= best)
+				break;
+			if (gl_lms.allocated[i+j] > best2)
+				best2 = gl_lms.allocated[i+j];
+		}
+		if (j == w)
+		{	// this is a valid spot
+			*x = i;
+			*y = best = best2;
+		}
+	}
+
+	if (best + h > BLOCK_HEIGHT)
+		return false;
+
+	for (i=0 ; i<w ; i++)
+		gl_lms.allocated[*x + i] = best + h;
+
+	return true;
+}
+
+/*
+================
+GL_BuildPolygonFromSurface
+================
+*/
+void GL_BuildPolygonFromSurface(msurface_t *fa)
+{
+	int			i, lindex, lnumverts;
+	medge_t		*pedges, *r_pedge;
+	int			vertpage;
+	float		*vec;
+	float		s, t;
+	glpoly_t	*poly;
+	vec3_t		total;
+
+// reconstruct the polygon
+	pedges = currentmodel->edges;
+	lnumverts = fa->numedges;
+	vertpage = 0;
+
+	VectorClear (total);
+	//
+	// 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 = currentmodel->vertexes[r_pedge->v[0]].position;
+		}
+		else
+		{
+			r_pedge = &pedges[-lindex];
+			vec = currentmodel->vertexes[r_pedge->v[1]].position;
+		}
+		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
+		s /= fa->texinfo->image->width;
+
+		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
+		t /= fa->texinfo->image->height;
+
+		VectorAdd (total, vec, total);
+		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;
+	}
+
+	poly->numverts = lnumverts;
+
+}
+
+/*
+========================
+GL_CreateSurfaceLightmap
+========================
+*/
+void GL_CreateSurfaceLightmap (msurface_t *surf)
+{
+	int		smax, tmax;
+	byte	*base;
+
+	if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
+		return;
+
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+
+	if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) )
+	{
+		LM_UploadBlock( false );
+		LM_InitBlock();
+		if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) )
+		{
+			ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed\n", smax, tmax );
+		}
+	}
+
+	surf->lightmaptexturenum = gl_lms.current_lightmap_texture;
+
+	base = gl_lms.lightmap_buffer;
+	base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES;
+
+	R_SetCacheState( surf );
+	R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES);
+}
+
+
+/*
+==================
+GL_BeginBuildingLightmaps
+
+==================
+*/
+void GL_BeginBuildingLightmaps (model_t *m)
+{
+	static lightstyle_t	lightstyles[MAX_LIGHTSTYLES];
+	int				i;
+	unsigned		dummy[128*128];
+
+	memset( gl_lms.allocated, 0, sizeof(gl_lms.allocated) );
+
+	r_framecount = 1;		// no dlightcache
+
+	GL_EnableMultitexture( true );
+	GL_SelectTexture( GL_TEXTURE1_SGIS );
+
+	/*
+	** setup the base lightstyles so the lightmaps won't have to be regenerated
+	** the first time they're seen
+	*/
+	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
+	{
+		lightstyles[i].rgb[0] = 1;
+		lightstyles[i].rgb[1] = 1;
+		lightstyles[i].rgb[2] = 1;
+		lightstyles[i].white = 3;
+	}
+	r_newrefdef.lightstyles = lightstyles;
+
+	if (!gl_state.lightmap_textures)
+	{
+		gl_state.lightmap_textures	= TEXNUM_LIGHTMAPS;
+//		gl_state.lightmap_textures	= gl_state.texture_extension_number;
+//		gl_state.texture_extension_number = gl_state.lightmap_textures + MAX_LIGHTMAPS;
+	}
+
+	gl_lms.current_lightmap_texture = 1;
+
+	/*
+	** if mono lightmaps are enabled and we want to use alpha
+	** blending (a,1-a) then we're likely running on a 3DLabs
+	** Permedia2.  In a perfect world we'd use a GL_ALPHA lightmap
+	** in order to conserve space and maximize bandwidth, however 
+	** this isn't a perfect world.
+	**
+	** So we have to use alpha lightmaps, but stored in GL_RGBA format,
+	** which means we only get 1/16th the color resolution we should when
+	** using alpha lightmaps.  If we find another board that supports
+	** only alpha lightmaps but that can at least support the GL_ALPHA
+	** format then we should change this code to use real alpha maps.
+	*/
+	if ( toupper( gl_monolightmap->string[0] ) == 'A' )
+	{
+		gl_lms.internal_format = gl_tex_alpha_format;
+	}
+	/*
+	** try to do hacked colored lighting with a blended texture
+	*/
+	else if ( toupper( gl_monolightmap->string[0] ) == 'C' )
+	{
+		gl_lms.internal_format = gl_tex_alpha_format;
+	}
+	else if ( toupper( gl_monolightmap->string[0] ) == 'I' )
+	{
+		gl_lms.internal_format = GL_INTENSITY8;
+	}
+	else if ( toupper( gl_monolightmap->string[0] ) == 'L' ) 
+	{
+		gl_lms.internal_format = GL_LUMINANCE8;
+	}
+	else
+	{
+		gl_lms.internal_format = gl_tex_solid_format;
+	}
+
+	/*
+	** initialize the dynamic lightmap texture
+	*/
+	GL_Bind( gl_state.lightmap_textures + 0 );
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	qglTexImage2D( GL_TEXTURE_2D, 
+				   0, 
+				   gl_lms.internal_format,
+				   BLOCK_WIDTH, BLOCK_HEIGHT, 
+				   0, 
+				   GL_LIGHTMAP_FORMAT, 
+				   GL_UNSIGNED_BYTE, 
+				   dummy );
+}
+
+/*
+=======================
+GL_EndBuildingLightmaps
+=======================
+*/
+void GL_EndBuildingLightmaps (void)
+{
+	LM_UploadBlock( false );
+	GL_EnableMultitexture( false );
+}
+
--- /dev/null
+++ b/ref_gl/gl_warp.c
@@ -1,0 +1,662 @@
+/*
+Copyright (C) 1997-2001 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 "gl_local.h"
+
+extern	model_t	*loadmodel;
+
+char	skyname[MAX_QPATH];
+float	skyrotate;
+vec3_t	skyaxis;
+image_t	*sky_images[6];
+
+msurface_t	*warpface;
+
+#define	SUBDIVIDE_SIZE	64
+//#define	SUBDIVIDE_SIZE	1024
+
+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;
+	vec3_t	total;
+	float	total_s, total_t;
+
+	if (numverts > 60)
+		ri.Sys_Error (ERR_DROP, "numverts = %i", numverts);
+
+	BoundPoly (numverts, verts, mins, maxs);
+
+	for (i=0 ; i<3 ; i++)
+	{
+		m = (mins[i] + maxs[i]) * 0.5;
+		m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 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;
+	}
+
+	// add a point in the center to help keep warp valid
+	poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float));
+	poly->next = warpface->polys;
+	warpface->polys = poly;
+	poly->numverts = numverts+2;
+	VectorClear (total);
+	total_s = 0;
+	total_t = 0;
+	for (i=0 ; i<numverts ; i++, verts+= 3)
+	{
+		VectorCopy (verts, poly->verts[i+1]);
+		s = DotProduct (verts, warpface->texinfo->vecs[0]);
+		t = DotProduct (verts, warpface->texinfo->vecs[1]);
+
+		total_s += s;
+		total_t += t;
+		VectorAdd (total, verts, total);
+
+		poly->verts[i+1][3] = s;
+		poly->verts[i+1][4] = t;
+	}
+
+	VectorScale (total, (1.0/numverts), poly->verts[0]);
+	poly->verts[0][3] = total_s/numverts;
+	poly->verts[0][4] = total_t/numverts;
+
+	// copy first vertex to last
+	memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0]));
+}
+
+/*
+================
+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	r_turbsin[] =
+{
+	#include "warpsin.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, *bp;
+	float		*v;
+	int			i;
+	float		s, t, os, ot;
+	float		scroll;
+	float		rdt = r_newrefdef.time;
+
+	if (fa->texinfo->flags & SURF_FLOWING)
+		scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) );
+	else
+		scroll = 0;
+	for (bp=fa->polys ; bp ; bp=bp->next)
+	{
+		p = bp;
+
+		qglBegin (GL_TRIANGLE_FAN);
+		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+		{
+			os = v[3];
+			ot = v[4];
+
+#if !id386
+			s = os + r_turbsin[(int)((ot*0.125+r_newrefdef.time) * TURBSCALE) & 255];
+#else
+			s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255];
+#endif
+			s += scroll;
+			s *= (1.0/64);
+
+#if !id386
+			t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255];
+#else
+			t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255];
+#endif
+			t *= (1.0/64);
+
+			qglTexCoord2f (s, t);
+			qglVertex3fv (v);
+		}
+		qglEnd ();
+	}
+}
+
+
+//===================================================================
+
+
+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];
+float	sky_min, sky_max;
+
+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);
+	qglVertex3fv (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];
+		if (dv < 0.001)
+			continue;	// don't divide by zero
+		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	ON_EPSILON		0.1			// point on plane side epsilon
+#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)
+		ri.Sys_Error (ERR_DROP, "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_AddSkySurface
+=================
+*/
+void R_AddSkySurface (msurface_t *fa)
+{
+	int			i;
+	vec3_t		verts[MAX_CLIP_VERTS];
+	glpoly_t	*p;
+
+	// calculate vertex values for sky box
+	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*2300;
+	b[1] = t*2300;
+	b[2] = 2300;
+
+	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];
+	}
+
+	// avoid bilerp seam
+	s = (s+1)*0.5;
+	t = (t+1)*0.5;
+
+	if (s < sky_min)
+		s = sky_min;
+	else if (s > sky_max)
+		s = sky_max;
+	if (t < sky_min)
+		t = sky_min;
+	else if (t > sky_max)
+		t = sky_max;
+
+	t = 1.0 - t;
+	qglTexCoord2f (s, t);
+	qglVertex3fv (v);
+}
+
+/*
+==============
+R_DrawSkyBox
+==============
+*/
+int	skytexorder[6] = {0,2,1,3,4,5};
+void R_DrawSkyBox (void)
+{
+	int		i;
+
+#if 0
+qglEnable (GL_BLEND);
+GL_TexEnv( GL_MODULATE );
+qglColor4f (1,1,1,0.5);
+qglDisable (GL_DEPTH_TEST);
+#endif
+	if (skyrotate)
+	{	// check for no sky at all
+		for (i=0 ; i<6 ; i++)
+			if (skymins[0][i] < skymaxs[0][i]
+			&& skymins[1][i] < skymaxs[1][i])
+				break;
+		if (i == 6)
+			return;		// nothing visible
+	}
+
+qglPushMatrix ();
+qglTranslatef (r_origin[0], r_origin[1], r_origin[2]);
+qglRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]);
+
+	for (i=0 ; i<6 ; i++)
+	{
+		if (skyrotate)
+		{	// hack, forces full sky to draw when rotating
+			skymins[0][i] = -1;
+			skymins[1][i] = -1;
+			skymaxs[0][i] = 1;
+			skymaxs[1][i] = 1;
+		}
+
+		if (skymins[0][i] >= skymaxs[0][i]
+		|| skymins[1][i] >= skymaxs[1][i])
+			continue;
+
+		GL_Bind (sky_images[skytexorder[i]]->texnum);
+
+		qglBegin (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);
+		qglEnd ();
+	}
+qglPopMatrix ();
+#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
+}
+
+
+/*
+============
+R_SetSky
+============
+*/
+// 3dstudio environment map names
+char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+void R_SetSky (char *name, float rotate, vec3_t axis)
+{
+	int		i;
+	char	pathname[MAX_QPATH];
+
+	strncpy (skyname, name, sizeof(skyname)-1);
+	skyrotate = rotate;
+	VectorCopy (axis, skyaxis);
+
+	for (i=0 ; i<6 ; i++)
+	{
+		// chop down rotating skies for less memory
+		if (gl_skymip->value || skyrotate)
+			gl_picmip->value++;
+
+		if ( qglColorTableEXT && gl_ext_palettedtexture->value )
+			Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]);
+		else
+			Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]);
+
+		sky_images[i] = GL_FindImage (pathname, it_sky);
+		if (!sky_images[i])
+			sky_images[i] = r_notexture;
+
+		if (gl_skymip->value || skyrotate)
+		{	// take less memory
+			gl_picmip->value--;
+			sky_min = 1.0/256;
+			sky_max = 255.0/256;
+		}
+		else	
+		{
+			sky_min = 1.0/512;
+			sky_max = 511.0/512;
+		}
+	}
+}
--- /dev/null
+++ b/ref_gl/qgl.h
@@ -1,0 +1,442 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+** QGL.H
+*/
+
+#ifndef __QGL_H__
+#define __QGL_H__
+
+#ifdef _WIN32
+#  include <windows.h>
+#endif
+
+#include <GL/gl.h>
+
+qboolean QGL_Init( const char *dllname );
+void     QGL_Shutdown( void );
+
+#ifndef APIENTRY
+#  define APIENTRY
+#endif
+
+extern  void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
+extern  void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
+extern  GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+extern  void ( APIENTRY * qglArrayElement )(GLint i);
+extern  void ( APIENTRY * qglBegin )(GLenum mode);
+extern  void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);
+extern  void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+extern  void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);
+extern  void ( APIENTRY * qglCallList )(GLuint list);
+extern  void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+extern  void ( APIENTRY * qglClear )(GLbitfield mask);
+extern  void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+extern  void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+extern  void ( APIENTRY * qglClearDepth )(GLclampd depth);
+extern  void ( APIENTRY * qglClearIndex )(GLfloat c);
+extern  void ( APIENTRY * qglClearStencil )(GLint s);
+extern  void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);
+extern  void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+extern  void ( APIENTRY * qglColor3bv )(const GLbyte *v);
+extern  void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+extern  void ( APIENTRY * qglColor3dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+extern  void ( APIENTRY * qglColor3fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue);
+extern  void ( APIENTRY * qglColor3iv )(const GLint *v);
+extern  void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue);
+extern  void ( APIENTRY * qglColor3sv )(const GLshort *v);
+extern  void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+extern  void ( APIENTRY * qglColor3ubv )(const GLubyte *v);
+extern  void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue);
+extern  void ( APIENTRY * qglColor3uiv )(const GLuint *v);
+extern  void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue);
+extern  void ( APIENTRY * qglColor3usv )(const GLushort *v);
+extern  void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+extern  void ( APIENTRY * qglColor4bv )(const GLbyte *v);
+extern  void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+extern  void ( APIENTRY * qglColor4dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+extern  void ( APIENTRY * qglColor4fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+extern  void ( APIENTRY * qglColor4iv )(const GLint *v);
+extern  void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+extern  void ( APIENTRY * qglColor4sv )(const GLshort *v);
+extern  void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+extern  void ( APIENTRY * qglColor4ubv )(const GLubyte *v);
+extern  void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+extern  void ( APIENTRY * qglColor4uiv )(const GLuint *v);
+extern  void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+extern  void ( APIENTRY * qglColor4usv )(const GLushort *v);
+extern  void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+extern  void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode);
+extern  void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+extern  void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+extern  void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+extern  void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+extern  void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+extern  void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+extern  void ( APIENTRY * qglCullFace )(GLenum mode);
+extern  void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range);
+extern  void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);
+extern  void ( APIENTRY * qglDepthFunc )(GLenum func);
+extern  void ( APIENTRY * qglDepthMask )(GLboolean flag);
+extern  void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);
+extern  void ( APIENTRY * qglDisable )(GLenum cap);
+extern  void ( APIENTRY * qglDisableClientState )(GLenum array);
+extern  void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count);
+extern  void ( APIENTRY * qglDrawBuffer )(GLenum mode);
+extern  void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+extern  void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+extern  void ( APIENTRY * qglEdgeFlag )(GLboolean flag);
+extern  void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+extern  void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag);
+extern  void ( APIENTRY * qglEnable )(GLenum cap);
+extern  void ( APIENTRY * qglEnableClientState )(GLenum array);
+extern  void ( APIENTRY * qglEnd )(void);
+extern  void ( APIENTRY * qglEndList )(void);
+extern  void ( APIENTRY * qglEvalCoord1d )(GLdouble u);
+extern  void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u);
+extern  void ( APIENTRY * qglEvalCoord1f )(GLfloat u);
+extern  void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u);
+extern  void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v);
+extern  void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u);
+extern  void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v);
+extern  void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u);
+extern  void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+extern  void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+extern  void ( APIENTRY * qglEvalPoint1 )(GLint i);
+extern  void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j);
+extern  void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+extern  void ( APIENTRY * qglFinish )(void);
+extern  void ( APIENTRY * qglFlush )(void);
+extern  void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglFogi )(GLenum pname, GLint param);
+extern  void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglFrontFace )(GLenum mode);
+extern  void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+extern  GLuint ( APIENTRY * qglGenLists )(GLsizei range);
+extern  void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures);
+extern  void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params);
+extern  void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation);
+extern  void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params);
+extern  GLenum ( APIENTRY * qglGetError )(void);
+extern  void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+extern  void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+extern  void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v);
+extern  void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values);
+extern  void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values);
+extern  void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values);
+extern  void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params);
+extern  void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask);
+extern  const GLubyte * ( APIENTRY * qglGetString )(GLenum name);
+extern  void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+extern  void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+extern  void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+extern  void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+extern  void ( APIENTRY * qglHint )(GLenum target, GLenum mode);
+extern  void ( APIENTRY * qglIndexMask )(GLuint mask);
+extern  void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+extern  void ( APIENTRY * qglIndexd )(GLdouble c);
+extern  void ( APIENTRY * qglIndexdv )(const GLdouble *c);
+extern  void ( APIENTRY * qglIndexf )(GLfloat c);
+extern  void ( APIENTRY * qglIndexfv )(const GLfloat *c);
+extern  void ( APIENTRY * qglIndexi )(GLint c);
+extern  void ( APIENTRY * qglIndexiv )(const GLint *c);
+extern  void ( APIENTRY * qglIndexs )(GLshort c);
+extern  void ( APIENTRY * qglIndexsv )(const GLshort *c);
+extern  void ( APIENTRY * qglIndexub )(GLubyte c);
+extern  void ( APIENTRY * qglIndexubv )(const GLubyte *c);
+extern  void ( APIENTRY * qglInitNames )(void);
+extern  void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+extern  GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap);
+extern  GLboolean ( APIENTRY * qglIsList )(GLuint list);
+extern  GLboolean ( APIENTRY * qglIsTexture )(GLuint texture);
+extern  void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param);
+extern  void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param);
+extern  void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern);
+extern  void ( APIENTRY * qglLineWidth )(GLfloat width);
+extern  void ( APIENTRY * qglListBase )(GLuint base);
+extern  void ( APIENTRY * qglLoadIdentity )(void);
+extern  void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m);
+extern  void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);
+extern  void ( APIENTRY * qglLoadName )(GLuint name);
+extern  void ( APIENTRY * qglLogicOp )(GLenum opcode);
+extern  void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+extern  void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+extern  void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+extern  void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+extern  void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+extern  void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+extern  void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+extern  void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+extern  void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param);
+extern  void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglMatrixMode )(GLenum mode);
+extern  void ( APIENTRY * qglMultMatrixd )(const GLdouble *m);
+extern  void ( APIENTRY * qglMultMatrixf )(const GLfloat *m);
+extern  void ( APIENTRY * qglNewList )(GLuint list, GLenum mode);
+extern  void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+extern  void ( APIENTRY * qglNormal3bv )(const GLbyte *v);
+extern  void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+extern  void ( APIENTRY * qglNormal3dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+extern  void ( APIENTRY * qglNormal3fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz);
+extern  void ( APIENTRY * qglNormal3iv )(const GLint *v);
+extern  void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+extern  void ( APIENTRY * qglNormal3sv )(const GLshort *v);
+extern  void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+extern  void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+extern  void ( APIENTRY * qglPassThrough )(GLfloat token);
+extern  void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+extern  void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+extern  void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+extern  void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param);
+extern  void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param);
+extern  void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+extern  void ( APIENTRY * qglPointSize )(GLfloat size);
+extern  void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);
+extern  void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);
+extern  void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask);
+extern  void ( APIENTRY * qglPopAttrib )(void);
+extern  void ( APIENTRY * qglPopClientAttrib )(void);
+extern  void ( APIENTRY * qglPopMatrix )(void);
+extern  void ( APIENTRY * qglPopName )(void);
+extern  void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+extern  void ( APIENTRY * qglPushAttrib )(GLbitfield mask);
+extern  void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask);
+extern  void ( APIENTRY * qglPushMatrix )(void);
+extern  void ( APIENTRY * qglPushName )(GLuint name);
+extern  void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y);
+extern  void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y);
+extern  void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y);
+extern  void ( APIENTRY * qglRasterPos2iv )(const GLint *v);
+extern  void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y);
+extern  void ( APIENTRY * qglRasterPos2sv )(const GLshort *v);
+extern  void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+extern  void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+extern  void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z);
+extern  void ( APIENTRY * qglRasterPos3iv )(const GLint *v);
+extern  void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z);
+extern  void ( APIENTRY * qglRasterPos3sv )(const GLshort *v);
+extern  void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+extern  void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+extern  void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+extern  void ( APIENTRY * qglRasterPos4iv )(const GLint *v);
+extern  void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+extern  void ( APIENTRY * qglRasterPos4sv )(const GLshort *v);
+extern  void ( APIENTRY * qglReadBuffer )(GLenum mode);
+extern  void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+extern  void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+extern  void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2);
+extern  void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+extern  void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2);
+extern  void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+extern  void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2);
+extern  void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+extern  void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2);
+extern  GLint ( APIENTRY * qglRenderMode )(GLenum mode);
+extern  void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+extern  void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+extern  void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z);
+extern  void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z);
+extern  void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+extern  void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer);
+extern  void ( APIENTRY * qglShadeModel )(GLenum mode);
+extern  void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);
+extern  void ( APIENTRY * qglStencilMask )(GLuint mask);
+extern  void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+extern  void ( APIENTRY * qglTexCoord1d )(GLdouble s);
+extern  void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglTexCoord1f )(GLfloat s);
+extern  void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglTexCoord1i )(GLint s);
+extern  void ( APIENTRY * qglTexCoord1iv )(const GLint *v);
+extern  void ( APIENTRY * qglTexCoord1s )(GLshort s);
+extern  void ( APIENTRY * qglTexCoord1sv )(const GLshort *v);
+extern  void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t);
+extern  void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);
+extern  void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t);
+extern  void ( APIENTRY * qglTexCoord2iv )(const GLint *v);
+extern  void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t);
+extern  void ( APIENTRY * qglTexCoord2sv )(const GLshort *v);
+extern  void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+extern  void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+extern  void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r);
+extern  void ( APIENTRY * qglTexCoord3iv )(const GLint *v);
+extern  void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r);
+extern  void ( APIENTRY * qglTexCoord3sv )(const GLshort *v);
+extern  void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+extern  void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+extern  void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+extern  void ( APIENTRY * qglTexCoord4iv )(const GLint *v);
+extern  void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+extern  void ( APIENTRY * qglTexCoord4sv )(const GLshort *v);
+extern  void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+extern  void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param);
+extern  void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param);
+extern  void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+extern  void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param);
+extern  void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+extern  void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+extern  void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+extern  void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+extern  void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param);
+extern  void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+extern  void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+extern  void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+extern  void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z);
+extern  void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+extern  void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y);
+extern  void ( APIENTRY * qglVertex2dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);
+extern  void ( APIENTRY * qglVertex2fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglVertex2i )(GLint x, GLint y);
+extern  void ( APIENTRY * qglVertex2iv )(const GLint *v);
+extern  void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y);
+extern  void ( APIENTRY * qglVertex2sv )(const GLshort *v);
+extern  void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+extern  void ( APIENTRY * qglVertex3dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+extern  void ( APIENTRY * qglVertex3fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z);
+extern  void ( APIENTRY * qglVertex3iv )(const GLint *v);
+extern  void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z);
+extern  void ( APIENTRY * qglVertex3sv )(const GLshort *v);
+extern  void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+extern  void ( APIENTRY * qglVertex4dv )(const GLdouble *v);
+extern  void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+extern  void ( APIENTRY * qglVertex4fv )(const GLfloat *v);
+extern  void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w);
+extern  void ( APIENTRY * qglVertex4iv )(const GLint *v);
+extern  void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+extern  void ( APIENTRY * qglVertex4sv )(const GLshort *v);
+extern  void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+extern  void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+extern	void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value );
+extern	void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value );
+extern	void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * );
+
+extern	void ( APIENTRY * qglLockArraysEXT) (int , int);
+extern	void ( APIENTRY * qglUnlockArraysEXT) (void);
+
+extern	void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat );
+extern	void ( APIENTRY * qglSelectTextureSGIS)( GLenum );
+
+#ifdef _WIN32
+
+extern  int   ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *);
+extern  int   ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR);
+extern  int   ( WINAPI * qwglGetPixelFormat)(HDC);
+extern  BOOL  ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *);
+extern  BOOL  ( WINAPI * qwglSwapBuffers)(HDC);
+
+extern BOOL  ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT);
+extern HGLRC ( WINAPI * qwglCreateContext)(HDC);
+extern HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int);
+extern BOOL  ( WINAPI * qwglDeleteContext)(HGLRC);
+extern HGLRC ( WINAPI * qwglGetCurrentContext)(VOID);
+extern HDC   ( WINAPI * qwglGetCurrentDC)(VOID);
+extern PROC  ( WINAPI * qwglGetProcAddress)(LPCSTR);
+extern BOOL  ( WINAPI * qwglMakeCurrent)(HDC, HGLRC);
+extern BOOL  ( WINAPI * qwglShareLists)(HGLRC, HGLRC);
+extern BOOL  ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD);
+
+extern BOOL  ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT,
+                                           FLOAT, int, LPGLYPHMETRICSFLOAT);
+
+extern BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT,
+                                            LPLAYERPLANEDESCRIPTOR);
+extern int  ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int,
+                                                CONST COLORREF *);
+extern int  ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int,
+                                                COLORREF *);
+extern BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL);
+extern BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT);
+
+extern BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval );
+
+extern BOOL ( WINAPI * qwglGetDeviceGammaRampEXT ) ( unsigned char *pRed, unsigned char *pGreen, unsigned char *pBlue );
+extern BOOL ( WINAPI * qwglSetDeviceGammaRampEXT ) ( const unsigned char *pRed, const unsigned char *pGreen, const unsigned char *pBlue );
+
+#endif
+
+/*
+** extension constants
+*/
+#define GL_POINT_SIZE_MIN_EXT				0x8126
+#define GL_POINT_SIZE_MAX_EXT				0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT	0x8128
+#define GL_DISTANCE_ATTENUATION_EXT			0x8129
+
+#ifdef __sgi
+#define GL_SHARED_TEXTURE_PALETTE_EXT		GL_TEXTURE_COLOR_TABLE_SGI
+#else
+#define GL_SHARED_TEXTURE_PALETTE_EXT		0x81FB
+#endif
+
+#define GL_TEXTURE0_SGIS					0x835E
+#define GL_TEXTURE1_SGIS					0x835F
+
+#endif
--- /dev/null
+++ b/ref_gl/ref_gl.001
@@ -1,0 +1,752 @@
+# Microsoft Developer Studio Project File - Name="ref_gl" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=ref_gl - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_gl.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_gl.mak" CFG="ref_gl - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ref_gl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Debug Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Release Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\ref_gl__"
+# PROP BASE Intermediate_Dir ".\ref_gl__"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386
+# SUBTRACT LINK32 /incremental:yes /debug
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\ref_gl__"
+# PROP BASE Intermediate_Dir ".\ref_gl__"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386
+# SUBTRACT LINK32 /profile
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug Alpha"
+# PROP BASE Intermediate_Dir "Debug Alpha"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA
+# ADD LINK32 opengl32.lib kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ref_gl__"
+# PROP BASE Intermediate_Dir "ref_gl__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Z<none> /Fr
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# SUBTRACT BASE LINK32 /debug
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# SUBTRACT LINK32 /debug
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ref_gl - Win32 Release"
+# Name "ref_gl - Win32 Debug"
+# Name "ref_gl - Win32 Debug Alpha"
+# Name "ref_gl - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\gl_draw.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_DR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_DR=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_DR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_image.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_IM=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_light.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_LI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_LI=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_LI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_mesh.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_ME=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\anormtab.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_ME=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_ME=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\anormtab.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_model.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_MO=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_MO=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_MO=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_rmain.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_RM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RM=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_RM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_rmisc.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_RMI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RMI=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_RMI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_rsurf.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_RS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RS=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_RS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_warp.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_WA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	".\warpsin.h"\
+	
+NODEP_CPP_GL_WA=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_WA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	".\warpsin.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\glw_imp.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GLW_I=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	"..\win32\winquake.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GLW_I=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GLW_I=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	"..\win32\winquake.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\game\q_shared.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\q_shwin.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\qgl_win.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_QGL_W=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_QGL_W=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_QGL_W=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	{$(INCLUDE)}"GL\gl.h"\
+	{$(INCLUDE)}"GL\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\anorms.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\anormtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_model.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\glw_win.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\game\q_shared.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qcommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qgl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qmenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\ref.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ref_gl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\warpsin.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\winquake.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\ref_gl.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/ref_gl/ref_gl.def
@@ -1,0 +1,2 @@
+EXPORTS
+	GetRefAPI
--- /dev/null
+++ b/ref_gl/ref_gl.dsp
@@ -1,0 +1,773 @@
+# Microsoft Developer Studio Project File - Name="ref_gl" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=ref_gl - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_gl.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_gl.mak" CFG="ref_gl - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ref_gl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Debug Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "ref_gl - Win32 Release Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\ref_gl__"
+# PROP BASE Intermediate_Dir ".\ref_gl__"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386
+# SUBTRACT LINK32 /incremental:yes /debug
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\ref_gl__"
+# PROP BASE Intermediate_Dir ".\ref_gl__"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386
+# SUBTRACT LINK32 /profile
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug Alpha"
+# PROP BASE Intermediate_Dir "Debug Alpha"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA
+# ADD LINK32 opengl32.lib kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ref_gl__"
+# PROP BASE Intermediate_Dir "ref_gl__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Z<none> /Fr
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# SUBTRACT BASE LINK32 /debug
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# SUBTRACT LINK32 /debug
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ref_gl - Win32 Release"
+# Name "ref_gl - Win32 Debug"
+# Name "ref_gl - Win32 Debug Alpha"
+# Name "ref_gl - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\gl_draw.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_DR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_DR=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_DR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_DR=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_image.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_IM=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_IM=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_light.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_LI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_LI=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_LI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_LI=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_mesh.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_ME=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\anormtab.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_ME=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_ME=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\anormtab.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_ME=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_model.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_MO=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_MO=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_MO=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_MO=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_rmain.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_RM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RM=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_RM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RM=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_rmisc.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_RMI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RMI=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_RMI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RMI=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_rsurf.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_RS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RS=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_RS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GL_RS=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_warp.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GL_WA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	".\warpsin.h"\
+	
+NODEP_CPP_GL_WA=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GL_WA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	".\warpsin.h"\
+	
+NODEP_CPP_GL_WA=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\glw_imp.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_GLW_I=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	"..\win32\winquake.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GLW_I=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_GLW_I=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	"..\win32\winquake.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_GLW_I=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\game\q_shared.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\q_shwin.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\qgl_win.c
+
+!IF  "$(CFG)" == "ref_gl - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Debug Alpha"
+
+DEP_CPP_QGL_W=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_QGL_W=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_gl - Win32 Release Alpha"
+
+DEP_CPP_QGL_W=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\glw_win.h"\
+	".\gl_local.h"\
+	".\gl_model.h"\
+	".\qgl.h"\
+	
+NODEP_CPP_QGL_W=\
+	".\L\gl.h"\
+	".\L\glu.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\anorms.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\anormtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\gl_model.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\glw_win.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\game\q_shared.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qcommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qgl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qmenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\ref.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ref_gl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\warpsin.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\winquake.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\ref_gl.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/ref_gl/ref_gl.plg
@@ -1,0 +1,17 @@
+--------------------Configuration: ref_gl - Win32 Release Alpha--------------------
+Begining build with project "G:\quake2\code\ref_gl\ref_gl.dsp", at root.
+Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library)
+
+Project's tools are:
+			"OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
+			"C/C++ Compiler for Alpha" with flags "/nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/ref_gl.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /FD /QAieee1 /c "
+			"Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" "
+			"Browser Database Maker" with flags "/nologo /o"..\ReleaseAXP/ref_gl.bsc" "
+			"COFF Linker for Alpha" with flags "kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/ref_gl.pdb" /debug /machine:ALPHA /def:".\ref_gl.def" /out:"..\ReleaseAXP/ref_gl.dll" /implib:"..\ReleaseAXP/ref_gl.lib" "
+			"Custom Build" with flags ""
+			"<Component 0xa>" with flags ""
+
+
+
+
+ref_gl.dll - 0 error(s), 0 warning(s)
--- /dev/null
+++ b/ref_gl/warpsin.h
@@ -1,0 +1,51 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+ 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677,
+ 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916,
+ 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998,
+ 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632,
+ 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068,
+ 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368,
+ 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562,
+ 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759,
+ 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222,
+ 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394,
+ 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883,
+ 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398,
+ 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647,
+ 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193,
+ 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281,
+ 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633,
+ 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677,
+ -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916,
+ -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998,
+ -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632,
+ -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068,
+ -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368,
+ -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562,
+ -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759,
+ -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222,
+ -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394,
+ -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883,
+ -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398,
+ -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647,
+ -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193,
+ -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281,
+ -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633,
--- /dev/null
+++ b/ref_soft/adivtab.h
@@ -1,0 +1,1077 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// table of quotients and remainders for [-15...16] / [-15...16]
+
+// numerator = -15
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{1, -7},
+{2, -1},
+{2, -3},
+{3, 0},
+{3, -3},
+{5, 0},
+{7, -1},
+{15, 0},
+{0, 0},
+{-15, 0},
+{-8, 1},
+{-5, 0},
+{-4, 1},
+{-3, 0},
+{-3, 3},
+{-3, 6},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-2, 13},
+{-1, 0},
+{-1, 1},
+// numerator = -14
+{0, -14},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, 0},
+{2, -2},
+{2, -4},
+{3, -2},
+{4, -2},
+{7, 0},
+{14, 0},
+{0, 0},
+{-14, 0},
+{-7, 0},
+{-5, 1},
+{-4, 2},
+{-3, 1},
+{-3, 4},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-2, 12},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+// numerator = -13
+{0, -13},
+{0, -13},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, -1},
+{2, -3},
+{3, -1},
+{4, -1},
+{6, -1},
+{13, 0},
+{0, 0},
+{-13, 0},
+{-7, 1},
+{-5, 2},
+{-4, 3},
+{-3, 2},
+{-3, 5},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+// numerator = -12
+{0, -12},
+{0, -12},
+{0, -12},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, 0},
+{2, -2},
+{3, 0},
+{4, 0},
+{6, 0},
+{12, 0},
+{0, 0},
+{-12, 0},
+{-6, 0},
+{-4, 0},
+{-3, 0},
+{-3, 3},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+// numerator = -11
+{0, -11},
+{0, -11},
+{0, -11},
+{0, -11},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, -1},
+{2, -3},
+{3, -2},
+{5, -1},
+{11, 0},
+{0, 0},
+{-11, 0},
+{-6, 1},
+{-4, 1},
+{-3, 1},
+{-3, 4},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+// numerator = -10
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, 0},
+{2, -2},
+{3, -1},
+{5, 0},
+{10, 0},
+{0, 0},
+{-10, 0},
+{-5, 0},
+{-4, 2},
+{-3, 2},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+// numerator = -9
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, -1},
+{3, 0},
+{4, -1},
+{9, 0},
+{0, 0},
+{-9, 0},
+{-5, 1},
+{-3, 0},
+{-3, 3},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+// numerator = -8
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, 0},
+{2, -2},
+{4, 0},
+{8, 0},
+{0, 0},
+{-8, 0},
+{-4, 0},
+{-3, 1},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+// numerator = -7
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, -1},
+{3, -1},
+{7, 0},
+{0, 0},
+{-7, 0},
+{-4, 1},
+{-3, 2},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+// numerator = -6
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, 0},
+{3, 0},
+{6, 0},
+{0, 0},
+{-6, 0},
+{-3, 0},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+// numerator = -5
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, -1},
+{5, 0},
+{0, 0},
+{-5, 0},
+{-3, 1},
+{-2, 1},
+{-2, 3},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+// numerator = -4
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{1, 0},
+{1, -1},
+{2, 0},
+{4, 0},
+{0, 0},
+{-4, 0},
+{-2, 0},
+{-2, 2},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+// numerator = -3
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{1, 0},
+{1, -1},
+{3, 0},
+{0, 0},
+{-3, 0},
+{-2, 1},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+// numerator = -2
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{1, 0},
+{2, 0},
+{0, 0},
+{-2, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+// numerator = -1
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{1, 0},
+{0, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+{-1, 15},
+// numerator = 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},
+{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},
+// numerator = 1
+{-1, -14},
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{0, 0},
+{1, 0},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+// numerator = 2
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, 0},
+{0, 0},
+{2, 0},
+{1, 0},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+// numerator = 3
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -1},
+{-3, 0},
+{0, 0},
+{3, 0},
+{1, 1},
+{1, 0},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+// numerator = 4
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -2},
+{-2, 0},
+{-4, 0},
+{0, 0},
+{4, 0},
+{2, 0},
+{1, 1},
+{1, 0},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+// numerator = 5
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -3},
+{-2, -1},
+{-3, -1},
+{-5, 0},
+{0, 0},
+{5, 0},
+{2, 1},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+// numerator = 6
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, 0},
+{-6, 0},
+{0, 0},
+{6, 0},
+{3, 0},
+{2, 0},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+// numerator = 7
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -2},
+{-4, -1},
+{-7, 0},
+{0, 0},
+{7, 0},
+{3, 1},
+{2, 1},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+// numerator = 8
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -1},
+{-4, 0},
+{-8, 0},
+{0, 0},
+{8, 0},
+{4, 0},
+{2, 2},
+{2, 0},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+// numerator = 9
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -3},
+{-3, 0},
+{-5, -1},
+{-9, 0},
+{0, 0},
+{9, 0},
+{4, 1},
+{3, 0},
+{2, 1},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+// numerator = 10
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -2},
+{-4, -2},
+{-5, 0},
+{-10, 0},
+{0, 0},
+{10, 0},
+{5, 0},
+{3, 1},
+{2, 2},
+{2, 0},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+// numerator = 11
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -4},
+{-3, -1},
+{-4, -1},
+{-6, -1},
+{-11, 0},
+{0, 0},
+{11, 0},
+{5, 1},
+{3, 2},
+{2, 3},
+{2, 1},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+// numerator = 12
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -3},
+{-3, 0},
+{-4, 0},
+{-6, 0},
+{-12, 0},
+{0, 0},
+{12, 0},
+{6, 0},
+{4, 0},
+{3, 0},
+{2, 2},
+{2, 0},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 12},
+{0, 12},
+{0, 12},
+{0, 12},
+// numerator = 13
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -5},
+{-3, -2},
+{-4, -3},
+{-5, -2},
+{-7, -1},
+{-13, 0},
+{0, 0},
+{13, 0},
+{6, 1},
+{4, 1},
+{3, 1},
+{2, 3},
+{2, 1},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 13},
+{0, 13},
+{0, 13},
+// numerator = 14
+{-1, -1},
+{-1, 0},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -4},
+{-3, -1},
+{-4, -2},
+{-5, -1},
+{-7, 0},
+{-14, 0},
+{0, 0},
+{14, 0},
+{7, 0},
+{4, 2},
+{3, 2},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 14},
+{0, 14},
+// numerator = 15
+{-1, 0},
+{-2, -13},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -6},
+{-3, -3},
+{-3, 0},
+{-4, -1},
+{-5, 0},
+{-8, -1},
+{-15, 0},
+{0, 0},
+{15, 0},
+{7, 1},
+{5, 0},
+{3, 3},
+{3, 0},
+{2, 3},
+{2, 1},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 15},
+// numerator = 16
+{-2, -14},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -5},
+{-3, -2},
+{-4, -4},
+{-4, 0},
+{-6, -2},
+{-8, 0},
+{-16, 0},
+{0, 0},
+{16, 0},
+{8, 0},
+{5, 1},
+{4, 0},
+{3, 1},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
--- /dev/null
+++ b/ref_soft/anorms.h
@@ -1,0 +1,181 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+{-0.525731, 0.000000, 0.850651}, 
+{-0.442863, 0.238856, 0.864188}, 
+{-0.295242, 0.000000, 0.955423}, 
+{-0.309017, 0.500000, 0.809017}, 
+{-0.162460, 0.262866, 0.951056}, 
+{0.000000, 0.000000, 1.000000}, 
+{0.000000, 0.850651, 0.525731}, 
+{-0.147621, 0.716567, 0.681718}, 
+{0.147621, 0.716567, 0.681718}, 
+{0.000000, 0.525731, 0.850651}, 
+{0.309017, 0.500000, 0.809017}, 
+{0.525731, 0.000000, 0.850651}, 
+{0.295242, 0.000000, 0.955423}, 
+{0.442863, 0.238856, 0.864188}, 
+{0.162460, 0.262866, 0.951056}, 
+{-0.681718, 0.147621, 0.716567}, 
+{-0.809017, 0.309017, 0.500000}, 
+{-0.587785, 0.425325, 0.688191}, 
+{-0.850651, 0.525731, 0.000000}, 
+{-0.864188, 0.442863, 0.238856}, 
+{-0.716567, 0.681718, 0.147621}, 
+{-0.688191, 0.587785, 0.425325}, 
+{-0.500000, 0.809017, 0.309017}, 
+{-0.238856, 0.864188, 0.442863}, 
+{-0.425325, 0.688191, 0.587785}, 
+{-0.716567, 0.681718, -0.147621}, 
+{-0.500000, 0.809017, -0.309017}, 
+{-0.525731, 0.850651, 0.000000}, 
+{0.000000, 0.850651, -0.525731}, 
+{-0.238856, 0.864188, -0.442863}, 
+{0.000000, 0.955423, -0.295242}, 
+{-0.262866, 0.951056, -0.162460}, 
+{0.000000, 1.000000, 0.000000}, 
+{0.000000, 0.955423, 0.295242}, 
+{-0.262866, 0.951056, 0.162460}, 
+{0.238856, 0.864188, 0.442863}, 
+{0.262866, 0.951056, 0.162460}, 
+{0.500000, 0.809017, 0.309017}, 
+{0.238856, 0.864188, -0.442863}, 
+{0.262866, 0.951056, -0.162460}, 
+{0.500000, 0.809017, -0.309017}, 
+{0.850651, 0.525731, 0.000000}, 
+{0.716567, 0.681718, 0.147621}, 
+{0.716567, 0.681718, -0.147621}, 
+{0.525731, 0.850651, 0.000000}, 
+{0.425325, 0.688191, 0.587785}, 
+{0.864188, 0.442863, 0.238856}, 
+{0.688191, 0.587785, 0.425325}, 
+{0.809017, 0.309017, 0.500000}, 
+{0.681718, 0.147621, 0.716567}, 
+{0.587785, 0.425325, 0.688191}, 
+{0.955423, 0.295242, 0.000000}, 
+{1.000000, 0.000000, 0.000000}, 
+{0.951056, 0.162460, 0.262866}, 
+{0.850651, -0.525731, 0.000000}, 
+{0.955423, -0.295242, 0.000000}, 
+{0.864188, -0.442863, 0.238856}, 
+{0.951056, -0.162460, 0.262866}, 
+{0.809017, -0.309017, 0.500000}, 
+{0.681718, -0.147621, 0.716567}, 
+{0.850651, 0.000000, 0.525731}, 
+{0.864188, 0.442863, -0.238856}, 
+{0.809017, 0.309017, -0.500000}, 
+{0.951056, 0.162460, -0.262866}, 
+{0.525731, 0.000000, -0.850651}, 
+{0.681718, 0.147621, -0.716567}, 
+{0.681718, -0.147621, -0.716567}, 
+{0.850651, 0.000000, -0.525731}, 
+{0.809017, -0.309017, -0.500000}, 
+{0.864188, -0.442863, -0.238856}, 
+{0.951056, -0.162460, -0.262866}, 
+{0.147621, 0.716567, -0.681718}, 
+{0.309017, 0.500000, -0.809017}, 
+{0.425325, 0.688191, -0.587785}, 
+{0.442863, 0.238856, -0.864188}, 
+{0.587785, 0.425325, -0.688191}, 
+{0.688191, 0.587785, -0.425325}, 
+{-0.147621, 0.716567, -0.681718}, 
+{-0.309017, 0.500000, -0.809017}, 
+{0.000000, 0.525731, -0.850651}, 
+{-0.525731, 0.000000, -0.850651}, 
+{-0.442863, 0.238856, -0.864188}, 
+{-0.295242, 0.000000, -0.955423}, 
+{-0.162460, 0.262866, -0.951056}, 
+{0.000000, 0.000000, -1.000000}, 
+{0.295242, 0.000000, -0.955423}, 
+{0.162460, 0.262866, -0.951056}, 
+{-0.442863, -0.238856, -0.864188}, 
+{-0.309017, -0.500000, -0.809017}, 
+{-0.162460, -0.262866, -0.951056}, 
+{0.000000, -0.850651, -0.525731}, 
+{-0.147621, -0.716567, -0.681718}, 
+{0.147621, -0.716567, -0.681718}, 
+{0.000000, -0.525731, -0.850651}, 
+{0.309017, -0.500000, -0.809017}, 
+{0.442863, -0.238856, -0.864188}, 
+{0.162460, -0.262866, -0.951056}, 
+{0.238856, -0.864188, -0.442863}, 
+{0.500000, -0.809017, -0.309017}, 
+{0.425325, -0.688191, -0.587785}, 
+{0.716567, -0.681718, -0.147621}, 
+{0.688191, -0.587785, -0.425325}, 
+{0.587785, -0.425325, -0.688191}, 
+{0.000000, -0.955423, -0.295242}, 
+{0.000000, -1.000000, 0.000000}, 
+{0.262866, -0.951056, -0.162460}, 
+{0.000000, -0.850651, 0.525731}, 
+{0.000000, -0.955423, 0.295242}, 
+{0.238856, -0.864188, 0.442863}, 
+{0.262866, -0.951056, 0.162460}, 
+{0.500000, -0.809017, 0.309017}, 
+{0.716567, -0.681718, 0.147621}, 
+{0.525731, -0.850651, 0.000000}, 
+{-0.238856, -0.864188, -0.442863}, 
+{-0.500000, -0.809017, -0.309017}, 
+{-0.262866, -0.951056, -0.162460}, 
+{-0.850651, -0.525731, 0.000000}, 
+{-0.716567, -0.681718, -0.147621}, 
+{-0.716567, -0.681718, 0.147621}, 
+{-0.525731, -0.850651, 0.000000}, 
+{-0.500000, -0.809017, 0.309017}, 
+{-0.238856, -0.864188, 0.442863}, 
+{-0.262866, -0.951056, 0.162460}, 
+{-0.864188, -0.442863, 0.238856}, 
+{-0.809017, -0.309017, 0.500000}, 
+{-0.688191, -0.587785, 0.425325}, 
+{-0.681718, -0.147621, 0.716567}, 
+{-0.442863, -0.238856, 0.864188}, 
+{-0.587785, -0.425325, 0.688191}, 
+{-0.309017, -0.500000, 0.809017}, 
+{-0.147621, -0.716567, 0.681718}, 
+{-0.425325, -0.688191, 0.587785}, 
+{-0.162460, -0.262866, 0.951056}, 
+{0.442863, -0.238856, 0.864188}, 
+{0.162460, -0.262866, 0.951056}, 
+{0.309017, -0.500000, 0.809017}, 
+{0.147621, -0.716567, 0.681718}, 
+{0.000000, -0.525731, 0.850651}, 
+{0.425325, -0.688191, 0.587785}, 
+{0.587785, -0.425325, 0.688191}, 
+{0.688191, -0.587785, 0.425325}, 
+{-0.955423, 0.295242, 0.000000}, 
+{-0.951056, 0.162460, 0.262866}, 
+{-1.000000, 0.000000, 0.000000}, 
+{-0.850651, 0.000000, 0.525731}, 
+{-0.955423, -0.295242, 0.000000}, 
+{-0.951056, -0.162460, 0.262866}, 
+{-0.864188, 0.442863, -0.238856}, 
+{-0.951056, 0.162460, -0.262866}, 
+{-0.809017, 0.309017, -0.500000}, 
+{-0.864188, -0.442863, -0.238856}, 
+{-0.951056, -0.162460, -0.262866}, 
+{-0.809017, -0.309017, -0.500000}, 
+{-0.681718, 0.147621, -0.716567}, 
+{-0.681718, -0.147621, -0.716567}, 
+{-0.850651, 0.000000, -0.525731}, 
+{-0.688191, 0.587785, -0.425325}, 
+{-0.587785, 0.425325, -0.688191}, 
+{-0.425325, 0.688191, -0.587785}, 
+{-0.425325, -0.688191, -0.587785}, 
+{-0.587785, -0.425325, -0.688191}, 
+{-0.688191, -0.587785, -0.425325}, 
--- /dev/null
+++ b/ref_soft/asm_draw.h
@@ -1,0 +1,121 @@
+//
+// asm_draw.h
+//
+// Include file for asm drawing routines.
+//
+
+//
+// !!! note that this file must match the corresponding C structures at all
+// times !!!
+//
+
+// !!! if this is changed, it must be changed in r_local.h too !!!
+#define	NEAR_CLIP	0.01
+
+// !!! if this is changed, it must be changed in r_local.h too !!!
+#define	CYCLE	128
+
+// espan_t structure
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define espan_t_u    	0
+#define espan_t_v	    4
+#define espan_t_count   8
+#define espan_t_pnext	12
+#define espan_t_size    16
+
+// sspan_t structure
+// !!! if this is changed, it must be changed in d_local.h too !!!
+#define sspan_t_u    	0
+#define sspan_t_v	    4
+#define sspan_t_count   8
+#define sspan_t_pnext	12
+#define sspan_t_size    16
+
+// edge_t structure
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define et_u			0
+#define et_u_step		4
+#define et_prev			8
+#define et_next			12
+#define et_surfs		16
+#define et_nextremove	20
+#define et_nearzi		24
+#define et_owner		28
+#define et_size			32
+
+// surf_t structure
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define SURF_T_SHIFT	6
+#define st_next			0
+#define st_prev			4
+#define st_spans		8
+#define st_key			12
+#define st_last_u		16
+#define st_spanstate	20
+#define st_flags		24
+#define st_data			28
+#define st_entity		32
+#define st_nearzi		36
+#define st_insubmodel	40
+#define st_d_ziorigin	44
+#define st_d_zistepu	48
+#define st_d_zistepv	52
+#define st_pad			56
+#define st_size			64
+
+// clipplane_t structure
+// !!! if this is changed, it must be changed in r_local.h too !!!
+#define cp_normal		0
+#define cp_dist			12
+#define cp_next			16
+#define cp_leftedge		20
+#define cp_rightedge	21
+#define cp_reserved		22
+#define cp_size			24
+
+// medge_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define me_v				0
+#define me_cachededgeoffset	4
+#define me_size				8
+
+// mvertex_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define mv_position		0
+#define mv_size			12
+
+// refdef_t structure
+// !!! if this is changed, it must be changed in render.h too !!!
+#define rd_vrect					0
+#define rd_aliasvrect				20
+#define rd_vrectright				40
+#define rd_vrectbottom				44
+#define rd_aliasvrectright			48
+#define rd_aliasvrectbottom			52
+#define rd_vrectrightedge			56
+#define rd_fvrectx					60
+#define rd_fvrecty					64
+#define rd_fvrectx_adj				68
+#define rd_fvrecty_adj				72
+#define rd_vrect_x_adj_shift20		76
+#define rd_vrectright_adj_shift20	80
+#define rd_fvrectright_adj			84
+#define rd_fvrectbottom_adj			88
+#define rd_fvrectright				92
+#define rd_fvrectbottom				96
+#define rd_horizontalFieldOfView	100
+#define rd_xOrigin					104
+#define rd_yOrigin					108
+#define rd_vieworg					112
+#define rd_viewangles				124
+#define rd_ambientlight				136
+#define rd_size						140
+
+// mtriangle_t structure
+// !!! if this is changed, it must be changed in model.h too !!!
+#define mtri_facesfront		0
+#define mtri_vertindex		4
+#define mtri_size			16	// !!! if this changes, array indexing in !!!
+								// !!! d_polysa.s must be changed to match !!!
+#define mtri_shift			4
+
--- /dev/null
+++ b/ref_soft/block16.inc
@@ -1,0 +1,116 @@
+LEnter16_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch0:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch1:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch2:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch3:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch4:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch5:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch6:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch7:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+LEnter8_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch8:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch9:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch10:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch11:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+LEnter4_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch12:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch13:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+LEnter2_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch14:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch15:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
--- /dev/null
+++ b/ref_soft/block8.inc
@@ -1,0 +1,116 @@
+LEnter16_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch0:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch1:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch2:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch3:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch4:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch5:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch6:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch7:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+LEnter8_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch8:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch9:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch10:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch11:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+LEnter4_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch12:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch13:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
+LEnter2_16:
+ mov al,ds:byte ptr[esi]
+ mov cl,ds:byte ptr[esi+ebx]
+ mov ah,dh
+ add edx,ebp
+ mov ch,dh
+ lea esi,ds:dword ptr[esi+ebx*2]
+ mov ax,ds:word ptr[12345678h+eax*2]
+LBPatch14:
+ add edx,ebp
+ mov ds:word ptr[edi],ax
+ mov cx,ds:word ptr[12345678h+ecx*2]
+LBPatch15:
+ mov ds:word ptr[2+edi],cx
+ add edi,04h
--- /dev/null
+++ b/ref_soft/d_if.inc
@@ -1,0 +1,81 @@
+;
+; d_ifacea.h
+;
+; Include file for asm driver interface.
+;
+
+;
+; !!! note that this file must match the corresponding C structures in
+; d_iface.h at all times !!!
+;
+
+; !!! if this is changed, it must be changed in r_shared.h too !!!
+ALIAS_ONSEAM				equ		00020h
+
+; !!! if this is changed, it must be changed in d_iface.h too !!!
+TURB_TEX_SIZE	equ		64
+
+; !!! if this is changed, it must be changed in d_iface.h too !!!
+CYCLE	equ		128
+
+; !!! if this is changed, it must be changed in r_shared.h too !!!
+MAXHEIGHT	equ		1024
+
+; !!! if this is changed, it must be changed in quakedef.h too !!!
+CACHE_SIZE	equ		32
+
+; particle_t structure
+; !!! if this is changed, it must be changed in d_iface.h too !!!
+; driver-usable fields
+pt_org				equ		0
+pt_color			equ		12
+; drivers never touch the following fields
+pt_next				equ		16
+pt_vel				equ		20
+pt_ramp				equ		32
+pt_die				equ		36
+pt_type				equ		40
+pt_size				equ		44
+
+PARTICLE_Z_CLIP	equ		8.0
+
+; finalvert_t structure
+; !!! if this is changed, it must be changed in d_iface.h too !!!
+fv_v				equ		0	; !!! if this is moved, cases where the !!!
+								; !!! address of this field is pushed in !!!
+								; !!! d_polysa.s must be changed !!!
+fv_flags			equ		24
+fv_reserved			equ		28
+fv_size				equ		32
+fv_shift			equ		5
+
+
+; stvert_t structure
+; !!! if this is changed, it must be changed in modelgen.h too !!!
+stv_onseam	equ		0
+stv_s		equ		4
+stv_t		equ		8
+stv_size	equ		12
+
+
+; trivertx_t structure
+; !!! if this is changed, it must be changed in modelgen.h too !!!
+tv_v				equ		0
+tv_lightnormalindex	equ		3
+tv_size				equ		4
+
+; affinetridesc_t structure
+; !!! if this is changed, it must be changed in d_iface.h too !!!
+atd_pskin			equ		0
+atd_pskindesc		equ		4
+atd_skinwidth		equ		8
+atd_skinheight		equ		12
+atd_ptriangles		equ		16
+atd_pfinalverts		equ		20
+atd_numtriangles	equ		24
+atd_drawtype		equ		28
+atd_seamfixupX16	equ		32
+atd_do_vis_thresh	equ		36
+atd_vis_thresh		equ		40
+atd_size			equ		44
+
--- /dev/null
+++ b/ref_soft/d_ifacea.h
@@ -1,0 +1,76 @@
+//
+// d_ifacea.h
+//
+// Include file for asm driver interface.
+//
+
+//
+// !!! note that this file must match the corresponding C structures in
+// d_iface.h at all times !!!
+//
+
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define TURB_TEX_SIZE	64		// base turbulent texture size
+
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define	CYCLE	128
+
+// !!! if this is changed, it must be changed in r_shared.h too !!!
+#define	MAXHEIGHT	1200
+
+// !!! if this is changed, it must be changed in qcommon.h too !!!
+#define CACHE_SIZE	32		// used to align key data structures
+
+// particle_t structure
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+// driver-usable fields
+#define pt_org				0
+#define pt_color			12
+// drivers never touch the following fields
+#define pt_next				16
+#define pt_vel				20
+#define pt_ramp				32
+#define pt_die				36
+#define pt_type				40
+#define pt_size				44
+
+#define PARTICLE_Z_CLIP	8.0
+
+// finalvert_t structure
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define fv_v				0	// !!! if this is moved, cases where the !!!
+								// !!! address of this field is pushed in !!!
+								// !!! d_polysa.s must be changed !!!
+#define fv_flags			24
+#define fv_reserved			28
+#define fv_size				32
+#define fv_shift			5
+
+
+// stvert_t structure
+// !!! if this is changed, it must be changed in modelgen.h too !!!
+#define stv_onseam	0
+#define stv_s		4
+#define stv_t		8
+#define stv_size	12
+
+
+// trivertx_t structure
+// !!! if this is changed, it must be changed in modelgen.h too !!!
+#define tv_v				0
+#define tv_lightnormalindex	3
+#define tv_size				4
+
+// affinetridesc_t structure
+// !!! if this is changed, it must be changed in d_iface.h too !!!
+#define atd_pskin			0
+#define atd_pskindesc		4
+#define atd_skinwidth		8
+#define atd_skinheight		12
+#define atd_ptriangles		16
+#define atd_pfinalverts		20
+#define atd_numtriangles	24
+#define atd_drawtype		28
+#define atd_seamfixupX16	32
+#define atd_size			36
+
--- /dev/null
+++ b/ref_soft/qasm.inc
@@ -1,0 +1,435 @@
+;
+; qasm.inc
+;
+; Include file for asm routines.
+;
+
+;
+; !!! note that this file must match the corresponding C structures at all
+; times !!!
+;
+
+; set to 0 to skip all asm code
+id386	equ		1
+
+; !!! must be kept the same as in d_iface.h !!!
+TRANSPARENT_COLOR	equ		255
+
+ifndef GLQUAKE
+	externdef _d_zistepu:dword
+	externdef _d_pzbuffer:dword
+	externdef _d_zistepv:dword
+	externdef _d_zrowbytes:dword
+	externdef _d_ziorigin:dword
+	externdef _r_turb_s:dword
+	externdef _r_turb_t:dword
+	externdef _r_turb_pdest:dword
+	externdef _r_turb_spancount:dword
+	externdef _r_turb_turb:dword
+	externdef _r_turb_pbase:dword
+	externdef _r_turb_sstep:dword
+	externdef _r_turb_tstep:dword
+	externdef	_r_bmodelactive:dword
+	externdef	_d_sdivzstepu:dword
+	externdef	_d_tdivzstepu:dword
+	externdef	_d_sdivzstepv:dword
+	externdef	_d_tdivzstepv:dword
+	externdef	_d_sdivzorigin:dword
+	externdef	_d_tdivzorigin:dword
+	externdef	_sadjust:dword
+	externdef	_tadjust:dword
+	externdef	_bbextents:dword
+	externdef	_bbextentt:dword
+	externdef	_cacheblock:dword
+	externdef	_d_viewbuffer:dword
+	externdef	_cachewidth:dword
+	externdef	_d_pzbuffer:dword
+	externdef	_d_zrowbytes:dword
+	externdef	_d_zwidth:dword
+	externdef _d_scantable:dword
+	externdef _r_lightptr:dword
+	externdef _r_numvblocks:dword
+	externdef _prowdestbase:dword
+	externdef _pbasesource:dword
+	externdef _r_lightwidth:dword
+	externdef _lightright:dword
+	externdef _lightrightstep:dword
+	externdef _lightdeltastep:dword
+	externdef _lightdelta:dword
+	externdef _lightright:dword
+	externdef _lightdelta:dword
+	externdef _sourcetstep:dword
+	externdef _surfrowbytes:dword
+	externdef _lightrightstep:dword
+	externdef _lightdeltastep:dword
+	externdef _r_sourcemax:dword
+	externdef _r_stepback:dword
+	externdef _colormap:dword
+	externdef _blocksize:dword
+	externdef _sourcesstep:dword
+	externdef _lightleft:dword
+	externdef _blockdivshift:dword
+	externdef _blockdivmask:dword
+	externdef _lightleftstep:dword
+	externdef _r_origin:dword
+	externdef _r_ppn:dword
+	externdef _r_pup:dword
+	externdef _r_pright:dword
+	externdef _ycenter:dword
+	externdef _xcenter:dword
+	externdef _d_vrectbottom_particle:dword
+	externdef _d_vrectright_particle:dword
+	externdef _d_vrecty:dword
+	externdef _d_vrectx:dword
+	externdef _d_pix_shift:dword
+	externdef _d_pix_min:dword
+	externdef _d_pix_max:dword
+	externdef _d_y_aspect_shift:dword
+	externdef _screenwidth:dword
+	externdef _r_leftclipped:dword
+	externdef _r_leftenter:dword
+	externdef _r_rightclipped:dword
+	externdef _r_rightenter:dword
+	externdef _modelorg:dword
+	externdef _xscale:dword
+	externdef _r_refdef:dword
+	externdef _yscale:dword
+	externdef _r_leftexit:dword
+	externdef _r_rightexit:dword
+	externdef _r_lastvertvalid:dword
+	externdef _cacheoffset:dword
+	externdef _newedges:dword
+	externdef _removeedges:dword
+	externdef _r_pedge:dword
+	externdef _r_framecount:dword
+	externdef _r_u1:dword
+	externdef _r_emitted:dword
+	externdef _edge_p:dword
+	externdef _surface_p:dword
+	externdef _surfaces:dword
+	externdef _r_lzi1:dword
+	externdef _r_v1:dword
+	externdef _r_ceilv1:dword
+	externdef _r_nearzi:dword
+	externdef _r_nearzionly:dword
+	externdef _edge_aftertail:dword
+	externdef _edge_tail:dword
+	externdef _current_iv:dword
+	externdef _edge_head_u_shift20:dword
+	externdef _span_p:dword
+	externdef _edge_head:dword
+	externdef _fv:dword
+	externdef _edge_tail_u_shift20:dword
+	externdef _r_apverts:dword
+	externdef _r_anumverts:dword
+	externdef _aliastransform:dword
+	externdef _r_avertexnormals:dword
+	externdef _r_plightvec:dword
+	externdef _r_ambientlight:dword
+	externdef _r_shadelight:dword
+	externdef _aliasxcenter:dword
+	externdef _aliasycenter:dword
+	externdef _a_sstepxfrac:dword
+	externdef _r_affinetridesc:dword
+	externdef _acolormap:dword
+	externdef _d_pcolormap:dword
+	externdef _r_affinetridesc:dword
+	externdef _d_sfrac:dword
+	externdef _d_ptex:dword
+	externdef _d_pedgespanpackage:dword
+	externdef _d_tfrac:dword
+	externdef _d_light:dword
+	externdef _d_zi:dword
+	externdef _d_pdest:dword
+	externdef _d_pz:dword
+	externdef _d_aspancount:dword
+	externdef _erroradjustup:dword
+	externdef _errorterm:dword
+	externdef _d_xdenom:dword
+	externdef _r_p0:dword
+	externdef _r_p1:dword
+	externdef _r_p2:dword
+	externdef _a_tstepxfrac:dword
+	externdef _r_sstepx:dword
+	externdef _r_tstepx:dword
+	externdef _a_ststepxwhole:dword
+	externdef _zspantable:dword
+	externdef _skintable:dword
+	externdef _r_zistepx:dword
+	externdef _erroradjustdown:dword
+	externdef _d_countextrastep:dword
+	externdef _ubasestep:dword
+	externdef _a_ststepxwhole:dword
+	externdef _a_tstepxfrac:dword
+	externdef _r_lstepx:dword
+	externdef _a_spans:dword
+	externdef _erroradjustdown:dword
+	externdef _d_pdestextrastep:dword
+	externdef _d_pzextrastep:dword
+	externdef _d_sfracextrastep:dword
+	externdef _d_ptexextrastep:dword
+	externdef _d_countextrastep:dword
+	externdef _d_tfracextrastep:dword
+	externdef _d_lightextrastep:dword
+	externdef _d_ziextrastep:dword
+	externdef _d_pdestbasestep:dword
+	externdef _d_pzbasestep:dword
+	externdef _d_sfracbasestep:dword
+	externdef _d_ptexbasestep:dword
+	externdef _ubasestep:dword
+	externdef _d_tfracbasestep:dword
+	externdef _d_lightbasestep:dword
+	externdef _d_zibasestep:dword
+	externdef _zspantable:dword
+	externdef _r_lstepy:dword
+	externdef _r_sstepy:dword
+	externdef _r_tstepy:dword
+	externdef _r_zistepy:dword
+	externdef _D_PolysetSetEdgeTable:dword
+	externdef _D_RasterizeAliasPolySmooth:dword
+
+	externdef float_point5:dword
+	externdef Float2ToThe31nd:dword
+	externdef izistep:dword
+	externdef izi:dword
+	externdef FloatMinus2ToThe31nd:dword
+	externdef float_1:dword
+	externdef float_particle_z_clip:dword
+	externdef float_minus_1:dword
+	externdef float_0:dword
+	externdef fp_16:dword
+	externdef fp_64k:dword
+	externdef fp_1m:dword
+	externdef fp_1m_minus_1:dword
+	externdef fp_8 :dword
+	externdef entryvec_table:dword
+	externdef advancetable:dword
+	externdef sstep:dword
+	externdef tstep:dword
+	externdef pspantemp:dword
+	externdef counttemp:dword
+	externdef jumptemp:dword
+	externdef reciprocal_table:dword
+	externdef DP_Count:dword
+	externdef DP_u:dword
+	externdef DP_v:dword
+	externdef DP_32768:dword
+	externdef DP_Color:dword
+	externdef DP_Pix:dword
+	externdef DP_EntryTable:dword
+	externdef	pbase:dword
+	externdef s:dword
+	externdef t:dword
+	externdef sfracf:dword
+	externdef tfracf:dword
+	externdef snext:dword
+	externdef tnext:dword
+	externdef	spancountminus1:dword
+	externdef zi16stepu:dword
+	externdef sdivz16stepu:dword
+	externdef tdivz16stepu:dword
+	externdef	zi8stepu:dword
+	externdef sdivz8stepu:dword
+	externdef tdivz8stepu:dword
+	externdef reciprocal_table_16:dword
+	externdef entryvec_table_16:dword
+	externdef fp_64kx64k:dword
+	externdef pz:dword
+	externdef spr8entryvec_table:dword
+endif
+
+	externdef _fpu_ceil_cw:dword
+	externdef _fpu_chop_cw:dword
+	externdef _snd_scaletable:dword
+	externdef _paintbuffer:dword
+	externdef _snd_linear_count:dword
+	externdef _snd_p:dword
+	externdef _snd_vol:dword
+	externdef _snd_out:dword
+	externdef _vright:dword
+	externdef _vup:dword
+	externdef _vpn:dword
+	externdef _BOPS_Error:dword
+
+; plane_t structure
+; !!! if this is changed, it must be changed in model.h too !!!
+; !!! if the size of this is changed, the array lookup in SV_HullPointContents
+;     must be changed too !!!
+pl_normal	equ		0
+pl_dist		equ		12
+pl_type		equ		16
+pl_signbits	equ		17
+pl_pad		equ		18
+pl_size		equ		20
+
+; hull_t structure
+; !!! if this is changed, it must be changed in model.h too !!!
+hu_clipnodes		equ		0
+hu_planes			equ		4
+hu_firstclipnode	equ		8
+hu_lastclipnode		equ		12
+hu_clip_mins		equ		16
+hu_clip_maxs		equ		28
+hu_size  			equ		40
+
+; dnode_t structure
+; !!! if this is changed, it must be changed in bspfile.h too !!!
+nd_planenum		equ		0
+nd_children		equ		4
+nd_mins			equ		8
+nd_maxs			equ		20
+nd_firstface	equ		32
+nd_numfaces		equ		36
+nd_size			equ		40
+
+; sfxcache_t structure
+; !!! if this is changed, it much be changed in sound.h too !!!
+sfxc_length		equ		0
+sfxc_loopstart	equ		4
+sfxc_speed		equ		8
+sfxc_width		equ		12
+sfxc_stereo		equ		16
+sfxc_data		equ		20
+
+; channel_t structure
+; !!! if this is changed, it much be changed in sound.h too !!!
+ch_sfx			equ		0
+ch_leftvol		equ		4
+ch_rightvol		equ		8
+ch_end			equ		12
+ch_pos			equ		16
+ch_looping		equ		20
+ch_entnum		equ		24
+ch_entchannel	equ		28
+ch_origin		equ		32
+ch_dist_mult	equ		44
+ch_master_vol	equ		48
+ch_size			equ		52
+
+; portable_samplepair_t structure
+; !!! if this is changed, it much be changed in sound.h too !!!
+psp_left		equ		0
+psp_right		equ		4
+psp_size		equ		8
+
+; !!! if this is changed, it must be changed in r_local.h too !!!
+NEAR_CLIP	equ		0.01
+
+; !!! if this is changed, it must be changed in r_local.h too !!!
+CYCLE	equ		128
+
+; espan_t structure
+; !!! if this is changed, it must be changed in r_shared.h too !!!
+espan_t_u    	equ		0
+espan_t_v	    equ		4
+espan_t_count   equ		8
+espan_t_pnext	equ		12
+espan_t_size    equ		16
+
+; sspan_t structure
+; !!! if this is changed, it must be changed in d_local.h too !!!
+sspan_t_u    	equ		0
+sspan_t_v	    equ		4
+sspan_t_count   equ		8
+sspan_t_size    equ		12
+
+; spanpackage_t structure
+; !!! if this is changed, it must be changed in d_polyset.c too !!!
+spanpackage_t_pdest				equ		0
+spanpackage_t_pz				equ		4
+spanpackage_t_count				equ		8
+spanpackage_t_ptex				equ		12
+spanpackage_t_sfrac				equ		16
+spanpackage_t_tfrac				equ		20
+spanpackage_t_light				equ		24
+spanpackage_t_zi				equ		28
+spanpackage_t_size				equ		32 
+
+; edge_t structure
+; !!! if this is changed, it must be changed in r_shared.h too !!!
+et_u			equ		0
+et_u_step		equ		4
+et_prev			equ		8
+et_next			equ		12
+et_surfs		equ		16
+et_nextremove	equ		20
+et_nearzi		equ		24
+et_owner		equ		28
+et_size			equ		32
+
+; surf_t structure
+; !!! if this is changed, it must be changed in r_shared.h too !!!
+SURF_T_SHIFT	equ		6
+st_next			equ		0
+st_prev			equ		4
+st_spans		equ		8
+st_key			equ		12
+st_last_u		equ		16
+st_spanstate	equ		20
+st_flags		equ		24
+st_data			equ		28
+st_entity		equ		32
+st_nearzi		equ		36
+st_insubmodel	equ		40
+st_d_ziorigin	equ		44
+st_d_zistepu	equ		48
+st_d_zistepv	equ		52
+st_pad			equ		56
+st_size			equ		64
+
+; clipplane_t structure
+; !!! if this is changed, it must be changed in r_local.h too !!!
+cp_normal		equ		0
+cp_dist			equ		12
+cp_next			equ		16
+cp_leftedge		equ		20
+cp_rightedge	equ		21
+cp_reserved		equ		22
+cp_size			equ		24
+
+; medge_t structure
+; !!! if this is changed, it must be changed in model.h too !!!
+me_v				equ		0
+me_cachededgeoffset	equ		4
+me_size				equ		8
+
+; mvertex_t structure
+; !!! if this is changed, it must be changed in model.h too !!!
+mv_position		equ		0
+mv_size			equ		12
+
+; refdef_t structure
+; !!! if this is changed, it must be changed in render.h too !!!
+rd_vrect					equ		0
+rd_aliasvrect				equ		20
+rd_vrectright				equ		40
+rd_vrectbottom				equ		44
+rd_aliasvrectright			equ		48
+rd_aliasvrectbottom			equ		52
+rd_vrectrightedge			equ		56
+rd_fvrectx					equ		60
+rd_fvrecty					equ		64
+rd_fvrectx_adj				equ		68
+rd_fvrecty_adj				equ		72
+rd_vrect_x_adj_shift20		equ		76
+rd_vrectright_adj_shift20	equ		80
+rd_fvrectright_adj			equ		84
+rd_fvrectbottom_adj			equ		88
+rd_fvrectright				equ		92
+rd_fvrectbottom				equ		96
+rd_horizontalFieldOfView	equ		100
+rd_xOrigin					equ		104
+rd_yOrigin					equ		108
+rd_vieworg					equ		112
+rd_viewangles				equ		124
+rd_ambientlight				equ		136
+rd_size						equ		140
+
+; mtriangle_t structure
+; !!! if this is changed, it must be changed in model.h too !!!
+mtri_facesfront		equ		0
+mtri_vertindex		equ		4
+mtri_size			equ		16	; !!! if this changes, array indexing in !!!
+								; !!! d_polysa.s must be changed to match !!!
+mtri_shift			equ		4
+
--- /dev/null
+++ b/ref_soft/r_aclip.c
@@ -1,0 +1,323 @@
+/*
+Copyright (C) 1997-2001 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_aclip.c: clip routines for drawing Alias models directly to the screen
+
+#include "r_local.h"
+
+static finalvert_t		fv[2][8];
+
+void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
+void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out);
+
+
+/*
+================
+R_Alias_clip_z
+
+pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
+================
+*/
+void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
+			(pfv1->xyz[2] - pfv0->xyz[2]);
+
+	out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
+	out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
+	out->xyz[2] = ALIAS_Z_CLIP_PLANE;
+
+	out->s =	pfv0->s + (pfv1->s - pfv0->s) * scale;
+	out->t =	pfv0->t + (pfv1->t - pfv0->t) * scale;
+	out->l =	pfv0->l + (pfv1->l - pfv0->l) * scale;
+
+	R_AliasProjectAndClipTestFinalVert (out);
+}
+
+
+#if	!id386
+
+void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	if (pfv0->v >= pfv1->v )
+	{
+		scale = (float)(r_refdef.aliasvrect.x - pfv0->u) /
+				(pfv1->u - pfv0->u);
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrect.x - pfv1->u) /
+				(pfv0->u - pfv1->u);
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	if ( pfv0->v >= pfv1->v )
+	{
+		scale = (float)(r_refdef.aliasvrectright - pfv0->u ) /
+				(pfv1->u - pfv0->u );
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrectright - pfv1->u ) /
+				(pfv0->u - pfv1->u );
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+	float		scale;
+
+	if (pfv0->v >= pfv1->v)
+	{
+		scale = (float)(r_refdef.aliasvrect.y - pfv0->v) /
+				(pfv1->v - pfv0->v);
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrect.y - pfv1->v) /
+				(pfv0->v - pfv1->v);
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+
+void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
+	finalvert_t *out)
+{
+	float		scale;
+
+	if (pfv0->v >= pfv1->v)
+	{
+		scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) /
+				(pfv1->v - pfv0->v);
+
+		out->u  = pfv0->u  + ( pfv1->u  - pfv0->u ) * scale + 0.5;
+		out->v  = pfv0->v  + ( pfv1->v  - pfv0->v ) * scale + 0.5;
+		out->s  = pfv0->s  + ( pfv1->s  - pfv0->s ) * scale + 0.5;
+		out->t  = pfv0->t  + ( pfv1->t  - pfv0->t ) * scale + 0.5;
+		out->l  = pfv0->l  + ( pfv1->l  - pfv0->l ) * scale + 0.5;
+		out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+	}
+	else
+	{
+		scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) /
+				(pfv0->v - pfv1->v);
+
+		out->u  = pfv1->u  + ( pfv0->u  - pfv1->u ) * scale + 0.5;
+		out->v  = pfv1->v  + ( pfv0->v  - pfv1->v ) * scale + 0.5;
+		out->s  = pfv1->s  + ( pfv0->s  - pfv1->s ) * scale + 0.5;
+		out->t  = pfv1->t  + ( pfv0->t  - pfv1->t ) * scale + 0.5;
+		out->l  = pfv1->l  + ( pfv0->l  - pfv1->l ) * scale + 0.5;
+		out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+	}
+}
+
+#endif
+
+
+int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
+	void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
+{
+	int			i,j,k;
+	int			flags, oldflags;
+	
+	j = count-1;
+	k = 0;
+	for (i=0 ; i<count ; j = i, i++)
+	{
+		oldflags = in[j].flags & flag;
+		flags = in[i].flags & flag;
+
+		if (flags && oldflags)
+			continue;
+		if (oldflags ^ flags)
+		{
+			clip (&in[j], &in[i], &out[k]);
+			out[k].flags = 0;
+			if (out[k].u < r_refdef.aliasvrect.x)
+				out[k].flags |= ALIAS_LEFT_CLIP;
+			if (out[k].v < r_refdef.aliasvrect.y)
+				out[k].flags |= ALIAS_TOP_CLIP;
+			if (out[k].u > r_refdef.aliasvrectright)
+				out[k].flags |= ALIAS_RIGHT_CLIP;
+			if (out[k].v > r_refdef.aliasvrectbottom)
+				out[k].flags |= ALIAS_BOTTOM_CLIP;	
+			k++;
+		}
+		if (!flags)
+		{
+			out[k] = in[i];
+			k++;
+		}
+	}
+	
+	return k;
+}
+
+
+/*
+================
+R_AliasClipTriangle
+================
+*/
+void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
+{
+	int				i, k, pingpong;
+	unsigned		clipflags;
+
+// copy vertexes and fix seam texture coordinates
+	fv[0][0] = *index0;
+	fv[0][1] = *index1;
+	fv[0][2] = *index2;
+
+// clip
+	clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
+
+	if (clipflags & ALIAS_Z_CLIP)
+	{
+		k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
+		if (k == 0)
+			return;
+
+		pingpong = 1;
+		clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
+	}
+	else
+	{
+		pingpong = 0;
+		k = 3;
+	}
+
+	if (clipflags & ALIAS_LEFT_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	if (clipflags & ALIAS_RIGHT_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	if (clipflags & ALIAS_BOTTOM_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	if (clipflags & ALIAS_TOP_CLIP)
+	{
+		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+							ALIAS_TOP_CLIP, k, R_Alias_clip_top);
+		if (k == 0)
+			return;
+
+		pingpong ^= 1;
+	}
+
+	for (i=0 ; i<k ; i++)
+	{
+		if (fv[pingpong][i].u < r_refdef.aliasvrect.x)
+			fv[pingpong][i].u = r_refdef.aliasvrect.x;
+		else if (fv[pingpong][i].u > r_refdef.aliasvrectright)
+			fv[pingpong][i].u = r_refdef.aliasvrectright;
+
+		if (fv[pingpong][i].v < r_refdef.aliasvrect.y)
+			fv[pingpong][i].v = r_refdef.aliasvrect.y;
+		else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom)
+			fv[pingpong][i].v = r_refdef.aliasvrectbottom;
+
+		fv[pingpong][i].flags = 0;
+	}
+
+// draw triangles
+	for (i=1 ; i<k-1 ; i++)
+	{
+		aliastriangleparms.a = &fv[pingpong][0];
+		aliastriangleparms.b = &fv[pingpong][i];
+		aliastriangleparms.c = &fv[pingpong][i+1];
+		R_DrawTriangle();
+	}
+}
+
--- /dev/null
+++ b/ref_soft/r_aclipa.asm
@@ -1,0 +1,200 @@
+ .386P
+ .model FLAT
+;
+; r_aliasa.s
+; x86 assembly-language Alias model transform and project code.
+;
+
+include qasm.inc
+include d_if.inc
+
+if id386
+
+_DATA SEGMENT	
+Ltemp0 dd 0	
+Ltemp1 dd 0	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+pfv0		equ		8+4
+pfv1		equ		8+8
+outparm			equ		8+12
+
+ public _R_Alias_clip_bottom	
+_R_Alias_clip_bottom:	
+ push esi	
+ push edi	
+
+ mov esi,ds:dword ptr[pfv0+esp]	
+ mov edi,ds:dword ptr[pfv1+esp]	
+
+ mov eax,ds:dword ptr[_r_refdef+rd_aliasvrectbottom]	
+
+LDoForwardOrBackward:	
+
+ mov edx,ds:dword ptr[fv_v+4+esi]	
+ mov ecx,ds:dword ptr[fv_v+4+edi]	
+
+ cmp edx,ecx	
+ jl LDoForward	
+
+ mov ecx,ds:dword ptr[fv_v+4+esi]	
+ mov edx,ds:dword ptr[fv_v+4+edi]	
+ mov edi,ds:dword ptr[pfv0+esp]	
+ mov esi,ds:dword ptr[pfv1+esp]	
+
+LDoForward:	
+
+ sub ecx,edx	
+ sub eax,edx	
+ mov ds:dword ptr[Ltemp1],ecx	
+ mov ds:dword ptr[Ltemp0],eax	
+ fild ds:dword ptr[Ltemp1]	
+ fild ds:dword ptr[Ltemp0]	
+ mov edx,ds:dword ptr[outparm+esp]	
+ mov eax,2	
+
+ fdivrp st(1),st(0)	; scale
+
+LDo3Forward:	
+ fild ds:dword ptr[fv_v+0+esi]	; fv0v0 | scale
+ fild ds:dword ptr[fv_v+0+edi]	; fv1v0 | fv0v0 | scale
+ fild ds:dword ptr[fv_v+4+esi]	; fv0v1 | fv1v0 | fv0v0 | scale
+ fild ds:dword ptr[fv_v+4+edi]	; fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale
+ fild ds:dword ptr[fv_v+8+esi]	; fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale
+ fild ds:dword ptr[fv_v+8+edi]	; fv1v2 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 |
+;  scale
+ fxch st(5)	; fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv1v2 |
+;  scale
+ fsub st(4),st(0)	; fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0-fv0v0 |
+;  fv1v2 | scale
+ fxch st(3)	; fv0v1 | fv0v2 | fv1v1 | fv0v0 | fv1v0-fv0v0 |
+;  fv1v2 | scale
+ fsub st(2),st(0)	; fv0v1 | fv0v2 | fv1v1-fv0v1 | fv0v0 |
+;  fv1v0-fv0v0 | fv1v2 | scale
+ fxch st(1)	; fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+;  fv1v0-fv0v0 | fv1v2 | scale
+ fsub st(5),st(0)	; fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+;  fv1v0-fv0v0 | fv1v2-fv0v2 | scale
+ fxch st(6)	; scale | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+;  fv1v0-fv0v0 | fv1v2-fv0v2 | fv0v2
+ fmul st(4),st(0)	; scale | fv0v1 | fv1v1-fv0v1 | fv0v0 |
+;  (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2
+ add edi,12	
+ fmul st(2),st(0)	; scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 |
+;  (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2
+ add esi,12	
+ add edx,12	
+ fmul st(5),st(0)	; scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 |
+;  (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale |
+;  fv0v2
+ fxch st(3)	; fv0v0 | fv0v1 | (fv1v1-fv0v1)*scale | scale |
+;  (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale |
+;  fv0v2
+ faddp st(4),st(0)	; fv0v1 | (fv1v1-fv0v1)*scale | scale |
+;  fv0v0+(fv1v0-fv0v0)*scale |
+;  (fv1v2-fv0v2)*scale | fv0v2
+ faddp st(1),st(0)	; fv0v1+(fv1v1-fv0v1)*scale | scale |
+;  fv0v0+(fv1v0-fv0v0)*scale |
+;  (fv1v2-fv0v2)*scale | fv0v2
+ fxch st(4)	; fv0v2 | scale | fv0v0+(fv1v0-fv0v0)*scale |
+;  (fv1v2-fv0v2)*scale | fv0v1+(fv1v1-fv0v1)*scale
+ faddp st(3),st(0)	; scale | fv0v0+(fv1v0-fv0v0)*scale |
+;  fv0v2+(fv1v2-fv0v2)*scale |
+;  fv0v1+(fv1v1-fv0v1)*scale
+ fxch st(1)	; fv0v0+(fv1v0-fv0v0)*scale | scale | 
+;  fv0v2+(fv1v2-fv0v2)*scale |
+;  fv0v1+(fv1v1-fv0v1)*scale
+ fadd ds:dword ptr[float_point5]	
+ fxch st(3)	; fv0v1+(fv1v1-fv0v1)*scale | scale | 
+;  fv0v2+(fv1v2-fv0v2)*scale |
+;  fv0v0+(fv1v0-fv0v0)*scale
+ fadd ds:dword ptr[float_point5]	
+ fxch st(2)	; fv0v2+(fv1v2-fv0v2)*scale | scale | 
+;  fv0v1+(fv1v1-fv0v1)*scale |
+;  fv0v0+(fv1v0-fv0v0)*scale
+ fadd ds:dword ptr[float_point5]	
+ fxch st(3)	; fv0v0+(fv1v0-fv0v0)*scale | scale | 
+;  fv0v1+(fv1v1-fv0v1)*scale |
+;  fv0v2+(fv1v2-fv0v2)*scale
+ fistp ds:dword ptr[fv_v+0-12+edx]	; scale | fv0v1+(fv1v1-fv0v1)*scale |
+;  fv0v2+(fv1v2-fv0v2)*scale
+ fxch st(1)	; fv0v1+(fv1v1-fv0v1)*scale | scale |
+;  fv0v2+(fv1v2-fv0v2)*scale | scale
+ fistp ds:dword ptr[fv_v+4-12+edx]	; scale | fv0v2+(fv1v2-fv0v2)*scale
+ fxch st(1)	; fv0v2+(fv1v2-fv0v2)*sc | scale
+ fistp ds:dword ptr[fv_v+8-12+edx]	; scale
+
+ dec eax	
+ jnz LDo3Forward	
+
+ fstp st(0)	
+
+ pop edi	
+ pop esi	
+
+ ret	
+
+
+ public _R_Alias_clip_top	
+_R_Alias_clip_top:	
+ push esi	
+ push edi	
+
+ mov esi,ds:dword ptr[pfv0+esp]	
+ mov edi,ds:dword ptr[pfv1+esp]	
+
+ mov eax,ds:dword ptr[_r_refdef+rd_aliasvrect+4]	
+ jmp LDoForwardOrBackward	
+
+
+
+ public _R_Alias_clip_right	
+_R_Alias_clip_right:	
+ push esi	
+ push edi	
+
+ mov esi,ds:dword ptr[pfv0+esp]	
+ mov edi,ds:dword ptr[pfv1+esp]	
+
+ mov eax,ds:dword ptr[_r_refdef+rd_aliasvrectright]	
+
+LRightLeftEntry:	
+
+
+ mov edx,ds:dword ptr[fv_v+4+esi]	
+ mov ecx,ds:dword ptr[fv_v+4+edi]	
+
+ cmp edx,ecx	
+ mov edx,ds:dword ptr[fv_v+0+esi]	
+
+ mov ecx,ds:dword ptr[fv_v+0+edi]	
+ jl LDoForward2	
+
+ mov ecx,ds:dword ptr[fv_v+0+esi]	
+ mov edx,ds:dword ptr[fv_v+0+edi]	
+ mov edi,ds:dword ptr[pfv0+esp]	
+ mov esi,ds:dword ptr[pfv1+esp]	
+
+LDoForward2:	
+
+ jmp LDoForward	
+
+
+ public _R_Alias_clip_left	
+_R_Alias_clip_left:	
+ push esi	
+ push edi	
+
+ mov esi,ds:dword ptr[pfv0+esp]	
+ mov edi,ds:dword ptr[pfv1+esp]	
+
+ mov eax,ds:dword ptr[_r_refdef+rd_aliasvrect+0]	
+ jmp LRightLeftEntry	
+
+
+
+_TEXT ENDS
+endif	;id386
+ END
--- /dev/null
+++ b/ref_soft/r_alias.c
@@ -1,0 +1,1198 @@
+/*
+Copyright (C) 1997-2001 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_alias.c: routines for setting up to draw alias models
+
+/*
+** use a real variable to control lerping
+*/
+#include "r_local.h"
+
+#define LIGHT_MIN	5		// lowest light value we'll allow, to avoid the
+							//  need for inner-loop light clamping
+
+//PGM
+extern byte iractive;
+//PGM
+
+int				r_amodels_drawn;
+
+affinetridesc_t	r_affinetridesc;
+
+vec3_t			r_plightvec;
+vec3_t          r_lerped[1024];
+vec3_t          r_lerp_frontv, r_lerp_backv, r_lerp_move;
+
+int				r_ambientlight;
+int				r_aliasblendcolor;
+float			r_shadelight;
+
+
+daliasframe_t	*r_thisframe, *r_lastframe;
+dmdl_t			*s_pmdl;
+
+float	aliastransform[3][4];
+float   aliasworldtransform[3][4];
+float   aliasoldworldtransform[3][4];
+
+static float	s_ziscale;
+static vec3_t	s_alias_forward, s_alias_right, s_alias_up;
+
+
+#define NUMVERTEXNORMALS	162
+
+float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
+#include "anorms.h"
+};
+
+
+void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
+void R_AliasSetUpTransform (void);
+void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
+void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
+
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
+
+void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
+
+/*
+================
+R_AliasCheckBBox
+================
+*/
+typedef struct {
+	int	index0;
+	int	index1;
+} aedge_t;
+
+static aedge_t	aedges[12] = {
+{0, 1}, {1, 2}, {2, 3}, {3, 0},
+{4, 5}, {5, 6}, {6, 7}, {7, 4},
+{0, 5}, {1, 4}, {2, 7}, {3, 6}
+};
+
+#define BBOX_TRIVIAL_ACCEPT 0
+#define BBOX_MUST_CLIP_XY   1
+#define BBOX_MUST_CLIP_Z    2
+#define BBOX_TRIVIAL_REJECT 8
+
+/*
+** R_AliasCheckFrameBBox
+**
+** Checks a specific alias frame bounding box
+*/
+unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
+{
+	unsigned long aggregate_and_clipcode = ~0U, 
+		          aggregate_or_clipcode = 0;
+	int           i;
+	vec3_t        mins, maxs;
+	vec3_t        transformed_min, transformed_max;
+	qboolean      zclipped = false, zfullyclipped = true;
+	float         minz = 9999.0F;
+
+	/*
+	** get the exact frame bounding box
+	*/
+	for (i=0 ; i<3 ; i++)
+	{
+		mins[i] = frame->translate[i];
+		maxs[i] = mins[i] + frame->scale[i]*255;
+	}
+
+	/*
+	** transform the min and max values into view space
+	*/
+	R_AliasTransformVector( mins, transformed_min, aliastransform );
+	R_AliasTransformVector( maxs, transformed_max, aliastransform );
+
+	if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
+		zfullyclipped = false;
+	if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
+		zfullyclipped = false;
+
+	if ( zfullyclipped )
+	{
+		return BBOX_TRIVIAL_REJECT;
+	}
+	if ( zclipped )
+	{
+		return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
+	}
+
+	/*
+	** build a transformed bounding box from the given min and max
+	*/
+	for ( i = 0; i < 8; i++ )
+	{
+		int      j;
+		vec3_t   tmp, transformed;
+		unsigned long clipcode = 0;
+
+		if ( i & 1 )
+			tmp[0] = mins[0];
+		else
+			tmp[0] = maxs[0];
+
+		if ( i & 2 )
+			tmp[1] = mins[1];
+		else
+			tmp[1] = maxs[1];
+
+		if ( i & 4 )
+			tmp[2] = mins[2];
+		else
+			tmp[2] = maxs[2];
+
+		R_AliasTransformVector( tmp, transformed, worldxf );
+
+		for ( j = 0; j < 4; j++ )
+		{
+			float dp = DotProduct( transformed, view_clipplanes[j].normal );
+
+			if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
+				clipcode |= 1 << j;
+		}
+
+		aggregate_and_clipcode &= clipcode;
+		aggregate_or_clipcode  |= clipcode;
+	}
+
+	if ( aggregate_and_clipcode )
+	{
+		return BBOX_TRIVIAL_REJECT;
+	}
+	if ( !aggregate_or_clipcode )
+	{
+		return BBOX_TRIVIAL_ACCEPT;
+	}
+
+	return BBOX_MUST_CLIP_XY;
+}
+
+qboolean R_AliasCheckBBox (void)
+{
+	unsigned long ccodes[2] = { 0, 0 };
+
+	ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
+
+	/*
+	** non-lerping model
+	*/
+	if ( currententity->backlerp == 0 )
+	{
+		if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
+			return BBOX_TRIVIAL_ACCEPT;
+		else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
+			return BBOX_TRIVIAL_REJECT;
+		else
+			return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
+	}
+
+	ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
+
+	if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
+		return BBOX_TRIVIAL_ACCEPT;
+	else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
+		return BBOX_TRIVIAL_REJECT;
+	else
+		return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
+}
+
+
+/*
+================
+R_AliasTransformVector
+================
+*/
+void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
+{
+	out[0] = DotProduct(in, xf[0]) + xf[0][3];
+	out[1] = DotProduct(in, xf[1]) + xf[1][3];
+	out[2] = DotProduct(in, xf[2]) + xf[2][3];
+}
+
+
+/*
+================
+R_AliasPreparePoints
+
+General clipped case
+================
+*/
+typedef struct
+{
+	int          num_points;
+	dtrivertx_t *last_verts;   // verts from the last frame
+	dtrivertx_t *this_verts;   // verts from this frame
+	finalvert_t *dest_verts;   // destination for transformed verts
+} aliasbatchedtransformdata_t;
+
+aliasbatchedtransformdata_t aliasbatchedtransformdata;
+
+void R_AliasPreparePoints (void)
+{
+	int			i;
+	dstvert_t	*pstverts;
+	dtriangle_t	*ptri;
+	finalvert_t	*pfv[3];
+	finalvert_t	finalverts[MAXALIASVERTS +
+						((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
+	finalvert_t	*pfinalverts;
+
+//PGM
+	iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
+//	iractive = 0;
+//	if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+//		iractive = 1;
+//PGM
+
+	// put work vertexes on stack, cache aligned
+	pfinalverts = (finalvert_t *)
+			(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+
+	aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
+	aliasbatchedtransformdata.last_verts = r_lastframe->verts;
+	aliasbatchedtransformdata.this_verts = r_thisframe->verts;
+	aliasbatchedtransformdata.dest_verts = pfinalverts;
+
+	R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
+		                        aliasbatchedtransformdata.dest_verts,
+								aliasbatchedtransformdata.last_verts,
+								aliasbatchedtransformdata.this_verts );
+
+// clip and draw all triangles
+//
+	pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
+	ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
+
+	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+	{
+		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
+		{
+			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
+			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
+			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
+
+			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
+				continue;		// completely clipped
+
+			// insert s/t coordinates
+			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
+			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
+
+			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
+			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
+
+			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
+			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
+
+			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
+			{	// totally unclipped
+				aliastriangleparms.a = pfv[2];
+				aliastriangleparms.b = pfv[1];
+				aliastriangleparms.c = pfv[0];
+
+				R_DrawTriangle();
+			}
+			else
+			{
+				R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
+			}
+		}
+	}
+	else
+	{
+		for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
+		{
+			pfv[0] = &pfinalverts[ptri->index_xyz[0]];
+			pfv[1] = &pfinalverts[ptri->index_xyz[1]];
+			pfv[2] = &pfinalverts[ptri->index_xyz[2]];
+
+			if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
+				continue;		// completely clipped
+
+			// insert s/t coordinates
+			pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
+			pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
+
+			pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
+			pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
+
+			pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
+			pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
+
+			if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
+			{	// totally unclipped
+				aliastriangleparms.a = pfv[0];
+				aliastriangleparms.b = pfv[1];
+				aliastriangleparms.c = pfv[2];
+
+				R_DrawTriangle();
+			}
+			else		
+			{	// partially clipped
+				R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
+			}
+		}
+	}
+}
+
+
+/*
+================
+R_AliasSetUpTransform
+================
+*/
+void R_AliasSetUpTransform (void)
+{
+	int				i;
+	static float	viewmatrix[3][4];
+	vec3_t			angles;
+
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: should use a look-up table
+// TODO: could cache lazily, stored in the entity
+// 
+	angles[ROLL] = currententity->angles[ROLL];
+	angles[PITCH] = currententity->angles[PITCH];
+	angles[YAW] = currententity->angles[YAW];
+	AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
+
+// TODO: can do this with simple matrix rearrangement
+
+	memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
+	memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
+
+	for (i=0 ; i<3 ; i++)
+	{
+		aliasoldworldtransform[i][0] = aliasworldtransform[i][0] =  s_alias_forward[i];
+		aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
+		aliasoldworldtransform[i][0] = aliasworldtransform[i][2] =  s_alias_up[i];
+	}
+
+	aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
+	aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
+	aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
+
+	aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
+	aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
+	aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
+
+// FIXME: can do more efficiently than full concatenation
+//	memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
+
+//	R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
+
+// TODO: should be global, set when vright, etc., set
+	VectorCopy (vright, viewmatrix[0]);
+	VectorCopy (vup, viewmatrix[1]);
+	VectorInverse (viewmatrix[1]);
+	VectorCopy (vpn, viewmatrix[2]);
+
+	viewmatrix[0][3] = 0;
+	viewmatrix[1][3] = 0;
+	viewmatrix[2][3] = 0;
+
+//	memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
+
+	R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
+
+	aliasworldtransform[0][3] = currententity->origin[0];
+	aliasworldtransform[1][3] = currententity->origin[1];
+	aliasworldtransform[2][3] = currententity->origin[2];
+
+	aliasoldworldtransform[0][3] = currententity->oldorigin[0];
+	aliasoldworldtransform[1][3] = currententity->oldorigin[1];
+	aliasoldworldtransform[2][3] = currententity->oldorigin[2];
+}
+
+
+/*
+================
+R_AliasTransformFinalVerts
+================
+*/
+#if id386 && !defined __linux__
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
+{
+	float  lightcos;
+	float	lerped_vert[3];
+	int    byte_to_dword_ptr_var;
+	int    tmpint;
+
+	float  one = 1.0F;
+	float  zi;
+
+	static float  FALIAS_Z_CLIP_PLANE = ALIAS_Z_CLIP_PLANE;
+	static float  PS_SCALE = POWERSUIT_SCALE;
+
+	__asm mov ecx, numpoints
+
+	/*
+	lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
+	lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
+	lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
+	*/
+top_of_loop:
+
+	__asm mov esi, oldv
+	__asm mov edi, newv
+
+	__asm xor ebx, ebx
+
+	__asm mov bl, byte ptr [esi+DTRIVERTX_V0]
+	__asm mov byte_to_dword_ptr_var, ebx
+	__asm fild dword ptr byte_to_dword_ptr_var      
+	__asm fmul dword ptr [r_lerp_backv+0]                  ; oldv[0]*rlb[0]
+
+	__asm mov bl, byte ptr [esi+DTRIVERTX_V1]
+	__asm mov byte_to_dword_ptr_var, ebx
+	__asm fild dword ptr byte_to_dword_ptr_var
+	__asm fmul dword ptr [r_lerp_backv+4]                  ; oldv[1]*rlb[1] | oldv[0]*rlb[0]
+
+	__asm mov bl, byte ptr [esi+DTRIVERTX_V2]
+	__asm mov byte_to_dword_ptr_var, ebx
+	__asm fild dword ptr byte_to_dword_ptr_var
+	__asm fmul dword ptr [r_lerp_backv+8]                  ; oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
+
+	__asm mov bl, byte ptr [edi+DTRIVERTX_V0]
+	__asm mov byte_to_dword_ptr_var, ebx
+	__asm fild dword ptr byte_to_dword_ptr_var      
+	__asm fmul dword ptr [r_lerp_frontv+0]                 ; newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
+
+	__asm mov bl, byte ptr [edi+DTRIVERTX_V1]
+	__asm mov byte_to_dword_ptr_var, ebx
+	__asm fild dword ptr byte_to_dword_ptr_var
+	__asm fmul dword ptr [r_lerp_frontv+4]                 ; newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
+
+	__asm mov bl, byte ptr [edi+DTRIVERTX_V2]
+	__asm mov byte_to_dword_ptr_var, ebx
+	__asm fild dword ptr byte_to_dword_ptr_var
+	__asm fmul dword ptr [r_lerp_frontv+8]                 ; newv[2]*rlf[2] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0]
+
+	__asm fxch st(5)                     ; oldv[0]*rlb[0] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2]
+	__asm faddp st(2), st                ; newv[1]*rlf[1] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2]
+	__asm faddp st(3), st                ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2]
+	__asm fxch st(1)                     ; oldv[2]*rlb[2] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2]
+	__asm faddp st(3), st                ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2]
+	__asm fadd dword ptr [r_lerp_move+0] ; lv0 | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2]
+	__asm fxch st(1)                     ; oldv[1]*rlb[1] + newv[1]*rlf[1] | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2]
+	__asm fadd dword ptr [r_lerp_move+4] ; lv1 | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2]
+	__asm fxch st(2)                     ; oldv[2]*rlb[2] + newv[2]*rlf[2] | lv0 | lv1
+	__asm fadd dword ptr [r_lerp_move+8] ; lv2 | lv0 | lv1
+	__asm fxch st(1)                     ; lv0 | lv2 | lv1
+	__asm fstp dword ptr [lerped_vert+0] ; lv2 | lv1
+	__asm fstp dword ptr [lerped_vert+8] ; lv2
+	__asm fstp dword ptr [lerped_vert+4] ; (empty)
+
+	__asm mov  eax, currententity
+	__asm mov  eax, dword ptr [eax+ENTITY_FLAGS]
+	__asm mov  ebx, RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM
+	__asm and  eax, ebx
+	__asm jz   not_powersuit
+
+	/*
+	**    lerped_vert[0] += lightnormal[0] * POWERSUIT_SCALE
+	**    lerped_vert[1] += lightnormal[1] * POWERSUIT_SCALE
+	**    lerped_vert[2] += lightnormal[2] * POWERSUIT_SCALE
+	*/
+
+	__asm xor ebx, ebx
+	__asm mov bl,  byte ptr [edi+DTRIVERTX_LNI]
+	__asm mov eax, 12
+	__asm mul ebx
+	__asm lea eax, [r_avertexnormals+eax]
+
+	__asm fld  dword ptr [eax+0]				; n[0]
+	__asm fmul PS_SCALE							; n[0] * PS
+	__asm fld  dword ptr [eax+4]				; n[1] | n[0] * PS
+	__asm fmul PS_SCALE							; n[1] * PS | n[0] * PS
+	__asm fld  dword ptr [eax+8]				; n[2] | n[1] * PS | n[0] * PS
+	__asm fmul PS_SCALE							; n[2] * PS | n[1] * PS | n[0] * PS
+	__asm fld  dword ptr [lerped_vert+0]		; lv0 | n[2] * PS | n[1] * PS | n[0] * PS
+	__asm faddp st(3), st						; n[2] * PS | n[1] * PS | n[0] * PS + lv0
+	__asm fld  dword ptr [lerped_vert+4]		; lv1 | n[2] * PS | n[1] * PS | n[0] * PS + lv0
+	__asm faddp st(2), st						; n[2] * PS | n[1] * PS + lv1 | n[0] * PS + lv0
+	__asm fadd dword ptr [lerped_vert+8]		; n[2] * PS + lv2 | n[1] * PS + lv1 | n[0] * PS + lv0
+	__asm fxch st(2)							; LV0 | LV1 | LV2
+	__asm fstp dword ptr [lerped_vert+0]		; LV1 | LV2
+	__asm fstp dword ptr [lerped_vert+4]		; LV2
+	__asm fstp dword ptr [lerped_vert+8]		; (empty)
+
+not_powersuit:
+
+	/*
+	fv->flags = 0;
+
+	fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
+	fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
+	fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
+	*/
+	__asm mov  eax, fv
+	__asm mov  dword ptr [eax+FINALVERT_FLAGS], 0
+
+	__asm fld  dword ptr [lerped_vert+0]           ; lv0
+	__asm fmul dword ptr [aliastransform+0]        ; lv0*at[0][0]
+	__asm fld  dword ptr [lerped_vert+4]           ; lv1 | lv0*at[0][0]
+	__asm fmul dword ptr [aliastransform+4]        ; lv1*at[0][1] | lv0*at[0][0]
+	__asm fld  dword ptr [lerped_vert+8]           ; lv2 | lv1*at[0][1] | lv0*at[0][0]
+	__asm fmul dword ptr [aliastransform+8]        ; lv2*at[0][2] | lv1*at[0][1] | lv0*at[0][0]
+	__asm fxch st(2)                               ; lv0*at[0][0] | lv1*at[0][1] | lv2*at[0][2]
+	__asm faddp st(1), st                          ; lv0*at[0][0] + lv1*at[0][1] | lv2*at[0][2]
+	__asm faddp st(1), st                          ; lv0*at[0][0] + lv1*at[0][1] + lv2*at[0][2]
+	__asm fadd  dword ptr [aliastransform+12]      ; FV.X
+
+	__asm fld  dword ptr [lerped_vert+0]           ; lv0
+	__asm fmul dword ptr [aliastransform+16]       ; lv0*at[1][0]
+	__asm fld  dword ptr [lerped_vert+4]           ; lv1 | lv0*at[1][0]
+	__asm fmul dword ptr [aliastransform+20]       ; lv1*at[1][1] | lv0*at[1][0]
+	__asm fld  dword ptr [lerped_vert+8]           ; lv2 | lv1*at[1][1] | lv0*at[1][0]
+	__asm fmul dword ptr [aliastransform+24]       ; lv2*at[1][2] | lv1*at[1][1] | lv0*at[1][0]
+	__asm fxch st(2)                               ; lv0*at[1][0] | lv1*at[1][1] | lv2*at[1][2]
+	__asm faddp st(1), st                          ; lv0*at[1][0] + lv1*at[1][1] | lv2*at[1][2]
+	__asm faddp st(1), st                          ; lv0*at[1][0] + lv1*at[1][1] + lv2*at[1][2]
+	__asm fadd dword ptr [aliastransform+28]       ; FV.Y | FV.X
+	__asm fxch st(1)                               ; FV.X | FV.Y
+	__asm fstp  dword ptr [eax+FINALVERT_X]        ; FV.Y
+	
+	__asm fld  dword ptr [lerped_vert+0]           ; lv0
+	__asm fmul dword ptr [aliastransform+32]       ; lv0*at[2][0]
+	__asm fld  dword ptr [lerped_vert+4]           ; lv1 | lv0*at[2][0]
+	__asm fmul dword ptr [aliastransform+36]       ; lv1*at[2][1] | lv0*at[2][0]
+	__asm fld  dword ptr [lerped_vert+8]           ; lv2 | lv1*at[2][1] | lv0*at[2][0]
+	__asm fmul dword ptr [aliastransform+40]       ; lv2*at[2][2] | lv1*at[2][1] | lv0*at[2][0]
+	__asm fxch st(2)                               ; lv0*at[2][0] | lv1*at[2][1] | lv2*at[2][2]
+	__asm faddp st(1), st                          ; lv0*at[2][0] + lv1*at[2][1] | lv2*at[2][2]
+	__asm faddp st(1), st                          ; lv0*at[2][0] + lv1*at[2][1] + lv2*at[2][2]
+	__asm fadd dword ptr [aliastransform+44]       ; FV.Z | FV.Y
+	__asm fxch st(1)                               ; FV.Y | FV.Z
+	__asm fstp dword ptr [eax+FINALVERT_Y]         ; FV.Z
+	__asm fstp dword ptr [eax+FINALVERT_Z]         ; (empty)
+
+	/*
+	**  lighting
+	**
+	**  plightnormal = r_avertexnormals[newv->lightnormalindex];
+	**	lightcos = DotProduct (plightnormal, r_plightvec);
+	**	temp = r_ambientlight;
+	*/
+	__asm xor ebx, ebx
+	__asm mov bl,  byte ptr [edi+DTRIVERTX_LNI]
+	__asm mov eax, 12
+	__asm mul ebx
+	__asm lea eax, [r_avertexnormals+eax]
+	__asm lea ebx, r_plightvec
+
+	__asm fld  dword ptr [eax+0]
+	__asm fmul dword ptr [ebx+0]
+	__asm fld  dword ptr [eax+4]
+	__asm fmul dword ptr [ebx+4]
+	__asm fld  dword ptr [eax+8]
+	__asm fmul dword ptr [ebx+8]
+	__asm fxch st(2)
+	__asm faddp st(1), st
+	__asm faddp st(1), st
+	__asm fstp dword ptr lightcos
+	__asm mov eax, lightcos
+	__asm mov ebx, r_ambientlight
+
+	/*
+	if (lightcos < 0)
+	{
+		temp += (int)(r_shadelight * lightcos);
+
+		// clamp; because we limited the minimum ambient and shading light, we
+		// don't have to clamp low light, just bright
+		if (temp < 0)
+			temp = 0;
+	}
+
+	fv->v[4] = temp;
+	*/
+	__asm or  eax, eax
+	__asm jns store_fv4
+
+	__asm fld   dword ptr r_shadelight
+	__asm fmul  dword ptr lightcos
+	__asm fistp dword ptr tmpint
+	__asm add   ebx, tmpint
+
+	__asm or    ebx, ebx
+	__asm jns   store_fv4
+	__asm mov   ebx, 0
+
+store_fv4:
+	__asm mov edi, fv
+	__asm mov dword ptr [edi+FINALVERT_V4], ebx
+
+	__asm mov edx, dword ptr [edi+FINALVERT_FLAGS]
+
+	/*
+	** do clip testing and projection here
+	*/
+	/*
+	if ( dest_vert->xyz[2] < ALIAS_Z_CLIP_PLANE )
+	{
+		dest_vert->flags |= ALIAS_Z_CLIP;
+	}
+	else
+	{
+		R_AliasProjectAndClipTestFinalVert( dest_vert );
+	}
+	*/
+	__asm mov eax, dword ptr [edi+FINALVERT_Z]
+	__asm and eax, eax
+	__asm js  alias_z_clip
+	__asm cmp eax, FALIAS_Z_CLIP_PLANE
+	__asm jl  alias_z_clip
+
+	/*
+	This is the code to R_AliasProjectAndClipTestFinalVert
+
+	float	zi;
+	float	x, y, z;
+
+	x = fv->xyz[0];
+	y = fv->xyz[1];
+	z = fv->xyz[2];
+	zi = 1.0 / z;
+
+	fv->v[5] = zi * s_ziscale;
+
+	fv->v[0] = (x * aliasxscale * zi) + aliasxcenter;
+	fv->v[1] = (y * aliasyscale * zi) + aliasycenter;
+	*/
+	__asm fld   one                             ; 1
+	__asm fdiv  dword ptr [edi+FINALVERT_Z]     ; zi
+
+	__asm mov   eax, dword ptr [edi+32]
+	__asm mov   eax, dword ptr [edi+64]
+
+	__asm fst   zi                              ; zi
+	__asm fmul  s_ziscale                       ; fv5
+	__asm fld   dword ptr [edi+FINALVERT_X]     ; x | fv5
+	__asm fmul  aliasxscale                     ; x * aliasxscale | fv5
+	__asm fld   dword ptr [edi+FINALVERT_Y]     ; y | x * aliasxscale | fv5
+	__asm fmul  aliasyscale                     ; y * aliasyscale | x * aliasxscale | fv5
+	__asm fxch  st(1)                           ; x * aliasxscale | y * aliasyscale | fv5
+	__asm fmul  zi                              ; x * asx * zi | y * asy | fv5
+	__asm fadd  aliasxcenter                    ; fv0 | y * asy | fv5
+	__asm fxch  st(1)                           ; y * asy | fv0 | fv5
+	__asm fmul  zi                              ; y * asy * zi | fv0 | fv5
+	__asm fadd  aliasycenter                    ; fv1 | fv0 | fv5
+	__asm fxch  st(2)                           ; fv5 | fv0 | fv1
+	__asm fistp dword ptr [edi+FINALVERT_V5]    ; fv0 | fv1
+	__asm fistp dword ptr [edi+FINALVERT_V0]    ; fv1
+	__asm fistp dword ptr [edi+FINALVERT_V1]    ; (empty)
+
+	/*
+	if (fv->v[0] < r_refdef.aliasvrect.x)
+		fv->flags |= ALIAS_LEFT_CLIP;
+	if (fv->v[1] < r_refdef.aliasvrect.y)
+		fv->flags |= ALIAS_TOP_CLIP;
+	if (fv->v[0] > r_refdef.aliasvrectright)
+		fv->flags |= ALIAS_RIGHT_CLIP;
+	if (fv->v[1] > r_refdef.aliasvrectbottom)
+		fv->flags |= ALIAS_BOTTOM_CLIP;
+	*/
+	__asm mov eax, dword ptr [edi+FINALVERT_V0]
+	__asm mov ebx, dword ptr [edi+FINALVERT_V1]
+
+	__asm cmp eax, r_refdef.aliasvrect.x
+	__asm jge ct_alias_top
+	__asm or  edx, ALIAS_LEFT_CLIP
+ct_alias_top:
+	__asm cmp ebx, r_refdef.aliasvrect.y
+	__asm jge ct_alias_right
+	__asm or edx, ALIAS_TOP_CLIP
+ct_alias_right:
+	__asm cmp eax, r_refdef.aliasvrectright
+	__asm jle ct_alias_bottom
+	__asm or edx, ALIAS_RIGHT_CLIP
+ct_alias_bottom:
+	__asm cmp ebx, r_refdef.aliasvrectbottom
+	__asm jle end_of_loop
+	__asm or  edx, ALIAS_BOTTOM_CLIP
+
+	__asm jmp end_of_loop
+
+alias_z_clip:
+	__asm or  edx, ALIAS_Z_CLIP
+
+end_of_loop:
+
+	__asm mov dword ptr [edi+FINALVERT_FLAGS], edx
+	__asm add oldv, DTRIVERTX_SIZE
+	__asm add newv, DTRIVERTX_SIZE
+	__asm add fv, FINALVERT_SIZE
+
+	__asm dec ecx
+	__asm jnz top_of_loop
+}
+#else
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
+{
+	int i;
+
+	for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
+	{
+		int		temp;
+		float	lightcos, *plightnormal;
+		vec3_t  lerped_vert;
+
+		lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
+		lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
+		lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
+
+		plightnormal = r_avertexnormals[newv->lightnormalindex];
+
+		// PMM - added double damage shell
+		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+		{
+			lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
+			lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
+			lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
+		}
+
+		fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
+		fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
+		fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
+
+		fv->flags = 0;
+
+		// lighting
+		lightcos = DotProduct (plightnormal, r_plightvec);
+		temp = r_ambientlight;
+
+		if (lightcos < 0)
+		{
+			temp += (int)(r_shadelight * lightcos);
+
+			// clamp; because we limited the minimum ambient and shading light, we
+			// don't have to clamp low light, just bright
+			if (temp < 0)
+				temp = 0;
+		}
+
+		fv->l = temp;
+
+		if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
+		{
+			fv->flags |= ALIAS_Z_CLIP;
+		}
+		else
+		{
+			R_AliasProjectAndClipTestFinalVert( fv );
+		}
+	}
+}
+
+#endif
+
+/*
+================
+R_AliasProjectAndClipTestFinalVert
+================
+*/
+void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
+{
+	float	zi;
+	float	x, y, z;
+
+	// project points
+	x = fv->xyz[0];
+	y = fv->xyz[1];
+	z = fv->xyz[2];
+	zi = 1.0 / z;
+
+	fv->zi = zi * s_ziscale;
+
+	fv->u = (x * aliasxscale * zi) + aliasxcenter;
+	fv->v = (y * aliasyscale * zi) + aliasycenter;
+
+	if (fv->u < r_refdef.aliasvrect.x)
+		fv->flags |= ALIAS_LEFT_CLIP;
+	if (fv->v < r_refdef.aliasvrect.y)
+		fv->flags |= ALIAS_TOP_CLIP;
+	if (fv->u > r_refdef.aliasvrectright)
+		fv->flags |= ALIAS_RIGHT_CLIP;
+	if (fv->v > r_refdef.aliasvrectbottom)
+		fv->flags |= ALIAS_BOTTOM_CLIP;	
+}
+
+/*
+===============
+R_AliasSetupSkin
+===============
+*/
+static qboolean R_AliasSetupSkin (void)
+{
+	int				skinnum;
+	image_t			*pskindesc;
+
+	if (currententity->skin)
+		pskindesc = currententity->skin;
+	else
+	{
+		skinnum = currententity->skinnum;
+		if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
+		{
+			ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n", 
+				currentmodel->name, skinnum);
+			skinnum = 0;
+		}
+
+		pskindesc = currentmodel->skins[skinnum];
+	}
+
+	if ( !pskindesc )
+		return false;
+
+	r_affinetridesc.pskin = pskindesc->pixels[0];
+	r_affinetridesc.skinwidth = pskindesc->width;
+	r_affinetridesc.skinheight = pskindesc->height;
+
+	R_PolysetUpdateTables ();		// FIXME: precalc edge lookups
+
+	return true;
+}
+
+
+/*
+================
+R_AliasSetupLighting
+
+  FIXME: put lighting into tables
+================
+*/
+void R_AliasSetupLighting (void)
+{
+	alight_t		lighting;
+	float			lightvec[3] = {-1, 0, 0};
+	vec3_t			light;
+	int				i, j;
+
+	// all components of light should be identical in software
+	if ( currententity->flags & RF_FULLBRIGHT )
+	{
+		for (i=0 ; i<3 ; i++)
+			light[i] = 1.0;
+	}
+	else
+	{
+		R_LightPoint (currententity->origin, light);
+	}
+
+	// save off light value for server to look at (BIG HACK!)
+	if ( currententity->flags & RF_WEAPONMODEL )
+		r_lightlevel->value = 150.0 * light[0];
+
+
+	if ( currententity->flags & RF_MINLIGHT )
+	{
+		for (i=0 ; i<3 ; i++)
+			if (light[i] < 0.1)
+				light[i] = 0.1;
+	}
+
+	if ( currententity->flags & RF_GLOW )
+	{	// bonus items will pulse with time
+		float	scale;
+		float	min;
+
+		scale = 0.1 * sin(r_newrefdef.time*7);
+		for (i=0 ; i<3 ; i++)
+		{
+			min = light[i] * 0.8;
+			light[i] += scale;
+			if (light[i] < min)
+				light[i] = min;
+		}
+	}
+
+	j = (light[0] + light[1] + light[2])*0.3333*255;
+
+	lighting.ambientlight = j;
+	lighting.shadelight = j;
+
+	lighting.plightvec = lightvec;
+
+// clamp lighting so it doesn't overbright as much
+	if (lighting.ambientlight > 128)
+		lighting.ambientlight = 128;
+	if (lighting.ambientlight + lighting.shadelight > 192)
+		lighting.shadelight = 192 - lighting.ambientlight;
+
+// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
+// to clamp off the bottom
+	r_ambientlight = lighting.ambientlight;
+
+	if (r_ambientlight < LIGHT_MIN)
+		r_ambientlight = LIGHT_MIN;
+
+	r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
+
+	if (r_ambientlight < LIGHT_MIN)
+		r_ambientlight = LIGHT_MIN;
+
+	r_shadelight = lighting.shadelight;
+
+	if (r_shadelight < 0)
+		r_shadelight = 0;
+
+	r_shadelight *= VID_GRADES;
+
+// rotate the lighting vector into the model's frame of reference
+	r_plightvec[0] =  DotProduct( lighting.plightvec, s_alias_forward );
+	r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
+	r_plightvec[2] =  DotProduct( lighting.plightvec, s_alias_up );
+}
+
+
+/*
+=================
+R_AliasSetupFrames
+
+=================
+*/
+void R_AliasSetupFrames( dmdl_t *pmdl )
+{
+	int thisframe = currententity->frame;
+	int lastframe = currententity->oldframe;
+
+	if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n", 
+			currentmodel->name, thisframe);
+		thisframe = 0;
+	}
+	if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n", 
+			currentmodel->name, lastframe);
+		lastframe = 0;
+	}
+
+	r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
+		+ thisframe * pmdl->framesize);
+
+	r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames 
+		+ lastframe * pmdl->framesize);
+}
+
+/*
+** R_AliasSetUpLerpData
+**
+** Precomputes lerp coefficients used for the whole frame.
+*/
+void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp )
+{
+	float	frontlerp;
+	vec3_t	translation, vectors[3];
+	int		i;
+
+	frontlerp = 1.0F - backlerp;
+
+	/*
+	** convert entity's angles into discrete vectors for R, U, and F
+	*/
+	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
+
+	/*
+	** translation is the vector from last position to this position
+	*/
+	VectorSubtract (currententity->oldorigin, currententity->origin, translation);
+
+	/*
+	** move should be the delta back to the previous frame * backlerp
+	*/
+	r_lerp_move[0] =  DotProduct(translation, vectors[0]);	// forward
+	r_lerp_move[1] = -DotProduct(translation, vectors[1]);	// left
+	r_lerp_move[2] =  DotProduct(translation, vectors[2]);	// up
+
+	VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
+
+	for (i=0 ; i<3 ; i++)
+	{
+		r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
+		r_lerp_backv[i]  = backlerp  * r_lastframe->scale[i];
+	}
+}
+
+/*
+================
+R_AliasDrawModel
+================
+*/
+void R_AliasDrawModel (void)
+{
+	extern void	(*d_pdrawspans)(void *);
+	extern void R_PolysetDrawSpans8_Opaque( void * );
+	extern void R_PolysetDrawSpans8_33( void * );
+	extern void R_PolysetDrawSpans8_66( void * );
+	extern void R_PolysetDrawSpansConstant8_33( void * );
+	extern void R_PolysetDrawSpansConstant8_66( void * );
+
+	s_pmdl = (dmdl_t *)currentmodel->extradata;
+
+	if ( r_lerpmodels->value == 0 )
+		currententity->backlerp = 0;
+
+	if ( currententity->flags & RF_WEAPONMODEL )
+	{
+		if ( r_lefthand->value == 1.0F )
+			aliasxscale = -aliasxscale;
+		else if ( r_lefthand->value == 2.0F )
+			return;
+	}
+
+	/*
+	** we have to set our frame pointers and transformations before
+	** doing any real work
+	*/
+	R_AliasSetupFrames( s_pmdl );
+	R_AliasSetUpTransform();
+
+	// see if the bounding box lets us trivially reject, also sets
+	// trivial accept status
+	if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
+	{
+		if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+		{
+			aliasxscale = -aliasxscale;
+		}
+		return;
+	}
+
+	// set up the skin and verify it exists
+	if ( !R_AliasSetupSkin () )
+	{
+		ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
+			currentmodel->name);
+		return;
+	}
+
+	r_amodels_drawn++;
+	R_AliasSetupLighting ();
+
+	/*
+	** select the proper span routine based on translucency
+	*/
+	// PMM - added double damage shell
+	// PMM - reordered to handle blending
+	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+	{
+		int		color;
+
+		// PMM - added double
+		color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
+		// PMM - reordered, old code first
+/*
+		if ( color == RF_SHELL_RED )
+			r_aliasblendcolor = SHELL_RED_COLOR;
+		else if ( color == RF_SHELL_GREEN )
+			r_aliasblendcolor = SHELL_GREEN_COLOR;
+		else if ( color == RF_SHELL_BLUE )
+			r_aliasblendcolor = SHELL_BLUE_COLOR;
+		else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
+			r_aliasblendcolor = SHELL_RG_COLOR;
+		else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
+			r_aliasblendcolor = SHELL_RB_COLOR;
+		else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
+			r_aliasblendcolor = SHELL_BG_COLOR;
+		// PMM - added this .. it's yellowish
+		else if ( color == (RF_SHELL_DOUBLE) )
+			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
+		else if ( color == (RF_SHELL_HALF_DAM) )
+			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
+		// pmm
+		else
+			r_aliasblendcolor = SHELL_WHITE_COLOR;
+*/
+		if ( color & RF_SHELL_RED )
+		{
+			if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
+				r_aliasblendcolor = SHELL_WHITE_COLOR;
+			else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
+				r_aliasblendcolor = SHELL_RB_COLOR;
+			else
+				r_aliasblendcolor = SHELL_RED_COLOR;
+		}
+		else if ( color & RF_SHELL_BLUE)
+		{
+			if ( color & RF_SHELL_DOUBLE )
+				r_aliasblendcolor = SHELL_CYAN_COLOR;
+			else
+				r_aliasblendcolor = SHELL_BLUE_COLOR;
+		}
+		else if ( color & (RF_SHELL_DOUBLE) )
+			r_aliasblendcolor = SHELL_DOUBLE_COLOR;
+		else if ( color & (RF_SHELL_HALF_DAM) )
+			r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
+		else if ( color & RF_SHELL_GREEN )
+			r_aliasblendcolor = SHELL_GREEN_COLOR;
+		else
+			r_aliasblendcolor = SHELL_WHITE_COLOR;
+
+
+		if ( currententity->alpha > 0.33 )
+			d_pdrawspans = R_PolysetDrawSpansConstant8_66;
+		else
+			d_pdrawspans = R_PolysetDrawSpansConstant8_33;
+	}
+	else if ( currententity->flags & RF_TRANSLUCENT )
+	{
+		if ( currententity->alpha > 0.66 )
+			d_pdrawspans = R_PolysetDrawSpans8_Opaque;
+		else if ( currententity->alpha > 0.33 )
+			d_pdrawspans = R_PolysetDrawSpans8_66;
+		else
+			d_pdrawspans = R_PolysetDrawSpans8_33;
+	}
+	else
+	{
+		d_pdrawspans = R_PolysetDrawSpans8_Opaque;
+	}
+
+	/*
+	** compute this_frame and old_frame addresses
+	*/
+	R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
+
+	if (currententity->flags & RF_DEPTHHACK)
+		s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
+	else
+		s_ziscale = (float)0x8000 * (float)0x10000;
+
+	R_AliasPreparePoints ();
+
+	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+	{
+		aliasxscale = -aliasxscale;
+	}
+}
+
+
+
--- /dev/null
+++ b/ref_soft/r_bsp.c
@@ -1,0 +1,637 @@
+/*
+Copyright (C) 1997-2001 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_bsp.c
+
+#include "r_local.h"
+
+//
+// current entity info
+//
+qboolean		insubmodel;
+entity_t		*currententity;
+vec3_t			modelorg;		// modelorg is the viewpoint reletive to
+								// the currently rendering entity
+vec3_t			r_entorigin;	// the currently rendering entity in world
+								// coordinates
+
+float			entity_rotation[3][3];
+
+int				r_currentbkey;
+
+typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
+
+#define MAX_BMODEL_VERTS	500			// 6K
+#define MAX_BMODEL_EDGES	1000		// 12K
+
+static mvertex_t	*pbverts;
+static bedge_t		*pbedges;
+static int			numbverts, numbedges;
+
+static mvertex_t	*pfrontenter, *pfrontexit;
+
+static qboolean		makeclippededge;
+
+
+//===========================================================================
+
+/*
+================
+R_EntityRotate
+================
+*/
+void R_EntityRotate (vec3_t vec)
+{
+	vec3_t	tvec;
+
+	VectorCopy (vec, tvec);
+	vec[0] = DotProduct (entity_rotation[0], tvec);
+	vec[1] = DotProduct (entity_rotation[1], tvec);
+	vec[2] = DotProduct (entity_rotation[2], tvec);
+}
+
+
+/*
+================
+R_RotateBmodel
+================
+*/
+void R_RotateBmodel (void)
+{
+	float	angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
+
+// TODO: should use a look-up table
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: could cache lazily, stored in the entity
+// TODO: share work with R_SetUpAliasTransform
+
+// yaw
+	angle = currententity->angles[YAW];		
+	angle = angle * M_PI*2 / 360;
+	s = sin(angle);
+	c = cos(angle);
+
+	temp1[0][0] = c;
+	temp1[0][1] = s;
+	temp1[0][2] = 0;
+	temp1[1][0] = -s;
+	temp1[1][1] = c;
+	temp1[1][2] = 0;
+	temp1[2][0] = 0;
+	temp1[2][1] = 0;
+	temp1[2][2] = 1;
+
+
+// pitch
+	angle = currententity->angles[PITCH];		
+	angle = angle * M_PI*2 / 360;
+	s = sin(angle);
+	c = cos(angle);
+
+	temp2[0][0] = c;
+	temp2[0][1] = 0;
+	temp2[0][2] = -s;
+	temp2[1][0] = 0;
+	temp2[1][1] = 1;
+	temp2[1][2] = 0;
+	temp2[2][0] = s;
+	temp2[2][1] = 0;
+	temp2[2][2] = c;
+
+	R_ConcatRotations (temp2, temp1, temp3);
+
+// roll
+	angle = currententity->angles[ROLL];		
+	angle = angle * M_PI*2 / 360;
+	s = sin(angle);
+	c = cos(angle);
+
+	temp1[0][0] = 1;
+	temp1[0][1] = 0;
+	temp1[0][2] = 0;
+	temp1[1][0] = 0;
+	temp1[1][1] = c;
+	temp1[1][2] = s;
+	temp1[2][0] = 0;
+	temp1[2][1] = -s;
+	temp1[2][2] = c;
+
+	R_ConcatRotations (temp1, temp3, entity_rotation);
+
+//
+// rotate modelorg and the transformation matrix
+//
+	R_EntityRotate (modelorg);
+	R_EntityRotate (vpn);
+	R_EntityRotate (vright);
+	R_EntityRotate (vup);
+
+	R_TransformFrustum ();
+}
+
+
+/*
+================
+R_RecursiveClipBPoly
+
+Clip a bmodel poly down the world bsp tree
+================
+*/
+void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
+{
+	bedge_t		*psideedges[2], *pnextedge, *ptedge;
+	int			i, side, lastside;
+	float		dist, frac, lastdist;
+	mplane_t	*splitplane, tplane;
+	mvertex_t	*pvert, *plastvert, *ptvert;
+	mnode_t		*pn;
+	int			area;
+
+	psideedges[0] = psideedges[1] = NULL;
+
+	makeclippededge = false;
+
+// transform the BSP plane into model space
+// FIXME: cache these?
+	splitplane = pnode->plane;
+	tplane.dist = splitplane->dist -
+			DotProduct(r_entorigin, splitplane->normal);
+	tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
+	tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
+	tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
+
+// clip edges to BSP plane
+	for ( ; pedges ; pedges = pnextedge)
+	{
+		pnextedge = pedges->pnext;
+
+	// set the status for the last point as the previous point
+	// FIXME: cache this stuff somehow?
+		plastvert = pedges->v[0];
+		lastdist = DotProduct (plastvert->position, tplane.normal) -
+				   tplane.dist;
+
+		if (lastdist > 0)
+			lastside = 0;
+		else
+			lastside = 1;
+
+		pvert = pedges->v[1];
+
+		dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
+
+		if (dist > 0)
+			side = 0;
+		else
+			side = 1;
+
+		if (side != lastside)
+		{
+		// clipped
+			if (numbverts >= MAX_BMODEL_VERTS)
+				return;
+
+		// generate the clipped vertex
+			frac = lastdist / (lastdist - dist);
+			ptvert = &pbverts[numbverts++];
+			ptvert->position[0] = plastvert->position[0] +
+					frac * (pvert->position[0] -
+					plastvert->position[0]);
+			ptvert->position[1] = plastvert->position[1] +
+					frac * (pvert->position[1] -
+					plastvert->position[1]);
+			ptvert->position[2] = plastvert->position[2] +
+					frac * (pvert->position[2] -
+					plastvert->position[2]);
+
+		// split into two edges, one on each side, and remember entering
+		// and exiting points
+		// FIXME: share the clip edge by having a winding direction flag?
+			if (numbedges >= (MAX_BMODEL_EDGES - 1))
+			{
+				ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
+				return;
+			}
+
+			ptedge = &pbedges[numbedges];
+			ptedge->pnext = psideedges[lastside];
+			psideedges[lastside] = ptedge;
+			ptedge->v[0] = plastvert;
+			ptedge->v[1] = ptvert;
+
+			ptedge = &pbedges[numbedges + 1];
+			ptedge->pnext = psideedges[side];
+			psideedges[side] = ptedge;
+			ptedge->v[0] = ptvert;
+			ptedge->v[1] = pvert;
+
+			numbedges += 2;
+
+			if (side == 0)
+			{
+			// entering for front, exiting for back
+				pfrontenter = ptvert;
+				makeclippededge = true;
+			}
+			else
+			{
+				pfrontexit = ptvert;
+				makeclippededge = true;
+			}
+		}
+		else
+		{
+		// add the edge to the appropriate side
+			pedges->pnext = psideedges[side];
+			psideedges[side] = pedges;
+		}
+	}
+
+// if anything was clipped, reconstitute and add the edges along the clip
+// plane to both sides (but in opposite directions)
+	if (makeclippededge)
+	{
+		if (numbedges >= (MAX_BMODEL_EDGES - 2))
+		{
+			ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
+			return;
+		}
+
+		ptedge = &pbedges[numbedges];
+		ptedge->pnext = psideedges[0];
+		psideedges[0] = ptedge;
+		ptedge->v[0] = pfrontexit;
+		ptedge->v[1] = pfrontenter;
+
+		ptedge = &pbedges[numbedges + 1];
+		ptedge->pnext = psideedges[1];
+		psideedges[1] = ptedge;
+		ptedge->v[0] = pfrontenter;
+		ptedge->v[1] = pfrontexit;
+
+		numbedges += 2;
+	}
+
+// draw or recurse further
+	for (i=0 ; i<2 ; i++)
+	{
+		if (psideedges[i])
+		{
+		// draw if we've reached a non-solid leaf, done if all that's left is a
+		// solid leaf, and continue down the tree if it's not a leaf
+			pn = pnode->children[i];
+
+		// we're done with this branch if the node or leaf isn't in the PVS
+			if (pn->visframe == r_visframecount)
+			{
+				if (pn->contents != CONTENTS_NODE)
+				{
+					if (pn->contents != CONTENTS_SOLID)
+					{
+						if (r_newrefdef.areabits)
+						{
+							area = ((mleaf_t *)pn)->area;
+							if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
+								continue;		// not visible
+						}
+
+						r_currentbkey = ((mleaf_t *)pn)->key;
+						R_RenderBmodelFace (psideedges[i], psurf);
+					}
+				}
+				else
+				{
+					R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
+									  psurf);
+				}
+			}
+		}
+	}
+}
+
+
+/*
+================
+R_DrawSolidClippedSubmodelPolygons
+
+Bmodel crosses multiple leafs
+================
+*/
+void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
+{
+	int			i, j, lindex;
+	vec_t		dot;
+	msurface_t	*psurf;
+	int			numsurfaces;
+	mplane_t	*pplane;
+	mvertex_t	bverts[MAX_BMODEL_VERTS];
+	bedge_t		bedges[MAX_BMODEL_EDGES], *pbedge;
+	medge_t		*pedge, *pedges;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+	numsurfaces = pmodel->nummodelsurfaces;
+	pedges = pmodel->edges;
+
+	for (i=0 ; i<numsurfaces ; 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)))
+			continue;
+
+	// FIXME: use bounding-box-based frustum clipping info?
+
+	// copy the edges to bedges, flipping if necessary so always
+	// clockwise winding
+	// FIXME: if edges and vertices get caches, these assignments must move
+	// outside the loop, and overflow checking must be done here
+		pbverts = bverts;
+		pbedges = bedges;
+		numbverts = numbedges = 0;
+		pbedge = &bedges[numbedges];
+		numbedges += psurf->numedges;
+
+		for (j=0 ; j<psurf->numedges ; j++)
+		{
+		   lindex = pmodel->surfedges[psurf->firstedge+j];
+
+			if (lindex > 0)
+			{
+				pedge = &pedges[lindex];
+				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
+				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
+			}
+			else
+			{
+				lindex = -lindex;
+				pedge = &pedges[lindex];
+				pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
+				pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
+			}
+
+			pbedge[j].pnext = &pbedge[j+1];
+		}
+
+		pbedge[j-1].pnext = NULL;	// mark end of edges
+
+		if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
+			R_RecursiveClipBPoly (pbedge, topnode, psurf);
+		else
+			R_RenderBmodelFace( pbedge, psurf );
+	}
+}
+
+
+/*
+================
+R_DrawSubmodelPolygons
+
+All in one leaf
+================
+*/
+void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
+{
+	int			i;
+	vec_t		dot;
+	msurface_t	*psurf;
+	int			numsurfaces;
+	mplane_t	*pplane;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+	numsurfaces = pmodel->nummodelsurfaces;
+
+	for (i=0 ; i<numsurfaces ; 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)))
+		{
+			r_currentkey = ((mleaf_t *)topnode)->key;
+
+		// FIXME: use bounding-box-based frustum clipping info?
+			R_RenderFace (psurf, clipflags);
+		}
+	}
+}
+
+
+int c_drawnode;
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+void R_RecursiveWorldNode (mnode_t *node, int clipflags)
+{
+	int			i, c, side, *pindex;
+	vec3_t		acceptpt, rejectpt;
+	mplane_t	*plane;
+	msurface_t	*surf, **mark;
+	float		d, dot;
+	mleaf_t		*pleaf;
+
+	if (node->contents == CONTENTS_SOLID)
+		return;		// solid
+
+	if (node->visframe != r_visframecount)
+		return;
+
+// cull the clipping planes if not trivial accept
+// FIXME: the compiler is doing a lousy job of optimizing here; it could be
+//  twice as fast in ASM
+	if (clipflags)
+	{
+		for (i=0 ; i<4 ; i++)
+		{
+			if (! (clipflags & (1<<i)) )
+				continue;	// don't need to clip against it
+
+		// generate accept and reject points
+		// FIXME: do with fast look-ups or integer tests based on the sign bit
+		// of the floating point values
+
+			pindex = pfrustum_indexes[i];
+
+			rejectpt[0] = (float)node->minmaxs[pindex[0]];
+			rejectpt[1] = (float)node->minmaxs[pindex[1]];
+			rejectpt[2] = (float)node->minmaxs[pindex[2]];
+			
+			d = DotProduct (rejectpt, view_clipplanes[i].normal);
+			d -= view_clipplanes[i].dist;
+			if (d <= 0)
+				return;
+			acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
+			acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
+			acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
+
+			d = DotProduct (acceptpt, view_clipplanes[i].normal);
+			d -= view_clipplanes[i].dist;
+
+			if (d >= 0)
+				clipflags &= ~(1<<i);	// node is entirely on screen
+		}
+	}
+
+c_drawnode++;
+
+// if a leaf node, draw stuff
+	if (node->contents != -1)
+	{
+		pleaf = (mleaf_t *)node;
+
+		// check for door connected areas
+		if (r_newrefdef.areabits)
+		{
+			if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
+				return;		// not visible
+		}
+
+		mark = pleaf->firstmarksurface;
+		c = pleaf->nummarksurfaces;
+
+		if (c)
+		{
+			do
+			{
+				(*mark)->visframe = r_framecount;
+				mark++;
+			} while (--c);
+		}
+
+		pleaf->key = r_currentkey;
+		r_currentkey++;		// all bmodels in a leaf share the same key
+	}
+	else
+	{
+	// 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], clipflags);
+
+	// draw stuff
+		c = node->numsurfaces;
+
+		if (c)
+		{
+			surf = r_worldmodel->surfaces + node->firstsurface;
+
+			if (dot < -BACKFACE_EPSILON)
+			{
+				do
+				{
+					if ((surf->flags & SURF_PLANEBACK) &&
+						(surf->visframe == r_framecount))
+					{
+						R_RenderFace (surf, clipflags);
+					}
+
+					surf++;
+				} while (--c);
+			}
+			else if (dot > BACKFACE_EPSILON)
+			{
+				do
+				{
+					if (!(surf->flags & SURF_PLANEBACK) &&
+						(surf->visframe == r_framecount))
+					{
+						R_RenderFace (surf, clipflags);
+					}
+
+					surf++;
+				} while (--c);
+			}
+
+		// all surfaces on the same node share the same sequence number
+			r_currentkey++;
+		}
+
+	// recurse down the back side
+		R_RecursiveWorldNode (node->children[!side], clipflags);
+	}
+}
+
+
+
+/*
+================
+R_RenderWorld
+================
+*/
+void R_RenderWorld (void)
+{
+
+	if (!r_drawworld->value)
+		return;
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+		return;
+
+	c_drawnode=0;
+
+	// auto cycle the world frame for texture animation
+	r_worldentity.frame = (int)(r_newrefdef.time*2);
+	currententity = &r_worldentity;
+
+	VectorCopy (r_origin, modelorg);
+	currentmodel = r_worldmodel;
+	r_pcurrentvertbase = currentmodel->vertexes;
+
+	R_RecursiveWorldNode (currentmodel->nodes, 15);
+}
+
+
--- /dev/null
+++ b/ref_soft/r_draw.c
@@ -1,0 +1,445 @@
+/*
+Copyright (C) 1997-2001 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
+
+#include "r_local.h"
+
+
+image_t		*draw_chars;				// 8*8 graphic characters
+
+//=============================================================================
+
+/*
+================
+Draw_FindPic
+================
+*/
+image_t *Draw_FindPic (char *name)
+{
+	image_t	*image;
+	char	fullname[MAX_QPATH];
+
+	if (name[0] != '/' && name[0] != '\\')
+	{
+		Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
+		image = R_FindImage (fullname, it_pic);
+	}
+	else
+		image = R_FindImage (name+1, it_pic);
+
+	return image;
+}
+
+
+
+/*
+===============
+Draw_InitLocal
+===============
+*/
+void Draw_InitLocal (void)
+{
+	draw_chars = Draw_FindPic ("conchars");
+}
+
+
+
+/*
+================
+Draw_Char
+
+Draws one 8*8 graphics character
+It can be clipped to the top of the screen to allow the console to be
+smoothly scrolled off.
+================
+*/
+void Draw_Char (int x, int y, int num)
+{
+	byte			*dest;
+	byte			*source;
+	int				drawline;	
+	int				row, col;
+
+	num &= 255;
+
+	if (num == 32 || num == 32+128)
+		return;
+
+	if (y <= -8)
+		return;			// totally off screen
+
+//	if ( ( y + 8 ) >= vid.height )
+	if ( ( y + 8 ) > vid.height )		// PGM - status text was missing in sw...
+		return;
+
+#ifdef PARANOID
+	if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
+		ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: (%i, %i)", x, y);
+	if (num < 0 || num > 255)
+		ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: char %i", num);
+#endif
+
+	row = num>>4;
+	col = num&15;
+	source = draw_chars->pixels[0] + (row<<10) + (col<<3);
+
+	if (y < 0)
+	{	// clipped
+		drawline = 8 + y;
+		source -= 128*y;
+		y = 0;
+	}
+	else
+		drawline = 8;
+
+
+	dest = vid.buffer + y*vid.rowbytes + x;
+
+	while (drawline--)
+	{
+		if (source[0] != TRANSPARENT_COLOR)
+			dest[0] = source[0];
+		if (source[1] != TRANSPARENT_COLOR)
+			dest[1] = source[1];
+		if (source[2] != TRANSPARENT_COLOR)
+			dest[2] = source[2];
+		if (source[3] != TRANSPARENT_COLOR)
+			dest[3] = source[3];
+		if (source[4] != TRANSPARENT_COLOR)
+			dest[4] = source[4];
+		if (source[5] != TRANSPARENT_COLOR)
+			dest[5] = source[5];
+		if (source[6] != TRANSPARENT_COLOR)
+			dest[6] = source[6];
+		if (source[7] != TRANSPARENT_COLOR)
+			dest[7] = source[7];
+		source += 128;
+		dest += vid.rowbytes;
+	}
+}
+
+/*
+=============
+Draw_GetPicSize
+=============
+*/
+void Draw_GetPicSize (int *w, int *h, char *pic)
+{
+	image_t *gl;
+
+	gl = Draw_FindPic (pic);
+	if (!gl)
+	{
+		*w = *h = -1;
+		return;
+	}
+	*w = gl->width;
+	*h = gl->height;
+}
+
+/*
+=============
+Draw_StretchPicImplementation
+=============
+*/
+void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t	*pic)
+{
+	byte			*dest, *source;
+	int				v, u, sv;
+	int				height;
+	int				f, fstep;
+	int				skip;
+
+	if ((x < 0) ||
+		(x + w > vid.width) ||
+		(y + h > vid.height))
+	{
+		ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
+	}
+
+	height = h;
+	if (y < 0)
+	{
+		skip = -y;
+		height += y;
+		y = 0;
+	}
+	else
+		skip = 0;
+
+	dest = vid.buffer + y * vid.rowbytes + x;
+
+	for (v=0 ; v<height ; v++, dest += vid.rowbytes)
+	{
+		sv = (skip + v)*pic->height/h;
+		source = pic->pixels[0] + sv*pic->width;
+		if (w == pic->width)
+			memcpy (dest, source, w);
+		else
+		{
+			f = 0;
+			fstep = pic->width*0x10000/w;
+			for (u=0 ; u<w ; u+=4)
+			{
+				dest[u] = source[f>>16];
+				f += fstep;
+				dest[u+1] = source[f>>16];
+				f += fstep;
+				dest[u+2] = source[f>>16];
+				f += fstep;
+				dest[u+3] = source[f>>16];
+				f += fstep;
+			}
+		}
+	}
+}
+
+/*
+=============
+Draw_StretchPic
+=============
+*/
+void Draw_StretchPic (int x, int y, int w, int h, char *name)
+{
+	image_t	*pic;
+
+	pic = Draw_FindPic (name);
+	if (!pic)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+		return;
+	}
+	Draw_StretchPicImplementation (x, y, w, h, pic);
+}
+
+/*
+=============
+Draw_StretchRaw
+=============
+*/
+void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
+{
+	image_t	pic;
+
+	pic.pixels[0] = data;
+	pic.width = cols;
+	pic.height = rows;
+	Draw_StretchPicImplementation (x, y, w, h, &pic);
+}
+
+/*
+=============
+Draw_Pic
+=============
+*/
+void Draw_Pic (int x, int y, char *name)
+{
+	image_t			*pic;
+	byte			*dest, *source;
+	int				v, u;
+	int				tbyte;
+	int				height;
+
+	pic = Draw_FindPic (name);
+	if (!pic)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+		return;
+	}
+
+	if ((x < 0) ||
+		(x + pic->width > vid.width) ||
+		(y + pic->height > vid.height))
+		return;	//	ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
+
+	height = pic->height;
+	source = pic->pixels[0];
+	if (y < 0)
+	{
+		height += y;
+		source += pic->width*-y;
+		y = 0;
+	}
+
+	dest = vid.buffer + y * vid.rowbytes + x;
+
+	if (!pic->transparent)
+	{
+		for (v=0 ; v<height ; v++)
+		{
+			memcpy (dest, source, pic->width);
+			dest += vid.rowbytes;
+			source += pic->width;
+		}
+	}
+	else
+	{
+		if (pic->width & 7)
+		{	// general
+			for (v=0 ; v<height ; v++)
+			{
+				for (u=0 ; u<pic->width ; u++)
+					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
+						dest[u] = tbyte;
+
+				dest += vid.rowbytes;
+				source += pic->width;
+			}
+		}
+		else
+		{	// unwound
+			for (v=0 ; v<height ; v++)
+			{
+				for (u=0 ; u<pic->width ; u+=8)
+				{
+					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
+						dest[u] = tbyte;
+					if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
+						dest[u+1] = tbyte;
+					if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
+						dest[u+2] = tbyte;
+					if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
+						dest[u+3] = tbyte;
+					if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
+						dest[u+4] = tbyte;
+					if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
+						dest[u+5] = tbyte;
+					if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
+						dest[u+6] = tbyte;
+					if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
+						dest[u+7] = tbyte;
+				}
+				dest += vid.rowbytes;
+				source += pic->width;
+			}
+		}
+	}
+}
+
+/*
+=============
+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, char *name)
+{
+	int			i, j;
+	byte		*psrc;
+	byte		*pdest;
+	image_t		*pic;
+	int			x2;
+
+	if (x < 0)
+	{
+		w += x;
+		x = 0;
+	}
+	if (y < 0)
+	{
+		h += y;
+		y = 0;
+	}
+	if (x + w > vid.width)
+		w = vid.width - x;
+	if (y + h > vid.height)
+		h = vid.height - y;
+	if (w <= 0 || h <= 0)
+		return;
+
+	pic = Draw_FindPic (name);
+	if (!pic)
+	{
+		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+		return;
+	}
+	x2 = x + w;
+	pdest = vid.buffer + y*vid.rowbytes;
+	for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
+	{
+		psrc = pic->pixels[0] + pic->width * ((i+y)&63);
+		for (j=x ; j<x2 ; j++)
+			pdest[j] = psrc[j&63];
+	}
+}
+
+
+/*
+=============
+Draw_Fill
+
+Fills a box of pixels with a single color
+=============
+*/
+void Draw_Fill (int x, int y, int w, int h, int c)
+{
+	byte			*dest;
+	int				u, v;
+
+	if (x+w > vid.width)
+		w = vid.width - x;
+	if (y+h > vid.height)
+		h = vid.height - y;
+	if (x < 0)
+	{
+		w += x;
+		x = 0;
+	}
+	if (y < 0)
+	{
+		h += y;
+		y = 0;
+	}
+	if (w < 0 || h < 0)
+		return;
+	dest = vid.buffer + y*vid.rowbytes + x;
+	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
+		for (u=0 ; u<w ; u++)
+			dest[u] = c;
+}
+//=============================================================================
+
+/*
+================
+Draw_FadeScreen
+
+================
+*/
+void Draw_FadeScreen (void)
+{
+	int			x,y;
+	byte		*pbuf;
+	int	t;
+
+	for (y=0 ; y<vid.height ; y++)
+	{
+		pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
+		t = (y & 1) << 1;
+
+		for (x=0 ; x<vid.width ; x++)
+		{
+			if ((x & 3) != t)
+				pbuf[x] = 0;
+		}
+	}
+}
--- /dev/null
+++ b/ref_soft/r_draw16.asm
@@ -1,0 +1,1234 @@
+ .386P
+ .model FLAT
+;
+; d_draw16.s
+; x86 assembly-language horizontal 8-bpp span-drawing code, with 16-pixel
+; subdivision.
+;
+
+include qasm.inc
+include d_if.inc
+
+if	id386
+
+;----------------------------------------------------------------------
+; 8-bpp horizontal span drawing code for polygons, with no transparency and
+; 16-pixel subdivision.
+;
+; Assumes there is at least one span in pspans, and that every span
+; contains at least one pixel
+;----------------------------------------------------------------------
+
+_DATA SEGMENT	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+; out-of-line, rarely-needed clamping code
+
+LClampHigh0:	
+ mov esi,ds:dword ptr[_bbextents]	
+ jmp LClampReentry0	
+LClampHighOrLow0:	
+ jg LClampHigh0	
+ xor esi,esi	
+ jmp LClampReentry0	
+
+LClampHigh1:	
+ mov edx,ds:dword ptr[_bbextentt]	
+ jmp LClampReentry1	
+LClampHighOrLow1:	
+ jg LClampHigh1	
+ xor edx,edx	
+ jmp LClampReentry1	
+
+LClampLow2:	
+ mov ebp,4096	
+ jmp LClampReentry2	
+LClampHigh2:	
+ mov ebp,ds:dword ptr[_bbextents]	
+ jmp LClampReentry2	
+
+LClampLow3:	
+ mov ecx,4096	
+ jmp LClampReentry3	
+LClampHigh3:	
+ mov ecx,ds:dword ptr[_bbextentt]	
+ jmp LClampReentry3	
+
+LClampLow4:	
+ mov eax,4096	
+ jmp LClampReentry4	
+LClampHigh4:	
+ mov eax,ds:dword ptr[_bbextents]	
+ jmp LClampReentry4	
+
+LClampLow5:	
+ mov ebx,4096	
+ jmp LClampReentry5	
+LClampHigh5:	
+ mov ebx,ds:dword ptr[_bbextentt]	
+ jmp LClampReentry5	
+
+
+pspans	equ		4+16
+
+ align 4	
+ public _D_DrawSpans16	
+_D_DrawSpans16:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+;
+; set up scaled-by-16 steps, for 16-long segments; also set up cacheblock
+; and span list pointers
+;
+; TODO: any overlap from rearranging?
+ fld ds:dword ptr[_d_sdivzstepu]	
+ fmul ds:dword ptr[fp_16]	
+ mov edx,ds:dword ptr[_cacheblock]	
+ fld ds:dword ptr[_d_tdivzstepu]	
+ fmul ds:dword ptr[fp_16]	
+ mov ebx,ds:dword ptr[pspans+esp]	; point to the first span descriptor
+ fld ds:dword ptr[_d_zistepu]	
+ fmul ds:dword ptr[fp_16]	
+ mov ds:dword ptr[pbase],edx	; pbase = cacheblock
+ fstp ds:dword ptr[zi16stepu]	
+ fstp ds:dword ptr[tdivz16stepu]	
+ fstp ds:dword ptr[sdivz16stepu]	
+
+LSpanLoop:	
+;
+; set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
+; initial s and t values
+;
+; FIXME: pipeline FILD?
+ fild ds:dword ptr[espan_t_v+ebx]	
+ fild ds:dword ptr[espan_t_u+ebx]	
+
+ fld st(1)	; dv | du | dv
+ fmul ds:dword ptr[_d_sdivzstepv]	; dv*d_sdivzstepv | du | dv
+ fld st(1)	; du | dv*d_sdivzstepv | du | dv
+ fmul ds:dword ptr[_d_sdivzstepu]	; du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+ fld st(2)	; du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+ fmul ds:dword ptr[_d_tdivzstepu]	; du*d_tdivzstepu | du*d_sdivzstepu |
+;  dv*d_sdivzstepv | du | dv
+ fxch st(1)	; du*d_sdivzstepu | du*d_tdivzstepu |
+;  dv*d_sdivzstepv | du | dv
+ faddp st(2),st(0)	; du*d_tdivzstepu |
+;  du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
+ fxch st(1)	; du*d_sdivzstepu + dv*d_sdivzstepv |
+;  du*d_tdivzstepu | du | dv
+ fld st(3)	; dv | du*d_sdivzstepu + dv*d_sdivzstepv |
+;  du*d_tdivzstepu | du | dv
+ fmul ds:dword ptr[_d_tdivzstepv]	; dv*d_tdivzstepv |
+;  du*d_sdivzstepu + dv*d_sdivzstepv |
+;  du*d_tdivzstepu | du | dv
+ fxch st(1)	; du*d_sdivzstepu + dv*d_sdivzstepv |
+;  dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
+ fadd ds:dword ptr[_d_sdivzorigin]	; sdivz = d_sdivzorigin + dv*d_sdivzstepv +
+;  du*d_sdivzstepu; stays in %st(2) at end
+ fxch st(4)	; dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
+;  s/z
+ fmul ds:dword ptr[_d_zistepv]	; dv*d_zistepv | dv*d_tdivzstepv |
+;  du*d_tdivzstepu | du | s/z
+ fxch st(1)	; dv*d_tdivzstepv |  dv*d_zistepv |
+;  du*d_tdivzstepu | du | s/z
+ faddp st(2),st(0)	; dv*d_zistepv |
+;  dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
+ fxch st(2)	; du | dv*d_tdivzstepv + du*d_tdivzstepu |
+;  dv*d_zistepv | s/z
+ fmul ds:dword ptr[_d_zistepu]	; du*d_zistepu |
+;  dv*d_tdivzstepv + du*d_tdivzstepu |
+;  dv*d_zistepv | s/z
+ fxch st(1)	; dv*d_tdivzstepv + du*d_tdivzstepu |
+;  du*d_zistepu | dv*d_zistepv | s/z
+ fadd ds:dword ptr[_d_tdivzorigin]	; tdivz = d_tdivzorigin + dv*d_tdivzstepv +
+;  du*d_tdivzstepu; stays in %st(1) at end
+ fxch st(2)	; dv*d_zistepv | du*d_zistepu | t/z | s/z
+ faddp st(1),st(0)	; dv*d_zistepv + du*d_zistepu | t/z | s/z
+
+ fld ds:dword ptr[fp_64k]	; fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
+ fxch st(1)	; dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
+ fadd ds:dword ptr[_d_ziorigin]	; zi = d_ziorigin + dv*d_zistepv +
+;  du*d_zistepu; stays in %st(0) at end
+; 1/z | fp_64k | t/z | s/z
+;
+; calculate and clamp s & t
+;
+ fdiv st(1),st(0)	; 1/z | z*64k | t/z | s/z
+
+;
+; point %edi to the first pixel in the span
+;
+ mov ecx,ds:dword ptr[_d_viewbuffer]	
+ mov eax,ds:dword ptr[espan_t_v+ebx]	
+ mov ds:dword ptr[pspantemp],ebx	; preserve spans pointer
+
+ mov edx,ds:dword ptr[_tadjust]	
+ mov esi,ds:dword ptr[_sadjust]	
+ mov edi,ds:dword ptr[_d_scantable+eax*4]	; v * screenwidth
+ add edi,ecx	
+ mov ecx,ds:dword ptr[espan_t_u+ebx]	
+ add edi,ecx	; pdest = &pdestspan[scans->u];
+ mov ecx,ds:dword ptr[espan_t_count+ebx]	
+
+;
+; now start the FDIV for the end of the span
+;
+ cmp ecx,16	
+ ja LSetupNotLast1	
+
+ dec ecx	
+ jz LCleanup1	; if only one pixel, no need to start an FDIV
+ mov ds:dword ptr[spancountminus1],ecx	
+
+; finish up the s and t calcs
+ fxch st(1)	; z*64k | 1/z | t/z | s/z
+
+ fld st(0)	; z*64k | z*64k | 1/z | t/z | s/z
+ fmul st(0),st(4)	; s | z*64k | 1/z | t/z | s/z
+ fxch st(1)	; z*64k | s | 1/z | t/z | s/z
+ fmul st(0),st(3)	; t | s | 1/z | t/z | s/z
+ fxch st(1)	; s | t | 1/z | t/z | s/z
+ fistp ds:dword ptr[s]	; 1/z | t | t/z | s/z
+ fistp ds:dword ptr[t]	; 1/z | t/z | s/z
+
+ fild ds:dword ptr[spancountminus1]	
+
+ fld ds:dword ptr[_d_tdivzstepu]	; C(d_tdivzstepu) | spancountminus1
+ fld ds:dword ptr[_d_zistepu]	; C(d_zistepu) | C(d_tdivzstepu) | spancountminus1
+ fmul st(0),st(2)	; C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1
+ fxch st(1)	; C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1
+ fmul st(0),st(2)	; C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1
+ fxch st(2)	; scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1
+ fmul ds:dword ptr[_d_sdivzstepu]	; C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 |
+;  C(d_tdivzstepu)*scm1
+ fxch st(1)	; C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 |
+;  C(d_tdivzstepu)*scm1
+ faddp st(3),st(0)	; C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1
+ fxch st(1)	; C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1
+ faddp st(3),st(0)	; C(d_sdivzstepu)*scm1
+ faddp st(3),st(0)	
+
+ fld ds:dword ptr[fp_64k]	
+ fdiv st(0),st(1)	; this is what we've gone to all this trouble to
+;  overlap
+ jmp LFDIVInFlight1	
+
+LCleanup1:	
+; finish up the s and t calcs
+ fxch st(1)	; z*64k | 1/z | t/z | s/z
+
+ fld st(0)	; z*64k | z*64k | 1/z | t/z | s/z
+ fmul st(0),st(4)	; s | z*64k | 1/z | t/z | s/z
+ fxch st(1)	; z*64k | s | 1/z | t/z | s/z
+ fmul st(0),st(3)	; t | s | 1/z | t/z | s/z
+ fxch st(1)	; s | t | 1/z | t/z | s/z
+ fistp ds:dword ptr[s]	; 1/z | t | t/z | s/z
+ fistp ds:dword ptr[t]	; 1/z | t/z | s/z
+ jmp LFDIVInFlight1	
+
+ align 4	
+LSetupNotLast1:	
+; finish up the s and t calcs
+ fxch st(1)	; z*64k | 1/z | t/z | s/z
+
+ fld st(0)	; z*64k | z*64k | 1/z | t/z | s/z
+ fmul st(0),st(4)	; s | z*64k | 1/z | t/z | s/z
+ fxch st(1)	; z*64k | s | 1/z | t/z | s/z
+ fmul st(0),st(3)	; t | s | 1/z | t/z | s/z
+ fxch st(1)	; s | t | 1/z | t/z | s/z
+ fistp ds:dword ptr[s]	; 1/z | t | t/z | s/z
+ fistp ds:dword ptr[t]	; 1/z | t/z | s/z
+
+ fadd ds:dword ptr[zi16stepu]	
+ fxch st(2)	
+ fadd ds:dword ptr[sdivz16stepu]	
+ fxch st(2)	
+ fld ds:dword ptr[tdivz16stepu]	
+ faddp st(2),st(0)	
+ fld ds:dword ptr[fp_64k]	
+ fdiv st(0),st(1)	; z = 1/1/z
+; this is what we've gone to all this trouble to
+;  overlap
+LFDIVInFlight1:	
+
+ add esi,ds:dword ptr[s]	
+ add edx,ds:dword ptr[t]	
+ mov ebx,ds:dword ptr[_bbextents]	
+ mov ebp,ds:dword ptr[_bbextentt]	
+ cmp esi,ebx	
+ ja LClampHighOrLow0	
+LClampReentry0:	
+ mov ds:dword ptr[s],esi	
+ mov ebx,ds:dword ptr[pbase]	
+ shl esi,16	
+ cmp edx,ebp	
+ mov ds:dword ptr[sfracf],esi	
+ ja LClampHighOrLow1	
+LClampReentry1:	
+ mov ds:dword ptr[t],edx	
+ mov esi,ds:dword ptr[s]	; sfrac = scans->sfrac;
+ shl edx,16	
+ mov eax,ds:dword ptr[t]	; tfrac = scans->tfrac;
+ sar esi,16	
+ mov ds:dword ptr[tfracf],edx	
+
+;
+; calculate the texture starting address
+;
+ sar eax,16	
+ mov edx,ds:dword ptr[_cachewidth]	
+ imul eax,edx	; (tfrac >> 16) * cachewidth
+ add esi,ebx	
+ add esi,eax	; psource = pbase + (sfrac >> 16) +
+;           ((tfrac >> 16) * cachewidth);
+;
+; determine whether last span or not
+;
+ cmp ecx,16	
+ jna LLastSegment	
+
+;
+; not the last segment; do full 16-wide segment
+;
+LNotLastSegment:	
+
+;
+; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+; get there
+;
+
+; pick up after the FDIV that was left in flight previously
+
+ fld st(0)	; duplicate it
+ fmul st(0),st(4)	; s = s/z * z
+ fxch st(1)	
+ fmul st(0),st(3)	; t = t/z * z
+ fxch st(1)	
+ fistp ds:dword ptr[snext]	
+ fistp ds:dword ptr[tnext]	
+ mov eax,ds:dword ptr[snext]	
+ mov edx,ds:dword ptr[tnext]	
+
+ mov bl,ds:byte ptr[esi]	; get first source texel
+ sub ecx,16	; count off this segments' pixels
+ mov ebp,ds:dword ptr[_sadjust]	
+ mov ds:dword ptr[counttemp],ecx	; remember count of remaining pixels
+
+ mov ecx,ds:dword ptr[_tadjust]	
+ mov ds:byte ptr[edi],bl	; store first dest pixel
+
+ add ebp,eax	
+ add ecx,edx	
+
+ mov eax,ds:dword ptr[_bbextents]	
+ mov edx,ds:dword ptr[_bbextentt]	
+
+ cmp ebp,4096	
+ jl LClampLow2	
+ cmp ebp,eax	
+ ja LClampHigh2	
+LClampReentry2:	
+
+ cmp ecx,4096	
+ jl LClampLow3	
+ cmp ecx,edx	
+ ja LClampHigh3	
+LClampReentry3:	
+
+ mov ds:dword ptr[snext],ebp	
+ mov ds:dword ptr[tnext],ecx	
+
+ sub ebp,ds:dword ptr[s]	
+ sub ecx,ds:dword ptr[t]	
+
+;
+; set up advancetable
+;
+ mov eax,ecx	
+ mov edx,ebp	
+ sar eax,20	; tstep >>= 16;
+ jz LZero	
+ sar edx,20	; sstep >>= 16;
+ mov ebx,ds:dword ptr[_cachewidth]	
+ imul eax,ebx	
+ jmp LSetUp1	
+
+LZero:	
+ sar edx,20	; sstep >>= 16;
+ mov ebx,ds:dword ptr[_cachewidth]	
+
+LSetUp1:	
+
+ add eax,edx	; add in sstep
+; (tstep >> 16) * cachewidth + (sstep >> 16);
+ mov edx,ds:dword ptr[tfracf]	
+ mov ds:dword ptr[advancetable+4],eax	; advance base in t
+ add eax,ebx	; ((tstep >> 16) + 1) * cachewidth +
+;  (sstep >> 16);
+ shl ebp,12	; left-justify sstep fractional part
+ mov ebx,ds:dword ptr[sfracf]	
+ shl ecx,12	; left-justify tstep fractional part
+ mov ds:dword ptr[advancetable],eax	; advance extra in t
+
+ mov ds:dword ptr[tstep],ecx	
+ add edx,ecx	; advance tfrac fractional part by tstep frac
+
+ sbb ecx,ecx	; turn tstep carry into -1 (0 if none)
+ add ebx,ebp	; advance sfrac fractional part by sstep frac
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	; point to next source texel
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov al,ds:byte ptr[esi]	
+ add ebx,ebp	
+ mov ds:byte ptr[1+edi],al	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[2+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[3+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[4+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[5+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[6+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[7+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+
+;
+; start FDIV for end of next segment in flight, so it can overlap
+;
+ mov ecx,ds:dword ptr[counttemp]	
+ cmp ecx,16	; more than one segment after this?
+ ja LSetupNotLast2	; yes
+
+ dec ecx	
+ jz LFDIVInFlight2	; if only one pixel, no need to start an FDIV
+ mov ds:dword ptr[spancountminus1],ecx	
+ fild ds:dword ptr[spancountminus1]	
+
+ fld ds:dword ptr[_d_zistepu]	; C(d_zistepu) | spancountminus1
+ fmul st(0),st(1)	; C(d_zistepu)*scm1 | scm1
+ fld ds:dword ptr[_d_tdivzstepu]	; C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1
+ fmul st(0),st(2)	; C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1
+ fxch st(1)	; C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1
+ faddp st(3),st(0)	; C(d_tdivzstepu)*scm1 | scm1
+ fxch st(1)	; scm1 | C(d_tdivzstepu)*scm1
+ fmul ds:dword ptr[_d_sdivzstepu]	; C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1
+ fxch st(1)	; C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1
+ faddp st(3),st(0)	; C(d_sdivzstepu)*scm1
+ fld ds:dword ptr[fp_64k]	; 64k | C(d_sdivzstepu)*scm1
+ fxch st(1)	; C(d_sdivzstepu)*scm1 | 64k
+ faddp st(4),st(0)	; 64k
+
+ fdiv st(0),st(1)	; this is what we've gone to all this trouble to
+;  overlap
+ jmp LFDIVInFlight2	
+
+ align 4	
+LSetupNotLast2:	
+ fadd ds:dword ptr[zi16stepu]	
+ fxch st(2)	
+ fadd ds:dword ptr[sdivz16stepu]	
+ fxch st(2)	
+ fld ds:dword ptr[tdivz16stepu]	
+ faddp st(2),st(0)	
+ fld ds:dword ptr[fp_64k]	
+ fdiv st(0),st(1)	; z = 1/1/z
+; this is what we've gone to all this trouble to
+;  overlap
+LFDIVInFlight2:	
+ mov ds:dword ptr[counttemp],ecx	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[8+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[9+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[10+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[11+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[12+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[13+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[14+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edi,16	
+ mov ds:dword ptr[tfracf],edx	
+ mov edx,ds:dword ptr[snext]	
+ mov ds:dword ptr[sfracf],ebx	
+ mov ebx,ds:dword ptr[tnext]	
+ mov ds:dword ptr[s],edx	
+ mov ds:dword ptr[t],ebx	
+
+ mov ecx,ds:dword ptr[counttemp]	; retrieve count
+
+;
+; determine whether last span or not
+;
+ cmp ecx,16	; are there multiple segments remaining?
+ mov ds:byte ptr[-1+edi],al	
+ ja LNotLastSegment	; yes
+
+;
+; last segment of scan
+;
+LLastSegment:	
+
+;
+; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+; get there. The number of pixels left is variable, and we want to land on the
+; last pixel, not step one past it, so we can't run into arithmetic problems
+;
+ test ecx,ecx	
+ jz LNoSteps	; just draw the last pixel and we're done
+
+; pick up after the FDIV that was left in flight previously
+
+
+ fld st(0)	; duplicate it
+ fmul st(0),st(4)	; s = s/z * z
+ fxch st(1)	
+ fmul st(0),st(3)	; t = t/z * z
+ fxch st(1)	
+ fistp ds:dword ptr[snext]	
+ fistp ds:dword ptr[tnext]	
+
+ mov al,ds:byte ptr[esi]	; load first texel in segment
+ mov ebx,ds:dword ptr[_tadjust]	
+ mov ds:byte ptr[edi],al	; store first pixel in segment
+ mov eax,ds:dword ptr[_sadjust]	
+
+ add eax,ds:dword ptr[snext]	
+ add ebx,ds:dword ptr[tnext]	
+
+ mov ebp,ds:dword ptr[_bbextents]	
+ mov edx,ds:dword ptr[_bbextentt]	
+
+ cmp eax,4096	
+ jl LClampLow4	
+ cmp eax,ebp	
+ ja LClampHigh4	
+LClampReentry4:	
+ mov ds:dword ptr[snext],eax	
+
+ cmp ebx,4096	
+ jl LClampLow5	
+ cmp ebx,edx	
+ ja LClampHigh5	
+LClampReentry5:	
+
+ cmp ecx,1	; don't bother 
+ je LOnlyOneStep	; if two pixels in segment, there's only one step,
+;  of the segment length
+ sub eax,ds:dword ptr[s]	
+ sub ebx,ds:dword ptr[t]	
+
+ add eax,eax	; convert to 15.17 format so multiply by 1.31
+ add ebx,ebx	;  reciprocal yields 16.48
+
+ imul ds:dword ptr[reciprocal_table_16-8+ecx*4]	; sstep = (snext - s) /
+;  (spancount-1)
+ mov ebp,edx	
+
+ mov eax,ebx	
+ imul ds:dword ptr[reciprocal_table_16-8+ecx*4]	; tstep = (tnext - t) /
+;  (spancount-1)
+LSetEntryvec:	
+;
+; set up advancetable
+;
+ mov ebx,ds:dword ptr[entryvec_table_16+ecx*4]	
+ mov eax,edx	
+ mov ds:dword ptr[jumptemp],ebx	; entry point into code for RET later
+ mov ecx,ebp	
+ sar edx,16	; tstep >>= 16;
+ mov ebx,ds:dword ptr[_cachewidth]	
+ sar ecx,16	; sstep >>= 16;
+ imul edx,ebx	
+
+ add edx,ecx	; add in sstep
+; (tstep >> 16) * cachewidth + (sstep >> 16);
+ mov ecx,ds:dword ptr[tfracf]	
+ mov ds:dword ptr[advancetable+4],edx	; advance base in t
+ add edx,ebx	; ((tstep >> 16) + 1) * cachewidth +
+;  (sstep >> 16);
+ shl ebp,16	; left-justify sstep fractional part
+ mov ebx,ds:dword ptr[sfracf]	
+ shl eax,16	; left-justify tstep fractional part
+ mov ds:dword ptr[advancetable],edx	; advance extra in t
+
+ mov ds:dword ptr[tstep],eax	
+ mov edx,ecx	
+ add edx,eax	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ jmp dword ptr[jumptemp]	; jump to the number-of-pixels handler
+
+;----------------------------------------
+
+LNoSteps:	
+ mov al,ds:byte ptr[esi]	; load first texel in segment
+ sub edi,15	; adjust for hardwired offset
+ jmp LEndSpan	
+
+
+LOnlyOneStep:	
+ sub eax,ds:dword ptr[s]	
+ sub ebx,ds:dword ptr[t]	
+ mov ebp,eax	
+ mov edx,ebx	
+ jmp LSetEntryvec	
+
+;----------------------------------------
+
+ public Entry2_16, Entry3_16, Entry4_16, Entry5_16	
+ public Entry6_16, Entry7_16, Entry8_16, Entry9_16	
+ public Entry10_16, Entry11_16, Entry12_16, Entry13_16	
+ public Entry14_16, Entry15_16, Entry16_16	
+
+Entry2_16:	
+ sub edi,14	; adjust for hardwired offsets
+ mov al,ds:byte ptr[esi]	
+ jmp LEntry2_16	
+
+;----------------------------------------
+
+Entry3_16:	
+ sub edi,13	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ jmp LEntry3_16	
+
+;----------------------------------------
+
+Entry4_16:	
+ sub edi,12	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry4_16	
+
+;----------------------------------------
+
+Entry5_16:	
+ sub edi,11	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry5_16	
+
+;----------------------------------------
+
+Entry6_16:	
+ sub edi,10	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry6_16	
+
+;----------------------------------------
+
+Entry7_16:	
+ sub edi,9	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry7_16	
+
+;----------------------------------------
+
+Entry8_16:	
+ sub edi,8	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry8_16	
+
+;----------------------------------------
+
+Entry9_16:	
+ sub edi,7	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry9_16	
+
+;----------------------------------------
+
+Entry10_16:	
+ sub edi,6	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry10_16	
+
+;----------------------------------------
+
+Entry11_16:	
+ sub edi,5	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry11_16	
+
+;----------------------------------------
+
+Entry12_16:	
+ sub edi,4	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry12_16	
+
+;----------------------------------------
+
+Entry13_16:	
+ sub edi,3	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry13_16	
+
+;----------------------------------------
+
+Entry14_16:	
+ sub edi,2	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry14_16	
+
+;----------------------------------------
+
+Entry15_16:	
+ dec edi	; adjust for hardwired offsets
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+ jmp LEntry15_16	
+
+;----------------------------------------
+
+Entry16_16:	
+ add edx,eax	
+ mov al,ds:byte ptr[esi]	
+ sbb ecx,ecx	
+ add ebx,ebp	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+
+ add edx,ds:dword ptr[tstep]	
+ sbb ecx,ecx	
+ mov ds:byte ptr[1+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry15_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[2+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry14_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[3+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry13_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[4+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry12_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[5+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry11_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[6+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry10_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[7+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry9_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[8+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry8_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[9+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry7_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[10+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry6_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[11+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry5_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[12+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+ add edx,ds:dword ptr[tstep]	
+LEntry4_16:	
+ sbb ecx,ecx	
+ mov ds:byte ptr[13+edi],al	
+ add ebx,ebp	
+ mov al,ds:byte ptr[esi]	
+ adc esi,ds:dword ptr[advancetable+4+ecx*4]	
+LEntry3_16:	
+ mov ds:byte ptr[14+edi],al	
+ mov al,ds:byte ptr[esi]	
+LEntry2_16:	
+
+LEndSpan:	
+
+;
+; clear s/z, t/z, 1/z from FP stack
+;
+ fstp st(0)	
+ fstp st(0)	
+ fstp st(0)	
+
+ mov ebx,ds:dword ptr[pspantemp]	; restore spans pointer
+ mov ebx,ds:dword ptr[espan_t_pnext+ebx]	; point to next span
+ test ebx,ebx	; any more spans?
+ mov ds:byte ptr[15+edi],al	
+ jnz LSpanLoop	; more spans
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+;----------------------------------------------------------------------
+; 8-bpp horizontal span z drawing codefor polygons, with no transparency.
+;
+; Assumes there is at least one span in pzspans, and that every span
+; contains at least one pixel
+;----------------------------------------------------------------------
+
+	
+
+; z-clamp on a non-negative gradient span
+LClamp:	
+ mov edx,040000000h	
+ xor ebx,ebx	
+ fstp st(0)	
+ jmp LZDraw	
+
+; z-clamp on a negative gradient span
+LClampNeg:	
+ mov edx,040000000h	
+ xor ebx,ebx	
+ fstp st(0)	
+ jmp LZDrawNeg	
+
+
+pzspans	equ		4+16
+
+ public _D_DrawZSpans	
+_D_DrawZSpans:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+ fld ds:dword ptr[_d_zistepu]	
+ mov eax,ds:dword ptr[_d_zistepu]	
+ mov esi,ds:dword ptr[pzspans+esp]	
+ test eax,eax	
+ jz LFNegSpan	
+
+ fmul ds:dword ptr[Float2ToThe31nd]	
+ fistp ds:dword ptr[izistep]	; note: we are relying on FP exceptions being turned
+; off here to avoid range problems
+ mov ebx,ds:dword ptr[izistep]	; remains loaded for all spans
+
+LFSpanLoop:	
+; set up the initial 1/z value
+ fild ds:dword ptr[espan_t_v+esi]	
+ fild ds:dword ptr[espan_t_u+esi]	
+ mov ecx,ds:dword ptr[espan_t_v+esi]	
+ mov edi,ds:dword ptr[_d_pzbuffer]	
+ fmul ds:dword ptr[_d_zistepu]	
+ fxch st(1)	
+ fmul ds:dword ptr[_d_zistepv]	
+ fxch st(1)	
+ fadd ds:dword ptr[_d_ziorigin]	
+ imul ecx,ds:dword ptr[_d_zrowbytes]	
+ faddp st(1),st(0)	
+
+; clamp if z is nearer than 2 (1/z > 0.5)
+ fcom ds:dword ptr[float_point5]	
+ add edi,ecx	
+ mov edx,ds:dword ptr[espan_t_u+esi]	
+ add edx,edx	; word count
+ mov ecx,ds:dword ptr[espan_t_count+esi]	
+ add edi,edx	; pdest = &pdestspan[scans->u];
+ push esi	; preserve spans pointer
+ fnstsw ax	
+ test ah,045h	
+ jz LClamp	
+
+ fmul ds:dword ptr[Float2ToThe31nd]	
+ fistp ds:dword ptr[izi]	; note: we are relying on FP exceptions being turned
+; off here to avoid problems when the span is closer
+; than 1/(2**31)
+ mov edx,ds:dword ptr[izi]	
+
+; at this point:
+; %ebx = izistep
+; %ecx = count
+; %edx = izi
+; %edi = pdest
+
+LZDraw:	
+
+; do a single pixel up front, if necessary to dword align the destination
+ test edi,2	
+ jz LFMiddle	
+ mov eax,edx	
+ add edx,ebx	
+ shr eax,16	
+ dec ecx	
+ mov ds:word ptr[edi],ax	
+ add edi,2	
+
+; do middle a pair of aligned dwords at a time
+LFMiddle:	
+ push ecx	
+ shr ecx,1	; count / 2
+ jz LFLast	; no aligned dwords to do
+ shr ecx,1	; (count / 2) / 2
+ jnc LFMiddleLoop	; even number of aligned dwords to do
+
+ mov eax,edx	
+ add edx,ebx	
+ shr eax,16	
+ mov esi,edx	
+ add edx,ebx	
+ and esi,0FFFF0000h	
+ or eax,esi	
+ mov ds:dword ptr[edi],eax	
+ add edi,4	
+ and ecx,ecx	
+ jz LFLast	
+
+LFMiddleLoop:	
+ mov eax,edx	
+ add edx,ebx	
+ shr eax,16	
+ mov esi,edx	
+ add edx,ebx	
+ and esi,0FFFF0000h	
+ or eax,esi	
+ mov ebp,edx	
+ mov ds:dword ptr[edi],eax	
+ add edx,ebx	
+ shr ebp,16	
+ mov esi,edx	
+ add edx,ebx	
+ and esi,0FFFF0000h	
+ or ebp,esi	
+ mov ds:dword ptr[4+edi],ebp	; FIXME: eliminate register contention
+ add edi,8	
+
+ dec ecx	
+ jnz LFMiddleLoop	
+
+LFLast:	
+ pop ecx	; retrieve count
+ pop esi	; retrieve span pointer
+
+; do the last, unaligned pixel, if there is one
+ and ecx,1	; is there an odd pixel left to do?
+ jz LFSpanDone	; no
+ shr edx,16	
+ mov ds:word ptr[edi],dx	; do the final pixel's z
+
+LFSpanDone:	
+ mov esi,ds:dword ptr[espan_t_pnext+esi]	
+ test esi,esi	
+ jnz LFSpanLoop	
+
+ jmp LFDone	
+
+LFNegSpan:	
+ fmul ds:dword ptr[FloatMinus2ToThe31nd]	
+ fistp ds:dword ptr[izistep]	; note: we are relying on FP exceptions being turned
+; off here to avoid range problems
+ mov ebx,ds:dword ptr[izistep]	; remains loaded for all spans
+
+LFNegSpanLoop:	
+; set up the initial 1/z value
+ fild ds:dword ptr[espan_t_v+esi]	
+ fild ds:dword ptr[espan_t_u+esi]	
+ mov ecx,ds:dword ptr[espan_t_v+esi]	
+ mov edi,ds:dword ptr[_d_pzbuffer]	
+ fmul ds:dword ptr[_d_zistepu]	
+ fxch st(1)	
+ fmul ds:dword ptr[_d_zistepv]	
+ fxch st(1)	
+ fadd ds:dword ptr[_d_ziorigin]	
+ imul ecx,ds:dword ptr[_d_zrowbytes]	
+ faddp st(1),st(0)	
+
+; clamp if z is nearer than 2 (1/z > 0.5)
+ fcom ds:dword ptr[float_point5]	
+ add edi,ecx	
+ mov edx,ds:dword ptr[espan_t_u+esi]	
+ add edx,edx	; word count
+ mov ecx,ds:dword ptr[espan_t_count+esi]	
+ add edi,edx	; pdest = &pdestspan[scans->u];
+ push esi	; preserve spans pointer
+ fnstsw ax	
+ test ah,045h	
+ jz LClampNeg	
+
+ fmul ds:dword ptr[Float2ToThe31nd]	
+ fistp ds:dword ptr[izi]	; note: we are relying on FP exceptions being turned
+; off here to avoid problems when the span is closer
+; than 1/(2**31)
+ mov edx,ds:dword ptr[izi]	
+
+; at this point:
+; %ebx = izistep
+; %ecx = count
+; %edx = izi
+; %edi = pdest
+
+LZDrawNeg:	
+
+; do a single pixel up front, if necessary to dword align the destination
+ test edi,2	
+ jz LFNegMiddle	
+ mov eax,edx	
+ sub edx,ebx	
+ shr eax,16	
+ dec ecx	
+ mov ds:word ptr[edi],ax	
+ add edi,2	
+
+; do middle a pair of aligned dwords at a time
+LFNegMiddle:	
+ push ecx	
+ shr ecx,1	; count / 2
+ jz LFNegLast	; no aligned dwords to do
+ shr ecx,1	; (count / 2) / 2
+ jnc LFNegMiddleLoop	; even number of aligned dwords to do
+
+ mov eax,edx	
+ sub edx,ebx	
+ shr eax,16	
+ mov esi,edx	
+ sub edx,ebx	
+ and esi,0FFFF0000h	
+ or eax,esi	
+ mov ds:dword ptr[edi],eax	
+ add edi,4	
+ and ecx,ecx	
+ jz LFNegLast	
+
+LFNegMiddleLoop:	
+ mov eax,edx	
+ sub edx,ebx	
+ shr eax,16	
+ mov esi,edx	
+ sub edx,ebx	
+ and esi,0FFFF0000h	
+ or eax,esi	
+ mov ebp,edx	
+ mov ds:dword ptr[edi],eax	
+ sub edx,ebx	
+ shr ebp,16	
+ mov esi,edx	
+ sub edx,ebx	
+ and esi,0FFFF0000h	
+ or ebp,esi	
+ mov ds:dword ptr[4+edi],ebp	; FIXME: eliminate register contention
+ add edi,8	
+
+ dec ecx	
+ jnz LFNegMiddleLoop	
+
+LFNegLast:	
+ pop ecx	; retrieve count
+ pop esi	; retrieve span pointer
+
+; do the last, unaligned pixel, if there is one
+ and ecx,1	; is there an odd pixel left to do?
+ jz LFNegSpanDone	; no
+ shr edx,16	
+ mov ds:word ptr[edi],dx	; do the final pixel's z
+
+LFNegSpanDone:	
+ mov esi,ds:dword ptr[espan_t_pnext+esi]	
+ test esi,esi	
+ jnz LFNegSpanLoop	
+
+LFDone:	
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+
+_TEXT ENDS
+endif	;id386
+ END
--- /dev/null
+++ b/ref_soft/r_drawa.asm
@@ -1,0 +1,822 @@
+ .386P
+ .model FLAT
+;
+; r_drawa.s
+; x86 assembly-language edge clipping and emission code
+;
+
+include qasm.inc
+include d_if.inc
+
+if	id386
+
+; !!! if these are changed, they must be changed in r_draw.c too !!!
+FULLY_CLIPPED_CACHED	equ		080000000h
+FRAMECOUNT_MASK			equ		07FFFFFFFh
+
+_DATA SEGMENT	
+
+Ld0 dd 0.0	
+Ld1 dd 0.0	
+Lstack dd 0	
+Lfp_near_clip dd NEAR_CLIP	
+Lceilv0 dd 0	
+Lv dd 0	
+Lu0 dd 0	
+Lv0 dd 0	
+Lzi0 dd 0	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+;----------------------------------------------------------------------
+; edge clipping code
+;----------------------------------------------------------------------
+
+pv0		equ		4+12
+pv1		equ		8+12
+clip	equ		12+12
+
+ align 4	
+ public _R_ClipEdge	
+_R_ClipEdge:	
+ push esi	; preserve register variables
+ push edi	
+ push ebx	
+ mov ds:dword ptr[Lstack],esp	; for clearing the stack later
+
+;	float		d0, d1, f;
+;	mvertex_t	clipvert;
+
+ mov ebx,ds:dword ptr[clip+esp]	
+ mov esi,ds:dword ptr[pv0+esp]	
+ mov edx,ds:dword ptr[pv1+esp]	
+
+;	if (clip)
+;	{
+ test ebx,ebx	
+ jz Lemit	
+
+;		do
+;		{
+
+Lcliploop:	
+
+;			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
+;			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
+ fld ds:dword ptr[mv_position+0+esi]	
+ fmul ds:dword ptr[cp_normal+0+ebx]	
+ fld ds:dword ptr[mv_position+4+esi]	
+ fmul ds:dword ptr[cp_normal+4+ebx]	
+ fld ds:dword ptr[mv_position+8+esi]	
+ fmul ds:dword ptr[cp_normal+8+ebx]	
+ fxch st(1)	
+ faddp st(2),st(0)	; d0mul2 | d0add0
+
+ fld ds:dword ptr[mv_position+0+edx]	
+ fmul ds:dword ptr[cp_normal+0+ebx]	
+ fld ds:dword ptr[mv_position+4+edx]	
+ fmul ds:dword ptr[cp_normal+4+ebx]	
+ fld ds:dword ptr[mv_position+8+edx]	
+ fmul ds:dword ptr[cp_normal+8+ebx]	
+ fxch st(1)	
+ faddp st(2),st(0)	; d1mul2 | d1add0 | d0mul2 | d0add0
+ fxch st(3)	; d0add0 | d1add0 | d0mul2 | d1mul2
+
+ faddp st(2),st(0)	; d1add0 | dot0 | d1mul2 
+ faddp st(2),st(0)	; dot0 | dot1
+
+ fsub ds:dword ptr[cp_dist+ebx]	; d0 | dot1
+ fxch st(1)	; dot1 | d0
+ fsub ds:dword ptr[cp_dist+ebx]	; d1 | d0
+ fxch st(1)	
+ fstp ds:dword ptr[Ld0]	
+ fstp ds:dword ptr[Ld1]	
+
+;			if (d0 >= 0)
+;			{
+ mov eax,ds:dword ptr[Ld0]	
+ mov ecx,ds:dword ptr[Ld1]	
+ or ecx,eax	
+ js Lp2	
+
+; both points are unclipped
+
+Lcontinue:	
+
+;
+;				R_ClipEdge (&clipvert, pv1, clip->next);
+;				return;
+;			}
+;		} while ((clip = clip->next) != NULL);
+ mov ebx,ds:dword ptr[cp_next+ebx]	
+ test ebx,ebx	
+ jnz Lcliploop	
+
+;	}
+
+;// add the edge
+;	R_EmitEdge (pv0, pv1);
+Lemit:	
+
+;
+; set integer rounding to ceil mode, set to single precision
+;
+; FIXME: do away with by manually extracting integers from floats?
+; FIXME: set less often
+ fldcw ds:word ptr[_fpu_ceil_cw]	
+
+;	edge_t	*edge, *pcheck;
+;	int		u_check;
+;	float	u, u_step;
+;	vec3_t	local, transformed;
+;	float	*world;
+;	int		v, v2, ceilv0;
+;	float	scale, lzi0, u0, v0;
+;	int		side;
+
+;	if (r_lastvertvalid)
+;	{
+ cmp ds:dword ptr[_r_lastvertvalid],0	
+ jz LCalcFirst	
+
+;		u0 = r_u1;
+;		v0 = r_v1;
+;		lzi0 = r_lzi1;
+;		ceilv0 = r_ceilv1;
+ mov eax,ds:dword ptr[_r_lzi1]	
+ mov ecx,ds:dword ptr[_r_u1]	
+ mov ds:dword ptr[Lzi0],eax	
+ mov ds:dword ptr[Lu0],ecx	
+ mov ecx,ds:dword ptr[_r_v1]	
+ mov eax,ds:dword ptr[_r_ceilv1]	
+ mov ds:dword ptr[Lv0],ecx	
+ mov ds:dword ptr[Lceilv0],eax	
+ jmp LCalcSecond	
+
+;	}
+
+LCalcFirst:	
+
+;	else
+;	{
+;		world = &pv0->position[0];
+
+ call near ptr LTransformAndProject	; v0 | lzi0 | u0
+
+ fst ds:dword ptr[Lv0]	
+ fxch st(2)	; u0 | lzi0 | v0
+ fstp ds:dword ptr[Lu0]	; lzi0 | v0
+ fstp ds:dword ptr[Lzi0]	; v0
+
+;		ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0);
+ fistp ds:dword ptr[Lceilv0]	
+
+;	}
+
+LCalcSecond:	
+
+;	world = &pv1->position[0];
+ mov esi,edx	
+
+ call near ptr LTransformAndProject	; v1 | lzi1 | u1
+
+ fld ds:dword ptr[Lu0]	; u0 | v1 | lzi1 | u1
+ fxch st(3)	; u1 | v1 | lzi1 | u0
+ fld ds:dword ptr[Lzi0]	; lzi0 | u1 | v1 | lzi1 | u0
+ fxch st(3)	; lzi1 | u1 | v1 | lzi0 | u0
+ fld ds:dword ptr[Lv0]	; v0 | lzi1 | u1 | v1 | lzi0 | u0
+ fxch st(3)	; v1 | lzi1 | u1 | v0 | lzi0 | u0
+
+;	r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1);
+ fist ds:dword ptr[_r_ceilv1]	
+
+ fldcw ds:word ptr[_fpu_chop_cw]	; put back normal floating-point state
+
+ fst ds:dword ptr[_r_v1]	
+ fxch st(4)	; lzi0 | lzi1 | u1 | v0 | v1 | u0
+
+;	if (r_lzi1 > lzi0)
+;		lzi0 = r_lzi1;
+ fcom st(1)	
+ fnstsw ax	
+ test ah,1	
+ jz LP0	
+ fstp st(0)	
+ fld st(0)	
+LP0:	
+
+ fxch st(1)	; lzi1 | lzi0 | u1 | v0 | v1 | u0
+ fstp ds:dword ptr[_r_lzi1]	; lzi0 | u1 | v0 | v1 | u0
+ fxch st(1)	
+ fst ds:dword ptr[_r_u1]	
+ fxch st(1)	
+
+;	if (lzi0 > r_nearzi)	// for mipmap finding
+;		r_nearzi = lzi0;
+ fcom ds:dword ptr[_r_nearzi]	
+ fnstsw ax	
+ test ah,045h	
+ jnz LP1	
+ fst ds:dword ptr[_r_nearzi]	
+LP1:	
+
+; // for right edges, all we want is the effect on 1/z
+;	if (r_nearzionly)
+;		return;
+ mov eax,ds:dword ptr[_r_nearzionly]	
+ test eax,eax	
+ jz LP2	
+LPop5AndDone:	
+ mov eax,ds:dword ptr[_cacheoffset]	
+ mov edx,ds:dword ptr[_r_framecount]	
+ cmp eax,07FFFFFFFh	
+ jz LDoPop	
+ and edx,offset FRAMECOUNT_MASK	
+ or edx,offset FULLY_CLIPPED_CACHED	
+ mov ds:dword ptr[_cacheoffset],edx	
+
+LDoPop:	
+ fstp st(0)	; u1 | v0 | v1 | u0
+ fstp st(0)	; v0 | v1 | u0
+ fstp st(0)	; v1 | u0
+ fstp st(0)	; u0
+ fstp st(0)	
+ jmp Ldone	
+
+LP2:	
+
+; // create the edge
+;	if (ceilv0 == r_ceilv1)
+;		return;		// horizontal edge
+ mov ebx,ds:dword ptr[Lceilv0]	
+ mov edi,ds:dword ptr[_edge_p]	
+ mov ecx,ds:dword ptr[_r_ceilv1]	
+ mov edx,edi	
+ mov esi,ds:dword ptr[_r_pedge]	
+ add edx,offset et_size	
+ cmp ebx,ecx	
+ jz LPop5AndDone	
+
+ mov eax,ds:dword ptr[_r_pedge]	
+ mov ds:dword ptr[et_owner+edi],eax	
+
+;	side = ceilv0 > r_ceilv1;
+;
+;	edge->nearzi = lzi0;
+ fstp ds:dword ptr[et_nearzi+edi]	; u1 | v0 | v1 | u0
+
+;	if (side == 1)
+;	{
+ jc LSide0	
+
+LSide1:	
+
+;	// leading edge (go from p2 to p1)
+
+;		u_step = ((u0 - r_u1) / (v0 - r_v1));
+ fsubp st(3),st(0)	; v0 | v1 | u0-u1
+ fsub st(0),st(1)	; v0-v1 | v1 | u0-u1
+ fdivp st(2),st(0)	; v1 | ustep
+
+;	r_emitted = 1;
+ mov ds:dword ptr[_r_emitted],1	
+
+;	edge = edge_p++;
+ mov ds:dword ptr[_edge_p],edx	
+
+; pretouch next edge
+ mov eax,ds:dword ptr[edx]	
+
+;		v2 = ceilv0 - 1;
+;		v = r_ceilv1;
+ mov eax,ecx	
+ lea ecx,ds:dword ptr[-1+ebx]	
+ mov ebx,eax	
+
+;		edge->surfs[0] = 0;
+;		edge->surfs[1] = surface_p - surfaces;
+ mov eax,ds:dword ptr[_surface_p]	
+ mov esi,ds:dword ptr[_surfaces]	
+ sub edx,edx	
+ sub eax,esi	
+ shr eax,offset SURF_T_SHIFT	
+ mov ds:dword ptr[et_surfs+edi],edx	
+ mov ds:dword ptr[et_surfs+2+edi],eax	
+
+ sub esi,esi	
+
+;		u = r_u1 + ((float)v - r_v1) * u_step;
+ mov ds:dword ptr[Lv],ebx	
+ fild ds:dword ptr[Lv]	; v | v1 | ustep
+ fsubrp st(1),st(0)	; v-v1 | ustep
+ fmul st(0),st(1)	; (v-v1)*ustep | ustep
+ fadd ds:dword ptr[_r_u1]	; u | ustep
+
+ jmp LSideDone	
+
+;	}
+
+LSide0:	
+
+;	else
+;	{
+;	// trailing edge (go from p1 to p2)
+
+;		u_step = ((r_u1 - u0) / (r_v1 - v0));
+ fsub st(0),st(3)	; u1-u0 | v0 | v1 | u0
+ fxch st(2)	; v1 | v0 | u1-u0 | u0
+ fsub st(0),st(1)	; v1-v0 | v0 | u1-u0 | u0
+ fdivp st(2),st(0)	; v0 | ustep | u0
+
+;	r_emitted = 1;
+ mov ds:dword ptr[_r_emitted],1	
+
+;	edge = edge_p++;
+ mov ds:dword ptr[_edge_p],edx	
+
+; pretouch next edge
+ mov eax,ds:dword ptr[edx]	
+
+;		v = ceilv0;
+;		v2 = r_ceilv1 - 1;
+ dec ecx	
+
+;		edge->surfs[0] = surface_p - surfaces;
+;		edge->surfs[1] = 0;
+ mov eax,ds:dword ptr[_surface_p]	
+ mov esi,ds:dword ptr[_surfaces]	
+ sub edx,edx	
+ sub eax,esi	
+ shr eax,offset SURF_T_SHIFT	
+ mov ds:dword ptr[et_surfs+2+edi],edx	
+ mov ds:dword ptr[et_surfs+edi],eax	
+
+ mov esi,1	
+
+;		u = u0 + ((float)v - v0) * u_step;
+ mov ds:dword ptr[Lv],ebx	
+ fild ds:dword ptr[Lv]	; v | v0 | ustep | u0
+ fsubrp st(1),st(0)	; v-v0 | ustep | u0
+ fmul st(0),st(1)	; (v-v0)*ustep | ustep | u0
+ faddp st(2),st(0)	; ustep | u
+ fxch st(1)	; u | ustep
+
+;	}
+
+LSideDone:	
+
+;	edge->u_step = u_step*0x100000;
+;	edge->u = u*0x100000 + 0xFFFFF;
+
+ fmul ds:dword ptr[fp_1m]	; u*0x100000 | ustep
+ fxch st(1)	; ustep | u*0x100000
+ fmul ds:dword ptr[fp_1m]	; ustep*0x100000 | u*0x100000
+ fxch st(1)	; u*0x100000 | ustep*0x100000
+ fadd ds:dword ptr[fp_1m_minus_1]	; u*0x100000 + 0xFFFFF | ustep*0x100000
+ fxch st(1)	; ustep*0x100000 | u*0x100000 + 0xFFFFF
+ fistp ds:dword ptr[et_u_step+edi]	; u*0x100000 + 0xFFFFF
+ fistp ds:dword ptr[et_u+edi]	
+
+; // we need to do this to avoid stepping off the edges if a very nearly
+; // horizontal edge is less than epsilon above a scan, and numeric error
+; // causes it to incorrectly extend to the scan, and the extension of the
+; // line goes off the edge of the screen
+; // FIXME: is this actually needed?
+;	if (edge->u < r_refdef.vrect_x_adj_shift20)
+;		edge->u = r_refdef.vrect_x_adj_shift20;
+;	if (edge->u > r_refdef.vrectright_adj_shift20)
+;		edge->u = r_refdef.vrectright_adj_shift20;
+ mov eax,ds:dword ptr[et_u+edi]	
+ mov edx,ds:dword ptr[_r_refdef+rd_vrect_x_adj_shift20]	
+ cmp eax,edx	
+ jl LP4	
+ mov edx,ds:dword ptr[_r_refdef+rd_vrectright_adj_shift20]	
+ cmp eax,edx	
+ jng LP5	
+LP4:	
+ mov ds:dword ptr[et_u+edi],edx	
+ mov eax,edx	
+LP5:	
+
+; // sort the edge in normally
+;	u_check = edge->u;
+;
+;	if (edge->surfs[0])
+;		u_check++;	// sort trailers after leaders
+ add eax,esi	
+
+;	if (!newedges[v] || newedges[v]->u >= u_check)
+;	{
+ mov esi,ds:dword ptr[_newedges+ebx*4]	
+ test esi,esi	
+ jz LDoFirst	
+ cmp ds:dword ptr[et_u+esi],eax	
+ jl LNotFirst	
+LDoFirst:	
+
+;		edge->next = newedges[v];
+;		newedges[v] = edge;
+ mov ds:dword ptr[et_next+edi],esi	
+ mov ds:dword ptr[_newedges+ebx*4],edi	
+
+ jmp LSetRemove	
+
+;	}
+
+LNotFirst:	
+
+;	else
+;	{
+;		pcheck = newedges[v];
+;
+;		while (pcheck->next && pcheck->next->u < u_check)
+;			pcheck = pcheck->next;
+LFindInsertLoop:	
+ mov edx,esi	
+ mov esi,ds:dword ptr[et_next+esi]	
+ test esi,esi	
+ jz LInsertFound	
+ cmp ds:dword ptr[et_u+esi],eax	
+ jl LFindInsertLoop	
+
+LInsertFound:	
+
+;		edge->next = pcheck->next;
+;		pcheck->next = edge;
+ mov ds:dword ptr[et_next+edi],esi	
+ mov ds:dword ptr[et_next+edx],edi	
+
+;	}
+
+LSetRemove:	
+
+;	edge->nextremove = removeedges[v2];
+;	removeedges[v2] = edge;
+ mov eax,ds:dword ptr[_removeedges+ecx*4]	
+ mov ds:dword ptr[_removeedges+ecx*4],edi	
+ mov ds:dword ptr[et_nextremove+edi],eax	
+
+Ldone:	
+ mov esp,ds:dword ptr[Lstack]	; clear temporary variables from stack
+
+ pop ebx	; restore register variables
+ pop edi	
+ pop esi	
+ ret	
+
+; at least one point is clipped
+
+Lp2:	
+ test eax,eax	
+ jns Lp1	
+
+;			else
+;			{
+;			// point 0 is clipped
+
+;				if (d1 < 0)
+;				{
+ mov eax,ds:dword ptr[Ld1]	
+ test eax,eax	
+ jns Lp3	
+
+;				// both points are clipped
+;				// we do cache fully clipped edges
+;					if (!leftclipped)
+ mov eax,ds:dword ptr[_r_leftclipped]	
+ mov ecx,ds:dword ptr[_r_pedge]	
+ test eax,eax	
+ jnz Ldone	
+
+;						r_pedge->framecount = r_framecount;
+ mov eax,ds:dword ptr[_r_framecount]	
+ and eax,offset FRAMECOUNT_MASK	
+ or eax,offset FULLY_CLIPPED_CACHED	
+ mov ds:dword ptr[_cacheoffset],eax	
+
+;					return;
+ jmp Ldone	
+
+;				}
+
+Lp1:	
+
+;			// point 0 is unclipped
+;				if (d1 >= 0)
+;				{
+;				// both points are unclipped
+;					continue;
+
+;			// only point 1 is clipped
+
+;				f = d0 / (d0 - d1);
+ fld ds:dword ptr[Ld0]	
+ fld ds:dword ptr[Ld1]	
+ fsubr st(0),st(1)	
+
+;			// we don't cache partially clipped edges
+ mov ds:dword ptr[_cacheoffset],07FFFFFFFh	
+
+ fdivp st(1),st(0)	
+
+ sub esp,offset mv_size	; allocate space for clipvert
+
+;				clipvert.position[0] = pv0->position[0] +
+;						f * (pv1->position[0] - pv0->position[0]);
+;				clipvert.position[1] = pv0->position[1] +
+;						f * (pv1->position[1] - pv0->position[1]);
+;				clipvert.position[2] = pv0->position[2] +
+;						f * (pv1->position[2] - pv0->position[2]);
+ fld ds:dword ptr[mv_position+8+edx]	
+ fsub ds:dword ptr[mv_position+8+esi]	
+ fld ds:dword ptr[mv_position+4+edx]	
+ fsub ds:dword ptr[mv_position+4+esi]	
+ fld ds:dword ptr[mv_position+0+edx]	
+ fsub ds:dword ptr[mv_position+0+esi]	; 0 | 1 | 2
+
+; replace pv1 with the clip point
+ mov edx,esp	
+ mov eax,ds:dword ptr[cp_leftedge+ebx]	
+ test al,al	
+
+ fmul st(0),st(3)	
+ fxch st(1)	; 1 | 0 | 2
+ fmul st(0),st(3)	
+ fxch st(2)	; 2 | 0 | 1
+ fmulp st(3),st(0)	; 0 | 1 | 2
+ fadd ds:dword ptr[mv_position+0+esi]	
+ fxch st(1)	; 1 | 0 | 2
+ fadd ds:dword ptr[mv_position+4+esi]	
+ fxch st(2)	; 2 | 0 | 1
+ fadd ds:dword ptr[mv_position+8+esi]	
+ fxch st(1)	; 0 | 2 | 1
+ fstp ds:dword ptr[mv_position+0+esp]	; 2 | 1
+ fstp ds:dword ptr[mv_position+8+esp]	; 1
+ fstp ds:dword ptr[mv_position+4+esp]	
+
+;				if (clip->leftedge)
+;				{
+ jz Ltestright	
+
+;					r_leftclipped = true;
+;					r_leftexit = clipvert;
+ mov ds:dword ptr[_r_leftclipped],1	
+ mov eax,ds:dword ptr[mv_position+0+esp]	
+ mov ds:dword ptr[_r_leftexit+mv_position+0],eax	
+ mov eax,ds:dword ptr[mv_position+4+esp]	
+ mov ds:dword ptr[_r_leftexit+mv_position+4],eax	
+ mov eax,ds:dword ptr[mv_position+8+esp]	
+ mov ds:dword ptr[_r_leftexit+mv_position+8],eax	
+
+ jmp Lcontinue	
+
+;				}
+
+Ltestright:	
+;				else if (clip->rightedge)
+;				{
+ test ah,ah	
+ jz Lcontinue	
+
+;					r_rightclipped = true;
+;					r_rightexit = clipvert;
+ mov ds:dword ptr[_r_rightclipped],1	
+ mov eax,ds:dword ptr[mv_position+0+esp]	
+ mov ds:dword ptr[_r_rightexit+mv_position+0],eax	
+ mov eax,ds:dword ptr[mv_position+4+esp]	
+ mov ds:dword ptr[_r_rightexit+mv_position+4],eax	
+ mov eax,ds:dword ptr[mv_position+8+esp]	
+ mov ds:dword ptr[_r_rightexit+mv_position+8],eax	
+
+;				}
+;
+;				R_ClipEdge (pv0, &clipvert, clip->next);
+;				return;
+;			}
+ jmp Lcontinue	
+
+;			}
+
+Lp3:	
+
+;			// only point 0 is clipped
+;				r_lastvertvalid = false;
+
+ mov ds:dword ptr[_r_lastvertvalid],0	
+
+;				f = d0 / (d0 - d1);
+ fld ds:dword ptr[Ld0]	
+ fld ds:dword ptr[Ld1]	
+ fsubr st(0),st(1)	
+
+;			// we don't cache partially clipped edges
+ mov ds:dword ptr[_cacheoffset],07FFFFFFFh	
+
+ fdivp st(1),st(0)	
+
+ sub esp,offset mv_size	; allocate space for clipvert
+
+;				clipvert.position[0] = pv0->position[0] +
+;						f * (pv1->position[0] - pv0->position[0]);
+;				clipvert.position[1] = pv0->position[1] +
+;						f * (pv1->position[1] - pv0->position[1]);
+;				clipvert.position[2] = pv0->position[2] +
+;						f * (pv1->position[2] - pv0->position[2]);
+ fld ds:dword ptr[mv_position+8+edx]	
+ fsub ds:dword ptr[mv_position+8+esi]	
+ fld ds:dword ptr[mv_position+4+edx]	
+ fsub ds:dword ptr[mv_position+4+esi]	
+ fld ds:dword ptr[mv_position+0+edx]	
+ fsub ds:dword ptr[mv_position+0+esi]	; 0 | 1 | 2
+
+ mov eax,ds:dword ptr[cp_leftedge+ebx]	
+ test al,al	
+
+ fmul st(0),st(3)	
+ fxch st(1)	; 1 | 0 | 2
+ fmul st(0),st(3)	
+ fxch st(2)	; 2 | 0 | 1
+ fmulp st(3),st(0)	; 0 | 1 | 2
+ fadd ds:dword ptr[mv_position+0+esi]	
+ fxch st(1)	; 1 | 0 | 2
+ fadd ds:dword ptr[mv_position+4+esi]	
+ fxch st(2)	; 2 | 0 | 1
+ fadd ds:dword ptr[mv_position+8+esi]	
+ fxch st(1)	; 0 | 2 | 1
+ fstp ds:dword ptr[mv_position+0+esp]	; 2 | 1
+ fstp ds:dword ptr[mv_position+8+esp]	; 1
+ fstp ds:dword ptr[mv_position+4+esp]	
+
+; replace pv0 with the clip point
+ mov esi,esp	
+
+;				if (clip->leftedge)
+;				{
+ jz Ltestright2	
+
+;					r_leftclipped = true;
+;					r_leftenter = clipvert;
+ mov ds:dword ptr[_r_leftclipped],1	
+ mov eax,ds:dword ptr[mv_position+0+esp]	
+ mov ds:dword ptr[_r_leftenter+mv_position+0],eax	
+ mov eax,ds:dword ptr[mv_position+4+esp]	
+ mov ds:dword ptr[_r_leftenter+mv_position+4],eax	
+ mov eax,ds:dword ptr[mv_position+8+esp]	
+ mov ds:dword ptr[_r_leftenter+mv_position+8],eax	
+
+ jmp Lcontinue	
+
+;				}
+
+Ltestright2:	
+;				else if (clip->rightedge)
+;				{
+ test ah,ah	
+ jz Lcontinue	
+
+;					r_rightclipped = true;
+;					r_rightenter = clipvert;
+ mov ds:dword ptr[_r_rightclipped],1	
+ mov eax,ds:dword ptr[mv_position+0+esp]	
+ mov ds:dword ptr[_r_rightenter+mv_position+0],eax	
+ mov eax,ds:dword ptr[mv_position+4+esp]	
+ mov ds:dword ptr[_r_rightenter+mv_position+4],eax	
+ mov eax,ds:dword ptr[mv_position+8+esp]	
+ mov ds:dword ptr[_r_rightenter+mv_position+8],eax	
+
+;				}
+ jmp Lcontinue	
+
+; %esi = vec3_t point to transform and project
+; %edx preserved
+LTransformAndProject:	
+
+;	// transform and project
+;		VectorSubtract (world, modelorg, local);
+ fld ds:dword ptr[mv_position+0+esi]	
+ fsub ds:dword ptr[_modelorg+0]	
+ fld ds:dword ptr[mv_position+4+esi]	
+ fsub ds:dword ptr[_modelorg+4]	
+ fld ds:dword ptr[mv_position+8+esi]	
+ fsub ds:dword ptr[_modelorg+8]	
+ fxch st(2)	; local[0] | local[1] | local[2]
+
+;		TransformVector (local, transformed);
+;	
+;		if (transformed[2] < NEAR_CLIP)
+;			transformed[2] = NEAR_CLIP;
+;	
+;		lzi0 = 1.0 / transformed[2];
+ fld st(0)	; local[0] | local[0] | local[1] | local[2]
+ fmul ds:dword ptr[_vpn+0]	; zm0 | local[0] | local[1] | local[2]
+ fld st(1)	; local[0] | zm0 | local[0] | local[1] |
+;  local[2]
+ fmul ds:dword ptr[_vright+0]	; xm0 | zm0 | local[0] | local[1] | local[2]
+ fxch st(2)	; local[0] | zm0 | xm0 | local[1] | local[2]
+ fmul ds:dword ptr[_vup+0]	; ym0 |  zm0 | xm0 | local[1] | local[2]
+ fld st(3)	; local[1] | ym0 |  zm0 | xm0 | local[1] |
+;  local[2]
+ fmul ds:dword ptr[_vpn+4]	; zm1 | ym0 | zm0 | xm0 | local[1] |
+;  local[2]
+ fld st(4)	; local[1] | zm1 | ym0 | zm0 | xm0 |
+;  local[1] | local[2]
+ fmul ds:dword ptr[_vright+4]	; xm1 | zm1 | ym0 |  zm0 | xm0 |
+;  local[1] | local[2]
+ fxch st(5)	; local[1] | zm1 | ym0 | zm0 | xm0 |
+;  xm1 | local[2]
+ fmul ds:dword ptr[_vup+4]	; ym1 | zm1 | ym0 | zm0 | xm0 |
+;  xm1 | local[2]
+ fxch st(1)	; zm1 | ym1 | ym0 | zm0 | xm0 |
+;  xm1 | local[2]
+ faddp st(3),st(0)	; ym1 | ym0 | zm2 | xm0 | xm1 | local[2]
+ fxch st(3)	; xm0 | ym0 | zm2 | ym1 | xm1 | local[2]
+ faddp st(4),st(0)	; ym0 | zm2 | ym1 | xm2 | local[2]
+ faddp st(2),st(0)	; zm2 | ym2 | xm2 | local[2]
+ fld st(3)	; local[2] | zm2 | ym2 | xm2 | local[2]
+ fmul ds:dword ptr[_vpn+8]	; zm3 | zm2 | ym2 | xm2 | local[2]
+ fld st(4)	; local[2] | zm3 | zm2 | ym2 | xm2 | local[2]
+ fmul ds:dword ptr[_vright+8]	; xm3 | zm3 | zm2 | ym2 | xm2 | local[2]
+ fxch st(5)	; local[2] | zm3 | zm2 | ym2 | xm2 | xm3
+ fmul ds:dword ptr[_vup+8]	; ym3 | zm3 | zm2 | ym2 | xm2 | xm3
+ fxch st(1)	; zm3 | ym3 | zm2 | ym2 | xm2 | xm3
+ faddp st(2),st(0)	; ym3 | zm4 | ym2 | xm2 | xm3
+ fxch st(4)	; xm3 | zm4 | ym2 | xm2 | ym3
+ faddp st(3),st(0)	; zm4 | ym2 | xm4 | ym3
+ fxch st(1)	; ym2 | zm4 | xm4 | ym3
+ faddp st(3),st(0)	; zm4 | xm4 | ym4
+
+ fcom ds:dword ptr[Lfp_near_clip]	
+ fnstsw ax	
+ test ah,1	
+ jz LNoClip	
+ fstp st(0)	
+ fld ds:dword ptr[Lfp_near_clip]	
+
+LNoClip:	
+
+ fdivr ds:dword ptr[float_1]	; lzi0 | x | y
+ fxch st(1)	; x | lzi0 | y
+
+;	// FIXME: build x/yscale into transform?
+;		scale = xscale * lzi0;
+;		u0 = (xcenter + scale*transformed[0]);
+ fld ds:dword ptr[_xscale]	; xscale | x | lzi0 | y
+ fmul st(0),st(2)	; scale | x | lzi0 | y
+ fmulp st(1),st(0)	; scale*x | lzi0 | y
+ fadd ds:dword ptr[_xcenter]	; u0 | lzi0 | y
+
+;		if (u0 < r_refdef.fvrectx_adj)
+;			u0 = r_refdef.fvrectx_adj;
+;		if (u0 > r_refdef.fvrectright_adj)
+;			u0 = r_refdef.fvrectright_adj;
+; FIXME: use integer compares of floats?
+ fcom ds:dword ptr[_r_refdef+rd_fvrectx_adj]	
+ fnstsw ax	
+ test ah,1	
+ jz LClampP0	
+ fstp st(0)	
+ fld ds:dword ptr[_r_refdef+rd_fvrectx_adj]	
+LClampP0:	
+ fcom ds:dword ptr[_r_refdef+rd_fvrectright_adj]	
+ fnstsw ax	
+ test ah,045h	
+ jnz LClampP1	
+ fstp st(0)	
+ fld ds:dword ptr[_r_refdef+rd_fvrectright_adj]	
+LClampP1:	
+
+ fld st(1)	; lzi0 | u0 | lzi0 | y
+
+;		scale = yscale * lzi0;
+;		v0 = (ycenter - scale*transformed[1]);
+ fmul ds:dword ptr[_yscale]	; scale | u0 | lzi0 | y
+ fmulp st(3),st(0)	; u0 | lzi0 | scale*y
+ fxch st(2)	; scale*y | lzi0 | u0
+ fsubr ds:dword ptr[_ycenter]	; v0 | lzi0 | u0
+
+;		if (v0 < r_refdef.fvrecty_adj)
+;			v0 = r_refdef.fvrecty_adj;
+;		if (v0 > r_refdef.fvrectbottom_adj)
+;			v0 = r_refdef.fvrectbottom_adj;
+; FIXME: use integer compares of floats?
+ fcom ds:dword ptr[_r_refdef+rd_fvrecty_adj]	
+ fnstsw ax	
+ test ah,1	
+ jz LClampP2	
+ fstp st(0)	
+ fld ds:dword ptr[_r_refdef+rd_fvrecty_adj]	
+LClampP2:	
+ fcom ds:dword ptr[_r_refdef+rd_fvrectbottom_adj]	
+ fnstsw ax	
+ test ah,045h	
+ jnz LClampP3	
+ fstp st(0)	
+ fld ds:dword ptr[_r_refdef+rd_fvrectbottom_adj]	
+LClampP3:	
+ ret	
+
+
+_TEXT ENDS
+endif	;id386
+ END
--- /dev/null
+++ b/ref_soft/r_edge.c
@@ -1,0 +1,1125 @@
+/*
+Copyright (C) 1997-2001 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_edge.c
+
+#include "r_local.h"
+
+#ifndef id386
+void R_SurfacePatch (void)
+{
+}
+
+void R_EdgeCodeStart (void)
+{
+}
+
+void R_EdgeCodeEnd (void)
+{
+}
+#endif
+
+
+#if 0
+the complex cases add new polys on most lines, so dont optimize for keeping them the same
+have multiple free span lists to try to get better coherence?
+low depth complexity -- 1 to 3 or so
+
+have a sentinal at both ends?
+#endif
+
+
+edge_t	*auxedges;
+edge_t	*r_edges, *edge_p, *edge_max;
+
+surf_t	*surfaces, *surface_p, *surf_max;
+
+// surfaces are generated in back to front order by the bsp, so if a surf
+// pointer is greater than another one, it should be drawn in front
+// surfaces[1] is the background, and is used as the active surface stack
+
+edge_t	*newedges[MAXHEIGHT];
+edge_t	*removeedges[MAXHEIGHT];
+
+espan_t	*span_p, *max_span_p;
+
+int		r_currentkey;
+
+int	current_iv;
+
+int	edge_head_u_shift20, edge_tail_u_shift20;
+
+static void (*pdrawfunc)(void);
+
+edge_t	edge_head;
+edge_t	edge_tail;
+edge_t	edge_aftertail;
+edge_t	edge_sentinel;
+
+float	fv;
+
+static int	miplevel;
+
+float		scale_for_mip;
+int			ubasestep, errorterm, erroradjustup, erroradjustdown;
+
+// FIXME: should go away
+extern void			R_RotateBmodel (void);
+extern void			R_TransformFrustum (void);
+
+
+
+void R_GenerateSpans (void);
+void R_GenerateSpansBackward (void);
+
+void R_LeadingEdge (edge_t *edge);
+void R_LeadingEdgeBackwards (edge_t *edge);
+void R_TrailingEdge (surf_t *surf, edge_t *edge);
+
+
+/*
+===============================================================================
+
+EDGE SCANNING
+
+===============================================================================
+*/
+
+/*
+==============
+R_BeginEdgeFrame
+==============
+*/
+void R_BeginEdgeFrame (void)
+{
+	int		v;
+
+	edge_p = r_edges;
+	edge_max = &r_edges[r_numallocatededges];
+
+	surface_p = &surfaces[2];	// background is surface 1,
+								//  surface 0 is a dummy
+	surfaces[1].spans = NULL;	// no background spans yet
+	surfaces[1].flags = SURF_DRAWBACKGROUND;
+
+// put the background behind everything in the world
+	if (sw_draworder->value)
+	{
+		pdrawfunc = R_GenerateSpansBackward;
+		surfaces[1].key = 0;
+		r_currentkey = 1;
+	}
+	else
+	{
+		pdrawfunc = R_GenerateSpans;
+		surfaces[1].key = 0x7FFfFFFF;
+		r_currentkey = 0;
+	}
+
+// FIXME: set with memset
+	for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
+	{
+		newedges[v] = removeedges[v] = NULL;
+	}
+}
+
+
+#if	!id386
+
+/*
+==============
+R_InsertNewEdges
+
+Adds the edges in the linked list edgestoadd, adding them to the edges in the
+linked list edgelist.  edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]).  edgelist is assumed to be sorted on u, with a
+sentinel at the end (actually, this is the active edge table starting at
+edge_head.next).
+==============
+*/
+void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
+{
+	edge_t	*next_edge;
+
+	do
+	{
+		next_edge = edgestoadd->next;
+edgesearch:
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		if (edgelist->u >= edgestoadd->u)
+			goto addedge;
+		edgelist=edgelist->next;
+		goto edgesearch;
+
+	// insert edgestoadd before edgelist
+addedge:
+		edgestoadd->next = edgelist;
+		edgestoadd->prev = edgelist->prev;
+		edgelist->prev->next = edgestoadd;
+		edgelist->prev = edgestoadd;
+	} while ((edgestoadd = next_edge) != NULL);
+}
+
+#endif	// !id386
+	
+
+#if	!id386
+
+/*
+==============
+R_RemoveEdges
+==============
+*/
+void R_RemoveEdges (edge_t *pedge)
+{
+
+	do
+	{
+		pedge->next->prev = pedge->prev;
+		pedge->prev->next = pedge->next;
+	} while ((pedge = pedge->nextremove) != NULL);
+}
+
+#endif	// !id386
+
+
+#if	!id386
+
+/*
+==============
+R_StepActiveU
+==============
+*/
+void R_StepActiveU (edge_t *pedge)
+{
+	edge_t		*pnext_edge, *pwedge;
+
+	while (1)
+	{
+nextedge:
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		pedge->u += pedge->u_step;
+		if (pedge->u < pedge->prev->u)
+			goto pushback;
+		pedge = pedge->next;
+			
+		goto nextedge;		
+		
+pushback:
+		if (pedge == &edge_aftertail)
+			return;
+			
+	// push it back to keep it sorted		
+		pnext_edge = pedge->next;
+
+	// pull the edge out of the edge list
+		pedge->next->prev = pedge->prev;
+		pedge->prev->next = pedge->next;
+
+	// find out where the edge goes in the edge list
+		pwedge = pedge->prev->prev;
+
+		while (pwedge->u > pedge->u)
+		{
+			pwedge = pwedge->prev;
+		}
+
+	// put the edge back into the edge list
+		pedge->next = pwedge->next;
+		pedge->prev = pwedge;
+		pedge->next->prev = pedge;
+		pwedge->next = pedge;
+
+		pedge = pnext_edge;
+		if (pedge == &edge_tail)
+			return;
+	}
+}
+
+#endif	// !id386
+
+
+/*
+==============
+R_CleanupSpan
+==============
+*/
+void R_CleanupSpan (void)
+{
+	surf_t	*surf;
+	int		iu;
+	espan_t	*span;
+
+// now that we've reached the right edge of the screen, we're done with any
+// unfinished surfaces, so emit a span for whatever's on top
+	surf = surfaces[1].next;
+	iu = edge_tail_u_shift20;
+	if (iu > surf->last_u)
+	{
+		span = span_p++;
+		span->u = surf->last_u;
+		span->count = iu - span->u;
+		span->v = current_iv;
+		span->pnext = surf->spans;
+		surf->spans = span;
+	}
+
+// reset spanstate for all surfaces in the surface stack
+	do
+	{
+		surf->spanstate = 0;
+		surf = surf->next;
+	} while (surf != &surfaces[1]);
+}
+
+
+/*
+==============
+R_LeadingEdgeBackwards
+==============
+*/
+void R_LeadingEdgeBackwards (edge_t *edge)
+{
+	espan_t			*span;
+	surf_t			*surf, *surf2;
+	int				iu;
+
+// it's adding a new surface in, so find the correct place
+	surf = &surfaces[edge->surfs[1]];
+
+// don't start a span if this is an inverted span, with the end
+// edge preceding the start edge (that is, we've already seen the
+// end edge)
+	if (++surf->spanstate == 1)
+	{
+		surf2 = surfaces[1].next;
+
+		if (surf->key > surf2->key)
+			goto newtop;
+
+	// if it's two surfaces on the same plane, the one that's already
+	// active is in front, so keep going unless it's a bmodel
+		if (surf->insubmodel && (surf->key == surf2->key))
+		{
+		// must be two bmodels in the same leaf; don't care, because they'll
+		// never be farthest anyway
+			goto newtop;
+		}
+
+continue_search:
+
+		do
+		{
+			surf2 = surf2->next;
+		} while (surf->key < surf2->key);
+
+		if (surf->key == surf2->key)
+		{
+		// if it's two surfaces on the same plane, the one that's already
+		// active is in front, so keep going unless it's a bmodel
+			if (!surf->insubmodel)
+				goto continue_search;
+
+		// must be two bmodels in the same leaf; don't care which is really
+		// in front, because they'll never be farthest anyway
+		}
+
+		goto gotposition;
+
+newtop:
+	// emit a span (obscures current top)
+		iu = edge->u >> 20;
+
+		if (iu > surf2->last_u)
+		{
+			span = span_p++;
+			span->u = surf2->last_u;
+			span->count = iu - span->u;
+			span->v = current_iv;
+			span->pnext = surf2->spans;
+			surf2->spans = span;
+		}
+
+		// set last_u on the new span
+		surf->last_u = iu;
+				
+gotposition:
+	// insert before surf2
+		surf->next = surf2;
+		surf->prev = surf2->prev;
+		surf2->prev->next = surf;
+		surf2->prev = surf;
+	}
+}
+
+
+/*
+==============
+R_TrailingEdge
+==============
+*/
+void R_TrailingEdge (surf_t *surf, edge_t *edge)
+{
+	espan_t			*span;
+	int				iu;
+
+// don't generate a span if this is an inverted span, with the end
+// edge preceding the start edge (that is, we haven't seen the
+// start edge yet)
+	if (--surf->spanstate == 0)
+	{
+		if (surf == surfaces[1].next)
+		{
+		// emit a span (current top going away)
+			iu = edge->u >> 20;
+			if (iu > surf->last_u)
+			{
+				span = span_p++;
+				span->u = surf->last_u;
+				span->count = iu - span->u;
+				span->v = current_iv;
+				span->pnext = surf->spans;
+				surf->spans = span;
+			}
+
+		// set last_u on the surface below
+			surf->next->last_u = iu;
+		}
+
+		surf->prev->next = surf->next;
+		surf->next->prev = surf->prev;
+	}
+}
+
+
+#if	!id386
+
+/*
+==============
+R_LeadingEdge
+==============
+*/
+void R_LeadingEdge (edge_t *edge)
+{
+	espan_t			*span;
+	surf_t			*surf, *surf2;
+	int				iu;
+	float			fu, newzi, testzi, newzitop, newzibottom;
+
+	if (edge->surfs[1])
+	{
+	// it's adding a new surface in, so find the correct place
+		surf = &surfaces[edge->surfs[1]];
+
+	// don't start a span if this is an inverted span, with the end
+	// edge preceding the start edge (that is, we've already seen the
+	// end edge)
+		if (++surf->spanstate == 1)
+		{
+			surf2 = surfaces[1].next;
+
+			if (surf->key < surf2->key)
+				goto newtop;
+
+		// if it's two surfaces on the same plane, the one that's already
+		// active is in front, so keep going unless it's a bmodel
+			if (surf->insubmodel && (surf->key == surf2->key))
+			{
+			// must be two bmodels in the same leaf; sort on 1/z
+				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
+				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
+						fu*surf->d_zistepu;
+				newzibottom = newzi * 0.99;
+
+				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
+						fu*surf2->d_zistepu;
+
+				if (newzibottom >= testzi)
+				{
+					goto newtop;
+				}
+
+				newzitop = newzi * 1.01;
+				if (newzitop >= testzi)
+				{
+					if (surf->d_zistepu >= surf2->d_zistepu)
+					{
+						goto newtop;
+					}
+				}
+			}
+
+continue_search:
+
+			do
+			{
+				surf2 = surf2->next;
+			} while (surf->key > surf2->key);
+
+			if (surf->key == surf2->key)
+			{
+			// if it's two surfaces on the same plane, the one that's already
+			// active is in front, so keep going unless it's a bmodel
+				if (!surf->insubmodel)
+					goto continue_search;
+
+			// must be two bmodels in the same leaf; sort on 1/z
+				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
+				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
+						fu*surf->d_zistepu;
+				newzibottom = newzi * 0.99;
+
+				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
+						fu*surf2->d_zistepu;
+
+				if (newzibottom >= testzi)
+				{
+					goto gotposition;
+				}
+
+				newzitop = newzi * 1.01;
+				if (newzitop >= testzi)
+				{
+					if (surf->d_zistepu >= surf2->d_zistepu)
+					{
+						goto gotposition;
+					}
+				}
+
+				goto continue_search;
+			}
+
+			goto gotposition;
+
+newtop:
+		// emit a span (obscures current top)
+			iu = edge->u >> 20;
+
+			if (iu > surf2->last_u)
+			{
+				span = span_p++;
+				span->u = surf2->last_u;
+				span->count = iu - span->u;
+				span->v = current_iv;
+				span->pnext = surf2->spans;
+				surf2->spans = span;
+			}
+
+			// set last_u on the new span
+			surf->last_u = iu;
+				
+gotposition:
+		// insert before surf2
+			surf->next = surf2;
+			surf->prev = surf2->prev;
+			surf2->prev->next = surf;
+			surf2->prev = surf;
+		}
+	}
+}
+
+
+/*
+==============
+R_GenerateSpans
+==============
+*/
+void R_GenerateSpans (void)
+{
+	edge_t			*edge;
+	surf_t			*surf;
+
+// clear active surfaces to just the background surface
+	surfaces[1].next = surfaces[1].prev = &surfaces[1];
+	surfaces[1].last_u = edge_head_u_shift20;
+
+// generate spans
+	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
+	{			
+		if (edge->surfs[0])
+		{
+		// it has a left surface, so a surface is going away for this span
+			surf = &surfaces[edge->surfs[0]];
+
+			R_TrailingEdge (surf, edge);
+
+			if (!edge->surfs[1])
+				continue;
+		}
+
+		R_LeadingEdge (edge);
+	}
+
+	R_CleanupSpan ();
+}
+
+#endif	// !id386
+
+
+/*
+==============
+R_GenerateSpansBackward
+==============
+*/
+void R_GenerateSpansBackward (void)
+{
+	edge_t			*edge;
+
+// clear active surfaces to just the background surface
+	surfaces[1].next = surfaces[1].prev = &surfaces[1];
+	surfaces[1].last_u = edge_head_u_shift20;
+
+// generate spans
+	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
+	{			
+		if (edge->surfs[0])
+			R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
+
+		if (edge->surfs[1])
+			R_LeadingEdgeBackwards (edge);
+	}
+
+	R_CleanupSpan ();
+}
+
+
+/*
+==============
+R_ScanEdges
+
+Input: 
+newedges[] array
+	this has links to edges, which have links to surfaces
+
+Output:
+Each surface has a linked list of its visible spans
+==============
+*/
+void R_ScanEdges (void)
+{
+	int		iv, bottom;
+	byte	basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
+	espan_t	*basespan_p;
+	surf_t	*s;
+
+	basespan_p = (espan_t *)
+			((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+	max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
+
+	span_p = basespan_p;
+
+// clear active edges to just the background edges around the whole screen
+// FIXME: most of this only needs to be set up once
+	edge_head.u = r_refdef.vrect.x << 20;
+	edge_head_u_shift20 = edge_head.u >> 20;
+	edge_head.u_step = 0;
+	edge_head.prev = NULL;
+	edge_head.next = &edge_tail;
+	edge_head.surfs[0] = 0;
+	edge_head.surfs[1] = 1;
+	
+	edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
+	edge_tail_u_shift20 = edge_tail.u >> 20;
+	edge_tail.u_step = 0;
+	edge_tail.prev = &edge_head;
+	edge_tail.next = &edge_aftertail;
+	edge_tail.surfs[0] = 1;
+	edge_tail.surfs[1] = 0;
+	
+	edge_aftertail.u = -1;		// force a move
+	edge_aftertail.u_step = 0;
+	edge_aftertail.next = &edge_sentinel;
+	edge_aftertail.prev = &edge_tail;
+
+// FIXME: do we need this now that we clamp x in r_draw.c?
+	edge_sentinel.u = 2000 << 24;		// make sure nothing sorts past this
+	edge_sentinel.prev = &edge_aftertail;
+
+//	
+// process all scan lines
+//
+	bottom = r_refdef.vrectbottom - 1;
+
+	for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
+	{
+		current_iv = iv;
+		fv = (float)iv;
+
+	// mark that the head (background start) span is pre-included
+		surfaces[1].spanstate = 1;
+
+		if (newedges[iv])
+		{
+			R_InsertNewEdges (newedges[iv], edge_head.next);
+		}
+
+		(*pdrawfunc) ();
+
+	// flush the span list if we can't be sure we have enough spans left for
+	// the next scan
+		if (span_p > max_span_p)
+		{
+			D_DrawSurfaces ();
+
+		// clear the surface span pointers
+			for (s = &surfaces[1] ; s<surface_p ; s++)
+				s->spans = NULL;
+
+			span_p = basespan_p;
+		}
+
+		if (removeedges[iv])
+			R_RemoveEdges (removeedges[iv]);
+
+		if (edge_head.next != &edge_tail)
+			R_StepActiveU (edge_head.next);
+	}
+
+// do the last scan (no need to step or sort or remove on the last scan)
+
+	current_iv = iv;
+	fv = (float)iv;
+
+// mark that the head (background start) span is pre-included
+	surfaces[1].spanstate = 1;
+
+	if (newedges[iv])
+		R_InsertNewEdges (newedges[iv], edge_head.next);
+
+	(*pdrawfunc) ();
+
+// draw whatever's left in the span list
+	D_DrawSurfaces ();
+}
+
+
+/*
+=========================================================================
+
+SURFACE FILLING
+
+=========================================================================
+*/
+
+msurface_t		*pface;
+surfcache_t		*pcurrentcache;
+vec3_t			transformed_modelorg;
+vec3_t			world_transformed_modelorg;
+vec3_t			local_modelorg;
+
+/*
+=============
+D_MipLevelForScale
+=============
+*/
+int D_MipLevelForScale (float scale)
+{
+	int		lmiplevel;
+
+	if (scale >= d_scalemip[0] )
+		lmiplevel = 0;
+	else if (scale >= d_scalemip[1] )
+		lmiplevel = 1;
+	else if (scale >= d_scalemip[2] )
+		lmiplevel = 2;
+	else
+		lmiplevel = 3;
+
+	if (lmiplevel < d_minmip)
+		lmiplevel = d_minmip;
+
+	return lmiplevel;
+}
+
+
+/*
+==============
+D_FlatFillSurface
+
+Simple single color fill with no texture mapping
+==============
+*/
+void D_FlatFillSurface (surf_t *surf, int color)
+{
+	espan_t	*span;
+	byte	*pdest;
+	int		u, u2;
+	
+	for (span=surf->spans ; span ; span=span->pnext)
+	{
+		pdest = (byte *)d_viewbuffer + r_screenwidth*span->v;
+		u = span->u;
+		u2 = span->u + span->count - 1;
+		for ( ; u <= u2 ; u++)
+			pdest[u] = color;
+	}
+}
+
+
+/*
+==============
+D_CalcGradients
+==============
+*/
+void D_CalcGradients (msurface_t *pface)
+{
+	mplane_t	*pplane;
+	float		mipscale;
+	vec3_t		p_temp1;
+	vec3_t		p_saxis, p_taxis;
+	float		t;
+
+	pplane = pface->plane;
+
+	mipscale = 1.0 / (float)(1 << miplevel);
+
+	TransformVector (pface->texinfo->vecs[0], p_saxis);
+	TransformVector (pface->texinfo->vecs[1], p_taxis);
+
+	t = xscaleinv * mipscale;
+	d_sdivzstepu = p_saxis[0] * t;
+	d_tdivzstepu = p_taxis[0] * t;
+
+	t = yscaleinv * mipscale;
+	d_sdivzstepv = -p_saxis[1] * t;
+	d_tdivzstepv = -p_taxis[1] * t;
+
+	d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
+			ycenter * d_sdivzstepv;
+	d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
+			ycenter * d_tdivzstepv;
+
+	VectorScale (transformed_modelorg, mipscale, p_temp1);
+
+	t = 0x10000*mipscale;
+	sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
+			((pface->texturemins[0] << 16) >> miplevel)
+			+ pface->texinfo->vecs[0][3]*t;
+	tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
+			((pface->texturemins[1] << 16) >> miplevel)
+			+ pface->texinfo->vecs[1][3]*t;
+
+	// PGM - changing flow speed for non-warping textures.
+	if (pface->texinfo->flags & SURF_FLOWING)
+	{
+		if(pface->texinfo->flags & SURF_WARP)
+			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) ));
+		else
+			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) ));
+	}
+	// PGM
+
+//
+// -1 (-epsilon) so we never wander off the edge of the texture
+//
+	bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
+	bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
+}
+
+
+/*
+==============
+D_BackgroundSurf
+
+The grey background filler seen when there is a hole in the map
+==============
+*/
+void D_BackgroundSurf (surf_t *s)
+{
+// set up a gradient for the background surface that places it
+// effectively at infinity distance from the viewpoint
+	d_zistepu = 0;
+	d_zistepv = 0;
+	d_ziorigin = -0.9;
+
+	D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF);
+	D_DrawZSpans (s->spans);
+}
+
+/*
+=================
+D_TurbulentSurf
+=================
+*/
+void D_TurbulentSurf (surf_t *s)
+{
+	d_zistepu = s->d_zistepu;
+	d_zistepv = s->d_zistepv;
+	d_ziorigin = s->d_ziorigin;
+
+	pface = s->msurf;
+	miplevel = 0;
+	cacheblock = pface->texinfo->image->pixels[0];
+	cachewidth = 64;
+
+	if (s->insubmodel)
+	{
+	// FIXME: we don't want to do all this for every polygon!
+	// TODO: store once at start of frame
+		currententity = s->entity;	//FIXME: make this passed in to
+									// R_RotateBmodel ()
+		VectorSubtract (r_origin, currententity->origin,
+				local_modelorg);
+		TransformVector (local_modelorg, transformed_modelorg);
+
+		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
+							// make entity passed in
+	}
+
+	D_CalcGradients (pface);
+
+//============
+//PGM
+	// textures that aren't warping are just flowing. Use NonTurbulent8 instead
+	if(!(pface->texinfo->flags & SURF_WARP))
+		NonTurbulent8 (s->spans);
+	else
+		Turbulent8 (s->spans);
+//PGM
+//============
+
+	D_DrawZSpans (s->spans);
+
+	if (s->insubmodel)
+	{
+	//
+	// restore the old drawing state
+	// FIXME: we don't want to do this every time!
+	// TODO: speed up
+	//
+		currententity = NULL;	// &r_worldentity;
+		VectorCopy (world_transformed_modelorg,
+					transformed_modelorg);
+		VectorCopy (base_vpn, vpn);
+		VectorCopy (base_vup, vup);
+		VectorCopy (base_vright, vright);
+		R_TransformFrustum ();
+	}
+}
+
+/*
+==============
+D_SkySurf
+==============
+*/
+void D_SkySurf (surf_t *s)
+{
+	pface = s->msurf;
+	miplevel = 0;
+	if (!pface->texinfo->image)
+		return;
+	cacheblock = pface->texinfo->image->pixels[0];
+	cachewidth = 256;
+
+	d_zistepu = s->d_zistepu;
+	d_zistepv = s->d_zistepv;
+	d_ziorigin = s->d_ziorigin;
+
+	D_CalcGradients (pface);
+
+	D_DrawSpans16 (s->spans);
+
+// set up a gradient for the background surface that places it
+// effectively at infinity distance from the viewpoint
+	d_zistepu = 0;
+	d_zistepv = 0;
+	d_ziorigin = -0.9;
+
+	D_DrawZSpans (s->spans);
+}
+
+/*
+==============
+D_SolidSurf
+
+Normal surface cached, texture mapped surface
+==============
+*/
+void D_SolidSurf (surf_t *s)
+{
+	d_zistepu = s->d_zistepu;
+	d_zistepv = s->d_zistepv;
+	d_ziorigin = s->d_ziorigin;
+
+	if (s->insubmodel)
+	{
+	// FIXME: we don't want to do all this for every polygon!
+	// TODO: store once at start of frame
+		currententity = s->entity;	//FIXME: make this passed in to
+									// R_RotateBmodel ()
+		VectorSubtract (r_origin, currententity->origin, local_modelorg);
+		TransformVector (local_modelorg, transformed_modelorg);
+
+		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
+							// make entity passed in
+	}
+	else
+		currententity = &r_worldentity;
+
+	pface = s->msurf;
+#if 1
+	miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
+#else
+	{
+		float dot;
+		float normal[3];
+
+		if ( s->insubmodel )
+		{
+			VectorCopy( pface->plane->normal, normal );
+//			TransformVector( pface->plane->normal, normal);
+			dot = DotProduct( normal, vpn );
+		}
+		else
+		{
+			VectorCopy( pface->plane->normal, normal );
+			dot = DotProduct( normal, vpn );
+		}
+
+		if ( pface->flags & SURF_PLANEBACK )
+			dot = -dot;
+
+		if ( dot > 0 )
+			printf( "blah" );
+
+		miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
+	}
+#endif
+
+// FIXME: make this passed in to D_CacheSurface
+	pcurrentcache = D_CacheSurface (pface, miplevel);
+
+	cacheblock = (pixel_t *)pcurrentcache->data;
+	cachewidth = pcurrentcache->width;
+
+	D_CalcGradients (pface);
+
+	D_DrawSpans16 (s->spans);
+
+	D_DrawZSpans (s->spans);
+
+	if (s->insubmodel)
+	{
+	//
+	// restore the old drawing state
+	// FIXME: we don't want to do this every time!
+	// TODO: speed up
+	//
+		VectorCopy (world_transformed_modelorg,
+					transformed_modelorg);
+		VectorCopy (base_vpn, vpn);
+		VectorCopy (base_vup, vup);
+		VectorCopy (base_vright, vright);
+		R_TransformFrustum ();
+		currententity = NULL;	//&r_worldentity;
+	}
+}
+
+/*
+=============
+D_DrawflatSurfaces
+
+To allow developers to see the polygon carving of the world
+=============
+*/
+void D_DrawflatSurfaces (void)
+{
+	surf_t			*s;
+
+	for (s = &surfaces[1] ; s<surface_p ; s++)
+	{
+		if (!s->spans)
+			continue;
+
+		d_zistepu = s->d_zistepu;
+		d_zistepv = s->d_zistepv;
+		d_ziorigin = s->d_ziorigin;
+
+		// make a stable color for each surface by taking the low
+		// bits of the msurface pointer
+		D_FlatFillSurface (s, (int)s->msurf & 0xFF);
+		D_DrawZSpans (s->spans);
+	}
+}
+
+/*
+==============
+D_DrawSurfaces
+
+Rasterize all the span lists.  Guaranteed zero overdraw.
+May be called more than once a frame if the surf list overflows (higher res)
+==============
+*/
+void D_DrawSurfaces (void)
+{
+	surf_t			*s;
+
+//	currententity = NULL;	//&r_worldentity;
+	VectorSubtract (r_origin, vec3_origin, modelorg);
+	TransformVector (modelorg, transformed_modelorg);
+	VectorCopy (transformed_modelorg, world_transformed_modelorg);
+
+	if (!sw_drawflat->value)
+	{
+		for (s = &surfaces[1] ; s<surface_p ; s++)
+		{
+			if (!s->spans)
+				continue;
+
+			r_drawnpolycount++;
+
+			if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) )
+				D_SolidSurf (s);
+			else if (s->flags & SURF_DRAWSKYBOX)
+				D_SkySurf (s);
+			else if (s->flags & SURF_DRAWBACKGROUND)
+				D_BackgroundSurf (s);
+			else if (s->flags & SURF_DRAWTURB)
+				D_TurbulentSurf (s);
+		}
+	}
+	else
+		D_DrawflatSurfaces ();
+
+	currententity = NULL;	//&r_worldentity;
+	VectorSubtract (r_origin, vec3_origin, modelorg);
+	R_TransformFrustum ();
+}
+
--- /dev/null
+++ b/ref_soft/r_edgea.asm
@@ -1,0 +1,733 @@
+ .386P
+ .model FLAT
+;
+; r_edgea.s
+; x86 assembly-language edge-processing code.
+;
+
+include qasm.inc
+
+if	id386
+
+_DATA SEGMENT	
+Ltemp dd 0	
+float_1_div_0100000h dd 035800000h	; 1.0/(float)0x100000
+float_point_999 dd 0.999	
+float_1_point_001 dd 1.001	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+;--------------------------------------------------------------------
+
+edgestoadd	equ		4+8		; note odd stack offsets because of interleaving
+edgelist	equ		8+12	; with pushes
+
+ public _R_EdgeCodeStart	
+_R_EdgeCodeStart:	
+
+ public _R_InsertNewEdges	
+_R_InsertNewEdges:	
+ push edi	
+ push esi	; preserve register variables
+ mov edx,ds:dword ptr[edgestoadd+esp]	
+ push ebx	
+ mov ecx,ds:dword ptr[edgelist+esp]	
+
+LDoNextEdge:	
+ mov eax,ds:dword ptr[et_u+edx]	
+ mov edi,edx	
+
+LContinueSearch:	
+ mov ebx,ds:dword ptr[et_u+ecx]	
+ mov esi,ds:dword ptr[et_next+ecx]	
+ cmp eax,ebx	
+ jle LAddedge	
+ mov ebx,ds:dword ptr[et_u+esi]	
+ mov ecx,ds:dword ptr[et_next+esi]	
+ cmp eax,ebx	
+ jle LAddedge2	
+ mov ebx,ds:dword ptr[et_u+ecx]	
+ mov esi,ds:dword ptr[et_next+ecx]	
+ cmp eax,ebx	
+ jle LAddedge	
+ mov ebx,ds:dword ptr[et_u+esi]	
+ mov ecx,ds:dword ptr[et_next+esi]	
+ cmp eax,ebx	
+ jg LContinueSearch	
+
+LAddedge2:	
+ mov edx,ds:dword ptr[et_next+edx]	
+ mov ebx,ds:dword ptr[et_prev+esi]	
+ mov ds:dword ptr[et_next+edi],esi	
+ mov ds:dword ptr[et_prev+edi],ebx	
+ mov ds:dword ptr[et_next+ebx],edi	
+ mov ds:dword ptr[et_prev+esi],edi	
+ mov ecx,esi	
+
+ cmp edx,0	
+ jnz LDoNextEdge	
+ jmp LDone	
+
+ align 4	
+LAddedge:	
+ mov edx,ds:dword ptr[et_next+edx]	
+ mov ebx,ds:dword ptr[et_prev+ecx]	
+ mov ds:dword ptr[et_next+edi],ecx	
+ mov ds:dword ptr[et_prev+edi],ebx	
+ mov ds:dword ptr[et_next+ebx],edi	
+ mov ds:dword ptr[et_prev+ecx],edi	
+
+ cmp edx,0	
+ jnz LDoNextEdge	
+
+LDone:	
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+
+ ret	
+
+;--------------------------------------------------------------------
+
+predge	equ		4+4
+
+ public _R_RemoveEdges	
+_R_RemoveEdges:	
+ push ebx	
+ mov eax,ds:dword ptr[predge+esp]	
+
+Lre_loop:	
+ mov ecx,ds:dword ptr[et_next+eax]	
+ mov ebx,ds:dword ptr[et_nextremove+eax]	
+ mov edx,ds:dword ptr[et_prev+eax]	
+ test ebx,ebx	
+ mov ds:dword ptr[et_prev+ecx],edx	
+ jz Lre_done	
+ mov ds:dword ptr[et_next+edx],ecx	
+
+ mov ecx,ds:dword ptr[et_next+ebx]	
+ mov edx,ds:dword ptr[et_prev+ebx]	
+ mov eax,ds:dword ptr[et_nextremove+ebx]	
+ mov ds:dword ptr[et_prev+ecx],edx	
+ test eax,eax	
+ mov ds:dword ptr[et_next+edx],ecx	
+ jnz Lre_loop	
+
+ pop ebx	
+ ret	
+
+Lre_done:	
+ mov ds:dword ptr[et_next+edx],ecx	
+ pop ebx	
+
+ ret	
+
+;--------------------------------------------------------------------
+
+pedgelist	equ		4+4		; note odd stack offset because of interleaving
+							; with pushes
+
+ public _R_StepActiveU	
+_R_StepActiveU:	
+ push edi	
+ mov edx,ds:dword ptr[pedgelist+esp]	
+ push esi	; preserve register variables
+ push ebx	
+
+ mov esi,ds:dword ptr[et_prev+edx]	
+
+LNewEdge:	
+ mov edi,ds:dword ptr[et_u+esi]	
+
+LNextEdge:	
+ mov eax,ds:dword ptr[et_u+edx]	
+ mov ebx,ds:dword ptr[et_u_step+edx]	
+ add eax,ebx	
+ mov esi,ds:dword ptr[et_next+edx]	
+ mov ds:dword ptr[et_u+edx],eax	
+ cmp eax,edi	
+ jl LPushBack	
+
+ mov edi,ds:dword ptr[et_u+esi]	
+ mov ebx,ds:dword ptr[et_u_step+esi]	
+ add edi,ebx	
+ mov edx,ds:dword ptr[et_next+esi]	
+ mov ds:dword ptr[et_u+esi],edi	
+ cmp edi,eax	
+ jl LPushBack2	
+
+ mov eax,ds:dword ptr[et_u+edx]	
+ mov ebx,ds:dword ptr[et_u_step+edx]	
+ add eax,ebx	
+ mov esi,ds:dword ptr[et_next+edx]	
+ mov ds:dword ptr[et_u+edx],eax	
+ cmp eax,edi	
+ jl LPushBack	
+
+ mov edi,ds:dword ptr[et_u+esi]	
+ mov ebx,ds:dword ptr[et_u_step+esi]	
+ add edi,ebx	
+ mov edx,ds:dword ptr[et_next+esi]	
+ mov ds:dword ptr[et_u+esi],edi	
+ cmp edi,eax	
+ jnl LNextEdge	
+
+LPushBack2:	
+ mov ebx,edx	
+ mov eax,edi	
+ mov edx,esi	
+ mov esi,ebx	
+
+LPushBack:	
+; push it back to keep it sorted
+ mov ecx,ds:dword ptr[et_prev+edx]	
+ mov ebx,ds:dword ptr[et_next+edx]	
+
+; done if the -1 in edge_aftertail triggered this
+ cmp edx,offset _edge_aftertail
+ jz LUDone	
+
+; pull the edge out of the edge list
+ mov edi,ds:dword ptr[et_prev+ecx]	
+ mov ds:dword ptr[et_prev+esi],ecx	
+ mov ds:dword ptr[et_next+ecx],ebx	
+
+; find out where the edge goes in the edge list
+LPushBackLoop:	
+ mov ecx,ds:dword ptr[et_prev+edi]	
+ mov ebx,ds:dword ptr[et_u+edi]	
+ cmp eax,ebx	
+ jnl LPushBackFound	
+
+ mov edi,ds:dword ptr[et_prev+ecx]	
+ mov ebx,ds:dword ptr[et_u+ecx]	
+ cmp eax,ebx	
+ jl LPushBackLoop	
+
+ mov edi,ecx	
+
+; put the edge back into the edge list
+LPushBackFound:	
+ mov ebx,ds:dword ptr[et_next+edi]	
+ mov ds:dword ptr[et_prev+edx],edi	
+ mov ds:dword ptr[et_next+edx],ebx	
+ mov ds:dword ptr[et_next+edi],edx	
+ mov ds:dword ptr[et_prev+ebx],edx	
+
+ mov edx,esi	
+ mov esi,ds:dword ptr[et_prev+esi]	
+
+ cmp edx,offset _edge_tail
+ jnz LNewEdge	
+
+LUDone:	
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+
+ ret	
+
+;--------------------------------------------------------------------
+
+surf	equ		4		; note this is loaded before any pushes
+
+ align 4	
+TrailingEdge:	
+ mov eax,ds:dword ptr[st_spanstate+esi]	; check for edge inversion
+ dec eax	
+ jnz LInverted	
+
+ mov ds:dword ptr[st_spanstate+esi],eax	
+ mov ecx,ds:dword ptr[st_insubmodel+esi]	
+ mov edx,ds:dword ptr[12345678h]	; surfaces[1].st_next
+LPatch0:	
+ mov eax,ds:dword ptr[_r_bmodelactive]	
+ sub eax,ecx	
+ cmp edx,esi	
+ mov ds:dword ptr[_r_bmodelactive],eax	
+ jnz LNoEmit	; surface isn't on top, just remove
+
+; emit a span (current top going away)
+ mov eax,ds:dword ptr[et_u+ebx]	
+ shr eax,20	; iu = integral pixel u
+ mov edx,ds:dword ptr[st_last_u+esi]	
+ mov ecx,ds:dword ptr[st_next+esi]	
+ cmp eax,edx	
+ jle LNoEmit2	; iu <= surf->last_u, so nothing to emit
+
+ mov ds:dword ptr[st_last_u+ecx],eax	; surf->next->last_u = iu;
+ sub eax,edx	
+ mov ds:dword ptr[espan_t_u+ebp],edx	; span->u = surf->last_u;
+
+ mov ds:dword ptr[espan_t_count+ebp],eax	; span->count = iu - span->u;
+ mov eax,ds:dword ptr[_current_iv]	
+ mov ds:dword ptr[espan_t_v+ebp],eax	; span->v = current_iv;
+ mov eax,ds:dword ptr[st_spans+esi]	
+ mov ds:dword ptr[espan_t_pnext+ebp],eax	; span->pnext = surf->spans;
+ mov ds:dword ptr[st_spans+esi],ebp	; surf->spans = span;
+ add ebp,offset espan_t_size	
+
+ mov edx,ds:dword ptr[st_next+esi]	; remove the surface from the surface
+ mov esi,ds:dword ptr[st_prev+esi]	; stack
+
+ mov ds:dword ptr[st_next+esi],edx	
+ mov ds:dword ptr[st_prev+edx],esi	
+ ret	
+
+LNoEmit2:	
+ mov ds:dword ptr[st_last_u+ecx],eax	; surf->next->last_u = iu;
+ mov edx,ds:dword ptr[st_next+esi]	; remove the surface from the surface
+ mov esi,ds:dword ptr[st_prev+esi]	; stack
+
+ mov ds:dword ptr[st_next+esi],edx	
+ mov ds:dword ptr[st_prev+edx],esi	
+ ret	
+
+LNoEmit:	
+ mov edx,ds:dword ptr[st_next+esi]	; remove the surface from the surface
+ mov esi,ds:dword ptr[st_prev+esi]	; stack
+
+ mov ds:dword ptr[st_next+esi],edx	
+ mov ds:dword ptr[st_prev+edx],esi	
+ ret	
+
+LInverted:	
+ mov ds:dword ptr[st_spanstate+esi],eax	
+ ret	
+
+;--------------------------------------------------------------------
+
+; trailing edge only
+Lgs_trailing:	
+ push offset Lgs_nextedge	
+ jmp TrailingEdge	
+
+
+ public _R_GenerateSpans	
+_R_GenerateSpans:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+; clear active surfaces to just the background surface
+ mov eax,ds:dword ptr[_surfaces]	
+ mov edx,ds:dword ptr[_edge_head_u_shift20]	
+ add eax,offset st_size	
+; %ebp = span_p throughout
+ mov ebp,ds:dword ptr[_span_p]	
+
+ mov ds:dword ptr[_r_bmodelactive],0	
+
+ mov ds:dword ptr[st_next+eax],eax	
+ mov ds:dword ptr[st_prev+eax],eax	
+ mov ds:dword ptr[st_last_u+eax],edx	
+ mov ebx,ds:dword ptr[_edge_head+et_next]	; edge=edge_head.next
+
+; generate spans
+ cmp ebx,offset _edge_tail	; done if empty list
+ jz Lgs_lastspan	
+
+Lgs_edgeloop:	
+
+ mov edi,ds:dword ptr[et_surfs+ebx]	
+ mov eax,ds:dword ptr[_surfaces]	
+ mov esi,edi	
+ and edi,0FFFF0000h	
+ and esi,0FFFFh	
+ jz Lgs_leading	; not a trailing edge
+
+; it has a left surface, so a surface is going away for this span
+ shl esi,offset SURF_T_SHIFT	
+ add esi,eax	
+ test edi,edi	
+ jz Lgs_trailing	
+
+; both leading and trailing
+ call near ptr TrailingEdge	
+ mov eax,ds:dword ptr[_surfaces]	
+
+; ---------------------------------------------------------------
+; handle a leading edge
+; ---------------------------------------------------------------
+
+Lgs_leading:	
+ shr edi,16-SURF_T_SHIFT	
+ mov eax,ds:dword ptr[_surfaces]	
+ add edi,eax	
+ mov esi,ds:dword ptr[12345678h]	; surf2 = surfaces[1].next;
+LPatch2:	
+ mov edx,ds:dword ptr[st_spanstate+edi]	
+ mov eax,ds:dword ptr[st_insubmodel+edi]	
+ test eax,eax	
+ jnz Lbmodel_leading	
+
+; handle a leading non-bmodel edge
+
+; don't start a span if this is an inverted span, with the end edge preceding
+; the start edge (that is, we've already seen the end edge)
+ test edx,edx	
+ jnz Lxl_done	
+
+
+; if (surf->key < surf2->key)
+;		goto newtop;
+ inc edx	
+ mov eax,ds:dword ptr[st_key+edi]	
+ mov ds:dword ptr[st_spanstate+edi],edx	
+ mov ecx,ds:dword ptr[st_key+esi]	
+ cmp eax,ecx	
+ jl Lnewtop	
+
+; main sorting loop to search through surface stack until insertion point
+; found. Always terminates because background surface is sentinel
+; do
+; {
+; 		surf2 = surf2->next;
+; } while (surf->key >= surf2->key);
+Lsortloopnb:	
+ mov esi,ds:dword ptr[st_next+esi]	
+ mov ecx,ds:dword ptr[st_key+esi]	
+ cmp eax,ecx	
+ jge Lsortloopnb	
+
+ jmp LInsertAndExit	
+
+
+; handle a leading bmodel edge
+ align 4	
+Lbmodel_leading:	
+
+; don't start a span if this is an inverted span, with the end edge preceding
+; the start edge (that is, we've already seen the end edge)
+ test edx,edx	
+ jnz Lxl_done	
+
+ mov ecx,ds:dword ptr[_r_bmodelactive]	
+ inc edx	
+ inc ecx	
+ mov ds:dword ptr[st_spanstate+edi],edx	
+ mov ds:dword ptr[_r_bmodelactive],ecx	
+
+; if (surf->key < surf2->key)
+;		goto newtop;
+ mov eax,ds:dword ptr[st_key+edi]	
+ mov ecx,ds:dword ptr[st_key+esi]	
+ cmp eax,ecx	
+ jl Lnewtop	
+
+; if ((surf->key == surf2->key) && surf->insubmodel)
+; {
+ jz Lzcheck_for_newtop	
+
+; main sorting loop to search through surface stack until insertion point
+; found. Always terminates because background surface is sentinel
+; do
+; {
+; 		surf2 = surf2->next;
+; } while (surf->key > surf2->key);
+Lsortloop:	
+ mov esi,ds:dword ptr[st_next+esi]	
+ mov ecx,ds:dword ptr[st_key+esi]	
+ cmp eax,ecx	
+ jg Lsortloop	
+
+ jne LInsertAndExit	
+
+; Do 1/z sorting to see if we've arrived in the right position
+ mov eax,ds:dword ptr[et_u+ebx]	
+ sub eax,0FFFFFh	
+ mov ds:dword ptr[Ltemp],eax	
+ fild ds:dword ptr[Ltemp]	
+
+ fmul ds:dword ptr[float_1_div_0100000h]	; fu = (float)(edge->u - 0xFFFFF) *
+;      (1.0 / 0x100000);
+
+ fld st(0)	; fu | fu
+ fmul ds:dword ptr[st_d_zistepu+edi]	; fu*surf->d_zistepu | fu
+ fld ds:dword ptr[_fv]	; fv | fu*surf->d_zistepu | fu
+ fmul ds:dword ptr[st_d_zistepv+edi]	; fv*surf->d_zistepv | fu*surf->d_zistepu | fu
+ fxch st(1)	; fu*surf->d_zistepu | fv*surf->d_zistepv | fu
+ fadd ds:dword ptr[st_d_ziorigin+edi]	; fu*surf->d_zistepu + surf->d_ziorigin |
+;  fv*surf->d_zistepv | fu
+
+ fld ds:dword ptr[st_d_zistepu+esi]	; surf2->d_zistepu |
+;  fu*surf->d_zistepu + surf->d_ziorigin |
+;  fv*surf->d_zistepv | fu
+ fmul st(0),st(3)	; fu*surf2->d_zistepu |
+;  fu*surf->d_zistepu + surf->d_ziorigin |
+;  fv*surf->d_zistepv | fu
+ fxch st(1)	; fu*surf->d_zistepu + surf->d_ziorigin |
+;  fu*surf2->d_zistepu |
+;  fv*surf->d_zistepv | fu
+ faddp st(2),st(0)	; fu*surf2->d_zistepu | newzi | fu
+
+ fld ds:dword ptr[_fv]	; fv | fu*surf2->d_zistepu | newzi | fu
+ fmul ds:dword ptr[st_d_zistepv+esi]	; fv*surf2->d_zistepv |
+;  fu*surf2->d_zistepu | newzi | fu
+ fld st(2)	; newzi | fv*surf2->d_zistepv |
+;  fu*surf2->d_zistepu | newzi | fu
+ fmul ds:dword ptr[float_point_999]	; newzibottom | fv*surf2->d_zistepv |
+;  fu*surf2->d_zistepu | newzi | fu
+
+ fxch st(2)	; fu*surf2->d_zistepu | fv*surf2->d_zistepv |
+;  newzibottom | newzi | fu
+ fadd ds:dword ptr[st_d_ziorigin+esi]	; fu*surf2->d_zistepu + surf2->d_ziorigin |
+;  fv*surf2->d_zistepv | newzibottom | newzi |
+;  fu
+ faddp st(1),st(0)	; testzi | newzibottom | newzi | fu
+ fxch st(1)	; newzibottom | testzi | newzi | fu
+
+; if (newzibottom >= testzi)
+;     goto Lgotposition;
+
+ fcomp st(1)	; testzi | newzi | fu
+
+ fxch st(1)	; newzi | testzi | fu
+ fmul ds:dword ptr[float_1_point_001]	; newzitop | testzi | fu
+ fxch st(1)	; testzi | newzitop | fu
+
+ fnstsw ax	
+ test ah,001h	
+ jz Lgotposition_fpop3	
+
+; if (newzitop >= testzi)
+; {
+
+ fcomp st(1)	; newzitop | fu
+ fnstsw ax	
+ test ah,045h	
+ jz Lsortloop_fpop2	
+
+; if (surf->d_zistepu >= surf2->d_zistepu)
+;     goto newtop;
+
+ fld ds:dword ptr[st_d_zistepu+edi]	; surf->d_zistepu | newzitop| fu
+ fcomp ds:dword ptr[st_d_zistepu+esi]	; newzitop | fu
+ fnstsw ax	
+ test ah,001h	
+ jz Lgotposition_fpop2	
+
+ fstp st(0)	; clear the FPstack
+ fstp st(0)	
+ mov eax,ds:dword ptr[st_key+edi]	
+ jmp Lsortloop	
+
+
+Lgotposition_fpop3:	
+ fstp st(0)	
+Lgotposition_fpop2:	
+ fstp st(0)	
+ fstp st(0)	
+ jmp LInsertAndExit	
+
+
+; emit a span (obscures current top)
+
+Lnewtop_fpop3:	
+ fstp st(0)	
+Lnewtop_fpop2:	
+ fstp st(0)	
+ fstp st(0)	
+ mov eax,ds:dword ptr[st_key+edi]	; reload the sorting key
+
+Lnewtop:	
+ mov eax,ds:dword ptr[et_u+ebx]	
+ mov edx,ds:dword ptr[st_last_u+esi]	
+ shr eax,20	; iu = integral pixel u
+ mov ds:dword ptr[st_last_u+edi],eax	; surf->last_u = iu;
+ cmp eax,edx	
+ jle LInsertAndExit	; iu <= surf->last_u, so nothing to emit
+
+ sub eax,edx	
+ mov ds:dword ptr[espan_t_u+ebp],edx	; span->u = surf->last_u;
+
+ mov ds:dword ptr[espan_t_count+ebp],eax	; span->count = iu - span->u;
+ mov eax,ds:dword ptr[_current_iv]	
+ mov ds:dword ptr[espan_t_v+ebp],eax	; span->v = current_iv;
+ mov eax,ds:dword ptr[st_spans+esi]	
+ mov ds:dword ptr[espan_t_pnext+ebp],eax	; span->pnext = surf->spans;
+ mov ds:dword ptr[st_spans+esi],ebp	; surf->spans = span;
+ add ebp,offset espan_t_size	
+
+LInsertAndExit:	
+; insert before surf2
+ mov ds:dword ptr[st_next+edi],esi	; surf->next = surf2;
+ mov eax,ds:dword ptr[st_prev+esi]	
+ mov ds:dword ptr[st_prev+edi],eax	; surf->prev = surf2->prev;
+ mov ds:dword ptr[st_prev+esi],edi	; surf2->prev = surf;
+ mov ds:dword ptr[st_next+eax],edi	; surf2->prev->next = surf;
+
+; ---------------------------------------------------------------
+; leading edge done
+; ---------------------------------------------------------------
+
+; ---------------------------------------------------------------
+; see if there are any more edges
+; ---------------------------------------------------------------
+
+Lgs_nextedge:	
+ mov ebx,ds:dword ptr[et_next+ebx]	
+ cmp ebx,offset _edge_tail
+ jnz Lgs_edgeloop	
+
+; clean up at the right edge
+Lgs_lastspan:	
+
+; now that we've reached the right edge of the screen, we're done with any
+; unfinished surfaces, so emit a span for whatever's on top
+ mov esi,ds:dword ptr[12345678h]	; surfaces[1].st_next
+LPatch3:	
+ mov eax,ds:dword ptr[_edge_tail_u_shift20]	
+ xor ecx,ecx	
+ mov edx,ds:dword ptr[st_last_u+esi]	
+ sub eax,edx	
+ jle Lgs_resetspanstate	
+
+ mov ds:dword ptr[espan_t_u+ebp],edx	
+ mov ds:dword ptr[espan_t_count+ebp],eax	
+ mov eax,ds:dword ptr[_current_iv]	
+ mov ds:dword ptr[espan_t_v+ebp],eax	
+ mov eax,ds:dword ptr[st_spans+esi]	
+ mov ds:dword ptr[espan_t_pnext+ebp],eax	
+ mov ds:dword ptr[st_spans+esi],ebp	
+ add ebp,offset espan_t_size	
+
+; reset spanstate for all surfaces in the surface stack
+Lgs_resetspanstate:	
+ mov ds:dword ptr[st_spanstate+esi],ecx	
+ mov esi,ds:dword ptr[st_next+esi]	
+ cmp esi,012345678h	; &surfaces[1]
+LPatch4:	
+ jnz Lgs_resetspanstate	
+
+; store the final span_p
+ mov ds:dword ptr[_span_p],ebp	
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+; ---------------------------------------------------------------
+; 1/z sorting for bmodels in the same leaf
+; ---------------------------------------------------------------
+ align 4	
+Lxl_done:	
+ inc edx	
+ mov ds:dword ptr[st_spanstate+edi],edx	
+
+ jmp Lgs_nextedge	
+
+
+ align 4	
+Lzcheck_for_newtop:	
+ mov eax,ds:dword ptr[et_u+ebx]	
+ sub eax,0FFFFFh	
+ mov ds:dword ptr[Ltemp],eax	
+ fild ds:dword ptr[Ltemp]	
+
+ fmul ds:dword ptr[float_1_div_0100000h]	; fu = (float)(edge->u - 0xFFFFF) *
+;      (1.0 / 0x100000);
+
+ fld st(0)	; fu | fu
+ fmul ds:dword ptr[st_d_zistepu+edi]	; fu*surf->d_zistepu | fu
+ fld ds:dword ptr[_fv]	; fv | fu*surf->d_zistepu | fu
+ fmul ds:dword ptr[st_d_zistepv+edi]	; fv*surf->d_zistepv | fu*surf->d_zistepu | fu
+ fxch st(1)	; fu*surf->d_zistepu | fv*surf->d_zistepv | fu
+ fadd ds:dword ptr[st_d_ziorigin+edi]	; fu*surf->d_zistepu + surf->d_ziorigin |
+;  fv*surf->d_zistepv | fu
+
+ fld ds:dword ptr[st_d_zistepu+esi]	; surf2->d_zistepu |
+;  fu*surf->d_zistepu + surf->d_ziorigin |
+;  fv*surf->d_zistepv | fu
+ fmul st(0),st(3)	; fu*surf2->d_zistepu |
+;  fu*surf->d_zistepu + surf->d_ziorigin |
+;  fv*surf->d_zistepv | fu
+ fxch st(1)	; fu*surf->d_zistepu + surf->d_ziorigin |
+;  fu*surf2->d_zistepu |
+;  fv*surf->d_zistepv | fu
+ faddp st(2),st(0)	; fu*surf2->d_zistepu | newzi | fu
+
+ fld ds:dword ptr[_fv]	; fv | fu*surf2->d_zistepu | newzi | fu
+ fmul ds:dword ptr[st_d_zistepv+esi]	; fv*surf2->d_zistepv |
+;  fu*surf2->d_zistepu | newzi | fu
+ fld st(2)	; newzi | fv*surf2->d_zistepv |
+;  fu*surf2->d_zistepu | newzi | fu
+ fmul ds:dword ptr[float_point_999]	; newzibottom | fv*surf2->d_zistepv |
+;  fu*surf2->d_zistepu | newzi | fu
+
+ fxch st(2)	; fu*surf2->d_zistepu | fv*surf2->d_zistepv |
+;  newzibottom | newzi | fu
+ fadd ds:dword ptr[st_d_ziorigin+esi]	; fu*surf2->d_zistepu + surf2->d_ziorigin |
+;  fv*surf2->d_zistepv | newzibottom | newzi |
+;  fu
+ faddp st(1),st(0)	; testzi | newzibottom | newzi | fu
+ fxch st(1)	; newzibottom | testzi | newzi | fu
+
+; if (newzibottom >= testzi)
+;     goto newtop;
+
+ fcomp st(1)	; testzi | newzi | fu
+
+ fxch st(1)	; newzi | testzi | fu
+ fmul ds:dword ptr[float_1_point_001]	; newzitop | testzi | fu
+ fxch st(1)	; testzi | newzitop | fu
+
+ fnstsw ax	
+ test ah,001h	
+ jz Lnewtop_fpop3	
+
+; if (newzitop >= testzi)
+; {
+
+ fcomp st(1)	; newzitop | fu
+ fnstsw ax	
+ test ah,045h	
+ jz Lsortloop_fpop2	
+
+; if (surf->d_zistepu >= surf2->d_zistepu)
+;     goto newtop;
+
+ fld ds:dword ptr[st_d_zistepu+edi]	; surf->d_zistepu | newzitop | fu
+ fcomp ds:dword ptr[st_d_zistepu+esi]	; newzitop | fu
+ fnstsw ax	
+ test ah,001h	
+ jz Lnewtop_fpop2	
+
+Lsortloop_fpop2:	
+ fstp st(0)	; clear the FP stack
+ fstp st(0)	
+ mov eax,ds:dword ptr[st_key+edi]	
+ jmp Lsortloop	
+
+
+ public _R_EdgeCodeEnd	
+_R_EdgeCodeEnd:	
+
+
+;----------------------------------------------------------------------
+; Surface array address code patching routine
+;----------------------------------------------------------------------
+
+ align 4	
+ public _R_SurfacePatch	
+_R_SurfacePatch:	
+
+ mov eax,ds:dword ptr[_surfaces]	
+ add eax,offset st_size	
+ mov ds:dword ptr[LPatch4-4],eax	
+
+ add eax,offset st_next	
+ mov ds:dword ptr[LPatch0-4],eax	
+ mov ds:dword ptr[LPatch2-4],eax	
+ mov ds:dword ptr[LPatch3-4],eax	
+
+ ret	
+
+_TEXT ENDS
+endif	;id386
+ END
--- /dev/null
+++ b/ref_soft/r_image.c
@@ -1,0 +1,617 @@
+/*
+Copyright (C) 1997-2001 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 "r_local.h"
+
+
+#define	MAX_RIMAGES	1024
+image_t		r_images[MAX_RIMAGES];
+int			numr_images;
+
+
+/*
+===============
+R_ImageList_f
+===============
+*/
+void	R_ImageList_f (void)
+{
+	int		i;
+	image_t	*image;
+	int		texels;
+
+	ri.Con_Printf (PRINT_ALL, "------------------\n");
+	texels = 0;
+
+	for (i=0, image=r_images ; i<numr_images ; i++, image++)
+	{
+		if (image->registration_sequence <= 0)
+			continue;
+		texels += image->width*image->height;
+		switch (image->type)
+		{
+		case it_skin:
+			ri.Con_Printf (PRINT_ALL, "M");
+			break;
+		case it_sprite:
+			ri.Con_Printf (PRINT_ALL, "S");
+			break;
+		case it_wall:
+			ri.Con_Printf (PRINT_ALL, "W");
+			break;
+		case it_pic:
+			ri.Con_Printf (PRINT_ALL, "P");
+			break;
+		default:
+			ri.Con_Printf (PRINT_ALL, " ");
+			break;
+		}
+
+		ri.Con_Printf (PRINT_ALL,  " %3i %3i : %s\n",
+			image->width, image->height, image->name);
+	}
+	ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels);
+}
+
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+/*
+==============
+LoadPCX
+==============
+*/
+void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+	byte	*raw;
+	pcx_t	*pcx;
+	int		x, y;
+	int		len;
+	int		dataByte, runLength;
+	byte	*out, *pix;
+
+	*pic = NULL;
+
+	//
+	// load the file
+	//
+	len = ri.FS_LoadFile (filename, (void **)&raw);
+	if (!raw)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
+		return;
+	}
+
+	//
+	// parse the PCX file
+	//
+	pcx = (pcx_t *)raw;
+
+    pcx->xmin = LittleShort(pcx->xmin);
+    pcx->ymin = LittleShort(pcx->ymin);
+    pcx->xmax = LittleShort(pcx->xmax);
+    pcx->ymax = LittleShort(pcx->ymax);
+    pcx->hres = LittleShort(pcx->hres);
+    pcx->vres = LittleShort(pcx->vres);
+    pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
+    pcx->palette_type = LittleShort(pcx->palette_type);
+
+	raw = &pcx->data;
+
+	if (pcx->manufacturer != 0x0a
+		|| pcx->version != 5
+		|| pcx->encoding != 1
+		|| pcx->bits_per_pixel != 8
+		|| pcx->xmax >= 640
+		|| pcx->ymax >= 480)
+	{
+		ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
+		return;
+	}
+
+	out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+	*pic = out;
+
+	pix = out;
+
+	if (palette)
+	{
+		*palette = malloc(768);
+		memcpy (*palette, (byte *)pcx + len - 768, 768);
+	}
+
+	if (width)
+		*width = pcx->xmax+1;
+	if (height)
+		*height = pcx->ymax+1;
+
+	for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+	{
+		for (x=0 ; x<=pcx->xmax ; )
+		{
+			dataByte = *raw++;
+
+			if((dataByte & 0xC0) == 0xC0)
+			{
+				runLength = dataByte & 0x3F;
+				dataByte = *raw++;
+			}
+			else
+				runLength = 1;
+
+			while(runLength-- > 0)
+				pix[x++] = dataByte;
+		}
+
+	}
+
+	if ( raw - (byte *)pcx > len)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
+		free (*pic);
+		*pic = NULL;
+	}
+
+	ri.FS_FreeFile (pcx);
+}
+
+/*
+=========================================================
+
+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;
+
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (char *name, byte **pic, int *width, int *height)
+{
+	int		columns, rows, numPixels;
+	byte	*pixbuf;
+	int		row, column;
+	byte	*buf_p;
+	byte	*buffer;
+	int		length;
+	TargaHeader		targa_header;
+	byte			*targa_rgba;
+
+	*pic = NULL;
+
+	//
+	// load the file
+	//
+	length = ri.FS_LoadFile (name, (void **)&buffer);
+	if (!buffer)
+	{
+		ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
+		return;
+	}
+
+	buf_p = buffer;
+
+	targa_header.id_length = *buf_p++;
+	targa_header.colormap_type = *buf_p++;
+	targa_header.image_type = *buf_p++;
+	
+	targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.colormap_size = *buf_p++;
+	targa_header.x_origin = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.y_origin = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.width = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.height = LittleShort ( *((short *)buf_p) );
+	buf_p+=2;
+	targa_header.pixel_size = *buf_p++;
+	targa_header.attributes = *buf_p++;
+
+	if (targa_header.image_type!=2 
+		&& targa_header.image_type!=10) 
+		ri.Sys_Error (ERR_DROP, "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))
+		ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+
+	columns = targa_header.width;
+	rows = targa_header.height;
+	numPixels = columns * rows;
+
+	if (width)
+		*width = columns;
+	if (height)
+		*height = rows;
+
+	targa_rgba = malloc (numPixels*4);
+	*pic = targa_rgba;
+
+	if (targa_header.id_length != 0)
+		buf_p += targa_header.id_length;  // 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 = *buf_p++;
+							green = *buf_p++;
+							red = *buf_p++;
+							*pixbuf++ = red;
+							*pixbuf++ = green;
+							*pixbuf++ = blue;
+							*pixbuf++ = 255;
+							break;
+					case 32:
+							blue = *buf_p++;
+							green = *buf_p++;
+							red = *buf_p++;
+							alphabyte = *buf_p++;
+							*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= *buf_p++;
+				packetSize = 1 + (packetHeader & 0x7f);
+				if (packetHeader & 0x80) {        // run-length packet
+					switch (targa_header.pixel_size) {
+						case 24:
+								blue = *buf_p++;
+								green = *buf_p++;
+								red = *buf_p++;
+								alphabyte = 255;
+								break;
+						case 32:
+								blue = *buf_p++;
+								green = *buf_p++;
+								red = *buf_p++;
+								alphabyte = *buf_p++;
+								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 = *buf_p++;
+									green = *buf_p++;
+									red = *buf_p++;
+									*pixbuf++ = red;
+									*pixbuf++ = green;
+									*pixbuf++ = blue;
+									*pixbuf++ = 255;
+									break;
+							case 32:
+									blue = *buf_p++;
+									green = *buf_p++;
+									red = *buf_p++;
+									alphabyte = *buf_p++;
+									*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:;
+		}
+	}
+
+	ri.FS_FreeFile (buffer);
+}
+
+
+//=======================================================
+
+image_t *R_FindFreeImage (void)
+{
+	image_t		*image;
+	int			i;
+
+	// find a free image_t
+	for (i=0, image=r_images ; i<numr_images ; i++,image++)
+	{
+		if (!image->registration_sequence)
+			break;
+	}
+	if (i == numr_images)
+	{
+		if (numr_images == MAX_RIMAGES)
+			ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
+		numr_images++;
+	}
+	image = &r_images[i];
+
+	return image;
+}
+
+/*
+================
+GL_LoadPic
+
+================
+*/
+image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
+{
+	image_t		*image;
+	int			i, c, b;
+
+	image = R_FindFreeImage ();
+	if (strlen(name) >= sizeof(image->name))
+		ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
+	strcpy (image->name, name);
+	image->registration_sequence = registration_sequence;
+
+	image->width = width;
+	image->height = height;
+	image->type = type;
+
+	c = width*height;
+	image->pixels[0] = malloc (c);
+	image->transparent = false;
+	for (i=0 ; i<c ; i++)
+	{
+		b = pic[i];
+		if (b == 255)
+			image->transparent = true;
+		image->pixels[0][i] = b;
+	}
+
+	return image;
+}
+
+/*
+================
+R_LoadWal
+================
+*/
+image_t *R_LoadWal (char *name)
+{
+	miptex_t	*mt;
+	int			ofs;
+	image_t		*image;
+	int			size;
+
+	ri.FS_LoadFile (name, (void **)&mt);
+	if (!mt)
+	{
+		ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name);
+		return r_notexture_mip;
+	}
+
+	image = R_FindFreeImage ();
+	strcpy (image->name, name);
+	image->width = LittleLong (mt->width);
+	image->height = LittleLong (mt->height);
+	image->type = it_wall;
+	image->registration_sequence = registration_sequence;
+
+	size = image->width*image->height * (256+64+16+4)/256;
+	image->pixels[0] = malloc (size);
+	image->pixels[1] = image->pixels[0] + image->width*image->height;
+	image->pixels[2] = image->pixels[1] + image->width*image->height/4;
+	image->pixels[3] = image->pixels[2] + image->width*image->height/16;
+
+	ofs = LittleLong (mt->offsets[0]);
+	memcpy ( image->pixels[0], (byte *)mt + ofs, size);
+
+	ri.FS_FreeFile ((void *)mt);
+
+	return image;
+}
+
+
+/*
+===============
+R_FindImage
+
+Finds or loads the given image
+===============
+*/
+image_t	*R_FindImage (char *name, imagetype_t type)
+{
+	image_t	*image;
+	int		i, len;
+	byte	*pic, *palette;
+	int		width, height;
+
+	if (!name)
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
+	len = strlen(name);
+	if (len<5)
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
+
+	// look for it
+	for (i=0, image=r_images ; i<numr_images ; i++,image++)
+	{
+		if (!strcmp(name, image->name))
+		{
+			image->registration_sequence = registration_sequence;
+			return image;
+		}
+	}
+
+	//
+	// load the pic from disk
+	//
+	pic = NULL;
+	palette = NULL;
+	if (!strcmp(name+len-4, ".pcx"))
+	{
+		LoadPCX (name, &pic, &palette, &width, &height);
+		if (!pic)
+			return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name);
+		image = GL_LoadPic (name, pic, width, height, type);
+	}
+	else if (!strcmp(name+len-4, ".wal"))
+	{
+		image = R_LoadWal (name);
+	}
+	else if (!strcmp(name+len-4, ".tga"))
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name);
+	else
+		return NULL;	// ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name);
+
+	if (pic)
+		free(pic);
+	if (palette)
+		free(palette);
+
+	return image;
+}
+
+
+
+/*
+===============
+R_RegisterSkin
+===============
+*/
+struct image_s *R_RegisterSkin (char *name)
+{
+	return R_FindImage (name, it_skin);
+}
+
+
+/*
+================
+R_FreeUnusedImages
+
+Any image that was not touched on this registration sequence
+will be freed.
+================
+*/
+void R_FreeUnusedImages (void)
+{
+	int		i;
+	image_t	*image;
+
+	for (i=0, image=r_images ; i<numr_images ; i++, image++)
+	{
+		if (image->registration_sequence == registration_sequence)
+		{
+			Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height);
+			continue;		// used this sequence
+		}
+		if (!image->registration_sequence)
+			continue;		// free texture
+		if (image->type == it_pic)
+			continue;		// don't free pics
+		// free it
+		free (image->pixels[0]);	// the other mip levels just follow
+		memset (image, 0, sizeof(*image));
+	}
+}
+
+
+
+/*
+===============
+R_InitImages
+===============
+*/
+void	R_InitImages (void)
+{
+	registration_sequence = 1;
+}
+
+/*
+===============
+R_ShutdownImages
+===============
+*/
+void	R_ShutdownImages (void)
+{
+	int		i;
+	image_t	*image;
+
+	for (i=0, image=r_images ; i<numr_images ; i++, image++)
+	{
+		if (!image->registration_sequence)
+			continue;		// free texture
+		// free it
+		free (image->pixels[0]);	// the other mip levels just follow
+		memset (image, 0, sizeof(*image));
+	}
+}
+
--- /dev/null
+++ b/ref_soft/r_light.c
@@ -1,0 +1,442 @@
+/*
+Copyright (C) 1997-2001 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 "r_local.h"
+
+int	r_dlightframecount;
+
+
+/*
+=============================================================================
+
+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 != -1)
+		return;
+
+	splitplane = node->plane;
+	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
+	
+//=====
+//PGM
+	i=light->intensity;
+	if(i<0)
+		i=-i;
+//PGM
+//=====
+
+	if (dist > i)	// PGM (dist > light->intensity)
+	{
+		R_MarkLights (light, bit, node->children[0]);
+		return;
+	}
+	if (dist < -i)	// PGM (dist < -light->intensity)
+	{
+		R_MarkLights (light, bit, node->children[1]);
+		return;
+	}
+		
+// mark the polygons
+	surf = r_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 (model_t *model)
+{
+	int		i;
+	dlight_t	*l;
+
+	r_dlightframecount = r_framecount;
+	for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++)
+	{
+		R_MarkLights ( l, 1<<i, 
+			model->nodes + model->firstnode);
+	}
+}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+vec3_t	pointcolor;
+mplane_t		*lightplane;		// used as shadow plane
+vec3_t			lightspot;
+
+int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
+{
+	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;
+	float		*scales;
+	int			maps;
+	float		samp;
+	int			r;
+
+	if (node->contents != -1)
+		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;
+	if (plane->type < 3)	// axial planes
+		mid[plane->type] = plane->dist;
+
+// 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 = r_worldmodel->surfaces + node->firstsurface;
+	for (i=0 ; i<node->numsurfaces ; i++, surf++)
+	{
+		if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 
+			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;
+		VectorCopy (vec3_origin, pointcolor);
+		if (lightmap)
+		{
+			lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
+
+			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+					maps++)
+			{
+				samp = *lightmap * /* 0.5 * */ (1.0/255);	// adjust for gl scale
+				scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb;
+				VectorMA (pointcolor, samp, scales, pointcolor);
+				lightmap += ((surf->extents[0]>>4)+1) *
+						((surf->extents[1]>>4)+1);
+			}
+		}
+		
+		return 1;
+	}
+
+// go down back side
+	return RecursiveLightPoint (node->children[!side], mid, end);
+}
+
+/*
+===============
+R_LightPoint
+===============
+*/
+void R_LightPoint (vec3_t p, vec3_t color)
+{
+	vec3_t		end;
+	float		r;
+	int			lnum;
+	dlight_t	*dl;
+	float		light;
+	vec3_t		dist;
+	float		add;
+	
+	if (!r_worldmodel->lightdata)
+	{
+		color[0] = color[1] = color[2] = 1.0;
+		return;
+	}
+	
+	end[0] = p[0];
+	end[1] = p[1];
+	end[2] = p[2] - 2048;
+	
+	r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
+	
+	if (r == -1)
+	{
+		VectorCopy (vec3_origin, color);
+	}
+	else
+	{
+		VectorCopy (pointcolor, color);
+	}
+
+	//
+	// add dynamic lights
+	//
+	light = 0;
+	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+	{
+		dl = &r_newrefdef.dlights[lnum];
+		VectorSubtract (currententity->origin,
+						dl->origin,
+						dist);
+		add = dl->intensity - VectorLength(dist);
+		add *= (1.0/256);
+		if (add > 0)
+		{
+			VectorMA (color, add, dl->color, color);
+		}
+	}
+}
+
+//===================================================================
+
+
+unsigned		blocklights[1024];	// allow some very large lightmaps
+
+/*
+===============
+R_AddDynamicLights
+===============
+*/
+void R_AddDynamicLights (void)
+{
+	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;
+	dlight_t	*dl;
+	int			negativeLight;	//PGM
+
+	surf = r_drawsurf.surf;
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+	tex = surf->texinfo;
+
+	for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+	{
+		if ( !(surf->dlightbits & (1<<lnum) ) )
+			continue;		// not lit by this light
+
+		dl = &r_newrefdef.dlights[lnum];
+		rad = dl->intensity;
+
+//=====
+//PGM
+		negativeLight = 0;
+		if(rad < 0)
+		{
+			negativeLight = 1;
+			rad = -rad;
+		}
+//PGM
+//=====
+
+		dist = DotProduct (dl->origin, surf->plane->normal) -
+				surf->plane->dist;
+		rad -= fabs(dist);
+		minlight = 32;		// dl->minlight;
+		if (rad < minlight)
+			continue;
+		minlight = rad - minlight;
+
+		for (i=0 ; i<3 ; i++)
+		{
+			impact[i] = dl->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);
+//====
+//PGM
+				if(!negativeLight)
+				{
+					if (dist < minlight)
+						blocklights[t*smax + s] += (rad - dist)*256;
+				}
+				else
+				{
+					if (dist < minlight)
+						blocklights[t*smax + s] -= (rad - dist)*256;
+					if(blocklights[t*smax + s] < minlight)
+						blocklights[t*smax + s] = minlight;
+				}
+//PGM
+//====
+			}
+		}
+	}
+}
+
+/*
+===============
+R_BuildLightMap
+
+Combine and scale multiple lightmaps into the 8.8 format in blocklights
+===============
+*/
+void R_BuildLightMap (void)
+{
+	int			smax, tmax;
+	int			t;
+	int			i, size;
+	byte		*lightmap;
+	unsigned	scale;
+	int			maps;
+	msurface_t	*surf;
+
+	surf = r_drawsurf.surf;
+
+	smax = (surf->extents[0]>>4)+1;
+	tmax = (surf->extents[1]>>4)+1;
+	size = smax*tmax;
+
+	if (r_fullbright->value || !r_worldmodel->lightdata)
+	{
+		for (i=0 ; i<size ; i++)
+			blocklights[i] = 0;
+		return;
+	}
+
+// clear to no light
+	for (i=0 ; i<size ; i++)
+		blocklights[i] = 0;
+
+
+// add all the lightmaps
+	lightmap = surf->samples;
+	if (lightmap)
+		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+			 maps++)
+		{
+			scale = r_drawsurf.lightadj[maps];	// 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 ();
+
+// bound, invert, and shift
+	for (i=0 ; i<size ; i++)
+	{
+		t = (int)blocklights[i];
+		if (t < 0)
+			t = 0;
+		t = (255*256 - t) >> (8 - VID_CBITS);
+
+		if (t < (1 << 6))
+			t = (1 << 6);
+
+		blocklights[i] = t;
+	}
+}
+
--- /dev/null
+++ b/ref_soft/r_local.h
@@ -1,0 +1,849 @@
+/*
+Copyright (C) 1997-2001 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+
+#include "../client/ref.h"
+
+#define REF_VERSION     "SOFT 0.01"
+
+// up / down
+#define PITCH   0
+
+// left / right
+#define YAW             1
+
+// fall over
+#define ROLL    2
+
+
+/*
+
+  skins will be outline flood filled and mip mapped
+  pics and sprites with alpha will be outline flood filled
+  pic won't be mip mapped
+
+  model skin
+  sprite frame
+  wall texture
+  pic
+
+*/
+
+typedef enum 
+{
+	it_skin,
+	it_sprite,
+	it_wall,
+	it_pic,
+	it_sky
+} imagetype_t;
+
+typedef struct image_s
+{
+	char    name[MAX_QPATH];        // game path, including extension
+	imagetype_t     type;
+	int             width, height;
+	qboolean        transparent;    // true if any 255 pixels in image
+	int             registration_sequence;  // 0 = free
+	byte		*pixels[4];				// mip levels
+} image_t;
+
+
+//===================================================================
+
+typedef unsigned char pixel_t;
+
+typedef struct vrect_s
+{
+	int                             x,y,width,height;
+	struct vrect_s  *pnext;
+} vrect_t;
+
+typedef struct
+{
+	pixel_t                 *buffer;                // invisible buffer
+	pixel_t                 *colormap;              // 256 * VID_GRADES size
+	pixel_t                 *alphamap;              // 256 * 256 translucency map
+	int                             rowbytes;               // may be > width if displayed in a window
+									// can be negative for stupid dibs
+	int						width;          
+	int						height;
+} viddef_t;
+
+typedef enum
+{
+	rserr_ok,
+
+	rserr_invalid_fullscreen,
+	rserr_invalid_mode,
+
+	rserr_unknown
+} rserr_t;
+
+extern viddef_t vid;
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct
+{
+	vrect_t         vrect;                          // subwindow in video for refresh
+									// FIXME: not need vrect next field here?
+	vrect_t         aliasvrect;                     // scaled Alias version
+	int                     vrectright, vrectbottom;        // right & bottom screen coords
+	int                     aliasvrectright, aliasvrectbottom;      // scaled Alias versions
+	float           vrectrightedge;                 // rightmost right edge we care about,
+										//  for use in edge list
+	float           fvrectx, fvrecty;               // for floating-point compares
+	float           fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
+	int                     vrect_x_adj_shift20;    // (vrect.x + 0.5 - epsilon) << 20
+	int                     vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
+	float           fvrectright_adj, fvrectbottom_adj;
+										// right and bottom edges, for clamping
+	float           fvrectright;                    // rightmost edge, for Alias clamping
+	float           fvrectbottom;                   // bottommost edge, for Alias clamping
+	float           horizontalFieldOfView;  // at Z = 1.0, this many X is visible 
+										// 2.0 = 90 degrees
+	float           xOrigin;                        // should probably always be 0.5
+	float           yOrigin;                        // between be around 0.3 to 0.5
+
+	vec3_t          vieworg;
+	vec3_t          viewangles;
+	
+	int                     ambientlight;
+} oldrefdef_t;
+
+extern oldrefdef_t      r_refdef;
+
+#include "r_model.h"
+
+#define CACHE_SIZE      32
+
+/*
+====================================================
+
+  CONSTANTS
+
+====================================================
+*/
+
+#define VID_CBITS       6
+#define VID_GRADES      (1 << VID_CBITS)
+
+
+// r_shared.h: general refresh-related stuff shared between the refresh and the
+// driver
+
+
+#define MAXVERTS        64              // max points in a surface polygon
+#define MAXWORKINGVERTS (MAXVERTS+4)    // max points in an intermediate
+										//  polygon (while processing)
+// !!! if this is changed, it must be changed in d_ifacea.h too !!!
+#define MAXHEIGHT       1200
+#define MAXWIDTH        1600
+
+#define INFINITE_DISTANCE       0x10000         // distance that's always guaranteed to
+										//  be farther away than anything in
+										//  the scene
+
+
+// d_iface.h: interface header file for rasterization driver modules
+
+#define WARP_WIDTH              320
+#define WARP_HEIGHT             240
+
+#define MAX_LBM_HEIGHT  480
+
+
+#define PARTICLE_Z_CLIP 8.0
+
+// !!! must be kept the same as in quakeasm.h !!!
+#define TRANSPARENT_COLOR       0xFF
+
+
+// !!! if this is changed, it must be changed in d_ifacea.h too !!!
+#define TURB_TEX_SIZE   64              // base turbulent texture size
+
+// !!! if this is changed, it must be changed in d_ifacea.h too !!!
+#define CYCLE                   128             // turbulent cycle size
+
+#define SCANBUFFERPAD           0x1000
+
+#define DS_SPAN_LIST_END        -128
+
+#define NUMSTACKEDGES           2000
+#define MINEDGES                        NUMSTACKEDGES
+#define NUMSTACKSURFACES        1000
+#define MINSURFACES                     NUMSTACKSURFACES
+#define MAXSPANS                        3000
+
+// flags in finalvert_t.flags
+#define ALIAS_LEFT_CLIP                         0x0001
+#define ALIAS_TOP_CLIP                          0x0002
+#define ALIAS_RIGHT_CLIP                        0x0004
+#define ALIAS_BOTTOM_CLIP                       0x0008
+#define ALIAS_Z_CLIP                            0x0010
+#define ALIAS_XY_CLIP_MASK                      0x000F
+
+#define SURFCACHE_SIZE_AT_320X240    1024*768
+
+#define BMODEL_FULLY_CLIPPED    0x10 // value returned by R_BmodelCheckBBox ()
+									 //  if bbox is trivially rejected
+
+#define XCENTERING      (1.0 / 2.0)
+#define YCENTERING      (1.0 / 2.0)
+
+#define CLIP_EPSILON            0.001
+
+#define BACKFACE_EPSILON        0.01
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+#define NEAR_CLIP       0.01
+
+
+#define MAXALIASVERTS           2000    // TODO: tune this
+#define ALIAS_Z_CLIP_PLANE      4
+
+// turbulence stuff
+
+#define AMP             8*0x10000
+#define AMP2    3
+#define SPEED   20
+
+
+/*
+====================================================
+
+TYPES
+
+====================================================
+*/
+
+typedef struct
+{
+	float   u, v;
+	float   s, t;
+	float   zi;
+} emitpoint_t;
+
+/*
+** if you change this structure be sure to change the #defines
+** listed after it!
+*/
+#define SMALL_FINALVERT 0
+
+#if SMALL_FINALVERT
+
+typedef struct finalvert_s {
+	short           u, v, s, t;
+	int             l;
+	int             zi;
+	int             flags;
+	float   xyz[3];         // eye space
+} finalvert_t;
+
+#define FINALVERT_V0     0
+#define FINALVERT_V1     2
+#define FINALVERT_V2     4
+#define FINALVERT_V3     6
+#define FINALVERT_V4     8
+#define FINALVERT_V5    12
+#define FINALVERT_FLAGS 16
+#define FINALVERT_X     20
+#define FINALVERT_Y     24
+#define FINALVERT_Z     28
+#define FINALVERT_SIZE  32
+
+#else
+
+typedef struct finalvert_s {
+	int             u, v, s, t;
+	int             l;
+	int             zi;
+	int             flags;
+	float   xyz[3];         // eye space
+} finalvert_t;
+
+#define FINALVERT_V0     0
+#define FINALVERT_V1     4
+#define FINALVERT_V2     8
+#define FINALVERT_V3    12
+#define FINALVERT_V4    16
+#define FINALVERT_V5    20
+#define FINALVERT_FLAGS 24
+#define FINALVERT_X     28
+#define FINALVERT_Y     32
+#define FINALVERT_Z     36
+#define FINALVERT_SIZE  40
+
+#endif
+
+typedef struct
+{
+	void                            *pskin;
+	int                                     pskindesc;
+	int                                     skinwidth;
+	int                                     skinheight;
+	dtriangle_t                     *ptriangles;
+	finalvert_t                     *pfinalverts;
+	int                                     numtriangles;
+	int                                     drawtype;
+	int                                     seamfixupX16;
+	qboolean                        do_vis_thresh;
+	int                                     vis_thresh;
+} affinetridesc_t;
+
+typedef struct
+{
+	byte            *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
+	image_t			*image;
+	int                     surfmip;        // mipmapped ratio of surface texels / world pixels
+	int                     surfwidth;      // in mipmapped texels
+	int                     surfheight;     // in mipmapped texels
+} drawsurf_t;
+
+
+
+typedef struct {
+	int                     ambientlight;
+	int                     shadelight;
+	float           *plightvec;
+} alight_t;
+
+// clipped bmodel edges
+
+typedef struct bedge_s
+{
+	mvertex_t               *v[2];
+	struct bedge_s  *pnext;
+} bedge_t;
+
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct clipplane_s
+{
+	vec3_t          normal;
+	float           dist;
+	struct          clipplane_s     *next;
+	byte            leftedge;
+	byte            rightedge;
+	byte            reserved[2];
+} clipplane_t;
+
+
+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;
+	image_t							*image;
+	byte                            data[4];        // width*height elements
+} surfcache_t;
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct espan_s
+{
+	int                             u, v, count;
+	struct espan_s  *pnext;
+} espan_t;
+
+// used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C)
+typedef struct
+{
+	int                     nump;
+	emitpoint_t     *pverts;
+	byte            *pixels;                        // image
+	int                     pixel_width;            // image width
+	int         pixel_height;       // image height
+	vec3_t          vup, vright, vpn;       // in worldspace, for plane eq
+	float       dist;
+	float       s_offset, t_offset;
+	float       viewer_position[3];
+	void       (*drawspanlet)( void );
+	int         stipple_parity;
+} polydesc_t;
+
+// FIXME: compress, make a union if that will help
+// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
+typedef struct surf_s
+{
+	struct surf_s   *next;                  // active surface stack in r_edge.c
+	struct surf_s   *prev;                  // used in r_edge.c for active surf stack
+	struct espan_s  *spans;                 // pointer to linked list of spans to draw
+	int                     key;                            // sorting key (BSP order)
+	int                     last_u;                         // set during tracing
+	int                     spanstate;                      // 0 = not in span
+									// 1 = in span
+									// -1 = in inverted span (end before
+									//  start)
+	int                     flags;                          // currentface flags
+	msurface_t      *msurf;
+	entity_t        *entity;
+	float           nearzi;                         // nearest 1/z on surface, for mipmapping
+	qboolean        insubmodel;
+	float           d_ziorigin, d_zistepu, d_zistepv;
+
+	int                     pad[2];                         // to 64 bytes
+} surf_t;
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct edge_s
+{
+	fixed16_t               u;
+	fixed16_t               u_step;
+	struct edge_s   *prev, *next;
+	unsigned short  surfs[2];
+	struct edge_s   *nextremove;
+	float                   nearzi;
+	medge_t                 *owner;
+} edge_t;
+
+
+/*
+====================================================
+
+VARS
+
+====================================================
+*/
+
+extern int              d_spanpixcount;
+extern int              r_framecount;           // sequence # of current frame since Quake
+									//  started
+extern float    r_aliasuvscale;         // scale-up factor for screen u and v
+									//  on Alias vertices passed to driver
+extern qboolean r_dowarp;
+
+extern affinetridesc_t  r_affinetridesc;
+
+extern vec3_t   r_pright, r_pup, r_ppn;
+
+void D_DrawSurfaces (void);
+void R_DrawParticle( void );
+void D_ViewChanged (void);
+void D_WarpScreen (void);
+void R_PolysetUpdateTables (void);
+
+extern void *acolormap; // FIXME: should go away
+
+//=======================================================================//
+
+// callbacks to Quake
+
+extern drawsurf_t       r_drawsurf;
+
+void R_DrawSurface (void);
+
+extern int              c_surf;
+
+extern byte             r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+
+
+
+
+extern float    scale_for_mip;
+
+extern qboolean         d_roverwrapped;
+extern surfcache_t      *sc_rover;
+extern surfcache_t      *d_initial_rover;
+
+extern float    d_sdivzstepu, d_tdivzstepu, d_zistepu;
+extern float    d_sdivzstepv, d_tdivzstepv, d_zistepv;
+extern float    d_sdivzorigin, d_tdivzorigin, d_ziorigin;
+
+extern  fixed16_t       sadjust, tadjust;
+extern  fixed16_t       bbextents, bbextentt;
+
+
+void D_DrawSpans16 (espan_t *pspans);
+void D_DrawZSpans (espan_t *pspans);
+void Turbulent8 (espan_t *pspan);
+void NonTurbulent8 (espan_t *pspan);	//PGM
+
+surfcache_t     *D_CacheSurface (msurface_t *surface, int miplevel);
+
+extern int      d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
+
+extern int      d_pix_min, d_pix_max, d_pix_shift;
+
+extern pixel_t  *d_viewbuffer;
+extern short *d_pzbuffer;
+extern unsigned int d_zrowbytes, d_zwidth;
+extern short    *zspantable[MAXHEIGHT];
+extern int      d_scantable[MAXHEIGHT];
+
+extern int              d_minmip;
+extern float    d_scalemip[3];
+
+//===================================================================
+
+extern int              cachewidth;
+extern pixel_t  *cacheblock;
+extern int              r_screenwidth;
+
+extern int              r_drawnpolycount;
+
+extern int      sintable[1280];
+extern int      intsintable[1280];
+extern int		blanktable[1280];		// PGM
+
+extern  vec3_t  vup, base_vup;
+extern  vec3_t  vpn, base_vpn;
+extern  vec3_t  vright, base_vright;
+
+extern  surf_t  *surfaces, *surface_p, *surf_max;
+
+// surfaces are generated in back to front order by the bsp, so if a surf
+// pointer is greater than another one, it should be drawn in front
+// surfaces[1] is the background, and is used as the active surface stack.
+// surfaces[0] is a dummy, because index 0 is used to indicate no surface
+//  attached to an edge_t
+
+//===================================================================
+
+extern vec3_t   sxformaxis[4];  // s axis transformed into viewspace
+extern vec3_t   txformaxis[4];  // t axis transformed into viewspac
+
+extern  float   xcenter, ycenter;
+extern  float   xscale, yscale;
+extern  float   xscaleinv, yscaleinv;
+extern  float   xscaleshrink, yscaleshrink;
+
+extern void TransformVector (vec3_t in, vec3_t out);
+extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
+	fixed8_t endvertu, fixed8_t endvertv);
+
+extern int      ubasestep, errorterm, erroradjustup, erroradjustdown;
+
+//===========================================================================
+
+extern cvar_t   *sw_aliasstats;
+extern cvar_t   *sw_clearcolor;
+extern cvar_t   *sw_drawflat;
+extern cvar_t   *sw_draworder;
+extern cvar_t   *sw_maxedges;
+extern cvar_t   *sw_maxsurfs;
+extern cvar_t   *sw_mipcap;
+extern cvar_t   *sw_mipscale;
+extern cvar_t   *sw_mode;
+extern cvar_t   *sw_reportsurfout;
+extern cvar_t   *sw_reportedgeout;
+extern cvar_t   *sw_stipplealpha;
+extern cvar_t   *sw_surfcacheoverride;
+extern cvar_t   *sw_waterwarp;
+
+extern cvar_t   *r_fullbright;
+extern cvar_t	*r_lefthand;
+extern cvar_t   *r_drawentities;
+extern cvar_t   *r_drawworld;
+extern cvar_t   *r_dspeeds;
+extern cvar_t   *r_lerpmodels;
+
+extern cvar_t   *r_speeds;
+
+extern cvar_t   *r_lightlevel;  //FIXME HACK
+
+extern cvar_t	*vid_fullscreen;
+extern	cvar_t	*vid_gamma;
+
+
+extern  clipplane_t     view_clipplanes[4];
+extern int              *pfrustum_indexes[4];
+
+
+//=============================================================================
+
+void R_RenderWorld (void);
+
+//=============================================================================
+
+extern  mplane_t        screenedge[4];
+
+extern  vec3_t  r_origin;
+
+extern	entity_t	r_worldentity;
+extern  model_t         *currentmodel;
+extern  entity_t                *currententity;
+extern  vec3_t  modelorg;
+extern  vec3_t  r_entorigin;
+
+extern  float   verticalFieldOfView;
+extern  float   xOrigin, yOrigin;
+
+extern  int             r_visframecount;
+
+extern msurface_t *r_alpha_surfaces;
+
+//=============================================================================
+
+void R_ClearPolyList (void);
+void R_DrawPolyList (void);
+
+//
+// current entity info
+//
+extern  qboolean                insubmodel;
+
+void R_DrawAlphaSurfaces( void );
+
+void R_DrawSprite (void);
+void R_DrawBeam( entity_t *e );
+
+void R_RenderFace (msurface_t *fa, int clipflags);
+void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf);
+void R_TransformPlane (mplane_t *p, float *normal, float *dist);
+void R_TransformFrustum (void);
+void R_DrawSurfaceBlock16 (void);
+void R_DrawSurfaceBlock8 (void);
+
+#if     id386
+
+void R_DrawSurfaceBlock8_mip0 (void);
+void R_DrawSurfaceBlock8_mip1 (void);
+void R_DrawSurfaceBlock8_mip2 (void);
+void R_DrawSurfaceBlock8_mip3 (void);
+
+#endif
+
+void R_GenSkyTile (void *pdest);
+void R_GenSkyTile16 (void *pdest);
+void R_Surf8Patch (void);
+void R_Surf16Patch (void);
+void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode);
+void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode);
+
+void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel);
+surf_t *R_GetSurf (void);
+void R_AliasDrawModel (void);
+void R_BeginEdgeFrame (void);
+void R_ScanEdges (void);
+void D_DrawSurfaces (void);
+void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);
+void R_StepActiveU (edge_t *pedge);
+void R_RemoveEdges (edge_t *pedge);
+void R_PushDlights (model_t *model);
+
+extern void R_Surf8Start (void);
+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_RotateBmodel (void);
+
+extern int      c_faceclip;
+extern int      r_polycount;
+extern int      r_wholepolycount;
+
+extern int                      ubasestep, errorterm, erroradjustup, erroradjustdown;
+
+extern fixed16_t        sadjust, tadjust;
+extern fixed16_t        bbextents, bbextentt;
+
+extern mvertex_t        *r_ptverts, *r_ptvertsmax;
+
+extern float                    entity_rotation[3][3];
+
+extern int              r_currentkey;
+extern int              r_currentbkey;
+
+void    R_InitTurb (void);
+
+void R_DrawParticles (void);
+void R_SurfacePatch (void);
+
+extern int              r_amodels_drawn;
+extern edge_t   *auxedges;
+extern int              r_numallocatededges;
+extern edge_t   *r_edges, *edge_p, *edge_max;
+
+extern  edge_t  *newedges[MAXHEIGHT];
+extern  edge_t  *removeedges[MAXHEIGHT];
+
+// FIXME: make stack vars when debugging done
+extern  edge_t  edge_head;
+extern  edge_t  edge_tail;
+extern  edge_t  edge_aftertail;
+
+extern	int	r_aliasblendcolor;
+
+extern float    aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
+
+extern int              r_outofsurfaces;
+extern int              r_outofedges;
+
+extern mvertex_t        *r_pcurrentvertbase;
+extern int                      r_maxvalidedgeoffset;
+
+typedef struct
+{
+	finalvert_t *a, *b, *c;
+} aliastriangleparms_t;
+
+extern aliastriangleparms_t aliastriangleparms;
+
+void R_DrawTriangle( void );
+//void R_DrawTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
+void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
+
+
+extern float    r_time1;
+extern float	da_time1, da_time2;
+extern float	dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
+extern float	se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
+extern int              r_frustum_indexes[4*6];
+extern int              r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
+extern qboolean r_surfsonstack;
+
+extern	mleaf_t		*r_viewleaf;
+extern	int			r_viewcluster, r_oldviewcluster;
+
+extern int              r_clipflags;
+extern int              r_dlightframecount;
+extern qboolean r_fov_greater_than_90;
+
+extern  image_t         *r_notexture_mip;
+extern  model_t         *r_worldmodel;
+
+void R_PrintAliasStats (void);
+void R_PrintTimes (void);
+void R_PrintDSpeeds (void);
+void R_AnimateLight (void);
+void R_LightPoint (vec3_t p, vec3_t color);
+void R_SetupFrame (void);
+void R_cshift_f (void);
+void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);
+void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);
+void R_SplitEntityOnNode2 (mnode_t *node);
+
+extern  refdef_t        r_newrefdef;
+
+extern  surfcache_t     *sc_rover, *sc_base;
+
+extern  void            *colormap;
+
+//====================================================================
+
+float R_DLightPoint (vec3_t p);
+
+void R_NewMap (void);
+void R_Register (void);
+void R_UnRegister (void);
+void Draw_InitLocal (void);
+qboolean R_Init( void *hInstance, void *wndProc );
+void R_Shutdown (void);
+void R_InitCaches (void);
+void D_FlushCaches (void);
+
+void	R_ScreenShot_f( void );
+void    R_BeginRegistration (char *map);
+struct model_s  *R_RegisterModel (char *name);
+void    R_EndRegistration (void);
+
+void    R_RenderFrame (refdef_t *fd);
+
+struct image_s  *Draw_FindPic (char *name);
+
+void    Draw_GetPicSize (int *w, int *h, char *name);
+void    Draw_Pic (int x, int y, char *name);
+void    Draw_StretchPic (int x, int y, int w, int h, char *name);
+void    Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data);
+void    Draw_Char (int x, int y, int c);
+void    Draw_TileClear (int x, int y, int w, int h, char *name);
+void    Draw_Fill (int x, int y, int w, int h, int c);
+void    Draw_FadeScreen (void);
+
+void    Draw_GetPalette (void);
+
+void	 R_BeginFrame( float camera_separation );
+
+void	R_CinematicSetPalette( const unsigned char *palette );
+
+extern unsigned d_8to24table[256]; // base
+
+void    Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
+void    Sys_SetFPCW (void);
+
+void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height);
+
+void    R_InitImages (void);
+void	R_ShutdownImages (void);
+image_t *R_FindImage (char *name, imagetype_t type);
+void    R_FreeUnusedImages (void);
+
+void	R_GammaCorrectAndSetPalette( const unsigned char *pal );
+
+extern mtexinfo_t  *sky_texinfo[6];
+
+void R_InitSkyBox (void);
+
+typedef struct swstate_s
+{
+	qboolean fullscreen;
+	int      prev_mode;				// last valid SW mode
+
+	byte		gammatable[256];
+	byte		currentpalette[1024];
+
+} swstate_t;
+
+void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha );
+
+extern swstate_t sw_state;
+
+/*
+====================================================================
+
+IMPORTED FUNCTIONS
+
+====================================================================
+*/
+
+extern  refimport_t     ri;
+
+/*
+====================================================================
+
+IMPLEMENTATION FUNCTIONS
+
+====================================================================
+*/
+
+void		SWimp_BeginFrame( float camera_separation );
+void		SWimp_EndFrame (void);
+int			SWimp_Init( void *hInstance, void *wndProc );
+void		SWimp_SetPalette( const unsigned char *palette);
+void		SWimp_Shutdown( void );
+rserr_t		SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen );
+void		SWimp_AppActivate( qboolean active );
+
--- /dev/null
+++ b/ref_soft/r_main.c
@@ -1,0 +1,1422 @@
+/*
+Copyright (C) 1997-2001 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 "r_local.h"
+
+viddef_t	vid;
+refimport_t	ri;
+
+unsigned	d_8to24table[256];
+
+entity_t	r_worldentity;
+
+char		skyname[MAX_QPATH];
+float		skyrotate;
+vec3_t		skyaxis;
+image_t		*sky_images[6];
+
+refdef_t	r_newrefdef;
+model_t		*currentmodel;
+
+model_t		*r_worldmodel;
+
+byte		r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+
+swstate_t sw_state;
+
+void		*colormap;
+vec3_t		viewlightvec;
+alight_t	r_viewlighting = {128, 192, viewlightvec};
+float		r_time1;
+int			r_numallocatededges;
+float		r_aliasuvscale = 1.0;
+int			r_outofsurfaces;
+int			r_outofedges;
+
+qboolean	r_dowarp;
+
+mvertex_t	*r_pcurrentvertbase;
+
+int			c_surf;
+int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
+qboolean	r_surfsonstack;
+int			r_clipflags;
+
+//
+// view origin
+//
+vec3_t	vup, base_vup;
+vec3_t	vpn, base_vpn;
+vec3_t	vright, base_vright;
+vec3_t	r_origin;
+
+//
+// screen size info
+//
+oldrefdef_t	r_refdef;
+float		xcenter, ycenter;
+float		xscale, yscale;
+float		xscaleinv, yscaleinv;
+float		xscaleshrink, yscaleshrink;
+float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
+
+int		r_screenwidth;
+
+float	verticalFieldOfView;
+float	xOrigin, yOrigin;
+
+mplane_t	screenedge[4];
+
+//
+// refresh flags
+//
+int		r_framecount = 1;	// so frame counts initialized to 0 don't match
+int		r_visframecount;
+int		d_spanpixcount;
+int		r_polycount;
+int		r_drawnpolycount;
+int		r_wholepolycount;
+
+int			*pfrustum_indexes[4];
+int			r_frustum_indexes[4*6];
+
+mleaf_t		*r_viewleaf;
+int			r_viewcluster, r_oldviewcluster;
+
+image_t  	*r_notexture_mip;
+
+float	da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
+float	se_time1, se_time2, de_time1, de_time2;
+
+void R_MarkLeaves (void);
+
+cvar_t	*r_lefthand;
+cvar_t	*sw_aliasstats;
+cvar_t	*sw_allow_modex;
+cvar_t	*sw_clearcolor;
+cvar_t	*sw_drawflat;
+cvar_t	*sw_draworder;
+cvar_t	*sw_maxedges;
+cvar_t	*sw_maxsurfs;
+cvar_t  *sw_mode;
+cvar_t	*sw_reportedgeout;
+cvar_t	*sw_reportsurfout;
+cvar_t  *sw_stipplealpha;
+cvar_t	*sw_surfcacheoverride;
+cvar_t	*sw_waterwarp;
+
+cvar_t	*r_drawworld;
+cvar_t	*r_drawentities;
+cvar_t	*r_dspeeds;
+cvar_t	*r_fullbright;
+cvar_t  *r_lerpmodels;
+cvar_t  *r_novis;
+
+cvar_t	*r_speeds;
+cvar_t	*r_lightlevel;	//FIXME HACK
+
+cvar_t	*vid_fullscreen;
+cvar_t	*vid_gamma;
+
+//PGM
+cvar_t	*sw_lockpvs;
+//PGM
+
+#define	STRINGER(x) "x"
+
+
+#if	!id386
+
+// r_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+
+// d_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+float	d_sdivzstepu, d_tdivzstepu, d_zistepu;
+float	d_sdivzstepv, d_tdivzstepv, d_zistepv;
+float	d_sdivzorigin, d_tdivzorigin, d_ziorigin;
+
+fixed16_t	sadjust, tadjust, bbextents, bbextentt;
+
+pixel_t			*cacheblock;
+int				cachewidth;
+pixel_t			*d_viewbuffer;
+short			*d_pzbuffer;
+unsigned int	d_zrowbytes;
+unsigned int	d_zwidth;
+
+
+#endif	// !id386
+
+byte	r_notexture_buffer[1024];
+
+/*
+==================
+R_InitTextures
+==================
+*/
+void	R_InitTextures (void)
+{
+	int		x,y, m;
+	byte	*dest;
+	
+// create a simple checkerboard texture for the default
+	r_notexture_mip = (image_t *)&r_notexture_buffer;
+	
+	r_notexture_mip->width = r_notexture_mip->height = 16;
+	r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
+	r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
+	r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
+	r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
+	
+	for (m=0 ; m<4 ; m++)
+	{
+		dest = r_notexture_mip->pixels[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;
+			}
+	}	
+}
+
+
+/*
+================
+R_InitTurb
+================
+*/
+void R_InitTurb (void)
+{
+	int		i;
+	
+	for (i=0 ; i<1280 ; i++)
+	{
+		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
+		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
+		blanktable[i] = 0;			//PGM
+	}
+}
+
+void R_ImageList_f( void );
+
+void R_Register (void)
+{
+	sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
+	sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );
+	sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
+	sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);
+	sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);
+	sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
+	sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);
+	sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);
+	sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);
+	sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);
+	sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);
+	sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+	sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);
+	sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);
+	sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );
+
+	r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+	r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
+	r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
+	r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
+	r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
+	r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);
+	r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
+	r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );
+	r_novis = ri.Cvar_Get( "r_novis", "0", 0 );
+
+	vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
+	vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
+
+	ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);
+	ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
+	ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
+
+	sw_mode->modified = true; // force us to do mode specific stuff later
+	vid_gamma->modified = true; // force us to rebuild the gamma table later
+
+//PGM
+	sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
+//PGM
+}
+
+void R_UnRegister (void)
+{
+	ri.Cmd_RemoveCommand( "screenshot" );
+	ri.Cmd_RemoveCommand ("modellist");
+	ri.Cmd_RemoveCommand( "imagelist" );
+}
+
+/*
+===============
+R_Init
+===============
+*/
+qboolean R_Init( void *hInstance, void *wndProc )
+{
+	R_InitImages ();
+	Mod_Init ();
+	Draw_InitLocal ();
+	R_InitTextures ();
+
+	R_InitTurb ();
+
+	view_clipplanes[0].leftedge = true;
+	view_clipplanes[1].rightedge = true;
+	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
+			view_clipplanes[3].leftedge = false;
+	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
+			view_clipplanes[3].rightedge = false;
+
+	r_refdef.xOrigin = XCENTERING;
+	r_refdef.yOrigin = YCENTERING;
+
+// TODO: collect 386-specific code in one place
+#if	id386
+	Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
+					     (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
+	Sys_SetFPCW ();		// get bit masks for FPCW	(FIXME: is this id386?)
+#endif	// id386
+
+	r_aliasuvscale = 1.0;
+
+	R_Register ();
+	Draw_GetPalette ();
+	SWimp_Init( hInstance, wndProc );
+
+	// create the window
+	R_BeginFrame( 0 );
+
+	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
+
+	return true;
+}
+
+/*
+===============
+R_Shutdown
+===============
+*/
+void R_Shutdown (void)
+{
+	// free z buffer
+	if (d_pzbuffer)
+	{
+		free (d_pzbuffer);
+		d_pzbuffer = NULL;
+	}
+	// free surface cache
+	if (sc_base)
+	{
+		D_FlushCaches ();
+		free (sc_base);
+		sc_base = NULL;
+	}
+
+	// free colormap
+	if (vid.colormap)
+	{
+		free (vid.colormap);
+		vid.colormap = NULL;
+	}
+	R_UnRegister ();
+	Mod_FreeAll ();
+	R_ShutdownImages ();
+
+	SWimp_Shutdown();
+}
+
+/*
+===============
+R_NewMap
+===============
+*/
+void R_NewMap (void)
+{
+	r_viewcluster = -1;
+
+	r_cnumsurfs = sw_maxsurfs->value;
+
+	if (r_cnumsurfs <= MINSURFACES)
+		r_cnumsurfs = MINSURFACES;
+
+	if (r_cnumsurfs > NUMSTACKSURFACES)
+	{
+		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
+		surface_p = surfaces;
+		surf_max = &surfaces[r_cnumsurfs];
+		r_surfsonstack = false;
+	// surface 0 doesn't really exist; it's just a dummy because index 0
+	// is used to indicate no edge attached to surface
+		surfaces--;
+		R_SurfacePatch ();
+	}
+	else
+	{
+		r_surfsonstack = true;
+	}
+
+	r_maxedgesseen = 0;
+	r_maxsurfsseen = 0;
+
+	r_numallocatededges = sw_maxedges->value;
+
+	if (r_numallocatededges < MINEDGES)
+		r_numallocatededges = MINEDGES;
+
+	if (r_numallocatededges <= NUMSTACKEDGES)
+	{
+		auxedges = NULL;
+	}
+	else
+	{
+		auxedges = malloc (r_numallocatededges * sizeof(edge_t));
+	}
+}
+
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+void R_MarkLeaves (void)
+{
+	byte	*vis;
+	mnode_t	*node;
+	int		i;
+	mleaf_t	*leaf;
+	int		cluster;
+
+	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
+		return;
+	
+	// development aid to let you run around and see exactly where
+	// the pvs ends
+	if (sw_lockpvs->value)
+		return;
+
+	r_visframecount++;
+	r_oldviewcluster = r_viewcluster;
+
+	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
+	{
+		// mark everything
+		for (i=0 ; i<r_worldmodel->numleafs ; i++)
+			r_worldmodel->leafs[i].visframe = r_visframecount;
+		for (i=0 ; i<r_worldmodel->numnodes ; i++)
+			r_worldmodel->nodes[i].visframe = r_visframecount;
+		return;
+	}
+
+	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
+	
+	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
+	{
+		cluster = leaf->cluster;
+		if (cluster == -1)
+			continue;
+		if (vis[cluster>>3] & (1<<(cluster&7)))
+		{
+			node = (mnode_t *)leaf;
+			do
+			{
+				if (node->visframe == r_visframecount)
+					break;
+				node->visframe = r_visframecount;
+				node = node->parent;
+			} while (node);
+		}
+	}
+
+#if 0
+	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
+	{
+		if (vis[i>>3] & (1<<(i&7)))
+		{
+			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
+			do
+			{
+				if (node->visframe == r_visframecount)
+					break;
+				node->visframe = r_visframecount;
+				node = node->parent;
+			} while (node);
+		}
+	}
+#endif
+}
+
+/*
+** R_DrawNullModel
+**
+** IMPLEMENT THIS!
+*/
+void R_DrawNullModel( void )
+{
+}
+
+/*
+=============
+R_DrawEntitiesOnList
+=============
+*/
+void R_DrawEntitiesOnList (void)
+{
+	int			i;
+	qboolean	translucent_entities = false;
+
+	if (!r_drawentities->value)
+		return;
+
+	// all bmodels have already been drawn by the edge list
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+
+		if ( currententity->flags & RF_TRANSLUCENT )
+		{
+			translucent_entities = true;
+			continue;
+		}
+
+		if ( currententity->flags & RF_BEAM )
+		{
+			modelorg[0] = -r_origin[0];
+			modelorg[1] = -r_origin[1];
+			modelorg[2] = -r_origin[2];
+			VectorCopy( vec3_origin, r_entorigin );
+			R_DrawBeam( currententity );
+		}
+		else
+		{
+			currentmodel = currententity->model;
+			if (!currentmodel)
+			{
+				R_DrawNullModel();
+				continue;
+			}
+			VectorCopy (currententity->origin, r_entorigin);
+			VectorSubtract (r_origin, r_entorigin, modelorg);
+
+			switch (currentmodel->type)
+			{
+			case mod_sprite:
+				R_DrawSprite ();
+				break;
+
+			case mod_alias:
+				R_AliasDrawModel ();
+				break;
+
+			default:
+				break;
+			}
+		}
+	}
+
+	if ( !translucent_entities )
+		return;
+
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+
+		if ( !( currententity->flags & RF_TRANSLUCENT ) )
+			continue;
+
+		if ( currententity->flags & RF_BEAM )
+		{
+			modelorg[0] = -r_origin[0];
+			modelorg[1] = -r_origin[1];
+			modelorg[2] = -r_origin[2];
+			VectorCopy( vec3_origin, r_entorigin );
+			R_DrawBeam( currententity );
+		}
+		else
+		{
+			currentmodel = currententity->model;
+			if (!currentmodel)
+			{
+				R_DrawNullModel();
+				continue;
+			}
+			VectorCopy (currententity->origin, r_entorigin);
+			VectorSubtract (r_origin, r_entorigin, modelorg);
+
+			switch (currentmodel->type)
+			{
+			case mod_sprite:
+				R_DrawSprite ();
+				break;
+
+			case mod_alias:
+				R_AliasDrawModel ();
+				break;
+
+			default:
+				break;
+			}
+		}
+	}
+}
+
+
+/*
+=============
+R_BmodelCheckBBox
+=============
+*/
+int R_BmodelCheckBBox (float *minmaxs)
+{
+	int			i, *pindex, clipflags;
+	vec3_t		acceptpt, rejectpt;
+	float		d;
+
+	clipflags = 0;
+
+	for (i=0 ; i<4 ; i++)
+	{
+	// generate accept and reject points
+	// FIXME: do with fast look-ups or integer tests based on the sign bit
+	// of the floating point values
+
+		pindex = pfrustum_indexes[i];
+
+		rejectpt[0] = minmaxs[pindex[0]];
+		rejectpt[1] = minmaxs[pindex[1]];
+		rejectpt[2] = minmaxs[pindex[2]];
+		
+		d = DotProduct (rejectpt, view_clipplanes[i].normal);
+		d -= view_clipplanes[i].dist;
+
+		if (d <= 0)
+			return BMODEL_FULLY_CLIPPED;
+
+		acceptpt[0] = minmaxs[pindex[3+0]];
+		acceptpt[1] = minmaxs[pindex[3+1]];
+		acceptpt[2] = minmaxs[pindex[3+2]];
+
+		d = DotProduct (acceptpt, view_clipplanes[i].normal);
+		d -= view_clipplanes[i].dist;
+
+		if (d <= 0)
+			clipflags |= (1<<i);
+	}
+
+	return clipflags;
+}
+
+
+/*
+===================
+R_FindTopnode
+
+Find the first node that splits the given box
+===================
+*/
+mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
+{
+	mplane_t	*splitplane;
+	int			sides;
+	mnode_t *node;
+
+	node = r_worldmodel->nodes;
+
+	while (1)
+	{
+		if (node->visframe != r_visframecount)
+			return NULL;		// not visible at all
+		
+		if (node->contents != CONTENTS_NODE)
+		{
+			if (node->contents != CONTENTS_SOLID)
+				return	node; // we've reached a non-solid leaf, so it's
+							//  visible and not BSP clipped
+			return NULL;	// in solid, so not visible
+		}
+		
+		splitplane = node->plane;
+		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
+		
+		if (sides == 3)
+			return node;	// this is the splitter
+		
+	// not split yet; recurse down the contacted side
+		if (sides & 1)
+			node = node->children[0];
+		else
+			node = node->children[1];
+	}
+}
+
+
+/*
+=============
+RotatedBBox
+
+Returns an axially aligned box that contains the input box at the given rotation
+=============
+*/
+void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
+{
+	vec3_t	tmp, v;
+	int		i, j;
+	vec3_t	forward, right, up;
+
+	if (!angles[0] && !angles[1] && !angles[2])
+	{
+		VectorCopy (mins, tmins);
+		VectorCopy (maxs, tmaxs);
+		return;
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		tmins[i] = 99999;
+		tmaxs[i] = -99999;
+	}
+
+	AngleVectors (angles, forward, right, up);
+
+	for ( i = 0; i < 8; i++ )
+	{
+		if ( i & 1 )
+			tmp[0] = mins[0];
+		else
+			tmp[0] = maxs[0];
+
+		if ( i & 2 )
+			tmp[1] = mins[1];
+		else
+			tmp[1] = maxs[1];
+
+		if ( i & 4 )
+			tmp[2] = mins[2];
+		else
+			tmp[2] = maxs[2];
+
+
+		VectorScale (forward, tmp[0], v);
+		VectorMA (v, -tmp[1], right, v);
+		VectorMA (v, tmp[2], up, v);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			if (v[j] < tmins[j])
+				tmins[j] = v[j];
+			if (v[j] > tmaxs[j])
+				tmaxs[j] = v[j];
+		}
+	}
+}
+
+/*
+=============
+R_DrawBEntitiesOnList
+=============
+*/
+void R_DrawBEntitiesOnList (void)
+{
+	int			i, clipflags;
+	vec3_t		oldorigin;
+	vec3_t		mins, maxs;
+	float		minmaxs[6];
+	mnode_t		*topnode;
+
+	if (!r_drawentities->value)
+		return;
+
+	VectorCopy (modelorg, oldorigin);
+	insubmodel = true;
+	r_dlightframecount = r_framecount;
+
+	for (i=0 ; i<r_newrefdef.num_entities ; i++)
+	{
+		currententity = &r_newrefdef.entities[i];
+		currentmodel = currententity->model;
+		if (!currentmodel)
+			continue;
+		if (currentmodel->nummodelsurfaces == 0)
+			continue;	// clip brush only
+		if ( currententity->flags & RF_BEAM )
+			continue;
+		if (currentmodel->type != mod_brush)
+			continue;
+	// see if the bounding box lets us trivially reject, also sets
+	// trivial accept status
+		RotatedBBox (currentmodel->mins, currentmodel->maxs,
+			currententity->angles, mins, maxs);
+		VectorAdd (mins, currententity->origin, minmaxs);
+		VectorAdd (maxs, currententity->origin, (minmaxs+3));
+
+		clipflags = R_BmodelCheckBBox (minmaxs);
+		if (clipflags == BMODEL_FULLY_CLIPPED)
+			continue;	// off the edge of the screen
+
+		topnode = R_FindTopnode (minmaxs, minmaxs+3);
+		if (!topnode)
+			continue;	// no part in a visible leaf
+
+		VectorCopy (currententity->origin, r_entorigin);
+		VectorSubtract (r_origin, r_entorigin, modelorg);
+
+		r_pcurrentvertbase = currentmodel->vertexes;
+
+	// FIXME: stop transforming twice
+		R_RotateBmodel ();
+
+	// calculate dynamic lighting for bmodel
+		R_PushDlights (currentmodel);
+
+		if (topnode->contents == CONTENTS_NODE)
+		{
+		// not a leaf; has to be clipped to the world BSP
+			r_clipflags = clipflags;
+			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
+		}
+		else
+		{
+		// falls entirely in one leaf, so we just put all the
+		// edges in the edge list and let 1/z sorting handle
+		// drawing order
+			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
+		}
+
+	// put back world rotation and frustum clipping		
+	// FIXME: R_RotateBmodel should just work off base_vxx
+		VectorCopy (base_vpn, vpn);
+		VectorCopy (base_vup, vup);
+		VectorCopy (base_vright, vright);
+		VectorCopy (oldorigin, modelorg);
+		R_TransformFrustum ();
+	}
+
+	insubmodel = false;
+}
+
+
+/*
+================
+R_EdgeDrawing
+================
+*/
+void R_EdgeDrawing (void)
+{
+	edge_t	ledges[NUMSTACKEDGES +
+				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
+	surf_t	lsurfs[NUMSTACKSURFACES +
+				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
+
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+		return;
+
+	if (auxedges)
+	{
+		r_edges = auxedges;
+	}
+	else
+	{
+		r_edges =  (edge_t *)
+				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+	}
+
+	if (r_surfsonstack)
+	{
+		surfaces =  (surf_t *)
+				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+		surf_max = &surfaces[r_cnumsurfs];
+	// surface 0 doesn't really exist; it's just a dummy because index 0
+	// is used to indicate no edge attached to surface
+		surfaces--;
+		R_SurfacePatch ();
+	}
+
+	R_BeginEdgeFrame ();
+
+	if (r_dspeeds->value)
+	{
+		rw_time1 = Sys_Milliseconds ();
+	}
+
+	R_RenderWorld ();
+
+	if (r_dspeeds->value)
+	{
+		rw_time2 = Sys_Milliseconds ();
+		db_time1 = rw_time2;
+	}
+
+	R_DrawBEntitiesOnList ();
+
+	if (r_dspeeds->value)
+	{
+		db_time2 = Sys_Milliseconds ();
+		se_time1 = db_time2;
+	}
+
+	R_ScanEdges ();
+}
+
+//=======================================================================
+
+
+/*
+=============
+R_CalcPalette
+
+=============
+*/
+void R_CalcPalette (void)
+{
+	static qboolean modified;
+	byte	palette[256][4], *in, *out;
+	int		i, j;
+	float	alpha, one_minus_alpha;
+	vec3_t	premult;
+	int		v;
+
+	alpha = r_newrefdef.blend[3];
+	if (alpha <= 0)
+	{
+		if (modified)
+		{	// set back to default
+			modified = false;
+			R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+			return;
+		}
+		return;
+	}
+
+	modified = true;
+	if (alpha > 1)
+		alpha = 1;
+
+	premult[0] = r_newrefdef.blend[0]*alpha*255;
+	premult[1] = r_newrefdef.blend[1]*alpha*255;
+	premult[2] = r_newrefdef.blend[2]*alpha*255;
+
+	one_minus_alpha = (1.0 - alpha);
+
+	in = (byte *)d_8to24table;
+	out = palette[0];
+	for (i=0 ; i<256 ; i++, in+=4, out+=4)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			v = premult[j] + one_minus_alpha * in[j];
+			if (v > 255)
+				v = 255;
+			out[j] = v;
+		}
+		out[3] = 255;
+	}
+
+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
+//	SWimp_SetPalette( palette[0] );
+}
+
+//=======================================================================
+
+void R_SetLightLevel (void)
+{
+	vec3_t		light;
+
+	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
+	{
+		r_lightlevel->value = 150.0;
+		return;
+	}
+
+	// save off light value for server to look at (BIG HACK!)
+	R_LightPoint (r_newrefdef.vieworg, light);
+	r_lightlevel->value = 150.0 * light[0];
+}
+
+
+/*
+@@@@@@@@@@@@@@@@
+R_RenderFrame
+
+@@@@@@@@@@@@@@@@
+*/
+void R_RenderFrame (refdef_t *fd)
+{
+	r_newrefdef = *fd;
+
+	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
+
+	VectorCopy (fd->vieworg, r_refdef.vieworg);
+	VectorCopy (fd->viewangles, r_refdef.viewangles);
+
+	if (r_speeds->value || r_dspeeds->value)
+		r_time1 = Sys_Milliseconds ();
+
+	R_SetupFrame ();
+
+	R_MarkLeaves ();	// done here so we know if we're in water
+
+	R_PushDlights (r_worldmodel);
+
+	R_EdgeDrawing ();
+
+	if (r_dspeeds->value)
+	{
+		se_time2 = Sys_Milliseconds ();
+		de_time1 = se_time2;
+	}
+
+	R_DrawEntitiesOnList ();
+
+	if (r_dspeeds->value)
+	{
+		de_time2 = Sys_Milliseconds ();
+		dp_time1 = Sys_Milliseconds ();
+	}
+
+	R_DrawParticles ();
+
+	if (r_dspeeds->value)
+		dp_time2 = Sys_Milliseconds ();
+
+	R_DrawAlphaSurfaces();
+
+	R_SetLightLevel ();
+
+	if (r_dowarp)
+		D_WarpScreen ();
+
+	if (r_dspeeds->value)
+		da_time1 = Sys_Milliseconds ();
+
+	if (r_dspeeds->value)
+		da_time2 = Sys_Milliseconds ();
+
+	R_CalcPalette ();
+
+	if (sw_aliasstats->value)
+		R_PrintAliasStats ();
+		
+	if (r_speeds->value)
+		R_PrintTimes ();
+
+	if (r_dspeeds->value)
+		R_PrintDSpeeds ();
+
+	if (sw_reportsurfout->value && r_outofsurfaces)
+		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
+
+	if (sw_reportedgeout->value && r_outofedges)
+		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
+}
+
+/*
+** R_InitGraphics
+*/
+void R_InitGraphics( int width, int height )
+{
+	vid.width  = width;
+	vid.height = height;
+
+	// free z buffer
+	if ( d_pzbuffer )
+	{
+		free( d_pzbuffer );
+		d_pzbuffer = NULL;
+	}
+
+	// free surface cache
+	if ( sc_base )
+	{
+		D_FlushCaches ();
+		free( sc_base );
+		sc_base = NULL;
+	}
+
+	d_pzbuffer = malloc(vid.width*vid.height*2);
+
+	R_InitCaches ();
+
+	R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
+}
+
+/*
+** R_BeginFrame
+*/
+void R_BeginFrame( float camera_separation )
+{
+	extern void Draw_BuildGammaTable( void );
+
+	/*
+	** rebuild the gamma correction palette if necessary
+	*/
+	if ( vid_gamma->modified )
+	{
+		Draw_BuildGammaTable();
+		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+		vid_gamma->modified = false;
+	}
+
+	while ( sw_mode->modified || vid_fullscreen->modified )
+	{
+		rserr_t err;
+
+		/*
+		** if this returns rserr_invalid_fullscreen then it set the mode but not as a
+		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
+		*/
+		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
+		{
+			R_InitGraphics( vid.width, vid.height );
+
+			sw_state.prev_mode = sw_mode->value;
+			vid_fullscreen->modified = false;
+			sw_mode->modified = false;
+		}
+		else
+		{
+			if ( err == rserr_invalid_mode )
+			{
+				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
+				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
+			}
+			else if ( err == rserr_invalid_fullscreen )
+			{
+				R_InitGraphics( vid.width, vid.height );
+
+				ri.Cvar_SetValue( "vid_fullscreen", 0);
+				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
+				sw_state.prev_mode = sw_mode->value;
+//				vid_fullscreen->modified = false;
+//				sw_mode->modified = false;
+			}
+			else
+			{
+				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
+			}
+		}
+	}
+}
+
+/*
+** R_GammaCorrectAndSetPalette
+*/
+void R_GammaCorrectAndSetPalette( const unsigned char *palette )
+{
+	int i;
+
+	for ( i = 0; i < 256; i++ )
+	{
+		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
+		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
+		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
+	}
+
+	SWimp_SetPalette( sw_state.currentpalette );
+}
+
+/*
+** R_CinematicSetPalette
+*/
+void R_CinematicSetPalette( const unsigned char *palette )
+{
+	byte palette32[1024];
+	int		i, j, w;
+	int		*d;
+
+	// clear screen to black to avoid any palette flash
+	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...
+	for (i=0 ; i<vid.height ; i++, d+=w)
+	{
+		d = (int *)(vid.buffer + i*vid.rowbytes);
+		for (j=0 ; j<w ; j++)
+			d[j] = 0;
+	}
+	// flush it to the screen
+	SWimp_EndFrame ();
+
+	if ( palette )
+	{
+		for ( i = 0; i < 256; i++ )
+		{
+			palette32[i*4+0] = palette[i*3+0];
+			palette32[i*4+1] = palette[i*3+1];
+			palette32[i*4+2] = palette[i*3+2];
+			palette32[i*4+3] = 0xFF;
+		}
+
+		R_GammaCorrectAndSetPalette( palette32 );
+	}
+	else
+	{
+		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+	}
+}
+
+/*
+================
+Draw_BuildGammaTable
+================
+*/
+void Draw_BuildGammaTable (void)
+{
+	int		i, inf;
+	float	g;
+
+	g = vid_gamma->value;
+
+	if (g == 1.0)
+	{
+		for (i=0 ; i<256 ; i++)
+			sw_state.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;
+		sw_state.gammatable[i] = inf;
+	}
+}
+
+/*
+** R_DrawBeam
+*/
+void R_DrawBeam( entity_t *e )
+{
+#define NUM_BEAM_SEGS 6
+
+	int	i;
+
+	vec3_t perpvec;
+	vec3_t direction, normalized_direction;
+	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+	vec3_t oldorigin, origin;
+
+	oldorigin[0] = e->oldorigin[0];
+	oldorigin[1] = e->oldorigin[1];
+	oldorigin[2] = e->oldorigin[2];
+
+	origin[0] = e->origin[0];
+	origin[1] = e->origin[1];
+	origin[2] = e->origin[2];
+
+	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+	if ( VectorNormalize( normalized_direction ) == 0 )
+		return;
+
+	PerpendicularVector( perpvec, normalized_direction );
+	VectorScale( perpvec, e->frame / 2, perpvec );
+
+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+	{
+		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+		VectorAdd( start_points[i], origin, start_points[i] );
+		VectorAdd( start_points[i], direction, end_points[i] );
+	}
+
+	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+	{
+		R_IMFlatShadedQuad( start_points[i],
+		                    end_points[i],
+							end_points[(i+1)%NUM_BEAM_SEGS],
+							start_points[(i+1)%NUM_BEAM_SEGS],
+							e->skinnum & 0xFF,
+							e->alpha );
+	}
+}
+
+
+//===================================================================
+
+/*
+============
+R_SetSky
+============
+*/
+// 3dstudio environment map names
+char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
+extern	mtexinfo_t		r_skytexinfo[6];
+void R_SetSky (char *name, float rotate, vec3_t axis)
+{
+	int		i;
+	char	pathname[MAX_QPATH];
+
+	strncpy (skyname, name, sizeof(skyname)-1);
+	skyrotate = rotate;
+	VectorCopy (axis, skyaxis);
+
+	for (i=0 ; i<6 ; i++)
+	{
+		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
+		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
+	}
+}
+
+
+/*
+===============
+Draw_GetPalette
+===============
+*/
+void Draw_GetPalette (void)
+{
+	byte	*pal, *out;
+	int		i;
+	int		r, g, b;
+
+	// get the palette and colormap
+	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
+	if (!vid.colormap)
+		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
+	vid.alphamap = vid.colormap + 64*256;
+
+	out = (byte *)d_8to24table;
+	for (i=0 ; i<256 ; i++, out+=4)
+	{
+		r = pal[i*3+0];
+		g = pal[i*3+1];
+		b = pal[i*3+2];
+
+        out[0] = r;
+        out[1] = g;
+        out[2] = b;
+	}
+
+	free (pal);
+}
+
+struct image_s *R_RegisterSkin (char *name);
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+refexport_t GetRefAPI (refimport_t rimp)
+{
+	refexport_t	re;
+
+	ri = rimp;
+
+	re.api_version = API_VERSION;
+
+	re.BeginRegistration = R_BeginRegistration;
+    re.RegisterModel = R_RegisterModel;
+    re.RegisterSkin = R_RegisterSkin;
+	re.RegisterPic = Draw_FindPic;
+	re.SetSky = R_SetSky;
+	re.EndRegistration = R_EndRegistration;
+
+	re.RenderFrame = R_RenderFrame;
+
+	re.DrawGetPicSize = Draw_GetPicSize;
+	re.DrawPic = Draw_Pic;
+	re.DrawStretchPic = Draw_StretchPic;
+	re.DrawChar = Draw_Char;
+	re.DrawTileClear = Draw_TileClear;
+	re.DrawFill = Draw_Fill;
+	re.DrawFadeScreen= Draw_FadeScreen;
+
+	re.DrawStretchRaw = Draw_StretchRaw;
+
+	re.Init = R_Init;
+	re.Shutdown = R_Shutdown;
+
+	re.CinematicSetPalette = R_CinematicSetPalette;
+	re.BeginFrame = R_BeginFrame;
+	re.EndFrame = SWimp_EndFrame;
+
+	re.AppActivate = SWimp_AppActivate;
+
+	Swap_Init ();
+
+	return re;
+}
+
+#ifndef REF_HARD_LINKED
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, error);
+	vsprintf (text, error, argptr);
+	va_end (argptr);
+
+	ri.Sys_Error (ERR_FATAL, "%s", text);
+}
+
+void Com_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	va_start (argptr, fmt);
+	vsprintf (text, fmt, argptr);
+	va_end (argptr);
+
+	ri.Con_Printf (PRINT_ALL, "%s", text);
+}
+
+#endif
--- /dev/null
+++ b/ref_soft/r_misc.c
@@ -1,0 +1,670 @@
+/*
+Copyright (C) 1997-2001 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 "r_local.h"
+
+#define NUM_MIPS	4
+
+cvar_t	*sw_mipcap;
+cvar_t	*sw_mipscale;
+
+surfcache_t		*d_initial_rover;
+qboolean		d_roverwrapped;
+int				d_minmip;
+float			d_scalemip[NUM_MIPS-1];
+
+static float	basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
+
+extern int			d_aflatcolor;
+
+int	d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
+
+int	d_pix_min, d_pix_max, d_pix_shift;
+
+int		d_scantable[MAXHEIGHT];
+short	*zspantable[MAXHEIGHT]; 
+
+/*
+================
+D_Patch
+================
+*/
+void D_Patch (void)
+{
+#if id386
+	extern void D_Aff8Patch( void );
+	static qboolean protectset8 = false;
+	extern void D_PolysetAff8Start( void );
+
+	if (!protectset8)
+	{
+		Sys_MakeCodeWriteable ((int)D_PolysetAff8Start,
+						     (int)D_Aff8Patch - (int)D_PolysetAff8Start);
+		Sys_MakeCodeWriteable ((long)R_Surf8Start,
+						 (long)R_Surf8End - (long)R_Surf8Start);
+		protectset8 = true;
+	}
+	colormap = vid.colormap;
+
+	R_Surf8Patch ();
+	D_Aff8Patch();
+#endif
+}
+/*
+================
+D_ViewChanged
+================
+*/
+unsigned char *alias_colormap;
+
+void D_ViewChanged (void)
+{
+	int		i;
+
+	scale_for_mip = xscale;
+	if (yscale > xscale)
+		scale_for_mip = yscale;
+
+	d_zrowbytes = vid.width * 2;
+	d_zwidth = vid.width;
+
+	d_pix_min = r_refdef.vrect.width / 320;
+	if (d_pix_min < 1)
+		d_pix_min = 1;
+
+	d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
+	d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
+	if (d_pix_max < 1)
+		d_pix_max = 1;
+
+	d_vrectx = r_refdef.vrect.x;
+	d_vrecty = r_refdef.vrect.y;
+	d_vrectright_particle = r_refdef.vrectright - d_pix_max;
+	d_vrectbottom_particle =
+			r_refdef.vrectbottom - d_pix_max;
+
+	for (i=0 ; i<vid.height; i++)
+	{
+		d_scantable[i] = i*r_screenwidth;
+		zspantable[i] = d_pzbuffer + i*d_zwidth;
+	}
+
+	/*
+	** clear Z-buffer and color-buffers if we're doing the gallery
+	*/
+	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+	{
+		memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
+		Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
+	}
+
+	alias_colormap = vid.colormap;
+
+	D_Patch ();
+}
+
+
+
+/*
+=============
+R_PrintTimes
+=============
+*/
+void R_PrintTimes (void)
+{
+	int		r_time2;
+	int		ms;
+
+	r_time2 = Sys_Milliseconds ();
+
+	ms = r_time2 - r_time1;
+	
+	ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
+				ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
+	c_surf = 0;
+}
+
+
+/*
+=============
+R_PrintDSpeeds
+=============
+*/
+void R_PrintDSpeeds (void)
+{
+	int	ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
+
+	r_time2 = Sys_Milliseconds ();
+
+	da_time = (da_time2 - da_time1);
+	dp_time = (dp_time2 - dp_time1);
+	rw_time = (rw_time2 - rw_time1);
+	db_time = (db_time2 - db_time1);
+	se_time = (se_time2 - se_time1);
+	de_time = (de_time2 - de_time1);
+	ms = (r_time2 - r_time1);
+
+	ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
+				ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
+}
+
+
+/*
+=============
+R_PrintAliasStats
+=============
+*/
+void R_PrintAliasStats (void)
+{
+	ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
+}
+
+
+
+/*
+===================
+R_TransformFrustum
+===================
+*/
+void R_TransformFrustum (void)
+{
+	int		i;
+	vec3_t	v, v2;
+	
+	for (i=0 ; i<4 ; i++)
+	{
+		v[0] = screenedge[i].normal[2];
+		v[1] = -screenedge[i].normal[0];
+		v[2] = screenedge[i].normal[1];
+
+		v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
+		v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
+		v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
+
+		VectorCopy (v2, view_clipplanes[i].normal);
+
+		view_clipplanes[i].dist = DotProduct (modelorg, v2);
+	}
+}
+
+
+#if !(defined __linux__ && defined __i386__)
+#if !id386
+
+/*
+================
+TransformVector
+================
+*/
+void TransformVector (vec3_t in, vec3_t out)
+{
+	out[0] = DotProduct(in,vright);
+	out[1] = DotProduct(in,vup);
+	out[2] = DotProduct(in,vpn);		
+}
+
+#else
+
+__declspec( naked ) void TransformVector( vec3_t vin, vec3_t vout )
+{
+	__asm mov eax, dword ptr [esp+4]
+	__asm mov edx, dword ptr [esp+8]
+
+	__asm fld  dword ptr [eax+0]
+	__asm fmul dword ptr [vright+0]
+	__asm fld  dword ptr [eax+0]
+	__asm fmul dword ptr [vup+0]
+	__asm fld  dword ptr [eax+0]
+	__asm fmul dword ptr [vpn+0]
+
+	__asm fld  dword ptr [eax+4]
+	__asm fmul dword ptr [vright+4]
+	__asm fld  dword ptr [eax+4]
+	__asm fmul dword ptr [vup+4]
+	__asm fld  dword ptr [eax+4]
+	__asm fmul dword ptr [vpn+4]
+
+	__asm fxch st(2)
+
+	__asm faddp st(5), st(0)
+	__asm faddp st(3), st(0)
+	__asm faddp st(1), st(0)
+
+	__asm fld  dword ptr [eax+8]
+	__asm fmul dword ptr [vright+8]
+	__asm fld  dword ptr [eax+8]
+	__asm fmul dword ptr [vup+8]
+	__asm fld  dword ptr [eax+8]
+	__asm fmul dword ptr [vpn+8]
+
+	__asm fxch st(2)
+
+	__asm faddp st(5), st(0)
+	__asm faddp st(3), st(0)
+	__asm faddp st(1), st(0)
+
+	__asm fstp dword ptr [edx+8]
+	__asm fstp dword ptr [edx+4]
+	__asm fstp dword ptr [edx+0]
+
+	__asm ret
+}
+
+#endif
+#endif
+
+
+/*
+================
+R_TransformPlane
+================
+*/
+void R_TransformPlane (mplane_t *p, float *normal, float *dist)
+{
+	float	d;
+	
+	d = DotProduct (r_origin, p->normal);
+	*dist = p->dist - d;
+// TODO: when we have rotating entities, this will need to use the view matrix
+	TransformVector (p->normal, normal);
+}
+
+
+/*
+===============
+R_SetUpFrustumIndexes
+===============
+*/
+void R_SetUpFrustumIndexes (void)
+{
+	int		i, j, *pindex;
+
+	pindex = r_frustum_indexes;
+
+	for (i=0 ; i<4 ; i++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			if (view_clipplanes[i].normal[j] < 0)
+			{
+				pindex[j] = j;
+				pindex[j+3] = j+3;
+			}
+			else
+			{
+				pindex[j] = j+3;
+				pindex[j+3] = j;
+			}
+		}
+
+	// FIXME: do just once at start
+		pfrustum_indexes[i] = pindex;
+		pindex += 6;
+	}
+}
+
+/*
+===============
+R_ViewChanged
+
+Called every time the vid structure or r_refdef changes.
+Guaranteed to be called before the first refresh
+===============
+*/
+void R_ViewChanged (vrect_t *vr)
+{
+	int		i;
+
+	r_refdef.vrect = *vr;
+
+	r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
+	verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
+
+	r_refdef.fvrectx = (float)r_refdef.vrect.x;
+	r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
+	r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
+	r_refdef.fvrecty = (float)r_refdef.vrect.y;
+	r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
+	r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
+	r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
+	r_refdef.fvrectright = (float)r_refdef.vrectright;
+	r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
+	r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
+	r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
+	r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
+	r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
+
+	r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
+	r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
+	r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
+	r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
+	r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
+			r_refdef.aliasvrect.width;
+	r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
+			r_refdef.aliasvrect.height;
+
+	xOrigin = r_refdef.xOrigin;
+	yOrigin = r_refdef.yOrigin;
+	
+// values for perspective projection
+// if math were exact, the values would range from 0.5 to to range+0.5
+// hopefully they wll be in the 0.000001 to range+.999999 and truncate
+// the polygon rasterization will never render in the first row or column
+// but will definately render in the [range] row and column, so adjust the
+// buffer origin to get an exact edge to edge fill
+	xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
+			r_refdef.vrect.x - 0.5;
+	aliasxcenter = xcenter * r_aliasuvscale;
+	ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
+			r_refdef.vrect.y - 0.5;
+	aliasycenter = ycenter * r_aliasuvscale;
+
+	xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
+	aliasxscale = xscale * r_aliasuvscale;
+	xscaleinv = 1.0 / xscale;
+
+	yscale = xscale;
+	aliasyscale = yscale * r_aliasuvscale;
+	yscaleinv = 1.0 / yscale;
+	xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
+	yscaleshrink = xscaleshrink;
+
+// left side clip
+	screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
+	screenedge[0].normal[1] = 0;
+	screenedge[0].normal[2] = 1;
+	screenedge[0].type = PLANE_ANYZ;
+	
+// right side clip
+	screenedge[1].normal[0] =
+			1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
+	screenedge[1].normal[1] = 0;
+	screenedge[1].normal[2] = 1;
+	screenedge[1].type = PLANE_ANYZ;
+	
+// top side clip
+	screenedge[2].normal[0] = 0;
+	screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
+	screenedge[2].normal[2] = 1;
+	screenedge[2].type = PLANE_ANYZ;
+	
+// bottom side clip
+	screenedge[3].normal[0] = 0;
+	screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
+	screenedge[3].normal[2] = 1;	
+	screenedge[3].type = PLANE_ANYZ;
+	
+	for (i=0 ; i<4 ; i++)
+		VectorNormalize (screenedge[i].normal);
+
+	D_ViewChanged ();
+}
+
+
+/*
+===============
+R_SetupFrame
+===============
+*/
+void R_SetupFrame (void)
+{
+	int			i;
+	vrect_t		vrect;
+
+	if (r_fullbright->modified)
+	{
+		r_fullbright->modified = false;
+		D_FlushCaches ();	// so all lighting changes
+	}
+	
+	r_framecount++;
+
+
+// build the transformation matrix for the given view angles
+	VectorCopy (r_refdef.vieworg, modelorg);
+	VectorCopy (r_refdef.vieworg, r_origin);
+
+	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
+
+// current viewleaf
+	if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+	{
+		r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
+		r_viewcluster = r_viewleaf->cluster;
+	}
+
+	if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
+		r_dowarp = true;
+	else
+		r_dowarp = false;
+
+	if (r_dowarp)
+	{	// warp into off screen buffer
+		vrect.x = 0;
+		vrect.y = 0;
+		vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
+		vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
+
+		d_viewbuffer = r_warpbuffer;
+		r_screenwidth = WARP_WIDTH;
+	}
+	else
+	{
+		vrect.x = r_newrefdef.x;
+		vrect.y = r_newrefdef.y;
+		vrect.width = r_newrefdef.width;
+		vrect.height = r_newrefdef.height;
+
+		d_viewbuffer = (void *)vid.buffer;
+		r_screenwidth = vid.rowbytes;
+	}
+	
+	R_ViewChanged (&vrect);
+
+// start off with just the four screen edge clip planes
+	R_TransformFrustum ();
+	R_SetUpFrustumIndexes ();
+
+// save base values
+	VectorCopy (vpn, base_vpn);
+	VectorCopy (vright, base_vright);
+	VectorCopy (vup, base_vup);
+
+// clear frame counts
+	c_faceclip = 0;
+	d_spanpixcount = 0;
+	r_polycount = 0;
+	r_drawnpolycount = 0;
+	r_wholepolycount = 0;
+	r_amodels_drawn = 0;
+	r_outofsurfaces = 0;
+	r_outofedges = 0;
+
+// d_setup
+	d_roverwrapped = false;
+	d_initial_rover = sc_rover;
+
+	d_minmip = sw_mipcap->value;
+	if (d_minmip > 3)
+		d_minmip = 3;
+	else if (d_minmip < 0)
+		d_minmip = 0;
+
+	for (i=0 ; i<(NUM_MIPS-1) ; i++)
+		d_scalemip[i] = basemip[i] * sw_mipscale->value;
+
+	d_aflatcolor = 0;
+}
+
+
+#if	!id386
+
+/*
+================
+R_SurfacePatch
+================
+*/
+void R_SurfacePatch (void)
+{
+	// we only patch code on Intel
+}
+
+#endif	// !id386
+
+
+/* 
+============================================================================== 
+ 
+						SCREEN SHOTS 
+ 
+============================================================================== 
+*/ 
+
+
+/* 
+============== 
+WritePCXfile 
+============== 
+*/ 
+void WritePCXfile (char *filename, byte *data, int width, int height,
+	int rowbytes, byte *palette) 
+{
+	int			i, j, length;
+	pcx_t		*pcx;
+	byte		*pack;
+	FILE		*f;
+
+	pcx = (pcx_t *)malloc (width*height*2+1000);
+	if (!pcx)
+		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);
+	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
+	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;
+	f = fopen (filename, "wb");
+	if (!f)
+		ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename);
+	else
+	{
+		fwrite ((void *)pcx, 1, length, f);
+		fclose (f);
+	}
+
+	free (pcx);
+} 
+ 
+
+
+/* 
+================== 
+R_ScreenShot_f
+================== 
+*/  
+void R_ScreenShot_f (void) 
+{ 
+	int			i; 
+	char		pcxname[80]; 
+	char		checkname[MAX_OSPATH];
+	FILE		*f;
+	byte		palette[768];
+
+	// create the scrnshots directory if it doesn't exist
+	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
+	Sys_Mkdir (checkname);
+
+// 
+// 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'; 
+		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
+		f = fopen (checkname, "r");
+		if (!f)
+			break;	// file doesn't exist
+		fclose (f);
+	} 
+	if (i==100) 
+	{
+		ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 
+		return;
+	}
+
+	// turn the current 32 bit palette into a 24 bit palette
+	for (i=0 ; i<256 ; i++)
+	{
+		palette[i*3+0] = sw_state.currentpalette[i*4+0];
+		palette[i*3+1] = sw_state.currentpalette[i*4+1];
+		palette[i*3+2] = sw_state.currentpalette[i*4+2];
+	}
+
+// 
+// save the pcx file 
+// 
+
+	WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
+				  palette);
+
+	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
+} 
+
--- /dev/null
+++ b/ref_soft/r_model.c
@@ -1,0 +1,1241 @@
+/*
+Copyright (C) 1997-2001 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 "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;
+
+// the inline * models from the current map are kept seperate
+model_t	mod_inline[MAX_MOD_KNOWN];
+
+int		registration_sequence;
+int		modfilelen;
+
+//===============================================================================
+
+
+/*
+================
+Mod_Modellist_f
+================
+*/
+void Mod_Modellist_f (void)
+{
+	int		i;
+	model_t	*mod;
+	int		total;
+
+	total = 0;
+	ri.Con_Printf (PRINT_ALL,"Loaded models:\n");
+	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name);
+		total += mod->extradatasize;
+	}
+	ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total);
+}
+
+/*
+===============
+Mod_Init
+===============
+*/
+void Mod_Init (void)
+{
+	memset (mod_novis, 0xff, sizeof(mod_novis));
+}
+
+/*
+==================
+Mod_ForName
+
+Loads in a model for the given name
+==================
+*/
+model_t *Mod_ForName (char *name, qboolean crash)
+{
+	model_t	*mod;
+	unsigned *buf;
+	int		i;
+	
+	if (!name[0])
+		ri.Sys_Error (ERR_DROP,"Mod_ForName: NULL name");
+
+	//
+	// inline models are grabbed only from worldmodel
+	//
+	if (name[0] == '*')
+	{
+		i = atoi(name+1);
+		if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
+			ri.Sys_Error (ERR_DROP, "bad inline model number");
+		return &mod_inline[i];
+	}
+
+	//
+	// search the currently loaded models
+	//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+		if (!strcmp (mod->name, name) )
+			return mod;
+			
+	//
+	// find a free model slot spot
+	//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			break;	// free spot
+	}
+	if (i == mod_numknown)
+	{
+		if (mod_numknown == MAX_MOD_KNOWN)
+			ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
+		mod_numknown++;
+	}
+	strcpy (mod->name, name);
+	
+	//
+	// load the file
+	//
+	modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf);
+	if (!buf)
+	{
+		if (crash)
+			ri.Sys_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name);
+		memset (mod->name, 0, sizeof(mod->name));
+		return NULL;
+	}
+	
+	loadmodel = mod;
+
+	//
+	// fill it in
+	//
+
+	// call the apropriate loader
+	
+	switch (LittleLong(*(unsigned *)buf))
+	{
+	case IDALIASHEADER:
+		loadmodel->extradata = Hunk_Begin (0x200000);
+		Mod_LoadAliasModel (mod, buf);
+		break;
+		
+	case IDSPRITEHEADER:
+		loadmodel->extradata = Hunk_Begin (0x10000);
+		Mod_LoadSpriteModel (mod, buf);
+		break;
+	
+	case IDBSPHEADER:
+		loadmodel->extradata = Hunk_Begin (0x1000000);
+		Mod_LoadBrushModel (mod, buf);
+		break;
+
+	default:
+		ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
+		break;
+	}
+
+	loadmodel->extradatasize = Hunk_End ();
+
+	ri.FS_FreeFile (buf);
+
+	return mod;
+}
+
+
+/*
+===============
+Mod_PointInLeaf
+===============
+*/
+mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
+{
+	mnode_t		*node;
+	float		d;
+	mplane_t	*plane;
+	
+	if (!model || !model->nodes)
+		ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
+
+	node = model->nodes;
+	while (1)
+	{
+		if (node->contents != -1)
+			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->vis->numclusters+7)>>3;	
+	out = decompressed;
+
+#if 0
+	memcpy (out, in, row);
+#else
+	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);
+#endif
+	
+	return decompressed;
+}
+
+/*
+==============
+Mod_ClusterPVS
+==============
+*/
+byte *Mod_ClusterPVS (int cluster, model_t *model)
+{
+	if (cluster == -1 || !model->vis)
+		return mod_novis;
+	return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
+		model);
+}
+
+/*
+===============================================================================
+
+					BRUSHMODEL LOADING
+
+===============================================================================
+*/
+
+byte	*mod_base;
+
+
+/*
+=================
+Mod_LoadLighting
+
+Converts the 24 bit lighting down to 8 bit
+by taking the brightest component
+=================
+*/
+void Mod_LoadLighting (lump_t *l)
+{
+	int		i, size;
+	byte	*in;
+
+	if (!l->filelen)
+	{
+		loadmodel->lightdata = NULL;
+		return;
+	}
+	size = l->filelen/3;
+	loadmodel->lightdata = Hunk_Alloc (size);
+	in = (void *)(mod_base + l->fileofs);
+	for (i=0 ; i<size ; i++, in+=3)
+	{
+		if (in[0] > in[1] && in[0] > in[2])
+			loadmodel->lightdata[i] = in[0];
+		else if (in[1] > in[0] && in[1] > in[2])
+			loadmodel->lightdata[i] = in[1];
+		else
+			loadmodel->lightdata[i] = in[2];
+	}
+}
+
+
+int		r_leaftovis[MAX_MAP_LEAFS];
+int		r_vistoleaf[MAX_MAP_LEAFS];
+int		r_numvisleafs;
+
+void	R_NumberLeafs (mnode_t *node)
+{
+	mleaf_t	*leaf;
+	int		leafnum;
+
+	if (node->contents != -1)
+	{
+		leaf = (mleaf_t *)node;
+		leafnum = leaf - loadmodel->leafs;
+		if (leaf->contents & CONTENTS_SOLID)
+			return;
+		r_leaftovis[leafnum] = r_numvisleafs;
+		r_vistoleaf[r_numvisleafs] = leafnum;
+		r_numvisleafs++;
+		return;
+	}
+
+	R_NumberLeafs (node->children[0]);
+	R_NumberLeafs (node->children[1]);
+}
+
+
+/*
+=================
+Mod_LoadVisibility
+=================
+*/
+void Mod_LoadVisibility (lump_t *l)
+{
+	int		i;
+
+	if (!l->filelen)
+	{
+		loadmodel->vis = NULL;
+		return;
+	}
+	loadmodel->vis = Hunk_Alloc ( l->filelen);	
+	memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
+
+	loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
+	for (i=0 ; i<loadmodel->vis->numclusters ; i++)
+	{
+		loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
+		loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
+	}
+}
+
+
+/*
+=================
+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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+8)*sizeof(*out));		// extra for skybox
+
+	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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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]);
+		}
+		out->headnode = LittleLong (in->headnode);
+		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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count + 13) * sizeof(*out));	// extra for skybox
+
+	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, *step;
+	int 	i, j, count;
+	float	len1, len2;
+	char	name[MAX_QPATH];
+	int		next;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+6)*sizeof(*out));	// extra for skybox
+
+	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 = VectorLength (out->vecs[0]);
+		len2 = VectorLength (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
+
+		out->flags = LittleLong (in->flags);
+
+		next = LittleLong (in->nexttexinfo);
+		if (next > 0)
+			out->next = loadmodel->texinfo + next;
+
+		Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
+		out->image = R_FindImage (name, it_wall);
+		if (!out->image)
+		{
+			out->image = r_notexture_mip; // texture not found
+			out->flags = 0;
+		}
+	}
+
+	// count animation frames
+	for (i=0 ; i<count ; i++)
+	{
+		out = &loadmodel->texinfo[i];
+		out->numframes = 1;
+		for (step = out->next ; step && step != out ; step=step->next)
+			out->numframes++;
+	}
+}
+
+/*
+================
+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 (s->extents[i] < 16)
+			s->extents[i] = 16;	// take at least one cache block
+		if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256)
+			ri.Sys_Error (ERR_DROP,"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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+6)*sizeof(*out));	// extra for skybox
+
+	loadmodel->surfaces = out;
+	loadmodel->numsurfaces = count;
+
+	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+	{
+		out->firstedge = LittleLong(in->firstedge);
+		out->numedges = LittleShort(in->numedges);		
+		if (out->numedges < 3)
+			ri.Sys_Error (ERR_DROP,"Surface with %s edges", out->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 is converted from 24 bit on disk to 8 bit
+
+		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/3;
+		
+	// set the drawing flags flag
+		
+		if (!out->texinfo->image)
+			continue;
+		if (out->texinfo->flags & SURF_SKY)
+		{
+			out->flags |= SURF_DRAWSKY;
+			continue;
+		}
+		
+		if (out->texinfo->flags & SURF_WARP)
+		{
+			out->flags |= SURF_DRAWTURB;
+			for (i=0 ; i<2 ; i++)
+			{
+				out->extents[i] = 16384;
+				out->texturemins[i] = -8192;
+			}
+			continue;
+		}
+//==============
+//PGM
+		// this marks flowing surfaces as turbulent, but with the new
+		// SURF_FLOW flag.
+		if (out->texinfo->flags & SURF_FLOWING)
+		{
+			out->flags |= SURF_DRAWTURB | SURF_FLOW;
+			for (i=0 ; i<2 ; i++)
+			{
+				out->extents[i] = 16384;
+				out->texturemins[i] = -8192;
+			}
+			continue;
+		}
+//PGM
+//==============
+	}
+}
+
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+	node->parent = parent;
+	if (node->contents != -1)
+		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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	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);
+		out->contents = CONTENTS_NODE;	// differentiate from leafs
+		
+		for (j=0 ; j<2 ; j++)
+		{
+			p = LittleLong (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;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));
+
+	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]);
+		}
+
+		out->contents = LittleLong(in->contents);
+		out->cluster = LittleShort(in->cluster);
+		out->area = LittleShort(in->area);
+
+		out->firstmarksurface = loadmodel->marksurfaces +
+			LittleShort(in->firstleafface);
+		out->nummarksurfaces = LittleShort(in->numleaffaces);
+	}	
+}
+
+
+/*
+=================
+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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( count*sizeof(*out));	
+
+	loadmodel->marksurfaces = out;
+	loadmodel->nummarksurfaces = count;
+
+	for ( i=0 ; i<count ; i++)
+	{
+		j = LittleShort(in[i]);
+		if (j >= loadmodel->numsurfaces)
+			ri.Sys_Error (ERR_DROP,"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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+24)*sizeof(*out));	// extra for skybox
+
+	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))
+		ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_Alloc ( (count+6)*sizeof(*out));		// extra for skybox
+	
+	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;
+	}
+}
+
+
+/*
+=================
+Mod_LoadBrushModel
+=================
+*/
+void Mod_LoadBrushModel (model_t *mod, void *buffer)
+{
+	int			i;
+	dheader_t	*header;
+	dmodel_t 	*bm;
+	
+	loadmodel->type = mod_brush;
+	if (loadmodel != mod_known)
+		ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world");
+	
+	header = (dheader_t *)buffer;
+
+	i = LittleLong (header->version);
+	if (i != BSPVERSION)
+		ri.Sys_Error (ERR_DROP,"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_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_LEAFFACES]);
+	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+	r_numvisleafs = 0;
+	R_NumberLeafs (loadmodel->nodes);
+	
+//
+// set up the submodels
+//
+	for (i=0 ; i<mod->numsubmodels ; i++)
+	{
+		model_t	*starmod;
+
+		bm = &mod->submodels[i];
+		starmod = &mod_inline[i];
+
+		*starmod = *loadmodel;
+		
+		starmod->firstmodelsurface = bm->firstface;
+		starmod->nummodelsurfaces = bm->numfaces;
+		starmod->firstnode = bm->headnode;
+		if (starmod->firstnode >= loadmodel->numnodes)
+			ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
+
+		VectorCopy (bm->maxs, starmod->maxs);
+		VectorCopy (bm->mins, starmod->mins);
+	
+		if (i == 0)
+			*loadmodel = *starmod;
+	}
+
+	R_InitSkyBox ();
+}
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadAliasModel
+=================
+*/
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
+{
+	int					i, j;
+	dmdl_t				*pinmodel, *pheader;
+	dstvert_t			*pinst, *poutst;
+	dtriangle_t			*pintri, *pouttri;
+	daliasframe_t		*pinframe, *poutframe;
+	int					*pincmd, *poutcmd;
+	int					version;
+
+	pinmodel = (dmdl_t *)buffer;
+
+	version = LittleLong (pinmodel->version);
+	if (version != ALIAS_VERSION)
+		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+				 mod->name, version, ALIAS_VERSION);
+
+	pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end));
+	
+	// byte swap the header fields and sanity check
+	for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
+		((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
+
+	if (pheader->skinheight > MAX_LBM_HEIGHT)
+		ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
+				   MAX_LBM_HEIGHT);
+
+	if (pheader->num_xyz <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name);
+
+	if (pheader->num_xyz > MAX_VERTS)
+		ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name);
+
+	if (pheader->num_st <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name);
+
+	if (pheader->num_tris <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name);
+
+	if (pheader->num_frames <= 0)
+		ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name);
+
+//
+// load base s and t vertices (not used in gl version)
+//
+	pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
+	poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
+
+	for (i=0 ; i<pheader->num_st ; i++)
+	{
+		poutst[i].s = LittleShort (pinst[i].s);
+		poutst[i].t = LittleShort (pinst[i].t);
+	}
+
+//
+// load triangle lists
+//
+	pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
+	pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
+
+	for (i=0 ; i<pheader->num_tris ; i++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
+			pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
+		}
+	}
+
+//
+// load the frames
+//
+	for (i=0 ; i<pheader->num_frames ; i++)
+	{
+		pinframe = (daliasframe_t *) ((byte *)pinmodel 
+			+ pheader->ofs_frames + i * pheader->framesize);
+		poutframe = (daliasframe_t *) ((byte *)pheader 
+			+ pheader->ofs_frames + i * pheader->framesize);
+
+		memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
+		for (j=0 ; j<3 ; j++)
+		{
+			poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
+			poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
+		}
+		// verts are all 8 bit, so no swapping needed
+		memcpy (poutframe->verts, pinframe->verts, 
+			pheader->num_xyz*sizeof(dtrivertx_t));
+
+	}
+
+	mod->type = mod_alias;
+
+	//
+	// load the glcmds
+	//
+	pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
+	poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
+	for (i=0 ; i<pheader->num_glcmds ; i++)
+		poutcmd[i] = LittleLong (pincmd[i]);
+
+
+	// register all skins
+	memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
+		pheader->num_skins*MAX_SKINNAME);
+	for (i=0 ; i<pheader->num_skins ; i++)
+	{
+		mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+	}
+}
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+	dsprite_t	*sprin, *sprout;
+	int			i;
+
+	sprin = (dsprite_t *)buffer;
+	sprout = Hunk_Alloc (modfilelen);
+
+	sprout->ident = LittleLong (sprin->ident);
+	sprout->version = LittleLong (sprin->version);
+	sprout->numframes = LittleLong (sprin->numframes);
+
+	if (sprout->version != SPRITE_VERSION)
+		ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+				 mod->name, sprout->version, SPRITE_VERSION);
+
+	if (sprout->numframes > MAX_MD2SKINS)
+		ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)",
+				 mod->name, sprout->numframes, MAX_MD2SKINS);
+
+	// byte swap everything
+	for (i=0 ; i<sprout->numframes ; i++)
+	{
+		sprout->frames[i].width = LittleLong (sprin->frames[i].width);
+		sprout->frames[i].height = LittleLong (sprin->frames[i].height);
+		sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
+		sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
+		memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
+		mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+	}
+
+	mod->type = mod_sprite;
+}
+
+//=============================================================================
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_BeginRegistration
+
+Specifies the model that will be used as the world
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_BeginRegistration (char *model)
+{
+	char	fullname[MAX_QPATH];
+	cvar_t	*flushmap;
+
+	registration_sequence++;
+	r_oldviewcluster = -1;		// force markleafs
+	Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
+
+	D_FlushCaches ();
+	// explicitly free the old map if different
+	// this guarantees that mod_known[0] is the world map
+	flushmap = ri.Cvar_Get ("flushmap", "0", 0);
+	if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
+		Mod_Free (&mod_known[0]);
+	r_worldmodel = R_RegisterModel (fullname);
+	R_NewMap ();
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_RegisterModel
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+struct model_s *R_RegisterModel (char *name)
+{
+	model_t	*mod;
+	int		i;
+	dsprite_t	*sprout;
+	dmdl_t		*pheader;
+
+	mod = Mod_ForName (name, false);
+	if (mod)
+	{
+		mod->registration_sequence = registration_sequence;
+
+		// register any images used by the models
+		if (mod->type == mod_sprite)
+		{
+			sprout = (dsprite_t *)mod->extradata;
+			for (i=0 ; i<sprout->numframes ; i++)
+				mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+		}
+		else if (mod->type == mod_alias)
+		{
+			pheader = (dmdl_t *)mod->extradata;
+			for (i=0 ; i<pheader->num_skins ; i++)
+				mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+//PGM
+			mod->numframes = pheader->num_frames;
+//PGM
+		}
+		else if (mod->type == mod_brush)
+		{
+			for (i=0 ; i<mod->numtexinfo ; i++)
+				mod->texinfo[i].image->registration_sequence = registration_sequence;
+		}
+	}
+	return mod;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_EndRegistration
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_EndRegistration (void)
+{
+	int		i;
+	model_t	*mod;
+
+	for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!mod->name[0])
+			continue;
+		if (mod->registration_sequence != registration_sequence)
+		{	// don't need this model
+			Hunk_Free (mod->extradata);
+			memset (mod, 0, sizeof(*mod));
+		}
+		else
+		{	// make sure it is paged in
+			Com_PageInMemory (mod->extradata, mod->extradatasize);
+		}
+	}
+
+	R_FreeUnusedImages ();
+}
+
+
+//=============================================================================
+
+/*
+================
+Mod_Free
+================
+*/
+void Mod_Free (model_t *mod)
+{
+	Hunk_Free (mod->extradata);
+	memset (mod, 0, sizeof(*mod));
+}
+
+/*
+================
+Mod_FreeAll
+================
+*/
+void Mod_FreeAll (void)
+{
+	int		i;
+
+	for (i=0 ; i<mod_numknown ; i++)
+	{
+		if (mod_known[i].extradatasize)
+			Mod_Free (&mod_known[i]);
+	}
+}
--- /dev/null
+++ b/ref_soft/r_model.h
@@ -1,0 +1,256 @@
+/*
+Copyright (C) 1997-2001 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__
+
+/*
+
+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;
+
+
+// FIXME: differentiate from texinfo SURF_ flags
+#define	SURF_PLANEBACK		2
+#define	SURF_DRAWSKY		4			// sky brush face
+#define SURF_DRAWTURB		0x10
+#define SURF_DRAWBACKGROUND	0x40
+#define SURF_DRAWSKYBOX		0x80		// sky box
+
+#define SURF_FLOW			0x100		//PGM
+
+// !!! 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 mtexinfo_s
+{
+	float		vecs[2][4];
+	float		mipadjust;
+	image_t		*image;
+	int			flags;
+	int			numframes;
+	struct mtexinfo_s	*next;		// animation chain
+} 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]
+
+	struct msurface_s *nextalphasurface;
+} msurface_t;
+
+
+#define	CONTENTS_NODE	-1
+typedef struct mnode_s
+{
+// common with leaf
+	int			contents;		// CONTENTS_NODE, 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 something other than CONTENTS_NODE
+	int			visframe;		// node needs to be traversed if current
+
+	short		minmaxs[6];		// for bounding box culling
+
+	struct mnode_s	*parent;
+
+// leaf specific
+	int			cluster;
+	int			area;
+
+	msurface_t	**firstmarksurface;
+	int			nummarksurfaces;
+	int			key;			// BSP sequence number for leaf's contents
+} mleaf_t;
+
+
+//===================================================================
+
+//
+// Whole model
+//
+
+typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t;
+
+typedef struct model_s
+{
+	char		name[MAX_QPATH];
+
+	int			registration_sequence;
+
+	modtype_t	type;
+	int			numframes;
+	
+	int			flags;
+
+//
+// volume occupied by the model graphics
+//		
+	vec3_t		mins, maxs;
+
+//
+// solid volume for clipping (sent from server)
+//
+	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;
+	int			firstnode;
+	mnode_t		*nodes;
+
+	int			numtexinfo;
+	mtexinfo_t	*texinfo;
+
+	int			numsurfaces;
+	msurface_t	*surfaces;
+
+	int			numsurfedges;
+	int			*surfedges;
+
+	int			nummarksurfaces;
+	msurface_t	**marksurfaces;
+
+	dvis_t		*vis;
+
+	byte		*lightdata;
+
+	// for alias models and sprites
+	image_t		*skins[MAX_MD2SKINS];
+	void		*extradata;
+	int			extradatasize;
+} 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_ClusterPVS (int cluster, model_t *model);
+
+void Mod_Modellist_f (void);
+void Mod_FreeAll (void);
+void Mod_Free (model_t *mod);
+
+extern	int		registration_sequence;
+
+#endif	// __MODEL__
--- /dev/null
+++ b/ref_soft/r_part.c
@@ -1,0 +1,638 @@
+/*
+Copyright (C) 1997-2001 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 "r_local.h"
+
+vec3_t r_pright, r_pup, r_ppn;
+
+#define PARTICLE_33     0
+#define PARTICLE_66     1
+#define PARTICLE_OPAQUE 2
+
+typedef struct
+{
+	particle_t *particle;
+	int         level;
+	int         color;
+} partparms_t;
+
+static partparms_t partparms;
+
+#if id386 && !defined __linux__
+
+static unsigned s_prefetch_address;
+
+/*
+** BlendParticleXX
+**
+** Inputs:
+** EAX = color
+** EDI = pdest
+**
+** Scratch:
+** EBX = scratch (dstcolor)
+** EBP = scratch
+**
+** Outputs:
+** none
+*/
+__declspec(naked) void BlendParticle33( void )
+{
+	//	return vid.alphamap[color + dstcolor*256];
+	__asm mov ebp, vid.alphamap
+	__asm xor ebx, ebx
+
+	__asm mov bl,  byte ptr [edi]
+	__asm shl ebx, 8
+
+	__asm add ebp, ebx
+	__asm add ebp, eax
+
+	__asm mov al,  byte ptr [ebp]
+
+	__asm mov byte ptr [edi], al
+
+	__asm ret
+}
+
+__declspec(naked) void BlendParticle66( void )
+{
+	//	return vid.alphamap[pcolor*256 + dstcolor];
+	__asm mov ebp, vid.alphamap
+	__asm xor ebx, ebx
+
+	__asm shl eax,  8
+	__asm mov bl,   byte ptr [edi]
+
+	__asm add ebp, ebx
+	__asm add ebp, eax
+
+	__asm mov al,  byte ptr [ebp]
+
+	__asm mov byte ptr [edi], al
+
+	__asm ret
+}
+
+__declspec(naked) void BlendParticle100( void )
+{
+	__asm mov byte ptr [edi], al
+	__asm ret
+}
+
+/*
+** R_DrawParticle (asm version)
+**
+** Since we use __declspec( naked ) we don't have a stack frame
+** that we can use.  Since I want to reserve EBP anyway, I tossed
+** all the important variables into statics.  This routine isn't
+** meant to be re-entrant, so this shouldn't cause any problems
+** other than a slightly higher global memory footprint.
+**
+*/
+__declspec(naked) void R_DrawParticle( void )
+{
+	static vec3_t	local, transformed;
+	static float	zi;
+	static int      u, v, tmp;
+	static short    izi;
+	static int      ebpsave;
+
+	static byte (*blendfunc)(void);
+
+	/*
+	** must be memvars since x86 can't load constants
+	** directly.  I guess I could use fld1, but that
+	** actually costs one more clock than fld [one]!
+	*/
+	static float    particle_z_clip    = PARTICLE_Z_CLIP;
+	static float    one                = 1.0F;
+	static float    point_five         = 0.5F;
+	static float    eight_thousand_hex = 0x8000;
+
+	/*
+	** save trashed variables
+	*/
+	__asm mov  ebpsave, ebp
+	__asm push esi
+	__asm push edi
+
+	/*
+	** transform the particle
+	*/
+	// VectorSubtract (pparticle->origin, r_origin, local);
+	__asm mov  esi, partparms.particle
+	__asm fld  dword ptr [esi+0]          ; p_o.x
+	__asm fsub dword ptr [r_origin+0]     ; p_o.x-r_o.x
+	__asm fld  dword ptr [esi+4]          ; p_o.y | p_o.x-r_o.x
+	__asm fsub dword ptr [r_origin+4]     ; p_o.y-r_o.y | p_o.x-r_o.x
+	__asm fld  dword ptr [esi+8]          ; p_o.z | p_o.y-r_o.y | p_o.x-r_o.x
+	__asm fsub dword ptr [r_origin+8]     ; p_o.z-r_o.z | p_o.y-r_o.y | p_o.x-r_o.x
+	__asm fxch st(2)                      ; p_o.x-r_o.x | p_o.y-r_o.y | p_o.z-r_o.z
+	__asm fstp dword ptr [local+0]        ; p_o.y-r_o.y | p_o.z-r_o.z
+	__asm fstp dword ptr [local+4]        ; p_o.z-r_o.z
+	__asm fstp dword ptr [local+8]        ; (empty)
+
+	// transformed[0] = DotProduct(local, r_pright);
+	// transformed[1] = DotProduct(local, r_pup);
+	// transformed[2] = DotProduct(local, r_ppn);
+	__asm fld  dword ptr [local+0]        ; l.x
+	__asm fmul dword ptr [r_pright+0]     ; l.x*pr.x
+	__asm fld  dword ptr [local+4]        ; l.y | l.x*pr.x
+	__asm fmul dword ptr [r_pright+4]     ; l.y*pr.y | l.x*pr.x
+	__asm fld  dword ptr [local+8]        ; l.z | l.y*pr.y | l.x*pr.x
+	__asm fmul dword ptr [r_pright+8]     ; l.z*pr.z | l.y*pr.y | l.x*pr.x
+	__asm fxch st(2)                      ; l.x*pr.x | l.y*pr.y | l.z*pr.z
+	__asm faddp st(1), st                 ; l.x*pr.x + l.y*pr.y | l.z*pr.z
+	__asm faddp st(1), st                 ; l.x*pr.x + l.y*pr.y + l.z*pr.z
+	__asm fstp  dword ptr [transformed+0] ; (empty)
+
+	__asm fld  dword ptr [local+0]        ; l.x
+	__asm fmul dword ptr [r_pup+0]        ; l.x*pr.x
+	__asm fld  dword ptr [local+4]        ; l.y | l.x*pr.x
+	__asm fmul dword ptr [r_pup+4]        ; l.y*pr.y | l.x*pr.x
+	__asm fld  dword ptr [local+8]        ; l.z | l.y*pr.y | l.x*pr.x
+	__asm fmul dword ptr [r_pup+8]        ; l.z*pr.z | l.y*pr.y | l.x*pr.x
+	__asm fxch st(2)                      ; l.x*pr.x | l.y*pr.y | l.z*pr.z
+	__asm faddp st(1), st                 ; l.x*pr.x + l.y*pr.y | l.z*pr.z
+	__asm faddp st(1), st                 ; l.x*pr.x + l.y*pr.y + l.z*pr.z
+	__asm fstp  dword ptr [transformed+4] ; (empty)
+
+	__asm fld  dword ptr [local+0]        ; l.x
+	__asm fmul dword ptr [r_ppn+0]        ; l.x*pr.x
+	__asm fld  dword ptr [local+4]        ; l.y | l.x*pr.x
+	__asm fmul dword ptr [r_ppn+4]        ; l.y*pr.y | l.x*pr.x
+	__asm fld  dword ptr [local+8]        ; l.z | l.y*pr.y | l.x*pr.x
+	__asm fmul dword ptr [r_ppn+8]        ; l.z*pr.z | l.y*pr.y | l.x*pr.x
+	__asm fxch st(2)                      ; l.x*pr.x | l.y*pr.y | l.z*pr.z
+	__asm faddp st(1), st                 ; l.x*pr.x + l.y*pr.y | l.z*pr.z
+	__asm faddp st(1), st                 ; l.x*pr.x + l.y*pr.y + l.z*pr.z
+	__asm fstp  dword ptr [transformed+8] ; (empty)
+
+	/*
+	** make sure that the transformed particle is not in front of
+	** the particle Z clip plane.  We can do the comparison in 
+	** integer space since we know the sign of one of the inputs
+	** and can figure out the sign of the other easily enough.
+	*/
+	//	if (transformed[2] < PARTICLE_Z_CLIP)
+	//		return;
+
+	__asm mov  eax, dword ptr [transformed+8]
+	__asm and  eax, eax
+	__asm js   end
+	__asm cmp  eax, particle_z_clip
+	__asm jl   end
+
+	/*
+	** project the point by initiating the 1/z calc
+	*/
+	//	zi = 1.0 / transformed[2];
+	__asm fld   one
+	__asm fdiv  dword ptr [transformed+8]
+
+	/*
+	** bind the blend function pointer to the appropriate blender
+	** while we're dividing
+	*/
+	//if ( level == PARTICLE_33 )
+	//	blendparticle = BlendParticle33;
+	//else if ( level == PARTICLE_66 )
+	//	blendparticle = BlendParticle66;
+	//else 
+	//	blendparticle = BlendParticle100;
+
+	__asm cmp partparms.level, PARTICLE_66
+	__asm je  blendfunc_66
+	__asm jl  blendfunc_33
+	__asm lea ebx, BlendParticle100
+	__asm jmp done_selecting_blend_func
+blendfunc_33:
+	__asm lea ebx, BlendParticle33
+	__asm jmp done_selecting_blend_func
+blendfunc_66:
+	__asm lea ebx, BlendParticle66
+done_selecting_blend_func:
+	__asm mov blendfunc, ebx
+
+	// prefetch the next particle
+	__asm mov ebp, s_prefetch_address
+	__asm mov ebp, [ebp]
+
+	// finish the above divide
+	__asm fstp  zi
+
+	// u = (int)(xcenter + zi * transformed[0] + 0.5);
+	// v = (int)(ycenter - zi * transformed[1] + 0.5);
+	__asm fld   zi                           ; zi
+	__asm fmul  dword ptr [transformed+0]    ; zi * transformed[0]
+	__asm fld   zi                           ; zi | zi * transformed[0]
+	__asm fmul  dword ptr [transformed+4]    ; zi * transformed[1] | zi * transformed[0]
+	__asm fxch  st(1)                        ; zi * transformed[0] | zi * transformed[1]
+	__asm fadd  xcenter                      ; xcenter + zi * transformed[0] | zi * transformed[1]
+	__asm fxch  st(1)                        ; zi * transformed[1] | xcenter + zi * transformed[0]
+	__asm fld   ycenter                      ; ycenter | zi * transformed[1] | xcenter + zi * transformed[0]
+    __asm fsubrp st(1), st(0)                ; ycenter - zi * transformed[1] | xcenter + zi * transformed[0]
+  	__asm fxch  st(1)                        ; xcenter + zi * transformed[0] | ycenter + zi * transformed[1]
+  	__asm fadd  point_five                   ; xcenter + zi * transformed[0] + 0.5 | ycenter - zi * transformed[1]
+  	__asm fxch  st(1)                        ; ycenter - zi * transformed[1] | xcenter + zi * transformed[0] + 0.5 
+  	__asm fadd  point_five                   ; ycenter - zi * transformed[1] + 0.5 | xcenter + zi * transformed[0] + 0.5 
+  	__asm fxch  st(1)                        ; u | v
+  	__asm fistp dword ptr [u]                ; v
+  	__asm fistp dword ptr [v]                ; (empty)
+
+	/*
+	** clip out the particle
+	*/
+
+	//	if ((v > d_vrectbottom_particle) || 
+	//		(u > d_vrectright_particle) ||
+	//		(v < d_vrecty) ||
+	//		(u < d_vrectx))
+	//	{
+	//		return;
+	//	}
+
+	__asm mov ebx, u
+	__asm mov ecx, v
+	__asm cmp ecx, d_vrectbottom_particle
+	__asm jg  end
+	__asm cmp ecx, d_vrecty
+	__asm jl  end
+	__asm cmp ebx, d_vrectright_particle
+	__asm jg  end
+	__asm cmp ebx, d_vrectx
+	__asm jl  end
+
+	/*
+	** compute addresses of zbuffer, framebuffer, and 
+	** compute the Z-buffer reference value.
+	**
+	** EBX      = U
+	** ECX      = V
+	**
+	** Outputs:
+	** ESI = Z-buffer address
+	** EDI = framebuffer address
+	*/
+	// ESI = d_pzbuffer + (d_zwidth * v) + u;
+	__asm mov esi, d_pzbuffer             ; esi = d_pzbuffer
+	__asm mov eax, d_zwidth               ; eax = d_zwidth
+	__asm mul ecx                         ; eax = d_zwidth*v
+	__asm add eax, ebx                    ; eax = d_zwidth*v+u
+	__asm shl eax, 1                      ; eax = 2*(d_zwidth*v+u)
+	__asm add esi, eax                    ; esi = ( short * ) ( d_pzbuffer + ( d_zwidth * v ) + u )
+
+	// initiate
+	// izi = (int)(zi * 0x8000);
+	__asm fld  zi
+	__asm fmul eight_thousand_hex
+
+	// EDI = pdest = d_viewbuffer + d_scantable[v] + u;
+	__asm lea edi, [d_scantable+ecx*4]
+	__asm mov edi, [edi]
+	__asm add edi, d_viewbuffer
+	__asm add edi, ebx
+
+	// complete
+	// izi = (int)(zi * 0x8000);
+	__asm fistp tmp
+	__asm mov   eax, tmp
+	__asm mov   izi, ax
+
+	/*
+	** determine the screen area covered by the particle,
+	** which also means clamping to a min and max
+	*/
+	//	pix = izi >> d_pix_shift;
+	__asm xor edx, edx
+	__asm mov dx, izi
+	__asm mov ecx, d_pix_shift
+	__asm shr dx, cl
+
+	//	if (pix < d_pix_min)
+	//		pix = d_pix_min;
+	__asm cmp edx, d_pix_min
+	__asm jge check_pix_max
+	__asm mov edx, d_pix_min
+	__asm jmp skip_pix_clamp
+
+	//	else if (pix > d_pix_max)
+	//		pix = d_pix_max;
+check_pix_max:
+	__asm cmp edx, d_pix_max
+	__asm jle skip_pix_clamp
+	__asm mov edx, d_pix_max
+
+skip_pix_clamp:
+
+	/*
+	** render the appropriate pixels
+	**
+	** ECX = count (used for inner loop)
+	** EDX = count (used for outer loop)
+	** ESI = zbuffer
+	** EDI = framebuffer
+	*/
+	__asm mov ecx, edx
+
+	__asm cmp ecx, 1
+	__asm ja  over
+
+over:
+
+	/*
+	** at this point:
+	**
+	** ECX = count
+	*/
+	__asm push ecx
+	__asm push edi
+	__asm push esi
+
+top_of_pix_vert_loop:
+
+top_of_pix_horiz_loop:
+
+	//	for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
+	//	{
+	//		for (i=0 ; i<pix ; i++)
+	//		{
+	//			if (pz[i] <= izi)
+	//			{
+	//				pdest[i] = blendparticle( color, pdest[i] );
+	//			}
+	//		}
+	//	}
+	__asm xor   eax, eax
+
+	__asm mov   ax, word ptr [esi]
+
+	__asm cmp   ax, izi
+	__asm jg    end_of_horiz_loop
+
+#if ENABLE_ZWRITES_FOR_PARTICLES
+  	__asm mov   bp, izi
+  	__asm mov   word ptr [esi], bp
+#endif
+
+	__asm mov   eax, partparms.color
+
+	__asm call  [blendfunc]
+
+	__asm add   edi, 1
+	__asm add   esi, 2
+
+end_of_horiz_loop:
+
+	__asm dec   ecx
+	__asm jnz   top_of_pix_horiz_loop
+
+	__asm pop   esi
+	__asm pop   edi
+
+	__asm mov   ebp, d_zwidth
+	__asm shl   ebp, 1
+
+	__asm add   esi, ebp
+	__asm add   edi, [r_screenwidth]
+
+	__asm pop   ecx
+	__asm push  ecx
+
+	__asm push  edi
+	__asm push  esi
+
+	__asm dec   edx
+	__asm jnz   top_of_pix_vert_loop
+
+	__asm pop   ecx
+	__asm pop   ecx
+	__asm pop   ecx
+
+end:
+	__asm pop edi
+	__asm pop esi
+	__asm mov ebp, ebpsave
+	__asm ret
+}
+
+#else
+
+static byte BlendParticle33( int pcolor, int dstcolor )
+{
+	return vid.alphamap[pcolor + dstcolor*256];
+}
+
+static byte BlendParticle66( int pcolor, int dstcolor )
+{
+	return vid.alphamap[pcolor*256+dstcolor];
+}
+
+static byte BlendParticle100( int pcolor, int dstcolor )
+{
+	dstcolor = dstcolor;
+	return pcolor;
+}
+
+/*
+** R_DrawParticle
+**
+** Yes, this is amazingly slow, but it's the C reference
+** implementation and should be both robust and vaguely
+** understandable.  The only time this path should be
+** executed is if we're debugging on x86 or if we're
+** recompiling and deploying on a non-x86 platform.
+**
+** To minimize error and improve readability I went the 
+** function pointer route.  This exacts some overhead, but
+** it pays off in clean and easy to understand code.
+*/
+void R_DrawParticle( void )
+{
+	particle_t *pparticle = partparms.particle;
+	int         level     = partparms.level;
+	vec3_t	local, transformed;
+	float	zi;
+	byte	*pdest;
+	short	*pz;
+	int      color = pparticle->color;
+	int		i, izi, pix, count, u, v;
+	byte  (*blendparticle)( int, int );
+
+	/*
+	** transform the particle
+	*/
+	VectorSubtract (pparticle->origin, r_origin, local);
+
+	transformed[0] = DotProduct(local, r_pright);
+	transformed[1] = DotProduct(local, r_pup);
+	transformed[2] = DotProduct(local, r_ppn);		
+
+	if (transformed[2] < PARTICLE_Z_CLIP)
+		return;
+
+	/*
+	** bind the blend function pointer to the appropriate blender
+	*/
+	if ( level == PARTICLE_33 )
+		blendparticle = BlendParticle33;
+	else if ( level == PARTICLE_66 )
+		blendparticle = BlendParticle66;
+	else 
+		blendparticle = BlendParticle100;
+
+	/*
+	** project the point
+	*/
+	// FIXME: preadjust xcenter and ycenter
+	zi = 1.0 / transformed[2];
+	u = (int)(xcenter + zi * transformed[0] + 0.5);
+	v = (int)(ycenter - zi * transformed[1] + 0.5);
+
+	if ((v > d_vrectbottom_particle) || 
+		(u > d_vrectright_particle) ||
+		(v < d_vrecty) ||
+		(u < d_vrectx))
+	{
+		return;
+	}
+
+	/*
+	** compute addresses of zbuffer, framebuffer, and 
+	** compute the Z-buffer reference value.
+	*/
+	pz = d_pzbuffer + (d_zwidth * v) + u;
+	pdest = d_viewbuffer + d_scantable[v] + u;
+	izi = (int)(zi * 0x8000);
+
+	/*
+	** determine the screen area covered by the particle,
+	** which also means clamping to a min and max
+	*/
+	pix = izi >> d_pix_shift;
+	if (pix < d_pix_min)
+		pix = d_pix_min;
+	else if (pix > d_pix_max)
+		pix = d_pix_max;
+
+	/*
+	** render the appropriate pixels
+	*/
+	count = pix;
+
+    switch (level) {
+    case PARTICLE_33 :
+        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+        {
+//FIXME--do it in blocks of 8?
+            for (i=0 ; i<pix ; i++)
+            {
+                if (pz[i] <= izi)
+                {
+                    pz[i]    = izi;
+                    pdest[i] = vid.alphamap[color + ((int)pdest[i]<<8)];
+                }
+            }
+        }
+        break;
+
+    case PARTICLE_66 :
+        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+        {
+            for (i=0 ; i<pix ; i++)
+            {
+                if (pz[i] <= izi)
+                {
+                    pz[i]    = izi;
+                    pdest[i] = vid.alphamap[(color<<8) + (int)pdest[i]];
+                }
+            }
+        }
+        break;
+
+    default:  //100
+        for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+        {
+            for (i=0 ; i<pix ; i++)
+            {
+                if (pz[i] <= izi)
+                {
+                    pz[i]    = izi;
+                    pdest[i] = color;
+                }
+            }
+        }
+        break;
+    }
+}
+
+#endif	// !id386
+
+/*
+** R_DrawParticles
+**
+** Responsible for drawing all of the particles in the particle list
+** throughout the world.  Doesn't care if we're using the C path or
+** if we're using the asm path, it simply assigns a function pointer
+** and goes.
+*/
+void R_DrawParticles (void)
+{
+	particle_t *p;
+	int         i;
+	extern unsigned long fpu_sp24_cw, fpu_chop_cw;
+
+	VectorScale( vright, xscaleshrink, r_pright );
+	VectorScale( vup, yscaleshrink, r_pup );
+	VectorCopy( vpn, r_ppn );
+
+#if id386 && !defined __linux__
+	__asm fldcw word ptr [fpu_sp24_cw]
+#endif
+
+	for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
+	{
+
+		if ( p->alpha > 0.66 )
+			partparms.level = PARTICLE_OPAQUE;
+		else if ( p->alpha > 0.33 )
+			partparms.level = PARTICLE_66;
+		else
+			partparms.level = PARTICLE_33;
+
+		partparms.particle = p;
+		partparms.color    = p->color;
+
+#if id386 && !defined __linux__
+		if ( i < r_newrefdef.num_particles-1 )
+			s_prefetch_address = ( unsigned int ) ( p + 1 );
+		else
+			s_prefetch_address = ( unsigned int ) r_newrefdef.particles;
+#endif
+
+		R_DrawParticle();
+	}
+
+#if id386 && !defined __linux__
+	__asm fldcw word ptr [fpu_chop_cw]
+#endif
+
+}
+
--- /dev/null
+++ b/ref_soft/r_poly.c
@@ -1,0 +1,1244 @@
+/*
+Copyright (C) 1997-2001 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 <assert.h>
+#include "r_local.h"
+
+#define AFFINE_SPANLET_SIZE      16
+#define AFFINE_SPANLET_SIZE_BITS 4
+
+typedef struct
+{
+	byte     *pbase, *pdest;
+	short	 *pz;
+	fixed16_t s, t;
+	fixed16_t sstep, tstep;
+	int       izi, izistep, izistep_times_2;
+	int       spancount;
+	unsigned  u, v;
+} spanletvars_t;
+
+spanletvars_t s_spanletvars;
+
+static int r_polyblendcolor;
+
+static espan_t	*s_polygon_spans;
+
+polydesc_t	r_polydesc;
+
+msurface_t *r_alpha_surfaces;
+
+extern int *r_turb_turb;
+
+static int		clip_current;
+vec5_t	r_clip_verts[2][MAXWORKINGVERTS+2];
+
+static int		s_minindex, s_maxindex;
+
+static void R_DrawPoly( qboolean iswater );
+
+/*
+** R_DrawSpanletOpaque
+*/
+void R_DrawSpanletOpaque( void )
+{
+	unsigned btemp;
+
+	do
+	{
+		unsigned ts, tt;
+
+		ts = s_spanletvars.s >> 16;
+		tt = s_spanletvars.t >> 16;
+
+		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+		if (btemp != 255)
+		{
+			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+			{
+				*s_spanletvars.pz    = s_spanletvars.izi >> 16;
+				*s_spanletvars.pdest = btemp;
+			}
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanletTurbulentStipple33
+*/
+void R_DrawSpanletTurbulentStipple33( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+	
+	if ( s_spanletvars.v & 1 )
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		if ( s_spanletvars.u & 1 )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep   *= 2;
+		s_spanletvars.tstep   *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+			
+			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+			
+			if ( *pz <= ( izi >> 16 ) )
+				*pdest = btemp;
+			
+			izi               += s_spanletvars.izistep_times_2;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+}
+
+/*
+** R_DrawSpanletTurbulentStipple66
+*/
+void R_DrawSpanletTurbulentStipple66( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+	
+	if ( !( s_spanletvars.v & 1 ) )
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		if ( s_spanletvars.u & 1 )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep   *= 2;
+		s_spanletvars.tstep   *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+			
+			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+			
+			if ( *pz <= ( izi >> 16 ) )
+				*pdest = btemp;
+			
+			izi               += s_spanletvars.izistep_times_2;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+	else
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		while ( s_spanletvars.spancount > 0 )
+		{
+			sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+			tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+			
+			btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+			
+			if ( *pz <= ( izi >> 16 ) )
+				*pdest = btemp;
+			
+			izi               += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest++;
+			pz++;
+			
+			s_spanletvars.spancount--;
+		}
+	}
+}
+
+/*
+** R_DrawSpanletTurbulentBlended
+*/
+void R_DrawSpanletTurbulentBlended66( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+
+	do
+	{
+		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
+			*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+
+	} while ( --s_spanletvars.spancount > 0 );
+}
+
+void R_DrawSpanletTurbulentBlended33( void )
+{
+	unsigned btemp;
+	int	     sturb, tturb;
+
+	do
+	{
+		sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+		tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+		btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+		if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
+			*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+
+	} while ( --s_spanletvars.spancount > 0 );
+}
+
+/*
+** R_DrawSpanlet33
+*/
+void R_DrawSpanlet33( void )
+{
+	unsigned btemp;
+
+	do
+	{
+		unsigned ts, tt;
+
+		ts = s_spanletvars.s >> 16;
+		tt = s_spanletvars.t >> 16;
+
+		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+
+		if ( btemp != 255 )
+		{
+			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+			{
+				*s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
+			}
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+void R_DrawSpanletConstant33( void )
+{
+	do
+	{
+		if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+		{
+			*s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256];
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanlet66
+*/
+void R_DrawSpanlet66( void )
+{
+	unsigned btemp;
+
+	do
+	{
+		unsigned ts, tt;
+
+		ts = s_spanletvars.s >> 16;
+		tt = s_spanletvars.t >> 16;
+
+		btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+
+		if ( btemp != 255 )
+		{
+			if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+			{
+				*s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
+			}
+		}
+
+		s_spanletvars.izi += s_spanletvars.izistep;
+		s_spanletvars.pdest++;
+		s_spanletvars.pz++;
+		s_spanletvars.s += s_spanletvars.sstep;
+		s_spanletvars.t += s_spanletvars.tstep;
+	} while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanlet33Stipple
+*/
+void R_DrawSpanlet33Stipple( void )
+{
+	unsigned btemp;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+	
+	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
+	{
+		s_spanletvars.pdest += s_spanletvars.spancount;
+		s_spanletvars.pz    += s_spanletvars.spancount;
+
+		if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+			s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+		else
+			s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+		
+		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep *= 2;
+		s_spanletvars.tstep *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			unsigned s = s_spanletvars.s >> 16;
+			unsigned t = s_spanletvars.t >> 16;
+
+			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+			
+			if ( btemp != 255 )
+			{
+				if ( *pz <= ( izi >> 16 ) )
+					*pdest = btemp;
+			}
+			
+			izi               += s_spanletvars.izistep_times_2;
+			s_spanletvars.s   += s_spanletvars.sstep;
+			s_spanletvars.t   += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+}
+
+/*
+** R_DrawSpanlet66Stipple
+*/
+void R_DrawSpanlet66Stipple( void )
+{
+	unsigned btemp;
+	byte    *pdest = s_spanletvars.pdest;
+	short   *pz    = s_spanletvars.pz;
+	int      izi   = s_spanletvars.izi;
+
+	s_spanletvars.pdest += s_spanletvars.spancount;
+	s_spanletvars.pz    += s_spanletvars.spancount;
+
+	if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+		s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+	else
+		s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+	if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
+	{
+		if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
+		{
+			izi += s_spanletvars.izistep;
+			s_spanletvars.s += s_spanletvars.sstep;
+			s_spanletvars.t += s_spanletvars.tstep;
+
+			pdest++;
+			pz++;
+			s_spanletvars.spancount--;
+		}
+
+		s_spanletvars.sstep *= 2;
+		s_spanletvars.tstep *= 2;
+
+		while ( s_spanletvars.spancount > 0 )
+		{
+			unsigned s = s_spanletvars.s >> 16;
+			unsigned t = s_spanletvars.t >> 16;
+			
+			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+
+			if ( btemp != 255 )
+			{
+				if ( *pz <= ( izi >> 16 ) )
+					*pdest = btemp;
+			}
+			
+			izi             += s_spanletvars.izistep_times_2;
+			s_spanletvars.s += s_spanletvars.sstep;
+			s_spanletvars.t += s_spanletvars.tstep;
+			
+			pdest += 2;
+			pz    += 2;
+			
+			s_spanletvars.spancount -= 2;
+		}
+	}
+	else
+	{
+		while ( s_spanletvars.spancount > 0 )
+		{
+			unsigned s = s_spanletvars.s >> 16;
+			unsigned t = s_spanletvars.t >> 16;
+			
+			btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+			
+			if ( btemp != 255 )
+			{
+				if ( *pz <= ( izi >> 16 ) )
+					*pdest = btemp;
+			}
+			
+			izi             += s_spanletvars.izistep;
+			s_spanletvars.s += s_spanletvars.sstep;
+			s_spanletvars.t += s_spanletvars.tstep;
+			
+			pdest++;
+			pz++;
+			
+			s_spanletvars.spancount--;
+		}
+	}
+}
+
+/*
+** R_ClipPolyFace
+**
+** Clips the winding at clip_verts[clip_current] and changes clip_current
+** Throws out the back side
+*/
+int R_ClipPolyFace (int nump, clipplane_t *pclipplane)
+{
+	int		i, outcount;
+	float	dists[MAXWORKINGVERTS+3];
+	float	frac, clipdist, *pclipnormal;
+	float	*in, *instep, *outstep, *vert2;
+
+	clipdist = pclipplane->dist;
+	pclipnormal = pclipplane->normal;
+	
+// calc dists
+	if (clip_current)
+	{
+		in = r_clip_verts[1][0];
+		outstep = r_clip_verts[0][0];
+		clip_current = 0;
+	}
+	else
+	{
+		in = r_clip_verts[0][0];
+		outstep = r_clip_verts[1][0];
+		clip_current = 1;
+	}
+	
+	instep = in;
+	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
+	{
+		dists[i] = DotProduct (instep, pclipnormal) - clipdist;
+	}
+	
+// handle wraparound case
+	dists[nump] = dists[0];
+	memcpy (instep, in, sizeof (vec5_t));
+
+
+// clip the winding
+	instep = in;
+	outcount = 0;
+
+	for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
+	{
+		if (dists[i] >= 0)
+		{
+			memcpy (outstep, instep, sizeof (vec5_t));
+			outstep += sizeof (vec5_t) / sizeof (float);
+			outcount++;
+		}
+
+		if (dists[i] == 0 || dists[i+1] == 0)
+			continue;
+
+		if ( (dists[i] > 0) == (dists[i+1] > 0) )
+			continue;
+			
+	// split it into a new vertex
+		frac = dists[i] / (dists[i] - dists[i+1]);
+			
+		vert2 = instep + sizeof (vec5_t) / sizeof (float);
+		
+		outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
+		outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
+		outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
+		outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
+		outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
+
+		outstep += sizeof (vec5_t) / sizeof (float);
+		outcount++;
+	}	
+	
+	return outcount;
+}
+
+/*
+** R_PolygonDrawSpans
+*/
+void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater )
+{
+	int			count;
+	fixed16_t	snext, tnext;
+	float		sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float		sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
+
+	s_spanletvars.pbase = cacheblock;
+
+	if ( iswater )
+		r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+
+	sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
+	tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
+	zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
+
+// we count on FP exceptions being turned off to avoid range problems
+	s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+	s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
+
+	s_spanletvars.pz = 0;
+
+	do
+	{
+		s_spanletvars.pdest   = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
+		s_spanletvars.pz      = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+		s_spanletvars.u       = pspan->u;
+		s_spanletvars.v       = pspan->v;
+
+		count = pspan->count;
+
+		if (count <= 0)
+			goto NextSpan;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+	// we count on FP exceptions being turned off to avoid range problems
+		s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
+
+		s_spanletvars.s = (int)(sdivz * z) + sadjust;
+		s_spanletvars.t = (int)(tdivz * z) + tadjust;
+
+		if ( !iswater )
+		{
+			if (s_spanletvars.s > bbextents)
+				s_spanletvars.s = bbextents;
+			else if (s_spanletvars.s < 0)
+				s_spanletvars.s = 0;
+
+			if (s_spanletvars.t > bbextentt)
+				s_spanletvars.t = bbextentt;
+			else if (s_spanletvars.t < 0)
+				s_spanletvars.t = 0;
+		}
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= AFFINE_SPANLET_SIZE )
+				s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
+			else
+				s_spanletvars.spancount = count;
+
+			count -= s_spanletvars.spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivzspanletstepu;
+				tdivz += tdivzspanletstepu;
+				zi += zispanletstepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				tnext = (int)(tdivz * z) + tadjust;
+
+				if ( !iswater )
+				{
+					if (snext > bbextents)
+						snext = bbextents;
+					else if (snext < AFFINE_SPANLET_SIZE)
+						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
+									//  from causing overstepping & running off the
+									//  edge of the texture
+
+					if (tnext > bbextentt)
+						tnext = bbextentt;
+					else if (tnext < AFFINE_SPANLET_SIZE)
+						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
+				}
+
+				s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
+				s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(s_spanletvars.spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				tnext = (int)(tdivz * z) + tadjust;
+
+				if ( !iswater )
+				{
+					if (snext > bbextents)
+						snext = bbextents;
+					else if (snext < AFFINE_SPANLET_SIZE)
+						snext = AFFINE_SPANLET_SIZE;	// prevent round-off error on <0 steps from
+									//  from causing overstepping & running off the
+									//  edge of the texture
+
+					if (tnext > bbextentt)
+						tnext = bbextentt;
+					else if (tnext < AFFINE_SPANLET_SIZE)
+						tnext = AFFINE_SPANLET_SIZE;	// guard against round-off error on <0 steps
+				}
+
+				if (s_spanletvars.spancount > 1)
+				{
+					s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
+					s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
+				}
+			}
+
+			if ( iswater )
+			{
+				s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
+				s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
+			}
+
+			r_polydesc.drawspanlet();
+
+			s_spanletvars.s = snext;
+			s_spanletvars.t = tnext;
+
+		} while (count > 0);
+
+NextSpan:
+		pspan++;
+
+	} while (pspan->count != DS_SPAN_LIST_END);
+}
+
+/*
+**
+** R_PolygonScanLeftEdge
+**
+** Goes through the polygon and scans the left edge, filling in 
+** screen coordinate data for the spans
+*/
+void R_PolygonScanLeftEdge (void)
+{
+	int			i, v, itop, ibottom, lmaxindex;
+	emitpoint_t	*pvert, *pnext;
+	espan_t		*pspan;
+	float		du, dv, vtop, vbottom, slope;
+	fixed16_t	u, u_step;
+
+	pspan = s_polygon_spans;
+	i = s_minindex;
+	if (i == 0)
+		i = r_polydesc.nump;
+
+	lmaxindex = s_maxindex;
+	if (lmaxindex == 0)
+		lmaxindex = r_polydesc.nump;
+
+	vtop = ceil (r_polydesc.pverts[i].v);
+
+	do
+	{
+		pvert = &r_polydesc.pverts[i];
+		pnext = pvert - 1;
+
+		vbottom = ceil (pnext->v);
+
+		if (vtop < vbottom)
+		{
+			du = pnext->u - pvert->u;
+			dv = pnext->v - pvert->v;
+
+			slope = du / dv;
+			u_step = (int)(slope * 0x10000);
+		// adjust u to ceil the integer portion
+			u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
+					(0x10000 - 1);
+			itop = (int)vtop;
+			ibottom = (int)vbottom;
+
+			for (v=itop ; v<ibottom ; v++)
+			{
+				pspan->u = u >> 16;
+				pspan->v = v;
+				u += u_step;
+				pspan++;
+			}
+		}
+
+		vtop = vbottom;
+
+		i--;
+		if (i == 0)
+			i = r_polydesc.nump;
+
+	} while (i != lmaxindex);
+}
+
+/*
+** R_PolygonScanRightEdge
+**
+** Goes through the polygon and scans the right edge, filling in
+** count values.
+*/
+void R_PolygonScanRightEdge (void)
+{
+	int			i, v, itop, ibottom;
+	emitpoint_t	*pvert, *pnext;
+	espan_t		*pspan;
+	float		du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
+	fixed16_t	u, u_step;
+
+	pspan = s_polygon_spans;
+	i = s_minindex;
+
+	vvert = r_polydesc.pverts[i].v;
+	if (vvert < r_refdef.fvrecty_adj)
+		vvert = r_refdef.fvrecty_adj;
+	if (vvert > r_refdef.fvrectbottom_adj)
+		vvert = r_refdef.fvrectbottom_adj;
+
+	vtop = ceil (vvert);
+
+	do
+	{
+		pvert = &r_polydesc.pverts[i];
+		pnext = pvert + 1;
+
+		vnext = pnext->v;
+		if (vnext < r_refdef.fvrecty_adj)
+			vnext = r_refdef.fvrecty_adj;
+		if (vnext > r_refdef.fvrectbottom_adj)
+			vnext = r_refdef.fvrectbottom_adj;
+
+		vbottom = ceil (vnext);
+
+		if (vtop < vbottom)
+		{
+			uvert = pvert->u;
+			if (uvert < r_refdef.fvrectx_adj)
+				uvert = r_refdef.fvrectx_adj;
+			if (uvert > r_refdef.fvrectright_adj)
+				uvert = r_refdef.fvrectright_adj;
+
+			unext = pnext->u;
+			if (unext < r_refdef.fvrectx_adj)
+				unext = r_refdef.fvrectx_adj;
+			if (unext > r_refdef.fvrectright_adj)
+				unext = r_refdef.fvrectright_adj;
+
+			du = unext - uvert;
+			dv = vnext - vvert;
+			slope = du / dv;
+			u_step = (int)(slope * 0x10000);
+		// adjust u to ceil the integer portion
+			u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
+					(0x10000 - 1);
+			itop = (int)vtop;
+			ibottom = (int)vbottom;
+
+			for (v=itop ; v<ibottom ; v++)
+			{
+				pspan->count = (u >> 16) - pspan->u;
+				u += u_step;
+				pspan++;
+			}
+		}
+
+		vtop = vbottom;
+		vvert = vnext;
+
+		i++;
+		if (i == r_polydesc.nump)
+			i = 0;
+
+	} while (i != s_maxindex);
+
+	pspan->count = DS_SPAN_LIST_END;	// mark the end of the span list 
+}
+
+/*
+** R_ClipAndDrawPoly
+*/
+void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured )
+{
+	emitpoint_t	outverts[MAXWORKINGVERTS+3], *pout;
+	float		*pv;
+	int			i, nump;
+	float		scale;
+	vec3_t		transformed, local;
+
+	if ( !textured )
+	{
+		r_polydesc.drawspanlet = R_DrawSpanletConstant33;
+	}
+	else
+	{
+
+		/*
+		** choose the correct spanlet routine based on alpha
+		*/
+		if ( alpha == 1 )
+		{
+			// isturbulent is ignored because we know that turbulent surfaces
+			// can't be opaque
+			r_polydesc.drawspanlet = R_DrawSpanletOpaque;
+		}
+		else
+		{
+			if ( sw_stipplealpha->value )
+			{
+				if ( isturbulent )
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
+					else 
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
+				}
+				else
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
+					else 
+						r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
+				}
+			}
+			else
+			{
+				if ( isturbulent )
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
+					else
+						r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
+				}
+				else
+				{
+					if ( alpha > 0.33 )
+						r_polydesc.drawspanlet = R_DrawSpanlet66;
+					else 
+						r_polydesc.drawspanlet = R_DrawSpanlet33;
+				}
+			}
+		}
+	}
+
+	// clip to the frustum in worldspace
+	nump = r_polydesc.nump;
+	clip_current = 0;
+
+	for (i=0 ; i<4 ; i++)
+	{
+		nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
+		if (nump < 3)
+			return;
+		if (nump > MAXWORKINGVERTS)
+			ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
+	}
+
+// transform vertices into viewspace and project
+	pv = &r_clip_verts[clip_current][0][0];
+
+	for (i=0 ; i<nump ; i++)
+	{
+		VectorSubtract (pv, r_origin, local);
+		TransformVector (local, transformed);
+
+		if (transformed[2] < NEAR_CLIP)
+			transformed[2] = NEAR_CLIP;
+
+		pout = &outverts[i];
+		pout->zi = 1.0 / transformed[2];
+
+		pout->s = pv[3];
+		pout->t = pv[4];
+		
+		scale = xscale * pout->zi;
+		pout->u = (xcenter + scale * transformed[0]);
+
+		scale = yscale * pout->zi;
+		pout->v = (ycenter - scale * transformed[1]);
+
+		pv += sizeof (vec5_t) / sizeof (pv);
+	}
+
+// draw it
+	r_polydesc.nump = nump;
+	r_polydesc.pverts = outverts;
+
+	R_DrawPoly( isturbulent );
+}
+
+/*
+** R_BuildPolygonFromSurface
+*/
+void R_BuildPolygonFromSurface(msurface_t *fa)
+{
+	int			i, lindex, lnumverts;
+	medge_t		*pedges, *r_pedge;
+	int			vertpage;
+	float		*vec;
+	vec5_t     *pverts;
+	float       tmins[2] = { 0, 0 };
+
+	r_polydesc.nump = 0;
+
+	// reconstruct the polygon
+	pedges = currentmodel->edges;
+	lnumverts = fa->numedges;
+	vertpage = 0;
+
+	pverts = r_clip_verts[0];
+
+	for (i=0 ; i<lnumverts ; i++)
+	{
+		lindex = currentmodel->surfedges[fa->firstedge + i];
+
+		if (lindex > 0)
+		{
+			r_pedge = &pedges[lindex];
+			vec = currentmodel->vertexes[r_pedge->v[0]].position;
+		}
+		else
+		{
+			r_pedge = &pedges[-lindex];
+			vec = currentmodel->vertexes[r_pedge->v[1]].position;
+		}
+
+		VectorCopy (vec, pverts[i] );
+	}
+
+	VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
+	VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
+	VectorCopy( fa->plane->normal, r_polydesc.vpn );
+	VectorCopy( r_origin, r_polydesc.viewer_position );
+
+	if ( fa->flags & SURF_PLANEBACK )
+	{
+		VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
+	}
+
+	if ( fa->texinfo->flags & SURF_WARP )
+	{
+		r_polydesc.pixels       = fa->texinfo->image->pixels[0];
+		r_polydesc.pixel_width  = fa->texinfo->image->width;
+		r_polydesc.pixel_height = fa->texinfo->image->height;
+	}
+	else
+	{
+		surfcache_t *scache;
+
+		scache = D_CacheSurface( fa, 0 );
+
+		r_polydesc.pixels       = scache->data;
+		r_polydesc.pixel_width  = scache->width;
+		r_polydesc.pixel_height = scache->height;
+
+		tmins[0] = fa->texturemins[0];
+		tmins[1] = fa->texturemins[1];
+	}
+
+	r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
+
+	r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
+	r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
+
+	// scrolling texture addition
+	if (fa->texinfo->flags & SURF_FLOWING)
+	{
+		r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
+	}
+
+	r_polydesc.nump = lnumverts;
+}
+
+/*
+** R_PolygonCalculateGradients
+*/
+void R_PolygonCalculateGradients (void)
+{
+	vec3_t		p_normal, p_saxis, p_taxis;
+	float		distinv;
+
+	TransformVector (r_polydesc.vpn, p_normal);
+	TransformVector (r_polydesc.vright, p_saxis);
+	TransformVector (r_polydesc.vup, p_taxis);
+
+	distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
+
+	d_sdivzstepu  =  p_saxis[0] * xscaleinv;
+	d_sdivzstepv  = -p_saxis[1] * yscaleinv;
+	d_sdivzorigin =  p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
+
+	d_tdivzstepu  =  p_taxis[0] * xscaleinv;
+	d_tdivzstepv  = -p_taxis[1] * yscaleinv;
+	d_tdivzorigin =  p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
+
+	d_zistepu =   p_normal[0] * xscaleinv * distinv;
+	d_zistepv =  -p_normal[1] * yscaleinv * distinv;
+	d_ziorigin =  p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
+
+	sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
+	tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup   ) + r_polydesc.t_offset ) * 0x10000 );
+
+// -1 (-epsilon) so we never wander off the edge of the texture
+	bbextents = (r_polydesc.pixel_width << 16) - 1;
+	bbextentt = (r_polydesc.pixel_height << 16) - 1;
+}
+
+/*
+** R_DrawPoly
+**
+** Polygon drawing function.  Uses the polygon described in r_polydesc
+** to calculate edges and gradients, then renders the resultant spans.
+**
+** This should NOT be called externally since it doesn't do clipping!
+*/
+static void R_DrawPoly( qboolean iswater )
+{
+	int			i, nump;
+	float		ymin, ymax;
+	emitpoint_t	*pverts;
+	espan_t	spans[MAXHEIGHT+1];
+
+	s_polygon_spans = spans;
+
+// find the top and bottom vertices, and make sure there's at least one scan to
+// draw
+	ymin = 999999.9;
+	ymax = -999999.9;
+	pverts = r_polydesc.pverts;
+
+	for (i=0 ; i<r_polydesc.nump ; i++)
+	{
+		if (pverts->v < ymin)
+		{
+			ymin = pverts->v;
+			s_minindex = i;
+		}
+
+		if (pverts->v > ymax)
+		{
+			ymax = pverts->v;
+			s_maxindex = i;
+		}
+
+		pverts++;
+	}
+
+	ymin = ceil (ymin);
+	ymax = ceil (ymax);
+
+	if (ymin >= ymax)
+		return;		// doesn't cross any scans at all
+
+	cachewidth = r_polydesc.pixel_width;
+	cacheblock = r_polydesc.pixels;
+
+// copy the first vertex to the last vertex, so we don't have to deal with
+// wrapping
+	nump = r_polydesc.nump;
+	pverts = r_polydesc.pverts;
+	pverts[nump] = pverts[0];
+
+	R_PolygonCalculateGradients ();
+	R_PolygonScanLeftEdge ();
+	R_PolygonScanRightEdge ();
+
+	R_PolygonDrawSpans( s_polygon_spans, iswater );
+}
+
+/*
+** R_DrawAlphaSurfaces
+*/
+void R_DrawAlphaSurfaces( void )
+{
+	msurface_t *s = r_alpha_surfaces;
+
+	currentmodel = r_worldmodel;
+
+	modelorg[0] = -r_origin[0];
+	modelorg[1] = -r_origin[1];
+	modelorg[2] = -r_origin[2];
+
+	while ( s )
+	{
+		R_BuildPolygonFromSurface( s );
+
+		if (s->texinfo->flags & SURF_TRANS66)
+			R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
+		else
+			R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
+
+		s = s->nextalphasurface;
+	}
+	
+	r_alpha_surfaces = NULL;
+}
+
+/*
+** R_IMFlatShadedQuad
+*/
+void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
+{
+	vec3_t s0, s1;
+
+	r_polydesc.nump = 4;
+	VectorCopy( r_origin, r_polydesc.viewer_position );
+
+	VectorCopy( a, r_clip_verts[0][0] );
+	VectorCopy( b, r_clip_verts[0][1] );
+	VectorCopy( c, r_clip_verts[0][2] );
+	VectorCopy( d, r_clip_verts[0][3] );
+
+	r_clip_verts[0][0][3] = 0;
+	r_clip_verts[0][1][3] = 0;
+	r_clip_verts[0][2][3] = 0;
+	r_clip_verts[0][3][3] = 0;
+
+	r_clip_verts[0][0][4] = 0;
+	r_clip_verts[0][1][4] = 0;
+	r_clip_verts[0][2][4] = 0;
+	r_clip_verts[0][3][4] = 0;
+
+	VectorSubtract( d, c, s0 );
+	VectorSubtract( c, b, s1 );
+	CrossProduct( s0, s1, r_polydesc.vpn );
+	VectorNormalize( r_polydesc.vpn );
+
+	r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
+
+	r_polyblendcolor = color;
+
+	R_ClipAndDrawPoly( alpha, false, false );
+}
+
--- /dev/null
+++ b/ref_soft/r_polysa.asm
@@ -1,0 +1,812 @@
+ .386P
+ .model FLAT
+;
+; d_polysa.s
+; x86 assembly-language polygon model drawing code
+;
+
+include qasm.inc
+include d_if.inc
+
+if	id386
+
+; !!! if this is changed, it must be changed in d_polyse.c too !!!
+;DPS_MAXSPANS			equ		(MAXHEIGHT+1)
+; 1 extra for spanpackage that marks end
+
+;SPAN_SIZE	equ		(((DPS_MAXSPANS + 1 + ((CACHE_SIZE - 1) / spanpackage_t_size)) + 1) * spanpackage_t_size)
+
+MASK_1K	equ		03FFh
+
+_DATA SEGMENT	
+
+ align 4	
+;p10_minus_p20 dd 0
+;p01_minus_p21 dd 0
+;temp0 dd 0
+;temp1 dd 0
+;Ltemp dd 0
+
+aff8entryvec_table dd LDraw8, LDraw7, LDraw6, LDraw5
+ dd LDraw4, LDraw3, LDraw2, LDraw1, LDraw8IR, LDraw7IR, LDraw6IR, LDraw5IR, LDraw4IR, LDraw3IR, LDraw2IR, LDraw1IR
+
+lzistepx dd 0	
+
+ externdef _rand1k:dword	
+ externdef _rand1k_index:dword	
+ externdef _alias_colormap:dword
+
+;PGM
+ externdef _irtable:dword
+ externdef _iractive:byte
+;PGM
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+
+;----------------------------------------------------------------------
+; 8-bpp horizontal span drawing code for affine polygons, with smooth
+; shading and no transparency
+;----------------------------------------------------------------------
+
+;===================================
+;===================================
+
+pspans	equ		4+8
+
+ public _D_PolysetAff8Start	
+_D_PolysetAff8Start:	
+
+ public _R_PolysetDrawSpans8_Opaque 
+_R_PolysetDrawSpans8_Opaque:
+
+ push esi	; preserve register variables
+ push ebx	
+
+ mov esi,ds:dword ptr[pspans+esp]	; point to the first span descriptor
+ mov ecx,ds:dword ptr[_r_zistepx]	
+
+ push ebp	; preserve caller's stack frame
+ push edi	
+
+ ror ecx,16	; put high 16 bits of 1/z step in low word
+ mov edx,ds:dword ptr[spanpackage_t_count+esi]	
+
+ mov ds:dword ptr[lzistepx],ecx	
+
+LSpanLoop:	
+
+;		lcount = d_aspancount - pspanpackage->count;
+;
+;		errorterm += erroradjustup;
+;		if (errorterm >= 0)
+;		{
+;			d_aspancount += d_countextrastep;
+;			errorterm -= erroradjustdown;
+;		}
+;		else
+;		{
+;			d_aspancount += ubasestep;
+;		}
+
+ mov eax,ds:dword ptr[_d_aspancount]
+ sub eax,edx
+
+ mov edx,ds:dword ptr[_erroradjustup]	
+ mov ebx,ds:dword ptr[_errorterm]	
+ add ebx,edx	
+ js LNoTurnover	
+
+ mov edx,ds:dword ptr[_erroradjustdown]	
+ mov edi,ds:dword ptr[_d_countextrastep]	
+ sub ebx,edx	
+ mov ebp,ds:dword ptr[_d_aspancount]	
+ mov ds:dword ptr[_errorterm],ebx	
+ add ebp,edi	
+ mov ds:dword ptr[_d_aspancount],ebp	
+ jmp LRightEdgeStepped	
+
+LNoTurnover:	
+ mov edi,ds:dword ptr[_d_aspancount]	
+ mov edx,ds:dword ptr[_ubasestep]	
+ mov ds:dword ptr[_errorterm],ebx	
+ add edi,edx	
+ mov ds:dword ptr[_d_aspancount],edi	
+
+LRightEdgeStepped:	
+ cmp eax,1	
+
+ jl LNextSpan	
+ jz LExactlyOneLong	
+
+;
+; set up advancetable
+;
+ mov ecx,ds:dword ptr[_a_ststepxwhole]	
+ mov edx,ds:dword ptr[_r_affinetridesc+atd_skinwidth]	
+
+ mov ds:dword ptr[advancetable+4],ecx	; advance base in t
+ add ecx,edx	
+
+ mov ds:dword ptr[advancetable],ecx	; advance extra in t
+ mov ecx,ds:dword ptr[_a_tstepxfrac]	
+
+ mov cx,ds:word ptr[_r_lstepx]	
+ mov edx,eax	; count
+
+ mov ds:dword ptr[tstep],ecx
+ add edx,7	
+
+ shr edx,3	; count of full and partial loops
+ mov ebx,ds:dword ptr[spanpackage_t_sfrac+esi]	
+
+ mov bx,dx	
+ mov ecx,ds:dword ptr[spanpackage_t_pz+esi]	
+
+ neg eax	
+
+ mov edi,ds:dword ptr[spanpackage_t_pdest+esi]	
+ and eax,7	; 0->0, 1->7, 2->6, ... , 7->1
+
+ sub edi,eax	; compensate for hardwired offsets
+ sub ecx,eax	
+
+ sub ecx,eax	
+ mov edx,ds:dword ptr[spanpackage_t_tfrac+esi]	
+
+ mov dx,ds:word ptr[spanpackage_t_light+esi]	
+ mov ebp,ds:dword ptr[spanpackage_t_zi+esi]	
+
+ ror ebp,16	; put high 16 bits of 1/z in low word
+ push esi	
+
+ push eax
+ mov al, [_iractive]
+ cmp al, 0
+ pop eax
+ jne IRInsert
+ 
+ mov esi,ds:dword ptr[spanpackage_t_ptex+esi]	
+ jmp dword ptr[aff8entryvec_table+eax*4]	
+
+IRInsert:
+ mov esi,ds:dword ptr[spanpackage_t_ptex+esi]
+ add eax, 8
+ jmp dword ptr[aff8entryvec_table+eax*4]	
+
+; %bx = count of full and partial loops
+; %ebx high word = sfrac
+; %ecx = pz
+; %dx = light
+; %edx high word = tfrac
+; %esi = ptex
+; %edi = pdest
+; %ebp = 1/z
+; tstep low word = C(r_lstepx)
+; tstep high word = C(a_tstepxfrac)
+; C(a_sstepxfrac) low word = 0
+; C(a_sstepxfrac) high word = C(a_sstepxfrac)
+
+;===
+;Standard Draw Loop
+;===
+LDrawLoop:	
+
+ mov al,[_iractive]
+ cmp al,0
+ jne LDrawLoopIR
+
+; FIXME: do we need to clamp light? We may need at least a buffer bit to
+; keep it from poking into tfrac and causing problems
+
+LDraw8:	
+ cmp bp,ds:word ptr[ecx]	
+ jl Lp1	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch8:	
+ mov ds:byte ptr[edi],al	
+Lp1:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw7:	
+ cmp bp,ds:word ptr[2+ecx]	
+ jl Lp2	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[2+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch7:	
+ mov ds:byte ptr[1+edi],al	
+Lp2:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw6:	
+ cmp bp,ds:word ptr[4+ecx]	
+ jl Lp3	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[4+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch6:	
+ mov ds:byte ptr[2+edi],al	
+Lp3:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw5:	
+ cmp bp,ds:word ptr[6+ecx]	
+ jl Lp4	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[6+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch5:	
+ mov ds:byte ptr[3+edi],al	
+Lp4:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw4:	
+ cmp bp,ds:word ptr[8+ecx]	
+ jl Lp5	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[8+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch4:	
+ mov ds:byte ptr[4+edi],al	
+Lp5:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw3:	
+ cmp bp,ds:word ptr[10+ecx]	
+ jl Lp6	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[10+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch3:	
+ mov ds:byte ptr[5+edi],al	
+Lp6:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw2:	
+ cmp bp,ds:word ptr[12+ecx]	
+ jl Lp7	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[12+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch2:	
+ mov ds:byte ptr[6+edi],al	
+Lp7:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw1:	
+ cmp bp,ds:word ptr[14+ecx]	
+ jl Lp8	
+ xor eax,eax	
+ mov ah,dh	
+ mov al,ds:byte ptr[esi]	
+ mov ds:word ptr[14+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch1:	
+ mov ds:byte ptr[7+edi],al	
+Lp8:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ add edi,8	
+ add ecx,16	
+
+ dec bx	
+ jnz LDrawLoop	
+
+ pop esi	; restore spans pointer
+LNextSpan:	
+ add esi,offset spanpackage_t_size	; point to next span
+LNextSpanESISet:	
+ mov edx,ds:dword ptr[spanpackage_t_count+esi]	
+ cmp edx,offset -999999	; any more spans?
+ jnz LSpanLoop	; yes
+
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ pop ebx	; restore register variables
+ pop esi	
+ ret	
+
+;=======
+; IR active draw loop
+;=======
+LDrawLoopIR:	
+
+; FIXME: do we need to clamp light? We may need at least a buffer bit to
+; keep it from poking into tfrac and causing problems
+
+LDraw8IR:	
+ cmp bp,ds:word ptr[ecx]	
+ jl Lp1IR
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch8IR:	
+ mov ds:byte ptr[edi],al	
+Lp1IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw7IR:	
+ cmp bp,ds:word ptr[2+ecx]	
+ jl Lp2IR	
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[2+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch7IR:	
+ mov ds:byte ptr[1+edi],al	
+Lp2IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw6IR:	
+ cmp bp,ds:word ptr[4+ecx]	
+ jl Lp3IR	
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[4+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch6IR:	
+ mov ds:byte ptr[2+edi],al	
+Lp3IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw5IR:	
+ cmp bp,ds:word ptr[6+ecx]	
+ jl Lp4IR
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[6+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch5IR:	
+ mov ds:byte ptr[3+edi],al	
+Lp4IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw4IR:	
+ cmp bp,ds:word ptr[8+ecx]	
+ jl Lp5IR
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[8+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch4IR:	
+ mov ds:byte ptr[4+edi],al	
+Lp5IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw3IR:	
+ cmp bp,ds:word ptr[10+ecx]	
+ jl Lp6IR	
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[10+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch3IR:	
+ mov ds:byte ptr[5+edi],al	
+Lp6IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw2IR:	
+ cmp bp,ds:word ptr[12+ecx]	
+ jl Lp7IR
+ xor eax,eax	
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[12+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch2IR:	
+ mov ds:byte ptr[6+edi],al	
+Lp7IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LDraw1IR:	
+ cmp bp,ds:word ptr[14+ecx]	
+ jl Lp8IR
+ xor eax,eax
+ mov al,ds:byte ptr[esi]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[14+ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch1IR:	
+ mov ds:byte ptr[7+edi],al	
+Lp8IR:	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebp,ds:dword ptr[lzistepx]	
+ adc ebp,0	
+ add ebx,ds:dword ptr[_a_sstepxfrac]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ add edi,8	
+ add ecx,16	
+
+ dec bx	
+ jnz LDrawLoopIR	
+
+ pop esi	; restore spans pointer
+LNextSpanIR:	
+ add esi,offset spanpackage_t_size	; point to next span
+LNextSpanESISetIR:	
+ mov edx,ds:dword ptr[spanpackage_t_count+esi]	
+ cmp edx,offset -999999	; any more spans?
+ jnz LSpanLoop	; yes
+
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ pop ebx	; restore register variables
+ pop esi	
+ ret	
+
+;=======
+; Standard One-Long Draw
+;=======
+; draw a one-long span
+
+LExactlyOneLong:	
+ mov al,[_iractive]
+ cmp al,0
+ jne LExactlyOneLongIR
+
+ mov ecx,ds:dword ptr[spanpackage_t_pz+esi]	
+ mov ebp,ds:dword ptr[spanpackage_t_zi+esi]	
+
+ ror ebp,16	; put high 16 bits of 1/z in low word
+ mov ebx,ds:dword ptr[spanpackage_t_ptex+esi]	
+
+ cmp bp,ds:word ptr[ecx]	
+ jl LNextSpan	
+ xor eax,eax	
+ mov edi,ds:dword ptr[spanpackage_t_pdest+esi]	
+ mov ah,ds:byte ptr[spanpackage_t_light+1+esi]	
+ add esi,offset spanpackage_t_size	; point to next span
+ mov al,ds:byte ptr[ebx]	
+ mov ds:word ptr[ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch9:	
+ mov ds:byte ptr[edi],al	
+
+ jmp LNextSpanESISet	
+
+
+;========
+;========
+; draw a one-long span
+
+LExactlyOneLongIR:	
+
+ mov ecx,ds:dword ptr[spanpackage_t_pz+esi]	
+ mov ebp,ds:dword ptr[spanpackage_t_zi+esi]	
+
+ ror ebp,16	; put high 16 bits of 1/z in low word
+ mov ebx,ds:dword ptr[spanpackage_t_ptex+esi]	
+
+ cmp bp,ds:word ptr[ecx]	
+ jl LNextSpanIR
+ xor eax,eax	
+ mov edi,ds:dword ptr[spanpackage_t_pdest+esi]	
+ add esi,offset spanpackage_t_size	; point to next span
+ mov al,ds:byte ptr[ebx]	
+ mov al,ds:byte ptr[_irtable+eax]
+ mov ds:word ptr[ecx],bp	
+ mov al,ds:byte ptr[12345678h+eax]	
+LPatch9IR:	
+ mov ds:byte ptr[edi],al	
+
+ jmp LNextSpanESISetIR
+
+;===================================
+;===================================
+ public _D_Aff8Patch	
+_D_Aff8Patch:	
+ mov eax,[_alias_colormap]
+ mov ds:dword ptr[LPatch1-4],eax	
+ mov ds:dword ptr[LPatch2-4],eax	
+ mov ds:dword ptr[LPatch3-4],eax	
+ mov ds:dword ptr[LPatch4-4],eax	
+ mov ds:dword ptr[LPatch5-4],eax	
+ mov ds:dword ptr[LPatch6-4],eax	
+ mov ds:dword ptr[LPatch7-4],eax	
+ mov ds:dword ptr[LPatch8-4],eax	
+ mov ds:dword ptr[LPatch9-4],eax	
+ mov ds:dword ptr[LPatch1IR-4],eax	
+ mov ds:dword ptr[LPatch2IR-4],eax	
+ mov ds:dword ptr[LPatch3IR-4],eax	
+ mov ds:dword ptr[LPatch4IR-4],eax	
+ mov ds:dword ptr[LPatch5IR-4],eax	
+ mov ds:dword ptr[LPatch6IR-4],eax	
+ mov ds:dword ptr[LPatch7IR-4],eax	
+ mov ds:dword ptr[LPatch8IR-4],eax	
+ mov ds:dword ptr[LPatch9IR-4],eax	
+
+ ret	
+
+
+
+;===================================
+;===================================
+
+height	equ		4+16
+
+ public _R_PolysetScanLeftEdge	
+_R_PolysetScanLeftEdge:	
+ push ebp	; preserve caller stack frame pointer
+ push esi	; preserve register variables
+ push edi	
+ push ebx	
+
+ mov eax,ds:dword ptr[height+esp]	
+ mov ecx,ds:dword ptr[_d_sfrac]
+
+ and eax,0FFFFh	
+ mov ebx,ds:dword ptr[_d_ptex]	
+ or ecx,eax	
+ mov esi,ds:dword ptr[_d_pedgespanpackage]	
+ mov edx,ds:dword ptr[_d_tfrac]	
+ mov edi,ds:dword ptr[_d_light]	
+ mov ebp,ds:dword ptr[_d_zi]	
+
+; %eax: scratch
+; %ebx: d_ptex
+; %ecx: d_sfrac in high word, count in low word
+; %edx: d_tfrac
+; %esi: d_pedgespanpackage, errorterm, scratch alternately
+; %edi: d_light
+; %ebp: d_zi
+
+;	do
+;	{
+
+LScanLoop:	
+
+;		d_pedgespanpackage->ptex = ptex;
+;		d_pedgespanpackage->pdest = d_pdest;
+;		d_pedgespanpackage->pz = d_pz;
+;		d_pedgespanpackage->count = d_aspancount;
+;		d_pedgespanpackage->light = d_light;
+;		d_pedgespanpackage->zi = d_zi;
+;		d_pedgespanpackage->sfrac = d_sfrac << 16;
+;		d_pedgespanpackage->tfrac = d_tfrac << 16;
+ mov ds:dword ptr[spanpackage_t_ptex+esi],ebx	
+ mov eax,ds:dword ptr[_d_pdest]	
+ mov ds:dword ptr[spanpackage_t_pdest+esi],eax	
+ mov eax,ds:dword ptr[_d_pz]	
+ mov ds:dword ptr[spanpackage_t_pz+esi],eax	
+ mov eax,ds:dword ptr[_d_aspancount]	
+ mov ds:dword ptr[spanpackage_t_count+esi],eax	
+ mov ds:dword ptr[spanpackage_t_light+esi],edi	
+ mov ds:dword ptr[spanpackage_t_zi+esi],ebp	
+ mov ds:dword ptr[spanpackage_t_sfrac+esi],ecx	
+ mov ds:dword ptr[spanpackage_t_tfrac+esi],edx	
+
+; pretouch the next cache line
+ mov al,ds:byte ptr[spanpackage_t_size+esi]	
+
+;		d_pedgespanpackage++;
+ add esi,offset spanpackage_t_size	
+ mov eax,ds:dword ptr[_erroradjustup]	
+ mov ds:dword ptr[_d_pedgespanpackage],esi	
+
+;		errorterm += erroradjustup;
+ mov esi,ds:dword ptr[_errorterm]	
+ add esi,eax	
+ mov eax,ds:dword ptr[_d_pdest]	
+
+;		if (errorterm >= 0)
+;		{
+ js LNoLeftEdgeTurnover	
+
+;			errorterm -= erroradjustdown;
+;			d_pdest += d_pdestextrastep;
+ sub esi,ds:dword ptr[_erroradjustdown]	
+ add eax,ds:dword ptr[_d_pdestextrastep]	
+ mov ds:dword ptr[_errorterm],esi	
+ mov ds:dword ptr[_d_pdest],eax	
+
+;			d_pz += d_pzextrastep;
+;			d_aspancount += d_countextrastep;
+;			d_ptex += d_ptexextrastep;
+;			d_sfrac += d_sfracextrastep;
+;			d_ptex += d_sfrac >> 16;
+;			d_sfrac &= 0xFFFF;
+;			d_tfrac += d_tfracextrastep;
+ mov eax,ds:dword ptr[_d_pz]	
+ mov esi,ds:dword ptr[_d_aspancount]	
+ add eax,ds:dword ptr[_d_pzextrastep]	
+ add ecx,ds:dword ptr[_d_sfracextrastep]	
+ adc ebx,ds:dword ptr[_d_ptexextrastep]	
+ add esi,ds:dword ptr[_d_countextrastep]	
+ mov ds:dword ptr[_d_pz],eax	
+ mov eax,ds:dword ptr[_d_tfracextrastep]	
+ mov ds:dword ptr[_d_aspancount],esi	
+ add edx,eax	
+
+;			if (d_tfrac & 0x10000)
+;			{
+ jnc LSkip1	
+
+;				d_ptex += r_affinetridesc.skinwidth;
+;				d_tfrac &= 0xFFFF;
+ add ebx,ds:dword ptr[_r_affinetridesc+atd_skinwidth]	
+
+;			}
+
+LSkip1:	
+
+;			d_light += d_lightextrastep;
+;			d_zi += d_ziextrastep;
+ add edi,ds:dword ptr[_d_lightextrastep]	
+ add ebp,ds:dword ptr[_d_ziextrastep]	
+
+;		}
+ mov esi,ds:dword ptr[_d_pedgespanpackage]	
+ dec ecx	
+ test ecx,0FFFFh	
+ jnz LScanLoop	
+
+ pop ebx	
+ pop edi	
+ pop esi	
+ pop ebp	
+ ret	
+
+;		else
+;		{
+
+LNoLeftEdgeTurnover:	
+ mov ds:dword ptr[_errorterm],esi	
+
+;			d_pdest += d_pdestbasestep;
+ add eax,ds:dword ptr[_d_pdestbasestep]	
+ mov ds:dword ptr[_d_pdest],eax	
+
+;			d_pz += d_pzbasestep;
+;			d_aspancount += ubasestep;
+;			d_ptex += d_ptexbasestep;
+;			d_sfrac += d_sfracbasestep;
+;			d_ptex += d_sfrac >> 16;
+;			d_sfrac &= 0xFFFF;
+ mov eax,ds:dword ptr[_d_pz]	
+ mov esi,ds:dword ptr[_d_aspancount]	
+ add eax,ds:dword ptr[_d_pzbasestep]	
+ add ecx,ds:dword ptr[_d_sfracbasestep]	
+ adc ebx,ds:dword ptr[_d_ptexbasestep]	
+ add esi,ds:dword ptr[_ubasestep]	
+ mov ds:dword ptr[_d_pz],eax	
+ mov ds:dword ptr[_d_aspancount],esi	
+
+;			d_tfrac += d_tfracbasestep;
+ mov esi,ds:dword ptr[_d_tfracbasestep]	
+ add edx,esi	
+
+;			if (d_tfrac & 0x10000)
+;			{
+ jnc LSkip2	
+
+;				d_ptex += r_affinetridesc.skinwidth;
+;				d_tfrac &= 0xFFFF;
+ add ebx,ds:dword ptr[_r_affinetridesc+atd_skinwidth]	
+
+;			}
+
+LSkip2:	
+
+;			d_light += d_lightbasestep;
+;			d_zi += d_zibasestep;
+ add edi,ds:dword ptr[_d_lightbasestep]	
+ add ebp,ds:dword ptr[_d_zibasestep]	
+
+;		}
+;	} while (--height);
+ mov esi,ds:dword ptr[_d_pedgespanpackage]	
+ dec ecx	
+ test ecx,0FFFFh	
+ jnz LScanLoop	
+
+ pop ebx	
+ pop edi	
+ pop esi	
+ pop ebp	
+ ret	
+
+_TEXT ENDS
+endif	;id386
+ END
--- /dev/null
+++ b/ref_soft/r_polyse.c
@@ -1,0 +1,1539 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// d_polyset.c: routines for drawing sets of polygons sharing the same
+// texture (used for Alias models)
+
+#include "r_local.h"
+
+int	rand1k[] = {
+#include "rand1k.h"
+};
+
+#define MASK_1K	0x3FF
+
+int		rand1k_index = 0;
+
+// TODO: put in span spilling to shrink list size
+// !!! if this is changed, it must be changed in d_polysa.s too !!!
+#define DPS_MAXSPANS			MAXHEIGHT+1	
+									// 1 extra for spanpackage that marks end
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct {
+	void			*pdest;
+	short			*pz;
+	int				count;
+	byte			*ptex;
+	int				sfrac, tfrac, light, zi;
+} spanpackage_t;
+
+typedef struct {
+	int		isflattop;
+	int		numleftedges;
+	int		*pleftedgevert0;
+	int		*pleftedgevert1;
+	int		*pleftedgevert2;
+	int		numrightedges;
+	int		*prightedgevert0;
+	int		*prightedgevert1;
+	int		*prightedgevert2;
+} edgetable;
+
+aliastriangleparms_t aliastriangleparms;
+
+int	r_p0[6], r_p1[6], r_p2[6];
+
+byte		*d_pcolormap;
+
+int			d_aflatcolor;
+int			d_xdenom;
+
+edgetable	*pedgetable;
+
+edgetable	edgetables[12] = {
+	{0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
+	{0, 2, r_p1, r_p0, r_p2,   1, r_p1, r_p2, NULL},
+	{1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
+	{0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
+	{0, 2, r_p0, r_p2, r_p1,   1, r_p0, r_p1, NULL},
+	{0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
+	{0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
+	{0, 2, r_p2, r_p1, r_p0,   1, r_p2, r_p0, NULL},
+	{0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
+	{1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
+	{1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
+	{0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
+};
+
+// FIXME: some of these can become statics
+int				a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
+int				r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
+int				r_zistepx, r_zistepy;
+int				d_aspancount, d_countextrastep;
+
+spanpackage_t			*a_spans;
+spanpackage_t			*d_pedgespanpackage;
+static int				ystart;
+byte					*d_pdest, *d_ptex;
+short					*d_pz;
+int						d_sfrac, d_tfrac, d_light, d_zi;
+int						d_ptexextrastep, d_sfracextrastep;
+int						d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
+int						d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
+int						d_sfracbasestep, d_tfracbasestep;
+int						d_ziextrastep, d_zibasestep;
+int						d_pzextrastep, d_pzbasestep;
+
+typedef struct {
+	int		quotient;
+	int		remainder;
+} adivtab_t;
+
+static adivtab_t	adivtab[32*32] = {
+#include "adivtab.h"
+};
+
+byte	*skintable[MAX_LBM_HEIGHT];
+int		skinwidth;
+byte	*skinstart;
+
+void	(*d_pdrawspans)(spanpackage_t *pspanpackage);
+
+void R_PolysetDrawSpans8_33 (spanpackage_t *pspanpackage);
+void R_PolysetDrawSpans8_66 (spanpackage_t *pspanpackage);
+void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage);
+
+void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage);
+void R_PolysetCalcGradients (int skinwidth);
+void R_DrawNonSubdiv (void);
+void R_PolysetSetEdgeTable (void);
+void R_RasterizeAliasPolySmooth (void);
+void R_PolysetScanLeftEdge(int height);
+void R_PolysetScanLeftEdge_C(int height);
+
+// ======================
+// PGM
+// 64 65 66 67 68 69 70 71   72 73 74 75 76 77 78 79
+byte iractive = 0;
+byte irtable[256] = { 79, 78, 77, 76, 75, 74, 73, 72,		// black/white
+					  71, 70, 69, 68, 67, 66, 65, 64,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// dark taupe
+					  72, 73, 74, 75, 76, 77, 78, 79,
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// slate grey
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  208, 208, 208, 208, 208, 208, 208, 208,	// unused?'
+					  64, 66, 68, 70, 72, 74, 76, 78,		// dark yellow
+					  
+					  64, 65, 66, 67, 68, 69, 70, 71,		// dark red
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// grey/tan
+					  72, 73, 74, 75, 76, 77, 78, 79,
+
+					  64, 66, 68, 70, 72, 74, 76, 78,		// chocolate
+					  68, 67, 66, 65, 64, 65, 66, 67,		// mauve / teal
+					  68, 69, 70, 71, 72, 73, 74, 75,
+					  76, 76, 77, 77, 78, 78, 79, 79,		
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// more mauve
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// olive
+					  72, 73, 74, 75, 76, 77, 78, 79,
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// maroon
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// sky blue
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  
+					  64, 65, 66, 67, 68, 69, 70, 71,		// olive again
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  64, 65, 66, 67, 68, 69, 70, 71,		// nuclear green
+					  64, 65, 66, 67, 68, 69, 70, 71,		// bright yellow
+
+					  64, 65, 66, 67, 68, 69, 70, 71,		// fire colors
+					  72, 73, 74, 75, 76, 77, 78, 79,
+					  208, 208, 64, 64, 70, 71, 72, 64,		// mishmash1
+					  66, 68, 70, 64, 65, 66, 67, 68};		// mishmash2
+// PGM
+// ======================
+
+/*
+================
+R_PolysetUpdateTables
+================
+*/
+void R_PolysetUpdateTables (void)
+{
+	int		i;
+	byte	*s;
+	
+	if (r_affinetridesc.skinwidth != skinwidth ||
+		r_affinetridesc.pskin != skinstart)
+	{
+		skinwidth = r_affinetridesc.skinwidth;
+		skinstart = r_affinetridesc.pskin;
+		s = skinstart;
+		for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
+			skintable[i] = s;
+	}
+}
+
+
+/*
+================
+R_DrawTriangle
+================
+*/
+void R_DrawTriangle( void )
+{
+	spanpackage_t spans[DPS_MAXSPANS];
+
+	int dv1_ab, dv0_ac;
+	int dv0_ab, dv1_ac;
+
+	/*
+	d_xdenom = ( aliastriangleparms.a->v[1] - aliastriangleparms.b->v[1] ) * ( aliastriangleparms.a->v[0] - aliastriangleparms.c->v[0] ) -
+			   ( aliastriangleparms.a->v[0] - aliastriangleparms.b->v[0] ) * ( aliastriangleparms.a->v[1] - aliastriangleparms.c->v[1] );
+	*/
+
+	dv0_ab = aliastriangleparms.a->u - aliastriangleparms.b->u;
+	dv1_ab = aliastriangleparms.a->v - aliastriangleparms.b->v;
+
+	if ( !( dv0_ab | dv1_ab ) )
+		return;
+
+	dv0_ac = aliastriangleparms.a->u - aliastriangleparms.c->u;
+	dv1_ac = aliastriangleparms.a->v - aliastriangleparms.c->v;
+
+	if ( !( dv0_ac | dv1_ac ) )
+		return;
+
+	d_xdenom = ( dv0_ac * dv1_ab ) - ( dv0_ab * dv1_ac );
+
+	if ( d_xdenom < 0 )
+	{
+		a_spans = spans;
+
+		r_p0[0] = aliastriangleparms.a->u;		// u
+		r_p0[1] = aliastriangleparms.a->v;		// v
+		r_p0[2] = aliastriangleparms.a->s;		// s
+		r_p0[3] = aliastriangleparms.a->t;		// t
+		r_p0[4] = aliastriangleparms.a->l;		// light
+		r_p0[5] = aliastriangleparms.a->zi;		// iz
+
+		r_p1[0] = aliastriangleparms.b->u;
+		r_p1[1] = aliastriangleparms.b->v;
+		r_p1[2] = aliastriangleparms.b->s;
+		r_p1[3] = aliastriangleparms.b->t;
+		r_p1[4] = aliastriangleparms.b->l;
+		r_p1[5] = aliastriangleparms.b->zi;
+
+		r_p2[0] = aliastriangleparms.c->u;
+		r_p2[1] = aliastriangleparms.c->v;
+		r_p2[2] = aliastriangleparms.c->s;
+		r_p2[3] = aliastriangleparms.c->t;
+		r_p2[4] = aliastriangleparms.c->l;
+		r_p2[5] = aliastriangleparms.c->zi;
+
+		R_PolysetSetEdgeTable ();
+		R_RasterizeAliasPolySmooth ();
+	}
+}
+
+
+/*
+===================
+R_PolysetScanLeftEdge_C
+====================
+*/
+void R_PolysetScanLeftEdge_C(int height)
+{
+	do
+	{
+		d_pedgespanpackage->pdest = d_pdest;
+		d_pedgespanpackage->pz = d_pz;
+		d_pedgespanpackage->count = d_aspancount;
+		d_pedgespanpackage->ptex = d_ptex;
+
+		d_pedgespanpackage->sfrac = d_sfrac;
+		d_pedgespanpackage->tfrac = d_tfrac;
+
+	// FIXME: need to clamp l, s, t, at both ends?
+		d_pedgespanpackage->light = d_light;
+		d_pedgespanpackage->zi = d_zi;
+
+		d_pedgespanpackage++;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_pdest += d_pdestextrastep;
+			d_pz += d_pzextrastep;
+			d_aspancount += d_countextrastep;
+			d_ptex += d_ptexextrastep;
+			d_sfrac += d_sfracextrastep;
+			d_ptex += d_sfrac >> 16;
+
+			d_sfrac &= 0xFFFF;
+			d_tfrac += d_tfracextrastep;
+			if (d_tfrac & 0x10000)
+			{
+				d_ptex += r_affinetridesc.skinwidth;
+				d_tfrac &= 0xFFFF;
+			}
+			d_light += d_lightextrastep;
+			d_zi += d_ziextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_pdest += d_pdestbasestep;
+			d_pz += d_pzbasestep;
+			d_aspancount += ubasestep;
+			d_ptex += d_ptexbasestep;
+			d_sfrac += d_sfracbasestep;
+			d_ptex += d_sfrac >> 16;
+			d_sfrac &= 0xFFFF;
+			d_tfrac += d_tfracbasestep;
+			if (d_tfrac & 0x10000)
+			{
+				d_ptex += r_affinetridesc.skinwidth;
+				d_tfrac &= 0xFFFF;
+			}
+			d_light += d_lightbasestep;
+			d_zi += d_zibasestep;
+		}
+	} while (--height);
+}
+
+/*
+===================
+FloorDivMod
+
+Returns mathematically correct (floor-based) quotient and remainder for
+numer and denom, both of which should contain no fractional part. The
+quotient must fit in 32 bits.
+FIXME: GET RID OF THIS! (FloorDivMod)
+====================
+*/
+void FloorDivMod (float numer, float denom, int *quotient,
+		int *rem)
+{
+	int		q, r;
+	float	x;
+
+	if (numer >= 0.0)
+	{
+
+		x = floor(numer / denom);
+		q = (int)x;
+		r = (int)floor(numer - (x * denom));
+	}
+	else
+	{
+	//
+	// perform operations with positive values, and fix mod to make floor-based
+	//
+		x = floor(-numer / denom);
+		q = -(int)x;
+		r = (int)floor(-numer - (x * denom));
+		if (r != 0)
+		{
+			q--;
+			r = (int)denom - r;
+		}
+	}
+
+	*quotient = q;
+	*rem = r;
+}
+
+
+/*
+===================
+R_PolysetSetUpForLineScan
+====================
+*/
+void R_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
+		fixed8_t endvertu, fixed8_t endvertv)
+{
+	float		dm, dn;
+	int			tm, tn;
+	adivtab_t	*ptemp;
+
+// TODO: implement x86 version
+
+	errorterm = -1;
+
+	tm = endvertu - startvertu;
+	tn = endvertv - startvertv;
+
+	if (((tm <= 16) && (tm >= -15)) &&
+		((tn <= 16) && (tn >= -15)))
+	{
+		ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
+		ubasestep = ptemp->quotient;
+		erroradjustup = ptemp->remainder;
+		erroradjustdown = tn;
+	}
+	else
+	{
+		dm = tm;
+		dn = tn;
+
+		FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
+
+		erroradjustdown = dn;
+	}
+}
+
+
+
+/*
+================
+R_PolysetCalcGradients
+================
+*/
+#if id386 && !defined __linux__
+void R_PolysetCalcGradients( int skinwidth )
+{
+	static float xstepdenominv, ystepdenominv, t0, t1;
+	static float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
+	static float one = 1.0F, negative_one = -1.0F;
+	static unsigned long t0_int, t1_int;
+
+	extern unsigned long fpu_sp24_ceil_cw, fpu_ceil_cw, fpu_chop_cw;
+
+	/*
+	p00_minus_p20 = r_p0[0] - r_p2[0];
+	p01_minus_p21 = r_p0[1] - r_p2[1];
+	p10_minus_p20 = r_p1[0] - r_p2[0];
+	p11_minus_p21 = r_p1[1] - r_p2[1];
+	*/
+
+	__asm mov eax, dword ptr [r_p0+0]
+	__asm mov ebx, dword ptr [r_p0+4]
+	__asm sub eax, dword ptr [r_p2+0]
+	__asm sub ebx, dword ptr [r_p2+4]
+	__asm mov p00_minus_p20, eax
+	__asm mov p01_minus_p21, ebx
+	__asm fild dword ptr p00_minus_p20
+	__asm fild dword ptr p01_minus_p21
+	__asm mov eax, dword ptr [r_p1+0]
+	__asm mov ebx, dword ptr [r_p1+4]
+	__asm sub eax, dword ptr [r_p2+0]
+	__asm sub ebx, dword ptr [r_p2+4]
+	__asm fstp p01_minus_p21
+	__asm fstp p00_minus_p20
+	__asm mov p10_minus_p20, eax
+	__asm mov p11_minus_p21, ebx
+	__asm fild dword ptr p10_minus_p20
+	__asm fild dword ptr p11_minus_p21
+	__asm fstp p11_minus_p21
+	__asm fstp p10_minus_p20
+
+	/*
+	xstepdenominv = 1.0 / (float)d_xdenom;
+
+	ystepdenominv = -xstepdenominv;
+	*/
+
+	/*
+	** put FPU in single precision ceil mode
+	*/
+	__asm fldcw word ptr [fpu_sp24_ceil_cw]
+//	__asm fldcw word ptr [fpu_ceil_cw]
+
+	__asm fild  dword ptr d_xdenom    ; d_xdenom
+	__asm fdivr one                   ; 1 / d_xdenom
+	__asm fst   xstepdenominv         ; 
+	__asm fmul  negative_one          ; -( 1 / d_xdenom )
+
+// ceil () for light so positive steps are exaggerated, negative steps
+// diminished,  pushing us away from underflow toward overflow. Underflow is
+// very visible, overflow is very unlikely, because of ambient lighting
+	/*
+	t0 = r_p0[4] - r_p2[4];
+	t1 = r_p1[4] - r_p2[4];
+	r_lstepx = (int)
+			ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
+	r_lstepy = (int)
+			ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
+	*/
+	__asm mov   eax, dword ptr [r_p0+16]
+	__asm mov   ebx, dword ptr [r_p1+16]
+	__asm sub   eax, dword ptr [r_p2+16]
+	__asm sub   ebx, dword ptr [r_p2+16]
+
+	__asm fstp  ystepdenominv       ; (empty)
+
+	__asm mov   t0_int, eax
+	__asm mov   t1_int, ebx
+	__asm fild  t0_int              ; t0
+	__asm fild  t1_int              ; t1 | t0
+	__asm fxch  st(1)               ; t0 | t1
+	__asm fstp  t0                  ; t1
+	__asm fst   t1                  ; t1
+	__asm fmul  p01_minus_p21       ; t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p01_minus_p21
+	__asm fmul  p11_minus_p21       ; t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t1                  ; t1 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p00_minus_p20       ; t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p10_minus_p20       ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fxch  st(2)               ; t0 * p11_minus_p21 | t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21
+	__asm fsubp st(3), st           ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fsubrp st(1), st          ; t1 * p00_minus_p20 - t0 * p10_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fxch  st(1)               ; t1 * p01_minus_p21 - t0 * p11_minus_p21 | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fmul  xstepdenominv       ; r_lstepx | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fxch  st(1)
+	__asm fmul  ystepdenominv       ; r_lstepy | r_lstepx
+	__asm fxch  st(1)               ; r_lstepx | r_lstepy
+	__asm fistp dword ptr [r_lstepx]
+	__asm fistp dword ptr [r_lstepy]
+
+	/*
+	** put FPU back into extended precision chop mode
+	*/
+	__asm fldcw word ptr [fpu_chop_cw]
+
+	/*
+	t0 = r_p0[2] - r_p2[2];
+	t1 = r_p1[2] - r_p2[2];
+	r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
+			ystepdenominv);
+	*/
+	__asm mov eax, dword ptr [r_p0+8]
+	__asm mov ebx, dword ptr [r_p1+8]
+	__asm sub eax, dword ptr [r_p2+8]
+	__asm sub ebx, dword ptr [r_p2+8]
+	__asm mov   t0_int, eax
+	__asm mov   t1_int, ebx
+	__asm fild  t0_int              ; t0
+	__asm fild  t1_int              ; t1 | t0
+	__asm fxch  st(1)               ; t0 | t1
+	__asm fstp  t0                  ; t1
+	__asm fst   t1                  ; (empty)
+
+	__asm fmul  p01_minus_p21       ; t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p01_minus_p21
+	__asm fmul  p11_minus_p21       ; t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t1                  ; t1 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p00_minus_p20       ; t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p10_minus_p20       ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fxch  st(2)               ; t0 * p11_minus_p21 | t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21
+	__asm fsubp st(3), st           ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fsubrp st(1), st           ; t1 * p00_minus_p20 - t0 * p10_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fxch  st(1)               ; t1 * p01_minus_p21 - t0 * p11_minus_p21 | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fmul  xstepdenominv       ; r_lstepx | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fxch  st(1)
+	__asm fmul  ystepdenominv       ; r_lstepy | r_lstepx
+	__asm fxch  st(1)               ; r_lstepx | r_lstepy
+	__asm fistp dword ptr [r_sstepx]
+	__asm fistp dword ptr [r_sstepy]
+
+	/*
+	t0 = r_p0[3] - r_p2[3];
+	t1 = r_p1[3] - r_p2[3];
+	r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+			ystepdenominv);
+	*/
+	__asm mov eax, dword ptr [r_p0+12]
+	__asm mov ebx, dword ptr [r_p1+12]
+	__asm sub eax, dword ptr [r_p2+12]
+	__asm sub ebx, dword ptr [r_p2+12]
+
+	__asm mov   t0_int, eax
+	__asm mov   t1_int, ebx
+	__asm fild  t0_int              ; t0
+	__asm fild  t1_int              ; t1 | t0
+	__asm fxch  st(1)               ; t0 | t1
+	__asm fstp  t0                  ; t1
+	__asm fst   t1                  ; (empty)
+
+	__asm fmul  p01_minus_p21       ; t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p01_minus_p21
+	__asm fmul  p11_minus_p21       ; t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t1                  ; t1 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p00_minus_p20       ; t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p10_minus_p20       ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fxch  st(2)               ; t0 * p11_minus_p21 | t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21
+	__asm fsubp st(3), st           ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fsubrp st(1), st           ; t1 * p00_minus_p20 - t0 * p10_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fxch  st(1)               ; t1 * p01_minus_p21 - t0 * p11_minus_p21 | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fmul  xstepdenominv       ; r_lstepx | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fxch  st(1)
+	__asm fmul  ystepdenominv       ; r_lstepy | r_lstepx
+	__asm fxch  st(1)               ; r_lstepx | r_lstepy
+	__asm fistp dword ptr [r_tstepx]
+	__asm fistp dword ptr [r_tstepy]
+
+	/*
+	t0 = r_p0[5] - r_p2[5];
+	t1 = r_p1[5] - r_p2[5];
+	r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+			ystepdenominv);
+	*/
+	__asm mov eax, dword ptr [r_p0+20]
+	__asm mov ebx, dword ptr [r_p1+20]
+	__asm sub eax, dword ptr [r_p2+20]
+	__asm sub ebx, dword ptr [r_p2+20]
+
+	__asm mov   t0_int, eax
+	__asm mov   t1_int, ebx
+	__asm fild  t0_int              ; t0
+	__asm fild  t1_int              ; t1 | t0
+	__asm fxch  st(1)               ; t0 | t1
+	__asm fstp  t0                  ; t1
+	__asm fst   t1                  ; (empty)
+
+	__asm fmul  p01_minus_p21       ; t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p01_minus_p21
+	__asm fmul  p11_minus_p21       ; t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t1                  ; t1 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p00_minus_p20       ; t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fld   t0                  ; t0 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fmul  p10_minus_p20       ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t0 * p11_minus_p21 | t1 * p01_minus_p21
+	__asm fxch  st(2)               ; t0 * p11_minus_p21 | t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21
+	__asm fsubp st(3), st           ; t0 * p10_minus_p20 | t1 * p00_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fsubrp st(1), st           ; t1 * p00_minus_p20 - t0 * p10_minus_p20 | t1 * p01_minus_p21 - t0 * p11_minus_p21
+	__asm fxch  st(1)               ; t1 * p01_minus_p21 - t0 * p11_minus_p21 | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fmul  xstepdenominv       ; r_lstepx | t1 * p00_minus_p20 - t0 * p10_minus_p20
+	__asm fxch  st(1)
+	__asm fmul  ystepdenominv       ; r_lstepy | r_lstepx
+	__asm fxch  st(1)               ; r_lstepx | r_lstepy
+	__asm fistp dword ptr [r_zistepx]
+	__asm fistp dword ptr [r_zistepy]
+
+	/*
+#if	id386ALIAS
+	a_sstepxfrac = r_sstepx << 16;
+	a_tstepxfrac = r_tstepx << 16;
+#else
+	a_sstepxfrac = r_sstepx & 0xFFFF;
+	a_tstepxfrac = r_tstepx & 0xFFFF;
+#endif
+	*/
+	__asm mov eax, d_pdrawspans
+	__asm cmp eax, offset R_PolysetDrawSpans8_Opaque
+	__asm mov eax, r_sstepx
+	__asm mov ebx, r_tstepx
+	__asm jne translucent
+//#if id386ALIAS
+	__asm shl eax, 16
+	__asm shl ebx, 16
+	__asm jmp done_with_steps
+//#else
+translucent:
+	__asm and eax, 0ffffh
+	__asm and ebx, 0ffffh
+//#endif
+done_with_steps:
+	__asm mov a_sstepxfrac, eax
+	__asm mov a_tstepxfrac, ebx
+
+	/*
+	a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
+	*/
+	__asm mov ebx, r_tstepx
+	__asm mov ecx, r_sstepx
+	__asm sar ebx, 16
+	__asm mov eax, skinwidth
+	__asm mul ebx
+	__asm sar ecx, 16
+	__asm add eax, ecx
+	__asm mov a_ststepxwhole, eax
+}
+#else
+void R_PolysetCalcGradients (int skinwidth)
+{
+	float	xstepdenominv, ystepdenominv, t0, t1;
+	float	p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
+
+	p00_minus_p20 = r_p0[0] - r_p2[0];
+	p01_minus_p21 = r_p0[1] - r_p2[1];
+	p10_minus_p20 = r_p1[0] - r_p2[0];
+	p11_minus_p21 = r_p1[1] - r_p2[1];
+
+	xstepdenominv = 1.0 / (float)d_xdenom;
+
+	ystepdenominv = -xstepdenominv;
+
+// ceil () for light so positive steps are exaggerated, negative steps
+// diminished,  pushing us away from underflow toward overflow. Underflow is
+// very visible, overflow is very unlikely, because of ambient lighting
+	t0 = r_p0[4] - r_p2[4];
+	t1 = r_p1[4] - r_p2[4];
+	r_lstepx = (int)
+			ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
+	r_lstepy = (int)
+			ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
+
+	t0 = r_p0[2] - r_p2[2];
+	t1 = r_p1[2] - r_p2[2];
+	r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
+			ystepdenominv);
+
+	t0 = r_p0[3] - r_p2[3];
+	t1 = r_p1[3] - r_p2[3];
+	r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+			ystepdenominv);
+
+	t0 = r_p0[5] - r_p2[5];
+	t1 = r_p1[5] - r_p2[5];
+	r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+			xstepdenominv);
+	r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+			ystepdenominv);
+
+//#if	id386ALIAS
+#if id386
+	if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+	{
+		a_sstepxfrac = r_sstepx << 16;
+		a_tstepxfrac = r_tstepx << 16;
+	}
+	else
+#endif
+	{
+//#else
+		a_sstepxfrac = r_sstepx & 0xFFFF;
+		a_tstepxfrac = r_tstepx & 0xFFFF;
+	}
+//#endif
+
+	a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
+}
+#endif
+
+/*
+================
+R_PolysetDrawThreshSpans8
+
+Random fizzle fade rasterizer
+================
+*/
+void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	byte	*lptex;
+	int		lsfrac, ltfrac;
+	int		llight;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					rand1k_index = (rand1k_index + 1) & MASK_1K;
+
+					if (rand1k[rand1k_index] <= r_affinetridesc.vis_thresh)
+					{
+						*lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
+						*lpz = lzi >> 16;
+					}
+				}
+
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+
+/*
+================
+R_PolysetDrawSpans8
+================
+*/
+void R_PolysetDrawSpans8_33( spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	byte	*lptex;
+	int		lsfrac, ltfrac;
+	int		llight;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
+
+					*lpdest = vid.alphamap[temp+ *lpdest*256];
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpansConstant8_33( spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lpz = pspanpackage->pz;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					*lpdest = vid.alphamap[r_aliasblendcolor + *lpdest*256];
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpans8_66(spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	byte	*lptex;
+	int		lsfrac, ltfrac;
+	int		llight;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
+
+					*lpdest = vid.alphamap[temp*256 + *lpdest];
+					*lpz = lzi >> 16;
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpansConstant8_66( spanpackage_t *pspanpackage)
+{
+	int		lcount;
+	byte	*lpdest;
+	int		lzi;
+	short	*lpz;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+			lpz = pspanpackage->pz;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+					*lpdest = vid.alphamap[r_aliasblendcolor*256 + *lpdest];
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+
+#if !id386
+void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage)
+{
+	int		lcount;
+
+	do
+	{
+		lcount = d_aspancount - pspanpackage->count;
+
+		errorterm += erroradjustup;
+		if (errorterm >= 0)
+		{
+			d_aspancount += d_countextrastep;
+			errorterm -= erroradjustdown;
+		}
+		else
+		{
+			d_aspancount += ubasestep;
+		}
+
+		if (lcount)
+		{
+			int		lsfrac, ltfrac;
+			byte	*lpdest;
+			byte	*lptex;
+			int		llight;
+			int		lzi;
+			short	*lpz;
+
+			lpdest = pspanpackage->pdest;
+			lptex = pspanpackage->ptex;
+			lpz = pspanpackage->pz;
+			lsfrac = pspanpackage->sfrac;
+			ltfrac = pspanpackage->tfrac;
+			llight = pspanpackage->light;
+			lzi = pspanpackage->zi;
+
+			do
+			{
+				if ((lzi >> 16) >= *lpz)
+				{
+//PGM
+					if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+						*lpdest = ((byte *)vid.colormap)[irtable[*lptex]];
+					else
+					*lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
+//PGM
+					*lpz = lzi >> 16;
+				}
+				lpdest++;
+				lzi += r_zistepx;
+				lpz++;
+				llight += r_lstepx;
+				lptex += a_ststepxwhole;
+				lsfrac += a_sstepxfrac;
+				lptex += lsfrac >> 16;
+				lsfrac &= 0xFFFF;
+				ltfrac += a_tstepxfrac;
+				if (ltfrac & 0x10000)
+				{
+					lptex += r_affinetridesc.skinwidth;
+					ltfrac &= 0xFFFF;
+				}
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	} while (pspanpackage->count != -999999);
+}
+#endif
+
+
+/*
+================
+R_PolysetFillSpans8
+================
+*/
+void R_PolysetFillSpans8 (spanpackage_t *pspanpackage)
+{
+	int				color;
+
+// FIXME: do z buffering
+
+	color = d_aflatcolor++;
+
+	while (1)
+	{
+		int		lcount;
+		byte	*lpdest;
+
+		lcount = pspanpackage->count;
+
+		if (lcount == -1)
+			return;
+
+		if (lcount)
+		{
+			lpdest = pspanpackage->pdest;
+
+			do
+			{
+				*lpdest++ = color;
+			} while (--lcount);
+		}
+
+		pspanpackage++;
+	}
+}
+
+/*
+================
+R_RasterizeAliasPolySmooth
+================
+*/
+void R_RasterizeAliasPolySmooth (void)
+{
+	int				initialleftheight, initialrightheight;
+	int				*plefttop, *prighttop, *pleftbottom, *prightbottom;
+	int				working_lstepx, originalcount;
+
+	plefttop = pedgetable->pleftedgevert0;
+	prighttop = pedgetable->prightedgevert0;
+
+	pleftbottom = pedgetable->pleftedgevert1;
+	prightbottom = pedgetable->prightedgevert1;
+
+	initialleftheight = pleftbottom[1] - plefttop[1];
+	initialrightheight = prightbottom[1] - prighttop[1];
+
+//
+// set the s, t, and light gradients, which are consistent across the triangle
+// because being a triangle, things are affine
+//
+	R_PolysetCalcGradients (r_affinetridesc.skinwidth);
+//
+// rasterize the polygon
+//
+
+//
+// scan out the top (and possibly only) part of the left edge
+//
+	d_pedgespanpackage = a_spans;
+
+	ystart = plefttop[1];
+	d_aspancount = plefttop[0] - prighttop[0];
+
+	d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+			(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
+//#if	id386ALIAS
+#if id386
+	if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+	{
+		d_sfrac = (plefttop[2] & 0xFFFF) << 16;
+		d_tfrac = (plefttop[3] & 0xFFFF) << 16;
+	}
+//#else
+	else
+#endif
+	{
+		d_sfrac = plefttop[2] & 0xFFFF;
+		d_tfrac = plefttop[3] & 0xFFFF;
+	}
+//#endif
+	d_light = plefttop[4];
+	d_zi = plefttop[5];
+
+	d_pdest = (byte *)d_viewbuffer +
+			ystart * r_screenwidth + plefttop[0];
+	d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
+
+	if (initialleftheight == 1)
+	{
+		d_pedgespanpackage->pdest = d_pdest;
+		d_pedgespanpackage->pz = d_pz;
+		d_pedgespanpackage->count = d_aspancount;
+		d_pedgespanpackage->ptex = d_ptex;
+
+		d_pedgespanpackage->sfrac = d_sfrac;
+		d_pedgespanpackage->tfrac = d_tfrac;
+
+	// FIXME: need to clamp l, s, t, at both ends?
+		d_pedgespanpackage->light = d_light;
+		d_pedgespanpackage->zi = d_zi;
+
+		d_pedgespanpackage++;
+	}
+	else
+	{
+		R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
+							  pleftbottom[0], pleftbottom[1]);
+
+//#if	id386ALIAS
+#if id386
+		if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+		{
+			d_pzbasestep = (d_zwidth + ubasestep) << 1;
+			d_pzextrastep = d_pzbasestep + 2;
+		}
+//#else
+		else
+#endif
+		{
+			d_pzbasestep = d_zwidth + ubasestep;
+			d_pzextrastep = d_pzbasestep + 1;
+		}
+//#endif
+
+		d_pdestbasestep = r_screenwidth + ubasestep;
+		d_pdestextrastep = d_pdestbasestep + 1;
+
+	// TODO: can reuse partial expressions here
+
+	// for negative steps in x along left edge, bias toward overflow rather than
+	// underflow (sort of turning the floor () we did in the gradient calcs into
+	// ceil (), but plus a little bit)
+		if (ubasestep < 0)
+			working_lstepx = r_lstepx - 1;
+		else
+			working_lstepx = r_lstepx;
+
+		d_countextrastep = ubasestep + 1;
+		d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
+				((r_tstepy + r_tstepx * ubasestep) >> 16) *
+				r_affinetridesc.skinwidth;
+//#if	id386ALIAS
+#if id386
+		if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+		{
+			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16;
+			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16;
+		}
+		else
+#endif
+		{
+//#else
+			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
+			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
+		}
+//#endif
+		d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
+		d_zibasestep = r_zistepy + r_zistepx * ubasestep;
+
+		d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
+				((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
+				r_affinetridesc.skinwidth;
+//#if	id386ALIAS
+#if id386
+		if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+		{
+			d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) << 16;
+			d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) << 16;
+		}
+		else
+#endif
+		{
+//#else
+			d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
+			d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
+		}
+//#endif
+		d_lightextrastep = d_lightbasestep + working_lstepx;
+		d_ziextrastep = d_zibasestep + r_zistepx;
+
+#if id386
+		if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+		{
+			R_PolysetScanLeftEdge (initialleftheight);
+		}
+		else
+#endif
+		{
+			R_PolysetScanLeftEdge_C(initialleftheight);
+		}
+	}
+
+//
+// scan out the bottom part of the left edge, if it exists
+//
+	if (pedgetable->numleftedges == 2)
+	{
+		int		height;
+
+		plefttop = pleftbottom;
+		pleftbottom = pedgetable->pleftedgevert2;
+
+		height = pleftbottom[1] - plefttop[1];
+
+// TODO: make this a function; modularize this function in general
+
+		ystart = plefttop[1];
+		d_aspancount = plefttop[0] - prighttop[0];
+		d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+				(plefttop[3] >> 16) * r_affinetridesc.skinwidth;
+		d_sfrac = 0;
+		d_tfrac = 0;
+		d_light = plefttop[4];
+		d_zi = plefttop[5];
+
+		d_pdest = (byte *)d_viewbuffer + ystart * r_screenwidth + plefttop[0];
+		d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
+
+		if (height == 1)
+		{
+			d_pedgespanpackage->pdest = d_pdest;
+			d_pedgespanpackage->pz = d_pz;
+			d_pedgespanpackage->count = d_aspancount;
+			d_pedgespanpackage->ptex = d_ptex;
+
+			d_pedgespanpackage->sfrac = d_sfrac;
+			d_pedgespanpackage->tfrac = d_tfrac;
+
+		// FIXME: need to clamp l, s, t, at both ends?
+			d_pedgespanpackage->light = d_light;
+			d_pedgespanpackage->zi = d_zi;
+
+			d_pedgespanpackage++;
+		}
+		else
+		{
+			R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
+								  pleftbottom[0], pleftbottom[1]);
+
+			d_pdestbasestep = r_screenwidth + ubasestep;
+			d_pdestextrastep = d_pdestbasestep + 1;
+
+//#if	id386ALIAS
+#if id386
+			if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+			{
+				d_pzbasestep = (d_zwidth + ubasestep) << 1;
+				d_pzextrastep = d_pzbasestep + 2;
+			}
+//#else
+			else
+#endif
+			{
+				d_pzbasestep = d_zwidth + ubasestep;
+				d_pzextrastep = d_pzbasestep + 1;
+			}
+//#endif
+
+			if (ubasestep < 0)
+				working_lstepx = r_lstepx - 1;
+			else
+				working_lstepx = r_lstepx;
+
+			d_countextrastep = ubasestep + 1;
+			d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
+					((r_tstepy + r_tstepx * ubasestep) >> 16) *
+					r_affinetridesc.skinwidth;
+//#if	id386ALIAS
+#if id386
+			if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+			{
+				d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16;
+				d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16;
+			}
+//#else
+			else
+#endif
+			{
+				d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
+				d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
+			}
+//#endif
+			d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
+			d_zibasestep = r_zistepy + r_zistepx * ubasestep;
+
+			d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
+					((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
+					r_affinetridesc.skinwidth;
+//#if	id386ALIAS
+#if id386
+			if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+			{
+				d_sfracextrastep = ((r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF)<<16;
+				d_tfracextrastep = ((r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF)<<16;
+			}
+			else
+#endif
+//#endif
+			{
+				d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
+				d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
+			}
+//#endif
+			d_lightextrastep = d_lightbasestep + working_lstepx;
+			d_ziextrastep = d_zibasestep + r_zistepx;
+
+#if id386
+			if ( d_pdrawspans == R_PolysetDrawSpans8_Opaque )
+			{
+				R_PolysetScanLeftEdge (height);
+			}
+			else
+#endif
+			{
+				R_PolysetScanLeftEdge_C(height);
+			}
+		}
+	}
+
+// scan out the top (and possibly only) part of the right edge, updating the
+// count field
+	d_pedgespanpackage = a_spans;
+
+	R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
+						  prightbottom[0], prightbottom[1]);
+	d_aspancount = 0;
+	d_countextrastep = ubasestep + 1;
+	originalcount = a_spans[initialrightheight].count;
+	a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
+	(*d_pdrawspans) (a_spans);
+
+// scan out the bottom part of the right edge, if it exists
+	if (pedgetable->numrightedges == 2)
+	{
+		int				height;
+		spanpackage_t	*pstart;
+
+		pstart = a_spans + initialrightheight;
+		pstart->count = originalcount;
+
+		d_aspancount = prightbottom[0] - prighttop[0];
+
+		prighttop = prightbottom;
+		prightbottom = pedgetable->prightedgevert2;
+
+		height = prightbottom[1] - prighttop[1];
+
+		R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
+							  prightbottom[0], prightbottom[1]);
+
+		d_countextrastep = ubasestep + 1;
+		a_spans[initialrightheight + height].count = -999999;
+											// mark end of the spanpackages
+		(*d_pdrawspans) (pstart);
+	}
+}
+
+
+/*
+================
+R_PolysetSetEdgeTable
+================
+*/
+void R_PolysetSetEdgeTable (void)
+{
+	int			edgetableindex;
+
+	edgetableindex = 0;	// assume the vertices are already in
+						//  top to bottom order
+
+//
+// determine which edges are right & left, and the order in which
+// to rasterize them
+//
+	if (r_p0[1] >= r_p1[1])
+	{
+		if (r_p0[1] == r_p1[1])
+		{
+			if (r_p0[1] < r_p2[1])
+				pedgetable = &edgetables[2];
+			else
+				pedgetable = &edgetables[5];
+
+			return;
+		}
+		else
+		{
+			edgetableindex = 1;
+		}
+	}
+
+	if (r_p0[1] == r_p2[1])
+	{
+		if (edgetableindex)
+			pedgetable = &edgetables[8];
+		else
+			pedgetable = &edgetables[9];
+
+		return;
+	}
+	else if (r_p1[1] == r_p2[1])
+	{
+		if (edgetableindex)
+			pedgetable = &edgetables[10];
+		else
+			pedgetable = &edgetables[11];
+
+		return;
+	}
+
+	if (r_p0[1] > r_p2[1])
+		edgetableindex += 2;
+
+	if (r_p1[1] > r_p2[1])
+		edgetableindex += 4;
+
+	pedgetable = &edgetables[edgetableindex];
+}
+
+
--- /dev/null
+++ b/ref_soft/r_rast.c
@@ -1,0 +1,852 @@
+/*
+Copyright (C) 1997-2001 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_rast.c
+
+#include <assert.h>
+
+#include "r_local.h"
+
+#define MAXLEFTCLIPEDGES		100
+
+// !!! if these are changed, they must be changed in asm_draw.h too !!!
+#define FULLY_CLIPPED_CACHED	0x80000000
+#define FRAMECOUNT_MASK			0x7FFFFFFF
+
+unsigned int	cacheoffset;
+
+int			c_faceclip;					// number of faces clipped
+
+
+clipplane_t	*entity_clipplanes;
+clipplane_t	view_clipplanes[4];
+clipplane_t	world_clipplanes[16];
+
+medge_t			*r_pedge;
+
+qboolean		r_leftclipped, r_rightclipped;
+static qboolean	makeleftedge, makerightedge;
+qboolean		r_nearzionly;
+
+int		sintable[1280];
+int		intsintable[1280];
+int		blanktable[1280];		// PGM
+
+mvertex_t	r_leftenter, r_leftexit;
+mvertex_t	r_rightenter, r_rightexit;
+
+typedef struct
+{
+	float	u,v;
+	int		ceilv;
+} evert_t;
+
+int				r_emitted;
+float			r_nearzi;
+float			r_u1, r_v1, r_lzi1;
+int				r_ceilv1;
+
+qboolean		r_lastvertvalid;
+int				r_skyframe;
+
+msurface_t		*r_skyfaces;
+mplane_t		r_skyplanes[6];
+mtexinfo_t		r_skytexinfo[6];
+mvertex_t		*r_skyverts;
+medge_t			*r_skyedges;
+int				*r_skysurfedges;
+
+// I just copied this data from a box map...
+int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
+
+int box_surfedges[24] = { 1,2,3,4,  -1,5,6,7,  8,9,-6,10,  -2,-7,-9,11,
+  12,-3,-11,-8,  -12,-10,-5,-4};
+int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
+
+int	box_faces[6] = {0,0,2,2,2,0};
+
+vec3_t	box_vecs[6][2] = {
+	{	{0,-1,0}, {-1,0,0} },
+	{ {0,1,0}, {0,0,-1} },
+	{	{0,-1,0}, {1,0,0} },
+	{ {1,0,0}, {0,0,-1} },
+	{ {0,-1,0}, {0,0,-1} },
+	{ {-1,0,0}, {0,0,-1} }
+};
+
+float	box_verts[8][3] = {
+	{-1,-1,-1},
+	{-1,1,-1},
+	{1,1,-1},
+	{1,-1,-1},
+	{-1,-1,1},
+	{-1,1,1},
+	{1,-1,1},
+	{1,1,1}
+};
+
+// down, west, up, north, east, south
+// {"rt", "bk", "lf", "ft", "up", "dn"};
+
+/*
+================
+R_InitSkyBox
+
+================
+*/
+void R_InitSkyBox (void)
+{
+	int		i;
+	extern model_t *loadmodel;
+
+	r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
+	loadmodel->numsurfaces += 6;
+	r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
+	loadmodel->numvertexes += 8;
+	r_skyedges = loadmodel->edges + loadmodel->numedges;
+	loadmodel->numedges += 12;
+	r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
+	loadmodel->numsurfedges += 24;
+	if (loadmodel->numsurfaces > MAX_MAP_FACES
+		|| loadmodel->numvertexes > MAX_MAP_VERTS
+		|| loadmodel->numedges > MAX_MAP_EDGES)
+		ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
+
+	memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
+	for (i=0 ; i<6 ; i++)
+	{
+		r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
+		r_skyplanes[i].dist = skybox_planes[i*2+1];
+
+		VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
+		VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
+
+		r_skyfaces[i].plane = &r_skyplanes[i];
+		r_skyfaces[i].numedges = 4;
+		r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
+		r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
+		r_skyfaces[i].texinfo = &r_skytexinfo[i];
+		r_skyfaces[i].texturemins[0] = -128;
+		r_skyfaces[i].texturemins[1] = -128;
+		r_skyfaces[i].extents[0] = 256;
+		r_skyfaces[i].extents[1] = 256;
+	}
+
+	for (i=0 ; i<24 ; i++)
+		if (box_surfedges[i] > 0)
+			r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
+		else
+			r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
+
+	for(i=0 ; i<12 ; i++)
+	{
+		r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
+		r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
+		r_skyedges[i].cachededgeoffset = 0;
+	}
+}
+
+/*
+================
+R_EmitSkyBox
+================
+*/
+void R_EmitSkyBox (void)
+{
+	int		i, j;
+	int		oldkey;
+
+	if (insubmodel)
+		return;		// submodels should never have skies
+	if (r_skyframe == r_framecount)
+		return;		// already set this frame
+
+	r_skyframe = r_framecount;
+
+	// set the eight fake vertexes
+	for (i=0 ; i<8 ; i++)
+		for (j=0 ; j<3 ; j++)
+			r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
+
+	// set the six fake planes
+	for (i=0 ; i<6 ; i++)
+		if (skybox_planes[i*2+1] > 0)
+			r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
+		else
+			r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
+
+	// fix texture offseets
+	for (i=0 ; i<6 ; i++)
+	{
+		r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
+		r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
+	}
+
+	// emit the six faces
+	oldkey = r_currentkey;
+	r_currentkey = 0x7ffffff0;
+ 	for (i=0 ; i<6 ; i++)
+	{
+		R_RenderFace (r_skyfaces + i, 15);
+	}
+	r_currentkey = oldkey;		// bsp sorting order
+}
+
+
+#if	!id386
+
+/*
+================
+R_EmitEdge
+================
+*/
+void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
+{
+	edge_t	*edge, *pcheck;
+	int		u_check;
+	float	u, u_step;
+	vec3_t	local, transformed;
+	float	*world;
+	int		v, v2, ceilv0;
+	float	scale, lzi0, u0, v0;
+	int		side;
+
+	if (r_lastvertvalid)
+	{
+		u0 = r_u1;
+		v0 = r_v1;
+		lzi0 = r_lzi1;
+		ceilv0 = r_ceilv1;
+	}
+	else
+	{
+		world = &pv0->position[0];
+	
+	// transform and project
+		VectorSubtract (world, modelorg, local);
+		TransformVector (local, transformed);
+	
+		if (transformed[2] < NEAR_CLIP)
+			transformed[2] = NEAR_CLIP;
+	
+		lzi0 = 1.0 / transformed[2];
+	
+	// FIXME: build x/yscale into transform?
+		scale = xscale * lzi0;
+		u0 = (xcenter + scale*transformed[0]);
+		if (u0 < r_refdef.fvrectx_adj)
+			u0 = r_refdef.fvrectx_adj;
+		if (u0 > r_refdef.fvrectright_adj)
+			u0 = r_refdef.fvrectright_adj;
+	
+		scale = yscale * lzi0;
+		v0 = (ycenter - scale*transformed[1]);
+		if (v0 < r_refdef.fvrecty_adj)
+			v0 = r_refdef.fvrecty_adj;
+		if (v0 > r_refdef.fvrectbottom_adj)
+			v0 = r_refdef.fvrectbottom_adj;
+	
+		ceilv0 = (int) ceil(v0);
+	}
+
+	world = &pv1->position[0];
+
+// transform and project
+	VectorSubtract (world, modelorg, local);
+	TransformVector (local, transformed);
+
+	if (transformed[2] < NEAR_CLIP)
+		transformed[2] = NEAR_CLIP;
+
+	r_lzi1 = 1.0 / transformed[2];
+
+	scale = xscale * r_lzi1;
+	r_u1 = (xcenter + scale*transformed[0]);
+	if (r_u1 < r_refdef.fvrectx_adj)
+		r_u1 = r_refdef.fvrectx_adj;
+	if (r_u1 > r_refdef.fvrectright_adj)
+		r_u1 = r_refdef.fvrectright_adj;
+
+	scale = yscale * r_lzi1;
+	r_v1 = (ycenter - scale*transformed[1]);
+	if (r_v1 < r_refdef.fvrecty_adj)
+		r_v1 = r_refdef.fvrecty_adj;
+	if (r_v1 > r_refdef.fvrectbottom_adj)
+		r_v1 = r_refdef.fvrectbottom_adj;
+
+	if (r_lzi1 > lzi0)
+		lzi0 = r_lzi1;
+
+	if (lzi0 > r_nearzi)	// for mipmap finding
+		r_nearzi = lzi0;
+
+// for right edges, all we want is the effect on 1/z
+	if (r_nearzionly)
+		return;
+
+	r_emitted = 1;
+
+	r_ceilv1 = (int) ceil(r_v1);
+
+
+// create the edge
+	if (ceilv0 == r_ceilv1)
+	{
+	// we cache unclipped horizontal edges as fully clipped
+		if (cacheoffset != 0x7FFFFFFF)
+		{
+			cacheoffset = FULLY_CLIPPED_CACHED |
+					(r_framecount & FRAMECOUNT_MASK);
+		}
+
+		return;		// horizontal edge
+	}
+
+	side = ceilv0 > r_ceilv1;
+
+	edge = edge_p++;
+
+	edge->owner = r_pedge;
+
+	edge->nearzi = lzi0;
+
+	if (side == 0)
+	{
+	// trailing edge (go from p1 to p2)
+		v = ceilv0;
+		v2 = r_ceilv1 - 1;
+
+		edge->surfs[0] = surface_p - surfaces;
+		edge->surfs[1] = 0;
+
+		u_step = ((r_u1 - u0) / (r_v1 - v0));
+		u = u0 + ((float)v - v0) * u_step;
+	}
+	else
+	{
+	// leading edge (go from p2 to p1)
+		v2 = ceilv0 - 1;
+		v = r_ceilv1;
+
+		edge->surfs[0] = 0;
+		edge->surfs[1] = surface_p - surfaces;
+
+		u_step = ((u0 - r_u1) / (v0 - r_v1));
+		u = r_u1 + ((float)v - r_v1) * u_step;
+	}
+
+	edge->u_step = u_step*0x100000;
+	edge->u = u*0x100000 + 0xFFFFF;
+
+// we need to do this to avoid stepping off the edges if a very nearly
+// horizontal edge is less than epsilon above a scan, and numeric error causes
+// it to incorrectly extend to the scan, and the extension of the line goes off
+// the edge of the screen
+// FIXME: is this actually needed?
+	if (edge->u < r_refdef.vrect_x_adj_shift20)
+		edge->u = r_refdef.vrect_x_adj_shift20;
+	if (edge->u > r_refdef.vrectright_adj_shift20)
+		edge->u = r_refdef.vrectright_adj_shift20;
+
+//
+// sort the edge in normally
+//
+	u_check = edge->u;
+	if (edge->surfs[0])
+		u_check++;	// sort trailers after leaders
+
+	if (!newedges[v] || newedges[v]->u >= u_check)
+	{
+		edge->next = newedges[v];
+		newedges[v] = edge;
+	}
+	else
+	{
+		pcheck = newedges[v];
+		while (pcheck->next && pcheck->next->u < u_check)
+			pcheck = pcheck->next;
+		edge->next = pcheck->next;
+		pcheck->next = edge;
+	}
+
+	edge->nextremove = removeedges[v2];
+	removeedges[v2] = edge;
+}
+
+
+/*
+================
+R_ClipEdge
+================
+*/
+void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
+{
+	float		d0, d1, f;
+	mvertex_t	clipvert;
+
+	if (clip)
+	{
+		do
+		{
+			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
+			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
+
+			if (d0 >= 0)
+			{
+			// point 0 is unclipped
+				if (d1 >= 0)
+				{
+				// both points are unclipped
+					continue;
+				}
+
+			// only point 1 is clipped
+
+			// we don't cache clipped edges
+				cacheoffset = 0x7FFFFFFF;
+
+				f = d0 / (d0 - d1);
+				clipvert.position[0] = pv0->position[0] +
+						f * (pv1->position[0] - pv0->position[0]);
+				clipvert.position[1] = pv0->position[1] +
+						f * (pv1->position[1] - pv0->position[1]);
+				clipvert.position[2] = pv0->position[2] +
+						f * (pv1->position[2] - pv0->position[2]);
+
+				if (clip->leftedge)
+				{
+					r_leftclipped = true;
+					r_leftexit = clipvert;
+				}
+				else if (clip->rightedge)
+				{
+					r_rightclipped = true;
+					r_rightexit = clipvert;
+				}
+
+				R_ClipEdge (pv0, &clipvert, clip->next);
+				return;
+			}
+			else
+			{
+			// point 0 is clipped
+				if (d1 < 0)
+				{
+				// both points are clipped
+				// we do cache fully clipped edges
+					if (!r_leftclipped)
+						cacheoffset = FULLY_CLIPPED_CACHED |
+								(r_framecount & FRAMECOUNT_MASK);
+					return;
+				}
+
+			// only point 0 is clipped
+				r_lastvertvalid = false;
+
+			// we don't cache partially clipped edges
+				cacheoffset = 0x7FFFFFFF;
+
+				f = d0 / (d0 - d1);
+				clipvert.position[0] = pv0->position[0] +
+						f * (pv1->position[0] - pv0->position[0]);
+				clipvert.position[1] = pv0->position[1] +
+						f * (pv1->position[1] - pv0->position[1]);
+				clipvert.position[2] = pv0->position[2] +
+						f * (pv1->position[2] - pv0->position[2]);
+
+				if (clip->leftedge)
+				{
+					r_leftclipped = true;
+					r_leftenter = clipvert;
+				}
+				else if (clip->rightedge)
+				{
+					r_rightclipped = true;
+					r_rightenter = clipvert;
+				}
+
+				R_ClipEdge (&clipvert, pv1, clip->next);
+				return;
+			}
+		} while ((clip = clip->next) != NULL);
+	}
+
+// add the edge
+	R_EmitEdge (pv0, pv1);
+}
+
+#endif	// !id386
+
+
+/*
+================
+R_EmitCachedEdge
+================
+*/
+void R_EmitCachedEdge (void)
+{
+	edge_t		*pedge_t;
+
+	pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
+
+	if (!pedge_t->surfs[0])
+		pedge_t->surfs[0] = surface_p - surfaces;
+	else
+		pedge_t->surfs[1] = surface_p - surfaces;
+
+	if (pedge_t->nearzi > r_nearzi)	// for mipmap finding
+		r_nearzi = pedge_t->nearzi;
+
+	r_emitted = 1;
+}
+
+
+/*
+================
+R_RenderFace
+================
+*/
+void R_RenderFace (msurface_t *fa, int clipflags)
+{
+	int			i, lindex;
+	unsigned	mask;
+	mplane_t	*pplane;
+	float		distinv;
+	vec3_t		p_normal;
+	medge_t		*pedges, tedge;
+	clipplane_t	*pclip;
+
+	// translucent surfaces are not drawn by the edge renderer
+	if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+	{
+		fa->nextalphasurface = r_alpha_surfaces;
+		r_alpha_surfaces = fa;
+		return;
+	}
+
+	// sky surfaces encountered in the world will cause the
+	// environment box surfaces to be emited
+	if ( fa->texinfo->flags & SURF_SKY )
+	{
+		R_EmitSkyBox ();	
+		return;
+	}
+
+// skip out if no more surfs
+	if ((surface_p) >= surf_max)
+	{
+		r_outofsurfaces++;
+		return;
+	}
+
+// ditto if not enough edges left, or switch to auxedges if possible
+	if ((edge_p + fa->numedges + 4) >= edge_max)
+	{
+		r_outofedges += fa->numedges;
+		return;
+	}
+
+	c_faceclip++;
+
+// set up clip planes
+	pclip = NULL;
+
+	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
+	{
+		if (clipflags & mask)
+		{
+			view_clipplanes[i].next = pclip;
+			pclip = &view_clipplanes[i];
+		}
+	}
+
+// push the edges through
+	r_emitted = 0;
+	r_nearzi = 0;
+	r_nearzionly = false;
+	makeleftedge = makerightedge = false;
+	pedges = currentmodel->edges;
+	r_lastvertvalid = false;
+
+	for (i=0 ; i<fa->numedges ; i++)
+	{
+		lindex = currentmodel->surfedges[fa->firstedge + i];
+
+		if (lindex > 0)
+		{
+			r_pedge = &pedges[lindex];
+
+		// if the edge is cached, we can just reuse the edge
+			if (!insubmodel)
+			{
+				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
+				{
+					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
+						r_framecount)
+					{
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+				else
+				{
+					if ((((unsigned long)edge_p - (unsigned long)r_edges) >
+						 r_pedge->cachededgeoffset) &&
+						(((edge_t *)((unsigned long)r_edges +
+						 r_pedge->cachededgeoffset))->owner == r_pedge))
+					{
+						R_EmitCachedEdge ();
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+			}
+
+		// assume it's cacheable
+			cacheoffset = (byte *)edge_p - (byte *)r_edges;
+			r_leftclipped = r_rightclipped = false;
+			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
+						&r_pcurrentvertbase[r_pedge->v[1]],
+						pclip);
+			r_pedge->cachededgeoffset = cacheoffset;
+
+			if (r_leftclipped)
+				makeleftedge = true;
+			if (r_rightclipped)
+				makerightedge = true;
+			r_lastvertvalid = true;
+		}
+		else
+		{
+			lindex = -lindex;
+			r_pedge = &pedges[lindex];
+		// if the edge is cached, we can just reuse the edge
+			if (!insubmodel)
+			{
+				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
+				{
+					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
+						r_framecount)
+					{
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+				else
+				{
+				// it's cached if the cached edge is valid and is owned
+				// by this medge_t
+					if ((((unsigned long)edge_p - (unsigned long)r_edges) >
+						 r_pedge->cachededgeoffset) &&
+						(((edge_t *)((unsigned long)r_edges +
+						 r_pedge->cachededgeoffset))->owner == r_pedge))
+					{
+						R_EmitCachedEdge ();
+						r_lastvertvalid = false;
+						continue;
+					}
+				}
+			}
+
+		// assume it's cacheable
+			cacheoffset = (byte *)edge_p - (byte *)r_edges;
+			r_leftclipped = r_rightclipped = false;
+			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
+						&r_pcurrentvertbase[r_pedge->v[0]],
+						pclip);
+			r_pedge->cachededgeoffset = cacheoffset;
+
+			if (r_leftclipped)
+				makeleftedge = true;
+			if (r_rightclipped)
+				makerightedge = true;
+			r_lastvertvalid = true;
+		}
+	}
+
+// if there was a clip off the left edge, add that edge too
+// FIXME: faster to do in screen space?
+// FIXME: share clipped edges?
+	if (makeleftedge)
+	{
+		r_pedge = &tedge;
+		r_lastvertvalid = false;
+		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
+	}
+
+// if there was a clip off the right edge, get the right r_nearzi
+	if (makerightedge)
+	{
+		r_pedge = &tedge;
+		r_lastvertvalid = false;
+		r_nearzionly = true;
+		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
+	}
+
+// if no edges made it out, return without posting the surface
+	if (!r_emitted)
+		return;
+
+	r_polycount++;
+
+	surface_p->msurf = fa;
+	surface_p->nearzi = r_nearzi;
+	surface_p->flags = fa->flags;
+	surface_p->insubmodel = insubmodel;
+	surface_p->spanstate = 0;
+	surface_p->entity = currententity;
+	surface_p->key = r_currentkey++;
+	surface_p->spans = NULL;
+
+	pplane = fa->plane;
+// FIXME: cache this?
+	TransformVector (pplane->normal, p_normal);
+// FIXME: cache this?
+	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
+
+	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
+	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
+	surface_p->d_ziorigin = p_normal[2] * distinv -
+			xcenter * surface_p->d_zistepu -
+			ycenter * surface_p->d_zistepv;
+
+	surface_p++;
+}
+
+
+/*
+================
+R_RenderBmodelFace
+================
+*/
+void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
+{
+	int			i;
+	unsigned	mask;
+	mplane_t	*pplane;
+	float		distinv;
+	vec3_t		p_normal;
+	medge_t		tedge;
+	clipplane_t	*pclip;
+
+	if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+	{
+		psurf->nextalphasurface = r_alpha_surfaces;
+		r_alpha_surfaces = psurf;
+		return;
+	}
+
+// skip out if no more surfs
+	if (surface_p >= surf_max)
+	{
+		r_outofsurfaces++;
+		return;
+	}
+
+// ditto if not enough edges left, or switch to auxedges if possible
+	if ((edge_p + psurf->numedges + 4) >= edge_max)
+	{
+		r_outofedges += psurf->numedges;
+		return;
+	}
+
+	c_faceclip++;
+
+// this is a dummy to give the caching mechanism someplace to write to
+	r_pedge = &tedge;
+
+// set up clip planes
+	pclip = NULL;
+
+	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
+	{
+		if (r_clipflags & mask)
+		{
+			view_clipplanes[i].next = pclip;
+			pclip = &view_clipplanes[i];
+		}
+	}
+
+// push the edges through
+	r_emitted = 0;
+	r_nearzi = 0;
+	r_nearzionly = false;
+	makeleftedge = makerightedge = false;
+// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
+// can be used?
+	r_lastvertvalid = false;
+
+	for ( ; pedges ; pedges = pedges->pnext)
+	{
+		r_leftclipped = r_rightclipped = false;
+		R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
+
+		if (r_leftclipped)
+			makeleftedge = true;
+		if (r_rightclipped)
+			makerightedge = true;
+	}
+
+// if there was a clip off the left edge, add that edge too
+// FIXME: faster to do in screen space?
+// FIXME: share clipped edges?
+	if (makeleftedge)
+	{
+		r_pedge = &tedge;
+		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
+	}
+
+// if there was a clip off the right edge, get the right r_nearzi
+	if (makerightedge)
+	{
+		r_pedge = &tedge;
+		r_nearzionly = true;
+		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
+	}
+
+// if no edges made it out, return without posting the surface
+	if (!r_emitted)
+		return;
+
+	r_polycount++;
+
+	surface_p->msurf = psurf;
+	surface_p->nearzi = r_nearzi;
+	surface_p->flags = psurf->flags;
+	surface_p->insubmodel = true;
+	surface_p->spanstate = 0;
+	surface_p->entity = currententity;
+	surface_p->key = r_currentbkey;
+	surface_p->spans = NULL;
+
+	pplane = psurf->plane;
+// FIXME: cache this?
+	TransformVector (pplane->normal, p_normal);
+// FIXME: cache this?
+	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
+
+	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
+	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
+	surface_p->d_ziorigin = p_normal[2] * distinv -
+			xcenter * surface_p->d_zistepu -
+			ycenter * surface_p->d_zistepv;
+
+	surface_p++;
+}
+
--- /dev/null
+++ b/ref_soft/r_scan.c
@@ -1,0 +1,591 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// d_scan.c
+//
+// Portable C scan-level rasterization code, all pixel depths.
+
+#include "r_local.h"
+
+unsigned char	*r_turb_pbase, *r_turb_pdest;
+fixed16_t		r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
+int				*r_turb_turb;
+int				r_turb_spancount;
+
+void D_DrawTurbulent8Span (void);
+
+
+/*
+=============
+D_WarpScreen
+
+this performs a slight compression of the screen at the same time as
+the sine warp, to keep the edges from wrapping
+=============
+*/
+void D_WarpScreen (void)
+{
+	int		w, h;
+	int		u,v, u2, v2;
+	byte	*dest;
+	int		*turb;
+	int		*col;
+	byte	**row;
+
+	static int	cached_width, cached_height;
+	static byte	*rowptr[1200+AMP2*2];
+	static int	column[1600+AMP2*2];
+
+	//
+	// these are constant over resolutions, and can be saved
+	//
+	w = r_newrefdef.width;
+	h = r_newrefdef.height;
+	if (w != cached_width || h != cached_height)
+	{
+		cached_width = w;
+		cached_height = h;
+		for (v=0 ; v<h+AMP2*2 ; v++)
+		{
+			v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
+			rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
+		}
+
+		for (u=0 ; u<w+AMP2*2 ; u++)
+		{
+			u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
+			column[u] = u2;
+		}
+	}
+
+	turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+	dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
+
+	for (v=0 ; v<h ; v++, dest += vid.rowbytes)
+	{
+		col = &column[turb[v]];
+		row = &rowptr[v];
+		for (u=0 ; u<w ; u+=4)
+		{
+			dest[u+0] = row[turb[u+0]][col[u+0]];
+			dest[u+1] = row[turb[u+1]][col[u+1]];
+			dest[u+2] = row[turb[u+2]][col[u+2]];
+			dest[u+3] = row[turb[u+3]][col[u+3]];
+		}
+	}
+}
+
+
+#if	!id386
+
+/*
+=============
+D_DrawTurbulent8Span
+=============
+*/
+void D_DrawTurbulent8Span (void)
+{
+	int		sturb, tturb;
+
+	do
+	{
+		sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
+		tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
+		*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
+		r_turb_s += r_turb_sstep;
+		r_turb_t += r_turb_tstep;
+	} while (--r_turb_spancount > 0);
+}
+
+#endif	// !id386
+
+
+/*
+=============
+Turbulent8
+=============
+*/
+void Turbulent8 (espan_t *pspan)
+{
+	int				count;
+	fixed16_t		snext, tnext;
+	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float			sdivz16stepu, tdivz16stepu, zi16stepu;
+	
+	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+
+	r_turb_sstep = 0;	// keep compiler happy
+	r_turb_tstep = 0;	// ditto
+
+	r_turb_pbase = (unsigned char *)cacheblock;
+
+	sdivz16stepu = d_sdivzstepu * 16;
+	tdivz16stepu = d_tdivzstepu * 16;
+	zi16stepu = d_zistepu * 16;
+
+	do
+	{
+		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
+				(r_screenwidth * pspan->v) + pspan->u);
+
+		count = pspan->count;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+		r_turb_s = (int)(sdivz * z) + sadjust;
+		if (r_turb_s > bbextents)
+			r_turb_s = bbextents;
+		else if (r_turb_s < 0)
+			r_turb_s = 0;
+
+		r_turb_t = (int)(tdivz * z) + tadjust;
+		if (r_turb_t > bbextentt)
+			r_turb_t = bbextentt;
+		else if (r_turb_t < 0)
+			r_turb_t = 0;
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= 16)
+				r_turb_spancount = 16;
+			else
+				r_turb_spancount = count;
+
+			count -= r_turb_spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivz16stepu;
+				tdivz += tdivz16stepu;
+				zi += zi16stepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				r_turb_sstep = (snext - r_turb_s) >> 4;
+				r_turb_tstep = (tnext - r_turb_t) >> 4;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(r_turb_spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				if (r_turb_spancount > 1)
+				{
+					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
+					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
+				}
+			}
+
+			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
+			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
+
+			D_DrawTurbulent8Span ();
+
+			r_turb_s = snext;
+			r_turb_t = tnext;
+
+		} while (count > 0);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+
+//====================
+//PGM
+/*
+=============
+NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
+	but the turbulence is automatically 0.
+=============
+*/
+void NonTurbulent8 (espan_t *pspan)
+{
+	int				count;
+	fixed16_t		snext, tnext;
+	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float			sdivz16stepu, tdivz16stepu, zi16stepu;
+	
+//	r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+	r_turb_turb = blanktable;
+
+	r_turb_sstep = 0;	// keep compiler happy
+	r_turb_tstep = 0;	// ditto
+
+	r_turb_pbase = (unsigned char *)cacheblock;
+
+	sdivz16stepu = d_sdivzstepu * 16;
+	tdivz16stepu = d_tdivzstepu * 16;
+	zi16stepu = d_zistepu * 16;
+
+	do
+	{
+		r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
+				(r_screenwidth * pspan->v) + pspan->u);
+
+		count = pspan->count;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+		r_turb_s = (int)(sdivz * z) + sadjust;
+		if (r_turb_s > bbextents)
+			r_turb_s = bbextents;
+		else if (r_turb_s < 0)
+			r_turb_s = 0;
+
+		r_turb_t = (int)(tdivz * z) + tadjust;
+		if (r_turb_t > bbextentt)
+			r_turb_t = bbextentt;
+		else if (r_turb_t < 0)
+			r_turb_t = 0;
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= 16)
+				r_turb_spancount = 16;
+			else
+				r_turb_spancount = count;
+
+			count -= r_turb_spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivz16stepu;
+				tdivz += tdivz16stepu;
+				zi += zi16stepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				r_turb_sstep = (snext - r_turb_s) >> 4;
+				r_turb_tstep = (tnext - r_turb_t) >> 4;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(r_turb_spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 16)
+					snext = 16;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 16)
+					tnext = 16;	// guard against round-off error on <0 steps
+
+				if (r_turb_spancount > 1)
+				{
+					r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
+					r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
+				}
+			}
+
+			r_turb_s = r_turb_s & ((CYCLE<<16)-1);
+			r_turb_t = r_turb_t & ((CYCLE<<16)-1);
+
+			D_DrawTurbulent8Span ();
+
+			r_turb_s = snext;
+			r_turb_t = tnext;
+
+		} while (count > 0);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+//PGM
+//====================
+
+
+#if	!id386
+
+/*
+=============
+D_DrawSpans16
+
+  FIXME: actually make this subdivide by 16 instead of 8!!!
+=============
+*/
+void D_DrawSpans16 (espan_t *pspan)
+{
+	int				count, spancount;
+	unsigned char	*pbase, *pdest;
+	fixed16_t		s, t, snext, tnext, sstep, tstep;
+	float			sdivz, tdivz, zi, z, du, dv, spancountminus1;
+	float			sdivz8stepu, tdivz8stepu, zi8stepu;
+
+	sstep = 0;	// keep compiler happy
+	tstep = 0;	// ditto
+
+	pbase = (unsigned char *)cacheblock;
+
+	sdivz8stepu = d_sdivzstepu * 8;
+	tdivz8stepu = d_tdivzstepu * 8;
+	zi8stepu = d_zistepu * 8;
+
+	do
+	{
+		pdest = (unsigned char *)((byte *)d_viewbuffer +
+				(r_screenwidth * pspan->v) + pspan->u);
+
+		count = pspan->count;
+
+	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+		z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+		s = (int)(sdivz * z) + sadjust;
+		if (s > bbextents)
+			s = bbextents;
+		else if (s < 0)
+			s = 0;
+
+		t = (int)(tdivz * z) + tadjust;
+		if (t > bbextentt)
+			t = bbextentt;
+		else if (t < 0)
+			t = 0;
+
+		do
+		{
+		// calculate s and t at the far end of the span
+			if (count >= 8)
+				spancount = 8;
+			else
+				spancount = count;
+
+			count -= spancount;
+
+			if (count)
+			{
+			// calculate s/z, t/z, zi->fixed s and t at far end of span,
+			// calculate s and t steps across span by shifting
+				sdivz += sdivz8stepu;
+				tdivz += tdivz8stepu;
+				zi += zi8stepu;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 8)
+					snext = 8;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 8)
+					tnext = 8;	// guard against round-off error on <0 steps
+
+				sstep = (snext - s) >> 3;
+				tstep = (tnext - t) >> 3;
+			}
+			else
+			{
+			// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+			// can't step off polygon), clamp, calculate s and t steps across
+			// span by division, biasing steps low so we don't run off the
+			// texture
+				spancountminus1 = (float)(spancount - 1);
+				sdivz += d_sdivzstepu * spancountminus1;
+				tdivz += d_tdivzstepu * spancountminus1;
+				zi += d_zistepu * spancountminus1;
+				z = (float)0x10000 / zi;	// prescale to 16.16 fixed-point
+				snext = (int)(sdivz * z) + sadjust;
+				if (snext > bbextents)
+					snext = bbextents;
+				else if (snext < 8)
+					snext = 8;	// prevent round-off error on <0 steps from
+								//  from causing overstepping & running off the
+								//  edge of the texture
+
+				tnext = (int)(tdivz * z) + tadjust;
+				if (tnext > bbextentt)
+					tnext = bbextentt;
+				else if (tnext < 8)
+					tnext = 8;	// guard against round-off error on <0 steps
+
+				if (spancount > 1)
+				{
+					sstep = (snext - s) / (spancount - 1);
+					tstep = (tnext - t) / (spancount - 1);
+				}
+			}
+
+			do
+			{
+				*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
+				s += sstep;
+				t += tstep;
+			} while (--spancount > 0);
+
+			s = snext;
+			t = tnext;
+
+		} while (count > 0);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+
+#endif
+
+
+#if	!id386
+
+/*
+=============
+D_DrawZSpans
+=============
+*/
+void D_DrawZSpans (espan_t *pspan)
+{
+	int				count, doublecount, izistep;
+	int				izi;
+	short			*pdest;
+	unsigned		ltemp;
+	float			zi;
+	float			du, dv;
+
+// FIXME: check for clamping/range problems
+// we count on FP exceptions being turned off to avoid range problems
+	izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+
+	do
+	{
+		pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+
+		count = pspan->count;
+
+	// calculate the initial 1/z
+		du = (float)pspan->u;
+		dv = (float)pspan->v;
+
+		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+	// we count on FP exceptions being turned off to avoid range problems
+		izi = (int)(zi * 0x8000 * 0x10000);
+
+		if ((long)pdest & 0x02)
+		{
+			*pdest++ = (short)(izi >> 16);
+			izi += izistep;
+			count--;
+		}
+
+		if ((doublecount = count >> 1) > 0)
+		{
+			do
+			{
+				ltemp = izi >> 16;
+				izi += izistep;
+				ltemp |= izi & 0xFFFF0000;
+				izi += izistep;
+				*(int *)pdest = ltemp;
+				pdest += 2;
+			} while (--doublecount > 0);
+		}
+
+		if (count & 1)
+			*pdest = (short)(izi >> 16);
+
+	} while ((pspan = pspan->pnext) != NULL);
+}
+
+#endif
+
--- /dev/null
+++ b/ref_soft/r_scana.asm
@@ -1,0 +1,73 @@
+ .386P
+ .model FLAT
+;
+; d_scana.s
+; x86 assembly-language turbulent texture mapping code
+;
+
+include qasm.inc
+include d_if.inc
+
+if id386
+
+_DATA SEGMENT	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+;----------------------------------------------------------------------
+; turbulent texture mapping code
+;----------------------------------------------------------------------
+
+ align 4	
+ public _D_DrawTurbulent8Span	
+_D_DrawTurbulent8Span:	
+ push ebp	; preserve caller's stack frame pointer
+ push esi	; preserve register variables
+ push edi	
+ push ebx	
+
+ mov esi,ds:dword ptr[_r_turb_s]	
+ mov ecx,ds:dword ptr[_r_turb_t]	
+ mov edi,ds:dword ptr[_r_turb_pdest]	
+ mov ebx,ds:dword ptr[_r_turb_spancount]	
+
+Llp:	
+ mov eax,ecx	
+ mov edx,esi	
+ sar eax,16	
+ mov ebp,ds:dword ptr[_r_turb_turb]	
+ sar edx,16	
+ and eax,offset CYCLE-1	
+ and edx,offset CYCLE-1	
+ mov eax,ds:dword ptr[ebp+eax*4]	
+ mov edx,ds:dword ptr[ebp+edx*4]	
+ add eax,esi	
+ sar eax,16	
+ add edx,ecx	
+ sar edx,16	
+ and eax,offset TURB_TEX_SIZE-1	
+ and edx,offset TURB_TEX_SIZE-1	
+ shl edx,6	
+ mov ebp,ds:dword ptr[_r_turb_pbase]	
+ add edx,eax	
+ inc edi	
+ add esi,ds:dword ptr[_r_turb_sstep]	
+ add ecx,ds:dword ptr[_r_turb_tstep]	
+ mov dl,ds:byte ptr[ebp+edx*1]	
+ dec ebx	
+ mov ds:byte ptr[-1+edi],dl	
+ jnz Llp	
+
+ mov ds:dword ptr[_r_turb_pdest],edi	
+
+ pop ebx	; restore register variables
+ pop edi	
+ pop esi	
+ pop ebp	; restore caller's stack frame pointer
+ ret	
+
+
+_TEXT ENDS
+endif	;id386
+ END
--- /dev/null
+++ b/ref_soft/r_spr8.asm
@@ -1,0 +1,884 @@
+ .386P
+ .model FLAT
+;
+; d_spr8.s
+; x86 assembly-language horizontal 8-bpp transparent span-drawing code.
+;
+
+include qasm.inc
+include d_if.inc
+
+if id386
+
+;----------------------------------------------------------------------
+; 8-bpp horizontal span drawing code for polygons, with transparency.
+;----------------------------------------------------------------------
+
+_TEXT SEGMENT	
+
+; out-of-line, rarely-needed clamping code
+
+LClampHigh0:	
+ mov esi,ds:dword ptr[_bbextents]	
+ jmp LClampReentry0	
+LClampHighOrLow0:	
+ jg LClampHigh0	
+ xor esi,esi	
+ jmp LClampReentry0	
+
+LClampHigh1:	
+ mov edx,ds:dword ptr[_bbextentt]	
+ jmp LClampReentry1	
+LClampHighOrLow1:	
+ jg LClampHigh1	
+ xor edx,edx	
+ jmp LClampReentry1	
+
+LClampLow2:	
+ mov ebp,2048	
+ jmp LClampReentry2	
+LClampHigh2:	
+ mov ebp,ds:dword ptr[_bbextents]	
+ jmp LClampReentry2	
+
+LClampLow3:	
+ mov ecx,2048	
+ jmp LClampReentry3	
+LClampHigh3:	
+ mov ecx,ds:dword ptr[_bbextentt]	
+ jmp LClampReentry3	
+
+LClampLow4:	
+ mov eax,2048	
+ jmp LClampReentry4	
+LClampHigh4:	
+ mov eax,ds:dword ptr[_bbextents]	
+ jmp LClampReentry4	
+
+LClampLow5:	
+ mov ebx,2048	
+ jmp LClampReentry5	
+LClampHigh5:	
+ mov ebx,ds:dword ptr[_bbextentt]	
+ jmp LClampReentry5	
+
+
+pspans	equ		4+16
+
+ align 4	
+ public _D_SpriteDrawSpansXXX
+_D_SpriteDrawSpansXXX:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+;
+; set up scaled-by-8 steps, for 8-long segments; also set up cacheblock
+; and span list pointers, and 1/z step in 0.32 fixed-point
+;
+; FIXME: any overlap from rearranging?
+ fld ds:dword ptr[_d_sdivzstepu]	
+ fmul ds:dword ptr[fp_8]	
+ mov edx,ds:dword ptr[_cacheblock]	
+ fld ds:dword ptr[_d_tdivzstepu]	
+ fmul ds:dword ptr[fp_8]	
+ mov ebx,ds:dword ptr[pspans+esp]	; point to the first span descriptor
+ fld ds:dword ptr[_d_zistepu]	
+ fmul ds:dword ptr[fp_8]	
+ mov ds:dword ptr[pbase],edx	; pbase = cacheblock
+ fld ds:dword ptr[_d_zistepu]	
+ fmul ds:dword ptr[fp_64kx64k]	
+ fxch st(3)	
+ fstp ds:dword ptr[sdivz8stepu]	
+ fstp ds:dword ptr[zi8stepu]	
+ fstp ds:dword ptr[tdivz8stepu]	
+ fistp ds:dword ptr[izistep]	
+ mov eax,ds:dword ptr[izistep]	
+ ror eax,16	; put upper 16 bits in low word
+ mov ecx,ds:dword ptr[sspan_t_count+ebx]	
+ mov ds:dword ptr[izistep],eax	
+
+ cmp ecx,0	
+ jle LNextSpan	
+
+LSpanLoop:	
+
+;
+; set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
+; initial s and t values
+;
+; FIXME: pipeline FILD?
+ fild ds:dword ptr[sspan_t_v+ebx]	
+ fild ds:dword ptr[sspan_t_u+ebx]	
+
+ fld st(1)	; dv | du | dv
+ fmul ds:dword ptr[_d_sdivzstepv]	; dv*d_sdivzstepv | du | dv
+ fld st(1)	; du | dv*d_sdivzstepv | du | dv
+ fmul ds:dword ptr[_d_sdivzstepu]	; du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+ fld st(2)	; du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
+ fmul ds:dword ptr[_d_tdivzstepu]	; du*d_tdivzstepu | du*d_sdivzstepu |
+;  dv*d_sdivzstepv | du | dv
+ fxch st(1)	; du*d_sdivzstepu | du*d_tdivzstepu |
+;  dv*d_sdivzstepv | du | dv
+ faddp st(2),st(0)	; du*d_tdivzstepu |
+;  du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
+ fxch st(1)	; du*d_sdivzstepu + dv*d_sdivzstepv |
+;  du*d_tdivzstepu | du | dv
+ fld st(3)	; dv | du*d_sdivzstepu + dv*d_sdivzstepv |
+;  du*d_tdivzstepu | du | dv
+ fmul ds:dword ptr[_d_tdivzstepv]	; dv*d_tdivzstepv |
+;  du*d_sdivzstepu + dv*d_sdivzstepv |
+;  du*d_tdivzstepu | du | dv
+ fxch st(1)	; du*d_sdivzstepu + dv*d_sdivzstepv |
+;  dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
+ fadd ds:dword ptr[_d_sdivzorigin]	; sdivz = d_sdivzorigin + dv*d_sdivzstepv +
+;  du*d_sdivzstepu; stays in %st(2) at end
+ fxch st(4)	; dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
+;  s/z
+ fmul ds:dword ptr[_d_zistepv]	; dv*d_zistepv | dv*d_tdivzstepv |
+;  du*d_tdivzstepu | du | s/z
+ fxch st(1)	; dv*d_tdivzstepv |  dv*d_zistepv |
+;  du*d_tdivzstepu | du | s/z
+ faddp st(2),st(0)	; dv*d_zistepv |
+;  dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
+ fxch st(2)	; du | dv*d_tdivzstepv + du*d_tdivzstepu |
+;  dv*d_zistepv | s/z
+ fmul ds:dword ptr[_d_zistepu]	; du*d_zistepu |
+;  dv*d_tdivzstepv + du*d_tdivzstepu |
+;  dv*d_zistepv | s/z
+ fxch st(1)	; dv*d_tdivzstepv + du*d_tdivzstepu |
+;  du*d_zistepu | dv*d_zistepv | s/z
+ fadd ds:dword ptr[_d_tdivzorigin]	; tdivz = d_tdivzorigin + dv*d_tdivzstepv +
+;  du*d_tdivzstepu; stays in %st(1) at end
+ fxch st(2)	; dv*d_zistepv | du*d_zistepu | t/z | s/z
+ faddp st(1),st(0)	; dv*d_zistepv + du*d_zistepu | t/z | s/z
+
+ fld ds:dword ptr[fp_64k]	; fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
+ fxch st(1)	; dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
+ fadd ds:dword ptr[_d_ziorigin]	; zi = d_ziorigin + dv*d_zistepv +
+;  du*d_zistepu; stays in %st(0) at end
+; 1/z | fp_64k | t/z | s/z
+
+ fld st(0)	; FIXME: get rid of stall on FMUL?
+ fmul ds:dword ptr[fp_64kx64k]	
+ fxch st(1)	
+
+;
+; calculate and clamp s & t
+;
+ fdiv st(2),st(0)	; 1/z | z*64k | t/z | s/z
+ fxch st(1)	
+
+ fistp ds:dword ptr[izi]	; 0.32 fixed-point 1/z
+ mov ebp,ds:dword ptr[izi]	
+
+;
+; set pz to point to the first z-buffer pixel in the span
+;
+ ror ebp,16	; put upper 16 bits in low word
+ mov eax,ds:dword ptr[sspan_t_v+ebx]	
+ mov ds:dword ptr[izi],ebp	
+ mov ebp,ds:dword ptr[sspan_t_u+ebx]	
+ imul ds:dword ptr[_d_zrowbytes]	
+ shl ebp,1	; a word per pixel
+ add eax,ds:dword ptr[_d_pzbuffer]	
+ add eax,ebp	
+ mov ds:dword ptr[pz],eax	
+
+;
+; point %edi to the first pixel in the span
+;
+ mov ebp,ds:dword ptr[_d_viewbuffer]	
+ mov eax,ds:dword ptr[sspan_t_v+ebx]	
+ push ebx	; preserve spans pointer
+ mov edx,ds:dword ptr[_tadjust]	
+ mov esi,ds:dword ptr[_sadjust]	
+ mov edi,ds:dword ptr[_d_scantable+eax*4]	; v * screenwidth
+ add edi,ebp	
+ mov ebp,ds:dword ptr[sspan_t_u+ebx]	
+ add edi,ebp	; pdest = &pdestspan[scans->u];
+
+;
+; now start the FDIV for the end of the span
+;
+ cmp ecx,8	
+ ja LSetupNotLast1	
+
+ dec ecx	
+ jz LCleanup1	; if only one pixel, no need to start an FDIV
+ mov ds:dword ptr[spancountminus1],ecx	
+
+; finish up the s and t calcs
+ fxch st(1)	; z*64k | 1/z | t/z | s/z
+
+ fld st(0)	; z*64k | z*64k | 1/z | t/z | s/z
+ fmul st(0),st(4)	; s | z*64k | 1/z | t/z | s/z
+ fxch st(1)	; z*64k | s | 1/z | t/z | s/z
+ fmul st(0),st(3)	; t | s | 1/z | t/z | s/z
+ fxch st(1)	; s | t | 1/z | t/z | s/z
+ fistp ds:dword ptr[s]	; 1/z | t | t/z | s/z
+ fistp ds:dword ptr[t]	; 1/z | t/z | s/z
+
+ fild ds:dword ptr[spancountminus1]	
+
+ fld ds:dword ptr[_d_tdivzstepu]	; _d_tdivzstepu | spancountminus1
+ fld ds:dword ptr[_d_zistepu]	; _d_zistepu | _d_tdivzstepu | spancountminus1
+ fmul st(0),st(2)	; _d_zistepu*scm1 | _d_tdivzstepu | scm1
+ fxch st(1)	; _d_tdivzstepu | _d_zistepu*scm1 | scm1
+ fmul st(0),st(2)	; _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
+ fxch st(2)	; scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1
+ fmul ds:dword ptr[_d_sdivzstepu]	; _d_sdivzstepu*scm1 | _d_zistepu*scm1 |
+;  _d_tdivzstepu*scm1
+ fxch st(1)	; _d_zistepu*scm1 | _d_sdivzstepu*scm1 |
+;  _d_tdivzstepu*scm1
+ faddp st(3),st(0)	; _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
+ fxch st(1)	; _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
+ faddp st(3),st(0)	; _d_sdivzstepu*scm1
+ faddp st(3),st(0)	
+
+ fld ds:dword ptr[fp_64k]	
+ fdiv st(0),st(1)	; this is what we've gone to all this trouble to
+;  overlap
+ jmp LFDIVInFlight1	
+
+LCleanup1:	
+; finish up the s and t calcs
+ fxch st(1)	; z*64k | 1/z | t/z | s/z
+
+ fld st(0)	; z*64k | z*64k | 1/z | t/z | s/z
+ fmul st(0),st(4)	; s | z*64k | 1/z | t/z | s/z
+ fxch st(1)	; z*64k | s | 1/z | t/z | s/z
+ fmul st(0),st(3)	; t | s | 1/z | t/z | s/z
+ fxch st(1)	; s | t | 1/z | t/z | s/z
+ fistp ds:dword ptr[s]	; 1/z | t | t/z | s/z
+ fistp ds:dword ptr[t]	; 1/z | t/z | s/z
+ jmp LFDIVInFlight1	
+
+ align 4	
+LSetupNotLast1:	
+; finish up the s and t calcs
+ fxch st(1)	; z*64k | 1/z | t/z | s/z
+
+ fld st(0)	; z*64k | z*64k | 1/z | t/z | s/z
+ fmul st(0),st(4)	; s | z*64k | 1/z | t/z | s/z
+ fxch st(1)	; z*64k | s | 1/z | t/z | s/z
+ fmul st(0),st(3)	; t | s | 1/z | t/z | s/z
+ fxch st(1)	; s | t | 1/z | t/z | s/z
+ fistp ds:dword ptr[s]	; 1/z | t | t/z | s/z
+ fistp ds:dword ptr[t]	; 1/z | t/z | s/z
+
+ fadd ds:dword ptr[zi8stepu]	
+ fxch st(2)	
+ fadd ds:dword ptr[sdivz8stepu]	
+ fxch st(2)	
+ fld ds:dword ptr[tdivz8stepu]	
+ faddp st(2),st(0)	
+ fld ds:dword ptr[fp_64k]	
+ fdiv st(0),st(1)	; z = 1/1/z
+; this is what we've gone to all this trouble to
+;  overlap
+LFDIVInFlight1:	
+
+ add esi,ds:dword ptr[s]	
+ add edx,ds:dword ptr[t]	
+ mov ebx,ds:dword ptr[_bbextents]	
+ mov ebp,ds:dword ptr[_bbextentt]	
+ cmp esi,ebx	
+ ja LClampHighOrLow0	
+LClampReentry0:	
+ mov ds:dword ptr[s],esi	
+ mov ebx,ds:dword ptr[pbase]	
+ shl esi,16	
+ cmp edx,ebp	
+ mov ds:dword ptr[sfracf],esi	
+ ja LClampHighOrLow1	
+LClampReentry1:	
+ mov ds:dword ptr[t],edx	
+ mov esi,ds:dword ptr[s]	; sfrac = scans->sfrac;
+ shl edx,16	
+ mov eax,ds:dword ptr[t]	; tfrac = scans->tfrac;
+ sar esi,16	
+ mov ds:dword ptr[tfracf],edx	
+
+;
+; calculate the texture starting address
+;
+ sar eax,16	
+ add esi,ebx	
+ imul eax,ds:dword ptr[_cachewidth]	; (tfrac >> 16) * cachewidth
+ add esi,eax	; psource = pbase + (sfrac >> 16) +
+;           ((tfrac >> 16) * cachewidth);
+
+;
+; determine whether last span or not
+;
+ cmp ecx,8	
+ jna LLastSegment	
+
+;
+; not the last segment; do full 8-wide segment
+;
+LNotLastSegment:	
+
+;
+; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+; get there
+;
+
+; pick up after the FDIV that was left in flight previously
+
+ fld st(0)	; duplicate it
+ fmul st(0),st(4)	; s = s/z * z
+ fxch st(1)	
+ fmul st(0),st(3)	; t = t/z * z
+ fxch st(1)	
+ fistp ds:dword ptr[snext]	
+ fistp ds:dword ptr[tnext]	
+ mov eax,ds:dword ptr[snext]	
+ mov edx,ds:dword ptr[tnext]	
+
+ sub ecx,8	; count off this segments' pixels
+ mov ebp,ds:dword ptr[_sadjust]	
+ push ecx	; remember count of remaining pixels
+ mov ecx,ds:dword ptr[_tadjust]	
+
+ add ebp,eax	
+ add ecx,edx	
+
+ mov eax,ds:dword ptr[_bbextents]	
+ mov edx,ds:dword ptr[_bbextentt]	
+
+ cmp ebp,2048	
+ jl LClampLow2	
+ cmp ebp,eax	
+ ja LClampHigh2	
+LClampReentry2:	
+
+ cmp ecx,2048	
+ jl LClampLow3	
+ cmp ecx,edx	
+ ja LClampHigh3	
+LClampReentry3:	
+
+ mov ds:dword ptr[snext],ebp	
+ mov ds:dword ptr[tnext],ecx	
+
+ sub ebp,ds:dword ptr[s]	
+ sub ecx,ds:dword ptr[t]	
+
+;
+; set up advancetable
+;
+ mov eax,ecx	
+ mov edx,ebp	
+ sar edx,19	; sstep >>= 16;
+ mov ebx,ds:dword ptr[_cachewidth]	
+ sar eax,19	; tstep >>= 16;
+ jz LIsZero	
+ imul eax,ebx	; (tstep >> 16) * cachewidth;
+LIsZero:	
+ add eax,edx	; add in sstep
+; (tstep >> 16) * cachewidth + (sstep >> 16);
+ mov edx,ds:dword ptr[tfracf]	
+ mov ds:dword ptr[advancetable+4],eax	; advance base in t
+ add eax,ebx	; ((tstep >> 16) + 1) * cachewidth +
+;  (sstep >> 16);
+ shl ebp,13	; left-justify sstep fractional part
+ mov ds:dword ptr[sstep],ebp	
+ mov ebx,ds:dword ptr[sfracf]	
+ shl ecx,13	; left-justify tstep fractional part
+ mov ds:dword ptr[advancetable],eax	; advance extra in t
+ mov ds:dword ptr[tstep],ecx	
+
+ mov ecx,ds:dword ptr[pz]	
+ mov ebp,ds:dword ptr[izi]	
+
+ cmp bp,ds:word ptr[ecx]	
+ jl Lp1	
+ mov al,ds:byte ptr[esi]	; get first source texel
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp1	
+ mov ds:word ptr[ecx],bp	
+ mov ds:byte ptr[edi],al	; store first dest pixel
+Lp1:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	; advance tfrac fractional part by tstep frac
+
+ sbb eax,eax	; turn tstep carry into -1 (0 if none)
+ add ebx,ds:dword ptr[sstep]	; advance sfrac fractional part by sstep frac
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	; point to next source texel
+
+ cmp bp,ds:word ptr[2+ecx]	
+ jl Lp2	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp2	
+ mov ds:word ptr[2+ecx],bp	
+ mov ds:byte ptr[1+edi],al	
+Lp2:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ cmp bp,ds:word ptr[4+ecx]	
+ jl Lp3	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp3	
+ mov ds:word ptr[4+ecx],bp	
+ mov ds:byte ptr[2+edi],al	
+Lp3:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ cmp bp,ds:word ptr[6+ecx]	
+ jl Lp4	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp4	
+ mov ds:word ptr[6+ecx],bp	
+ mov ds:byte ptr[3+edi],al	
+Lp4:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ cmp bp,ds:word ptr[8+ecx]	
+ jl Lp5	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp5	
+ mov ds:word ptr[8+ecx],bp	
+ mov ds:byte ptr[4+edi],al	
+Lp5:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+;
+; start FDIV for end of next segment in flight, so it can overlap
+;
+ pop eax	
+ cmp eax,8	; more than one segment after this?
+ ja LSetupNotLast2	; yes
+
+ dec eax	
+ jz LFDIVInFlight2	; if only one pixel, no need to start an FDIV
+ mov ds:dword ptr[spancountminus1],eax	
+ fild ds:dword ptr[spancountminus1]	
+
+ fld ds:dword ptr[_d_zistepu]	; _d_zistepu | spancountminus1
+ fmul st(0),st(1)	; _d_zistepu*scm1 | scm1
+ fld ds:dword ptr[_d_tdivzstepu]	; _d_tdivzstepu | _d_zistepu*scm1 | scm1
+ fmul st(0),st(2)	; _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
+ fxch st(1)	; _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1
+ faddp st(3),st(0)	; _d_tdivzstepu*scm1 | scm1
+ fxch st(1)	; scm1 | _d_tdivzstepu*scm1
+ fmul ds:dword ptr[_d_sdivzstepu]	; _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
+ fxch st(1)	; _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
+ faddp st(3),st(0)	; _d_sdivzstepu*scm1
+ fld ds:dword ptr[fp_64k]	; 64k | _d_sdivzstepu*scm1
+ fxch st(1)	; _d_sdivzstepu*scm1 | 64k
+ faddp st(4),st(0)	; 64k
+
+ fdiv st(0),st(1)	; this is what we've gone to all this trouble to
+;  overlap
+ jmp LFDIVInFlight2	
+
+ align 4	
+LSetupNotLast2:	
+ fadd ds:dword ptr[zi8stepu]	
+ fxch st(2)	
+ fadd ds:dword ptr[sdivz8stepu]	
+ fxch st(2)	
+ fld ds:dword ptr[tdivz8stepu]	
+ faddp st(2),st(0)	
+ fld ds:dword ptr[fp_64k]	
+ fdiv st(0),st(1)	; z = 1/1/z
+; this is what we've gone to all this trouble to
+;  overlap
+LFDIVInFlight2:	
+ push eax	
+
+ cmp bp,ds:word ptr[10+ecx]	
+ jl Lp6	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp6	
+ mov ds:word ptr[10+ecx],bp	
+ mov ds:byte ptr[5+edi],al	
+Lp6:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ cmp bp,ds:word ptr[12+ecx]	
+ jl Lp7	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp7	
+ mov ds:word ptr[12+ecx],bp	
+ mov ds:byte ptr[6+edi],al	
+Lp7:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ cmp bp,ds:word ptr[14+ecx]	
+ jl Lp8	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp8	
+ mov ds:word ptr[14+ecx],bp	
+ mov ds:byte ptr[7+edi],al	
+Lp8:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+ add edi,8	
+ add ecx,16	
+ mov ds:dword ptr[tfracf],edx	
+ mov edx,ds:dword ptr[snext]	
+ mov ds:dword ptr[sfracf],ebx	
+ mov ebx,ds:dword ptr[tnext]	
+ mov ds:dword ptr[s],edx	
+ mov ds:dword ptr[t],ebx	
+
+ mov ds:dword ptr[pz],ecx	
+ mov ds:dword ptr[izi],ebp	
+
+ pop ecx	; retrieve count
+
+;
+; determine whether last span or not
+;
+ cmp ecx,8	; are there multiple segments remaining?
+ ja LNotLastSegment	; yes
+
+;
+; last segment of scan
+;
+LLastSegment:	
+
+;
+; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
+; get there. The number of pixels left is variable, and we want to land on the
+; last pixel, not step one past it, so we can't run into arithmetic problems
+;
+ test ecx,ecx	
+ jz LNoSteps	; just draw the last pixel and we're done
+
+; pick up after the FDIV that was left in flight previously
+
+
+ fld st(0)	; duplicate it
+ fmul st(0),st(4)	; s = s/z * z
+ fxch st(1)	
+ fmul st(0),st(3)	; t = t/z * z
+ fxch st(1)	
+ fistp ds:dword ptr[snext]	
+ fistp ds:dword ptr[tnext]	
+
+ mov ebx,ds:dword ptr[_tadjust]	
+ mov eax,ds:dword ptr[_sadjust]	
+
+ add eax,ds:dword ptr[snext]	
+ add ebx,ds:dword ptr[tnext]	
+
+ mov ebp,ds:dword ptr[_bbextents]	
+ mov edx,ds:dword ptr[_bbextentt]	
+
+ cmp eax,2048	
+ jl LClampLow4	
+ cmp eax,ebp	
+ ja LClampHigh4	
+LClampReentry4:	
+ mov ds:dword ptr[snext],eax	
+
+ cmp ebx,2048	
+ jl LClampLow5	
+ cmp ebx,edx	
+ ja LClampHigh5	
+LClampReentry5:	
+
+ cmp ecx,1	; don't bother 
+ je LOnlyOneStep	; if two pixels in segment, there's only one step,
+;  of the segment length
+ sub eax,ds:dword ptr[s]	
+ sub ebx,ds:dword ptr[t]	
+
+ add eax,eax	; convert to 15.17 format so multiply by 1.31
+ add ebx,ebx	;  reciprocal yields 16.48
+ imul ds:dword ptr[reciprocal_table-8+ecx*4]	; sstep = (snext - s) / (spancount-1)
+ mov ebp,edx	
+
+ mov eax,ebx	
+ imul ds:dword ptr[reciprocal_table-8+ecx*4]	; tstep = (tnext - t) / (spancount-1)
+
+LSetEntryvec:	
+;
+; set up advancetable
+;
+ mov ebx,ds:dword ptr[spr8entryvec_table+ecx*4]	
+ mov eax,edx	
+ push ebx	; entry point into code for RET later
+ mov ecx,ebp	
+ sar ecx,16	; sstep >>= 16;
+ mov ebx,ds:dword ptr[_cachewidth]	
+ sar edx,16	; tstep >>= 16;
+ jz LIsZeroLast	
+ imul edx,ebx	; (tstep >> 16) * cachewidth;
+LIsZeroLast:	
+ add edx,ecx	; add in sstep
+; (tstep >> 16) * cachewidth + (sstep >> 16);
+ mov ecx,ds:dword ptr[tfracf]	
+ mov ds:dword ptr[advancetable+4],edx	; advance base in t
+ add edx,ebx	; ((tstep >> 16) + 1) * cachewidth +
+;  (sstep >> 16);
+ shl ebp,16	; left-justify sstep fractional part
+ mov ebx,ds:dword ptr[sfracf]	
+ shl eax,16	; left-justify tstep fractional part
+ mov ds:dword ptr[advancetable],edx	; advance extra in t
+
+ mov ds:dword ptr[tstep],eax	
+ mov ds:dword ptr[sstep],ebp	
+ mov edx,ecx	
+
+ mov ecx,ds:dword ptr[pz]	
+ mov ebp,ds:dword ptr[izi]	
+
+ ret	; jump to the number-of-pixels handler
+
+;----------------------------------------
+
+LNoSteps:	
+ mov ecx,ds:dword ptr[pz]	
+ sub edi,7	; adjust for hardwired offset
+ sub ecx,14	
+ jmp LEndSpan	
+
+
+LOnlyOneStep:	
+ sub eax,ds:dword ptr[s]	
+ sub ebx,ds:dword ptr[t]	
+ mov ebp,eax	
+ mov edx,ebx	
+ jmp LSetEntryvec	
+
+;----------------------------------------
+
+ public Spr8Entry2_8	
+Spr8Entry2_8:	
+ sub edi,6	; adjust for hardwired offsets
+ sub ecx,12	
+ mov al,ds:byte ptr[esi]	
+ jmp LLEntry2_8	
+
+;----------------------------------------
+
+ public Spr8Entry3_8	
+Spr8Entry3_8:	
+ sub edi,5	; adjust for hardwired offsets
+ sub ecx,10	
+ jmp LLEntry3_8	
+
+;----------------------------------------
+
+ public Spr8Entry4_8	
+Spr8Entry4_8:	
+ sub edi,4	; adjust for hardwired offsets
+ sub ecx,8	
+ jmp LLEntry4_8	
+
+;----------------------------------------
+
+ public Spr8Entry5_8	
+Spr8Entry5_8:	
+ sub edi,3	; adjust for hardwired offsets
+ sub ecx,6	
+ jmp LLEntry5_8	
+
+;----------------------------------------
+
+ public Spr8Entry6_8	
+Spr8Entry6_8:	
+ sub edi,2	; adjust for hardwired offsets
+ sub ecx,4	
+ jmp LLEntry6_8	
+
+;----------------------------------------
+
+ public Spr8Entry7_8	
+Spr8Entry7_8:	
+ dec edi	; adjust for hardwired offsets
+ sub ecx,2	
+ jmp LLEntry7_8	
+
+;----------------------------------------
+
+ public Spr8Entry8_8	
+Spr8Entry8_8:	
+ cmp bp,ds:word ptr[ecx]	
+ jl Lp9	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp9	
+ mov ds:word ptr[ecx],bp	
+ mov ds:byte ptr[edi],al	
+Lp9:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+LLEntry7_8:	
+ cmp bp,ds:word ptr[2+ecx]	
+ jl Lp10	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp10	
+ mov ds:word ptr[2+ecx],bp	
+ mov ds:byte ptr[1+edi],al	
+Lp10:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+LLEntry6_8:	
+ cmp bp,ds:word ptr[4+ecx]	
+ jl Lp11	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp11	
+ mov ds:word ptr[4+ecx],bp	
+ mov ds:byte ptr[2+edi],al	
+Lp11:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+LLEntry5_8:	
+ cmp bp,ds:word ptr[6+ecx]	
+ jl Lp12	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp12	
+ mov ds:word ptr[6+ecx],bp	
+ mov ds:byte ptr[3+edi],al	
+Lp12:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+LLEntry4_8:	
+ cmp bp,ds:word ptr[8+ecx]	
+ jl Lp13	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp13	
+ mov ds:word ptr[8+ecx],bp	
+ mov ds:byte ptr[4+edi],al	
+Lp13:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+LLEntry3_8:	
+ cmp bp,ds:word ptr[10+ecx]	
+ jl Lp14	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp14	
+ mov ds:word ptr[10+ecx],bp	
+ mov ds:byte ptr[5+edi],al	
+Lp14:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+LLEntry2_8:	
+ cmp bp,ds:word ptr[12+ecx]	
+ jl Lp15	
+ mov al,ds:byte ptr[esi]	
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp15	
+ mov ds:word ptr[12+ecx],bp	
+ mov ds:byte ptr[6+edi],al	
+Lp15:	
+ add ebp,ds:dword ptr[izistep]	
+ adc ebp,0	
+ add edx,ds:dword ptr[tstep]	
+ sbb eax,eax	
+ add ebx,ds:dword ptr[sstep]	
+ adc esi,ds:dword ptr[advancetable+4+eax*4]	
+
+LEndSpan:	
+ cmp bp,ds:word ptr[14+ecx]	
+ jl Lp16	
+ mov al,ds:byte ptr[esi]	; load first texel in segment
+ cmp al,offset TRANSPARENT_COLOR	
+ jz Lp16	
+ mov ds:word ptr[14+ecx],bp	
+ mov ds:byte ptr[7+edi],al	
+Lp16:	
+
+;
+; clear s/z, t/z, 1/z from FP stack
+;
+ fstp st(0)	
+ fstp st(0)	
+ fstp st(0)	
+
+ pop ebx	; restore spans pointer
+LNextSpan:	
+ add ebx,offset sspan_t_size	; point to next span
+ mov ecx,ds:dword ptr[sspan_t_count+ebx]	
+ cmp ecx,0	; any more spans?
+ jg LSpanLoop	; yes
+ jz LNextSpan	; yes, but this one's empty
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+_TEXT ENDS
+endif	; id386
+ END
--- /dev/null
+++ b/ref_soft/r_sprite.c
@@ -1,0 +1,123 @@
+/*
+Copyright (C) 1997-2001 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_sprite.c
+#include "r_local.h"
+
+extern polydesc_t r_polydesc;
+
+void R_BuildPolygonFromSurface(msurface_t *fa);
+void R_PolygonCalculateGradients (void);
+
+extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
+
+extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
+
+extern void	R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
+
+/*
+** R_DrawSprite
+**
+** Draw currententity / currentmodel as a single texture
+** mapped polygon
+*/
+void R_DrawSprite (void)
+{
+	vec5_t		*pverts;
+	vec3_t		left, up, right, down;
+	dsprite_t	*s_psprite;
+	dsprframe_t	*s_psprframe;
+
+
+	s_psprite = (dsprite_t *)currentmodel->extradata;
+#if 0
+	if (currententity->frame >= s_psprite->numframes
+		|| currententity->frame < 0)
+	{
+		ri.Con_Printf (PRINT_ALL, "No such sprite frame %i\n", 
+			currententity->frame);
+		currententity->frame = 0;
+	}
+#endif
+	currententity->frame %= s_psprite->numframes;
+
+	s_psprframe = &s_psprite->frames[currententity->frame];
+
+	r_polydesc.pixels       = currentmodel->skins[currententity->frame]->pixels[0];
+	r_polydesc.pixel_width  = s_psprframe->width;
+	r_polydesc.pixel_height = s_psprframe->height;
+	r_polydesc.dist         = 0;
+
+	// generate the sprite's axes, completely parallel to the viewplane.
+	VectorCopy (vup, r_polydesc.vup);
+	VectorCopy (vright, r_polydesc.vright);
+	VectorCopy (vpn, r_polydesc.vpn);
+
+// build the sprite poster in worldspace
+	VectorScale (r_polydesc.vright, 
+		s_psprframe->width - s_psprframe->origin_x, right);
+	VectorScale (r_polydesc.vup, 
+		s_psprframe->height - s_psprframe->origin_y, up);
+	VectorScale (r_polydesc.vright,
+		-s_psprframe->origin_x, left);
+	VectorScale (r_polydesc.vup,
+		-s_psprframe->origin_y, down);
+
+	// invert UP vector for sprites
+	VectorInverse( r_polydesc.vup );
+
+	pverts = r_clip_verts[0];
+
+	pverts[0][0] = r_entorigin[0] + up[0] + left[0];
+	pverts[0][1] = r_entorigin[1] + up[1] + left[1];
+	pverts[0][2] = r_entorigin[2] + up[2] + left[2];
+	pverts[0][3] = 0;
+	pverts[0][4] = 0;
+
+	pverts[1][0] = r_entorigin[0] + up[0] + right[0];
+	pverts[1][1] = r_entorigin[1] + up[1] + right[1];
+	pverts[1][2] = r_entorigin[2] + up[2] + right[2];
+	pverts[1][3] = s_psprframe->width;
+	pverts[1][4] = 0;
+
+	pverts[2][0] = r_entorigin[0] + down[0] + right[0];
+	pverts[2][1] = r_entorigin[1] + down[1] + right[1];
+	pverts[2][2] = r_entorigin[2] + down[2] + right[2];
+	pverts[2][3] = s_psprframe->width;
+	pverts[2][4] = s_psprframe->height;
+
+	pverts[3][0] = r_entorigin[0] + down[0] + left[0];
+	pverts[3][1] = r_entorigin[1] + down[1] + left[1];
+	pverts[3][2] = r_entorigin[2] + down[2] + left[2];
+	pverts[3][3] = 0;
+	pverts[3][4] = s_psprframe->height;
+
+	r_polydesc.nump = 4;
+	r_polydesc.s_offset = ( r_polydesc.pixel_width  >> 1);
+	r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
+	VectorCopy( modelorg, r_polydesc.viewer_position );
+
+	r_polydesc.stipple_parity = 1;
+	if ( currententity->flags & RF_TRANSLUCENT )
+		R_ClipAndDrawPoly ( currententity->alpha, false, true );
+	else
+		R_ClipAndDrawPoly ( 1.0F, false, true );
+	r_polydesc.stipple_parity = 0;
+}
+
--- /dev/null
+++ b/ref_soft/r_surf.c
@@ -1,0 +1,651 @@
+/*
+Copyright (C) 1997-2001 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 "r_local.h"
+
+drawsurf_t	r_drawsurf;
+
+int				lightleft, sourcesstep, blocksize, sourcetstep;
+int				lightdelta, lightdeltastep;
+int				lightright, lightleftstep, lightrightstep, blockdivshift;
+unsigned		blockdivmask;
+void			*prowdestbase;
+unsigned char	*pbasesource;
+int				surfrowbytes;	// used by ASM files
+unsigned		*r_lightptr;
+int				r_stepback;
+int				r_lightwidth;
+int				r_numhblocks, r_numvblocks;
+unsigned char	*r_source, *r_sourcemax;
+
+void R_DrawSurfaceBlock8_mip0 (void);
+void R_DrawSurfaceBlock8_mip1 (void);
+void R_DrawSurfaceBlock8_mip2 (void);
+void R_DrawSurfaceBlock8_mip3 (void);
+
+static void	(*surfmiptable[4])(void) = {
+	R_DrawSurfaceBlock8_mip0,
+	R_DrawSurfaceBlock8_mip1,
+	R_DrawSurfaceBlock8_mip2,
+	R_DrawSurfaceBlock8_mip3
+};
+
+void R_BuildLightMap (void);
+extern	unsigned		blocklights[1024];	// allow some very large lightmaps
+
+float           surfscale;
+qboolean        r_cache_thrash;         // set if surface cache is thrashing
+
+int         sc_size;
+surfcache_t	*sc_rover, *sc_base;
+
+/*
+===============
+R_TextureAnimation
+
+Returns the proper texture for a given time and base texture
+===============
+*/
+image_t *R_TextureAnimation (mtexinfo_t *tex)
+{
+	int		c;
+
+	if (!tex->next)
+		return tex->image;
+
+	c = currententity->frame % tex->numframes;
+	while (c)
+	{
+		tex = tex->next;
+		c--;
+	}
+
+	return tex->image;
+}
+
+
+/*
+===============
+R_DrawSurface
+===============
+*/
+void R_DrawSurface (void)
+{
+	unsigned char	*basetptr;
+	int				smax, tmax, twidth;
+	int				u;
+	int				soffset, basetoffset, texwidth;
+	int				horzblockstep;
+	unsigned char	*pcolumndest;
+	void			(*pblockdrawer)(void);
+	image_t			*mt;
+
+	surfrowbytes = r_drawsurf.rowbytes;
+
+	mt = r_drawsurf.image;
+	
+	r_source = mt->pixels[r_drawsurf.surfmip];
+	
+// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
+// from a source range of 0 - 255
+	
+	texwidth = mt->width >> r_drawsurf.surfmip;
+
+	blocksize = 16 >> r_drawsurf.surfmip;
+	blockdivshift = 4 - r_drawsurf.surfmip;
+	blockdivmask = (1 << blockdivshift) - 1;
+	
+	r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
+
+	r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
+	r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
+
+//==============================
+
+	pblockdrawer = surfmiptable[r_drawsurf.surfmip];
+// TODO: only needs to be set when there is a display settings change
+	horzblockstep = blocksize;
+
+	smax = mt->width >> r_drawsurf.surfmip;
+	twidth = texwidth;
+	tmax = mt->height >> r_drawsurf.surfmip;
+	sourcetstep = texwidth;
+	r_stepback = tmax * twidth;
+
+	r_sourcemax = r_source + (tmax * smax);
+
+	soffset = r_drawsurf.surf->texturemins[0];
+	basetoffset = r_drawsurf.surf->texturemins[1];
+
+// << 16 components are to guarantee positive values for %
+	soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
+	basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) 
+		+ (tmax << 16)) % tmax) * twidth)];
+
+	pcolumndest = r_drawsurf.surfdat;
+
+	for (u=0 ; u<r_numhblocks; u++)
+	{
+		r_lightptr = blocklights + u;
+
+		prowdestbase = pcolumndest;
+
+		pbasesource = basetptr + soffset;
+
+		(*pblockdrawer)();
+
+		soffset = soffset + blocksize;
+		if (soffset >= smax)
+			soffset = 0;
+
+		pcolumndest += horzblockstep;
+	}
+}
+
+
+//=============================================================================
+
+#if	!id386
+
+/*
+================
+R_DrawSurfaceBlock8_mip0
+================
+*/
+void R_DrawSurfaceBlock8_mip0 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 4;
+		lightrightstep = (r_lightptr[1] - lightright) >> 4;
+
+		for (i=0 ; i<16 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 4;
+
+			light = lightright;
+
+			for (b=15; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip1
+================
+*/
+void R_DrawSurfaceBlock8_mip1 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 3;
+		lightrightstep = (r_lightptr[1] - lightright) >> 3;
+
+		for (i=0 ; i<8 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 3;
+
+			light = lightright;
+
+			for (b=7; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip2
+================
+*/
+void R_DrawSurfaceBlock8_mip2 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 2;
+		lightrightstep = (r_lightptr[1] - lightright) >> 2;
+
+		for (i=0 ; i<4 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 2;
+
+			light = lightright;
+
+			for (b=3; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip3
+================
+*/
+void R_DrawSurfaceBlock8_mip3 (void)
+{
+	int				v, i, b, lightstep, lighttemp, light;
+	unsigned char	pix, *psource, *prowdest;
+
+	psource = pbasesource;
+	prowdest = prowdestbase;
+
+	for (v=0 ; v<r_numvblocks ; v++)
+	{
+	// FIXME: make these locals?
+	// FIXME: use delta rather than both right and left, like ASM?
+		lightleft = r_lightptr[0];
+		lightright = r_lightptr[1];
+		r_lightptr += r_lightwidth;
+		lightleftstep = (r_lightptr[0] - lightleft) >> 1;
+		lightrightstep = (r_lightptr[1] - lightright) >> 1;
+
+		for (i=0 ; i<2 ; i++)
+		{
+			lighttemp = lightleft - lightright;
+			lightstep = lighttemp >> 1;
+
+			light = lightright;
+
+			for (b=1; b>=0; b--)
+			{
+				pix = psource[b];
+				prowdest[b] = ((unsigned char *)vid.colormap)
+						[(light & 0xFF00) + pix];
+				light += lightstep;
+			}
+	
+			psource += sourcetstep;
+			lightright += lightrightstep;
+			lightleft += lightleftstep;
+			prowdest += surfrowbytes;
+		}
+
+		if (psource >= r_sourcemax)
+			psource -= r_stepback;
+	}
+}
+
+#endif
+
+
+//============================================================================
+
+
+/*
+================
+R_InitCaches
+
+================
+*/
+void R_InitCaches (void)
+{
+	int		size;
+	int		pix;
+
+	// calculate size to allocate
+	if (sw_surfcacheoverride->value)
+	{
+		size = sw_surfcacheoverride->value;
+	}
+	else
+	{
+		size = SURFCACHE_SIZE_AT_320X240;
+
+		pix = vid.width*vid.height;
+		if (pix > 64000)
+			size += (pix-64000)*3;
+	}		
+
+	// round up to page size
+	size = (size + 8191) & ~8191;
+
+	ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
+
+	sc_size = size;
+	sc_base = (surfcache_t *)malloc(size);
+	sc_rover = sc_base;
+	
+	sc_base->next = NULL;
+	sc_base->owner = NULL;
+	sc_base->size = sc_size;
+}
+
+
+/*
+==================
+D_FlushCaches
+==================
+*/
+void D_FlushCaches (void)
+{
+	surfcache_t     *c;
+	
+	if (!sc_base)
+		return;
+
+	for (c = sc_base ; c ; c = c->next)
+	{
+		if (c->owner)
+			*c->owner = NULL;
+	}
+	
+	sc_rover = sc_base;
+	sc_base->next = NULL;
+	sc_base->owner = NULL;
+	sc_base->size = sc_size;
+}
+
+/*
+=================
+D_SCAlloc
+=================
+*/
+surfcache_t     *D_SCAlloc (int width, int size)
+{
+	surfcache_t             *new;
+	qboolean                wrapped_this_time;
+
+	if ((width < 0) || (width > 256))
+		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
+
+	if ((size <= 0) || (size > 0x10000))
+		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
+	
+	size = (int)&((surfcache_t *)0)->data[size];
+	size = (size + 3) & ~3;
+	if (size > sc_size)
+		ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
+
+// if there is not size bytes after the rover, reset to the start
+	wrapped_this_time = false;
+
+	if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
+	{
+		if (sc_rover)
+		{
+			wrapped_this_time = true;
+		}
+		sc_rover = sc_base;
+	}
+		
+// colect and free surfcache_t blocks until the rover block is large enough
+	new = sc_rover;
+	if (sc_rover->owner)
+		*sc_rover->owner = NULL;
+	
+	while (new->size < size)
+	{
+	// free another
+		sc_rover = sc_rover->next;
+		if (!sc_rover)
+			ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
+		if (sc_rover->owner)
+			*sc_rover->owner = NULL;
+			
+		new->size += sc_rover->size;
+		new->next = sc_rover->next;
+	}
+
+// create a fragment out of any leftovers
+	if (new->size - size > 256)
+	{
+		sc_rover = (surfcache_t *)( (byte *)new + size);
+		sc_rover->size = new->size - size;
+		sc_rover->next = new->next;
+		sc_rover->width = 0;
+		sc_rover->owner = NULL;
+		new->next = sc_rover;
+		new->size = size;
+	}
+	else
+		sc_rover = new->next;
+	
+	new->width = width;
+// DEBUG
+	if (width > 0)
+		new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
+
+	new->owner = NULL;              // should be set properly after return
+
+	if (d_roverwrapped)
+	{
+		if (wrapped_this_time || (sc_rover >= d_initial_rover))
+			r_cache_thrash = true;
+	}
+	else if (wrapped_this_time)
+	{       
+		d_roverwrapped = true;
+	}
+
+	return new;
+}
+
+
+/*
+=================
+D_SCDump
+=================
+*/
+void D_SCDump (void)
+{
+	surfcache_t             *test;
+
+	for (test = sc_base ; test ; test = test->next)
+	{
+		if (test == sc_rover)
+			ri.Con_Printf (PRINT_ALL,"ROVER:\n");
+		ri.Con_Printf (PRINT_ALL,"%p : %i bytes     %i width\n",test, test->size, test->width);
+	}
+}
+
+//=============================================================================
+
+// if the num is not a power of 2, assume it will not repeat
+
+int     MaskForNum (int num)
+{
+	if (num==128)
+		return 127;
+	if (num==64)
+		return 63;
+	if (num==32)
+		return 31;
+	if (num==16)
+		return 15;
+	return 255;
+}
+
+int D_log2 (int num)
+{
+	int     c;
+	
+	c = 0;
+	
+	while (num>>=1)
+		c++;
+	return c;
+}
+
+//=============================================================================
+
+/*
+================
+D_CacheSurface
+================
+*/
+surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
+{
+	surfcache_t     *cache;
+
+//
+// if the surface is animating or flashing, flush the cache
+//
+	r_drawsurf.image = R_TextureAnimation (surface->texinfo);
+	r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
+	r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
+	r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
+	r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
+	
+//
+// see if the cache holds apropriate data
+//
+	cache = surface->cachespots[miplevel];
+
+	if (cache && !cache->dlight && surface->dlightframe != r_framecount
+			&& cache->image == r_drawsurf.image
+			&& cache->lightadj[0] == r_drawsurf.lightadj[0]
+			&& cache->lightadj[1] == r_drawsurf.lightadj[1]
+			&& cache->lightadj[2] == r_drawsurf.lightadj[2]
+			&& cache->lightadj[3] == r_drawsurf.lightadj[3] )
+		return cache;
+
+//
+// determine shape of surface
+//
+	surfscale = 1.0 / (1<<miplevel);
+	r_drawsurf.surfmip = miplevel;
+	r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
+	r_drawsurf.rowbytes = r_drawsurf.surfwidth;
+	r_drawsurf.surfheight = surface->extents[1] >> miplevel;
+	
+//
+// allocate memory if needed
+//
+	if (!cache)     // if a texture just animated, don't reallocate it
+	{
+		cache = D_SCAlloc (r_drawsurf.surfwidth,
+						   r_drawsurf.surfwidth * r_drawsurf.surfheight);
+		surface->cachespots[miplevel] = cache;
+		cache->owner = &surface->cachespots[miplevel];
+		cache->mipscale = surfscale;
+	}
+	
+	if (surface->dlightframe == r_framecount)
+		cache->dlight = 1;
+	else
+		cache->dlight = 0;
+
+	r_drawsurf.surfdat = (pixel_t *)cache->data;
+	
+	cache->image = r_drawsurf.image;
+	cache->lightadj[0] = r_drawsurf.lightadj[0];
+	cache->lightadj[1] = r_drawsurf.lightadj[1];
+	cache->lightadj[2] = r_drawsurf.lightadj[2];
+	cache->lightadj[3] = r_drawsurf.lightadj[3];
+
+//
+// draw and light the surface texture
+//
+	r_drawsurf.surf = surface;
+
+	c_surf++;
+
+	// calculate the lightings
+	R_BuildLightMap ();
+	
+	// rasterize the surface into the cache
+	R_DrawSurface ();
+
+	return cache;
+}
+
+
--- /dev/null
+++ b/ref_soft/r_surf8.asm
@@ -1,0 +1,771 @@
+ .386P
+ .model FLAT
+;
+; surf8.s
+; x86 assembly-language 8 bpp surface block drawing code.
+;
+
+include qasm.inc
+
+if	id386
+
+_DATA SEGMENT	
+
+sb_v dd 0	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+ align 4	
+ public _R_Surf8Start	
+_R_Surf8Start:	
+
+;----------------------------------------------------------------------
+; Surface block drawer for mip level 0
+;----------------------------------------------------------------------
+
+ align 4	
+ public _R_DrawSurfaceBlock8_mip0	
+_R_DrawSurfaceBlock8_mip0:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+;		for (v=0 ; v<numvblocks ; v++)
+;		{
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ mov eax,ds:dword ptr[_r_numvblocks]	
+
+ mov ds:dword ptr[sb_v],eax	
+ mov edi,ds:dword ptr[_prowdestbase]	
+
+ mov esi,ds:dword ptr[_pbasesource]	
+
+Lv_loop_mip0:	
+
+;			lightleft = lightptr[0];
+;			lightright = lightptr[1];
+;			lightdelta = (lightleft - lightright) & 0xFFFFF;
+ mov eax,ds:dword ptr[ebx]	; lightleft
+ mov edx,ds:dword ptr[4+ebx]	; lightright
+
+ mov ebp,eax	
+ mov ecx,ds:dword ptr[_r_lightwidth]	
+
+ mov ds:dword ptr[_lightright],edx	
+ sub ebp,edx	
+
+ and ebp,0FFFFFh	
+ lea ebx,ds:dword ptr[ebx+ecx*4]	
+
+;			lightptr += lightwidth;
+ mov ds:dword ptr[_r_lightptr],ebx	
+
+;			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+;			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+;			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+;					0xF0000000;
+ mov ecx,ds:dword ptr[4+ebx]	; lightptr[1]
+ mov ebx,ds:dword ptr[ebx]	; lightptr[0]
+
+ sub ebx,eax	
+ sub ecx,edx	
+
+ sar ecx,4	
+ or ebp,0F0000000h	
+
+ sar ebx,4	
+ mov ds:dword ptr[_lightrightstep],ecx	
+
+ sub ebx,ecx	
+ and ebx,0FFFFFh	
+
+ or ebx,0F0000000h	
+ sub ecx,ecx	; high word must be 0 in loop for addressing
+
+ mov ds:dword ptr[_lightdeltastep],ebx	
+ sub ebx,ebx	; high word must be 0 in loop for addressing
+
+Lblockloop8_mip0:	
+ mov ds:dword ptr[_lightdelta],ebp	
+ mov cl,ds:byte ptr[14+esi]	
+
+ sar ebp,4	
+ mov bh,dh	
+
+ mov bl,ds:byte ptr[15+esi]	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch0:	
+ mov bl,ds:byte ptr[13+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch1:	
+ mov cl,ds:byte ptr[12+esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ add edx,ebp	
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch2:	
+
+ mov bl,ds:byte ptr[11+esi]	
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch3:	
+
+ mov cl,ds:byte ptr[10+esi]	
+ mov ds:dword ptr[12+edi],eax	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch4:	
+ mov bl,ds:byte ptr[9+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch5:	
+ mov cl,ds:byte ptr[8+esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ add edx,ebp	
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch6:	
+
+ mov bl,ds:byte ptr[7+esi]	
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch7:	
+
+ mov cl,ds:byte ptr[6+esi]	
+ mov ds:dword ptr[8+edi],eax	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch8:	
+ mov bl,ds:byte ptr[5+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch9:	
+ mov cl,ds:byte ptr[4+esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ add edx,ebp	
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch10:	
+
+ mov bl,ds:byte ptr[3+esi]	
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch11:	
+
+ mov cl,ds:byte ptr[2+esi]	
+ mov ds:dword ptr[4+edi],eax	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch12:	
+ mov bl,ds:byte ptr[1+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch13:	
+ mov cl,ds:byte ptr[esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch14:	
+ mov edx,ds:dword ptr[_lightright]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch15:	
+ mov ebp,ds:dword ptr[_lightdelta]	
+
+ mov ds:dword ptr[edi],eax	
+
+ add esi,ds:dword ptr[_sourcetstep]	
+ add edi,ds:dword ptr[_surfrowbytes]	
+
+ add edx,ds:dword ptr[_lightrightstep]	
+ add ebp,ds:dword ptr[_lightdeltastep]	
+
+ mov ds:dword ptr[_lightright],edx	
+ jc Lblockloop8_mip0	
+
+;			if (pbasesource >= r_sourcemax)
+;				pbasesource -= stepback;
+
+ cmp esi,ds:dword ptr[_r_sourcemax]	
+ jb LSkip_mip0	
+ sub esi,ds:dword ptr[_r_stepback]	
+LSkip_mip0:	
+
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ dec ds:dword ptr[sb_v]	
+
+ jnz Lv_loop_mip0	
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+;----------------------------------------------------------------------
+; Surface block drawer for mip level 1
+;----------------------------------------------------------------------
+
+ align 4	
+ public _R_DrawSurfaceBlock8_mip1	
+_R_DrawSurfaceBlock8_mip1:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+;		for (v=0 ; v<numvblocks ; v++)
+;		{
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ mov eax,ds:dword ptr[_r_numvblocks]	
+
+ mov ds:dword ptr[sb_v],eax	
+ mov edi,ds:dword ptr[_prowdestbase]	
+
+ mov esi,ds:dword ptr[_pbasesource]	
+
+Lv_loop_mip1:	
+
+;			lightleft = lightptr[0];
+;			lightright = lightptr[1];
+;			lightdelta = (lightleft - lightright) & 0xFFFFF;
+ mov eax,ds:dword ptr[ebx]	; lightleft
+ mov edx,ds:dword ptr[4+ebx]	; lightright
+
+ mov ebp,eax	
+ mov ecx,ds:dword ptr[_r_lightwidth]	
+
+ mov ds:dword ptr[_lightright],edx	
+ sub ebp,edx	
+
+ and ebp,0FFFFFh	
+ lea ebx,ds:dword ptr[ebx+ecx*4]	
+
+;			lightptr += lightwidth;
+ mov ds:dword ptr[_r_lightptr],ebx	
+
+;			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+;			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+;			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+;					0xF0000000;
+ mov ecx,ds:dword ptr[4+ebx]	; lightptr[1]
+ mov ebx,ds:dword ptr[ebx]	; lightptr[0]
+
+ sub ebx,eax	
+ sub ecx,edx	
+
+ sar ecx,3	
+ or ebp,070000000h	
+
+ sar ebx,3	
+ mov ds:dword ptr[_lightrightstep],ecx	
+
+ sub ebx,ecx	
+ and ebx,0FFFFFh	
+
+ or ebx,0F0000000h	
+ sub ecx,ecx	; high word must be 0 in loop for addressing
+
+ mov ds:dword ptr[_lightdeltastep],ebx	
+ sub ebx,ebx	; high word must be 0 in loop for addressing
+
+Lblockloop8_mip1:	
+ mov ds:dword ptr[_lightdelta],ebp	
+ mov cl,ds:byte ptr[6+esi]	
+
+ sar ebp,3	
+ mov bh,dh	
+
+ mov bl,ds:byte ptr[7+esi]	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch22:	
+ mov bl,ds:byte ptr[5+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch23:	
+ mov cl,ds:byte ptr[4+esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ add edx,ebp	
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch24:	
+
+ mov bl,ds:byte ptr[3+esi]	
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch25:	
+
+ mov cl,ds:byte ptr[2+esi]	
+ mov ds:dword ptr[4+edi],eax	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch26:	
+ mov bl,ds:byte ptr[1+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch27:	
+ mov cl,ds:byte ptr[esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch28:	
+ mov edx,ds:dword ptr[_lightright]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch29:	
+ mov ebp,ds:dword ptr[_lightdelta]	
+
+ mov ds:dword ptr[edi],eax	
+ mov eax,ds:dword ptr[_sourcetstep]	
+
+ add esi,eax	
+ mov eax,ds:dword ptr[_surfrowbytes]	
+
+ add edi,eax	
+ mov eax,ds:dword ptr[_lightrightstep]	
+
+ add edx,eax	
+ mov eax,ds:dword ptr[_lightdeltastep]	
+
+ add ebp,eax	
+ mov ds:dword ptr[_lightright],edx	
+
+ jc Lblockloop8_mip1	
+
+;			if (pbasesource >= r_sourcemax)
+;				pbasesource -= stepback;
+
+ cmp esi,ds:dword ptr[_r_sourcemax]	
+ jb LSkip_mip1	
+ sub esi,ds:dword ptr[_r_stepback]	
+LSkip_mip1:	
+
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ dec ds:dword ptr[sb_v]	
+
+ jnz Lv_loop_mip1	
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+;----------------------------------------------------------------------
+; Surface block drawer for mip level 2
+;----------------------------------------------------------------------
+
+ align 4	
+ public _R_DrawSurfaceBlock8_mip2	
+_R_DrawSurfaceBlock8_mip2:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+;		for (v=0 ; v<numvblocks ; v++)
+;		{
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ mov eax,ds:dword ptr[_r_numvblocks]	
+
+ mov ds:dword ptr[sb_v],eax	
+ mov edi,ds:dword ptr[_prowdestbase]	
+
+ mov esi,ds:dword ptr[_pbasesource]	
+
+Lv_loop_mip2:	
+
+;			lightleft = lightptr[0];
+;			lightright = lightptr[1];
+;			lightdelta = (lightleft - lightright) & 0xFFFFF;
+ mov eax,ds:dword ptr[ebx]	; lightleft
+ mov edx,ds:dword ptr[4+ebx]	; lightright
+
+ mov ebp,eax	
+ mov ecx,ds:dword ptr[_r_lightwidth]	
+
+ mov ds:dword ptr[_lightright],edx	
+ sub ebp,edx	
+
+ and ebp,0FFFFFh	
+ lea ebx,ds:dword ptr[ebx+ecx*4]	
+
+;			lightptr += lightwidth;
+ mov ds:dword ptr[_r_lightptr],ebx	
+
+;			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+;			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+;			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+;					0xF0000000;
+ mov ecx,ds:dword ptr[4+ebx]	; lightptr[1]
+ mov ebx,ds:dword ptr[ebx]	; lightptr[0]
+
+ sub ebx,eax	
+ sub ecx,edx	
+
+ sar ecx,2	
+ or ebp,030000000h	
+
+ sar ebx,2	
+ mov ds:dword ptr[_lightrightstep],ecx	
+
+ sub ebx,ecx	
+
+ and ebx,0FFFFFh	
+
+ or ebx,0F0000000h	
+ sub ecx,ecx	; high word must be 0 in loop for addressing
+
+ mov ds:dword ptr[_lightdeltastep],ebx	
+ sub ebx,ebx	; high word must be 0 in loop for addressing
+
+Lblockloop8_mip2:	
+ mov ds:dword ptr[_lightdelta],ebp	
+ mov cl,ds:byte ptr[2+esi]	
+
+ sar ebp,2	
+ mov bh,dh	
+
+ mov bl,ds:byte ptr[3+esi]	
+ add edx,ebp	
+
+ mov ch,dh	
+ add edx,ebp	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch18:	
+ mov bl,ds:byte ptr[1+esi]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch19:	
+ mov cl,ds:byte ptr[esi]	
+
+ mov bh,dh	
+ add edx,ebp	
+
+ ror eax,16	
+ mov ch,dh	
+
+ mov ah,ds:byte ptr[12345678h+ebx]	
+LBPatch20:	
+ mov edx,ds:dword ptr[_lightright]	
+
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch21:	
+ mov ebp,ds:dword ptr[_lightdelta]	
+
+ mov ds:dword ptr[edi],eax	
+ mov eax,ds:dword ptr[_sourcetstep]	
+
+ add esi,eax	
+ mov eax,ds:dword ptr[_surfrowbytes]	
+
+ add edi,eax	
+ mov eax,ds:dword ptr[_lightrightstep]	
+
+ add edx,eax	
+ mov eax,ds:dword ptr[_lightdeltastep]	
+
+ add ebp,eax	
+ mov ds:dword ptr[_lightright],edx	
+
+ jc Lblockloop8_mip2	
+
+;			if (pbasesource >= r_sourcemax)
+;				pbasesource -= stepback;
+
+ cmp esi,ds:dword ptr[_r_sourcemax]	
+ jb LSkip_mip2	
+ sub esi,ds:dword ptr[_r_stepback]	
+LSkip_mip2:	
+
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ dec ds:dword ptr[sb_v]	
+
+ jnz Lv_loop_mip2	
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+;----------------------------------------------------------------------
+; Surface block drawer for mip level 3
+;----------------------------------------------------------------------
+
+ align 4	
+ public _R_DrawSurfaceBlock8_mip3	
+_R_DrawSurfaceBlock8_mip3:	
+ push ebp	; preserve caller's stack frame
+ push edi	
+ push esi	; preserve register variables
+ push ebx	
+
+;		for (v=0 ; v<numvblocks ; v++)
+;		{
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ mov eax,ds:dword ptr[_r_numvblocks]	
+
+ mov ds:dword ptr[sb_v],eax	
+ mov edi,ds:dword ptr[_prowdestbase]	
+
+ mov esi,ds:dword ptr[_pbasesource]	
+
+Lv_loop_mip3:	
+
+;			lightleft = lightptr[0];
+;			lightright = lightptr[1];
+;			lightdelta = (lightleft - lightright) & 0xFFFFF;
+ mov eax,ds:dword ptr[ebx]	; lightleft
+ mov edx,ds:dword ptr[4+ebx]	; lightright
+
+ mov ebp,eax	
+ mov ecx,ds:dword ptr[_r_lightwidth]	
+
+ mov ds:dword ptr[_lightright],edx	
+ sub ebp,edx	
+
+ and ebp,0FFFFFh	
+ lea ebx,ds:dword ptr[ebx+ecx*4]	
+
+ mov ds:dword ptr[_lightdelta],ebp	
+;			lightptr += lightwidth;
+ mov ds:dword ptr[_r_lightptr],ebx	
+
+;			lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
+;			lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
+;			lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
+;					0xF0000000;
+ mov ecx,ds:dword ptr[4+ebx]	; lightptr[1]
+ mov ebx,ds:dword ptr[ebx]	; lightptr[0]
+
+ sub ebx,eax	
+ sub ecx,edx	
+
+ sar ecx,1	
+
+ sar ebx,1	
+ mov ds:dword ptr[_lightrightstep],ecx	
+
+ sub ebx,ecx	
+ and ebx,0FFFFFh	
+
+ sar ebp,1	
+ or ebx,0F0000000h	
+
+ mov ds:dword ptr[_lightdeltastep],ebx	
+ sub ebx,ebx	; high word must be 0 in loop for addressing
+
+ mov bl,ds:byte ptr[1+esi]	
+ sub ecx,ecx	; high word must be 0 in loop for addressing
+
+ mov bh,dh	
+ mov cl,ds:byte ptr[esi]	
+
+ add edx,ebp	
+ mov ch,dh	
+
+ mov al,ds:byte ptr[12345678h+ebx]	
+LBPatch16:	
+ mov edx,ds:dword ptr[_lightright]	
+
+ mov ds:byte ptr[1+edi],al	
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch17:	
+
+ mov ds:byte ptr[edi],al	
+ mov eax,ds:dword ptr[_sourcetstep]	
+
+ add esi,eax	
+ mov eax,ds:dword ptr[_surfrowbytes]	
+
+ add edi,eax	
+ mov eax,ds:dword ptr[_lightdeltastep]	
+
+ mov ebp,ds:dword ptr[_lightdelta]	
+ mov cl,ds:byte ptr[esi]	
+
+ add ebp,eax	
+ mov eax,ds:dword ptr[_lightrightstep]	
+
+ sar ebp,1	
+ add edx,eax	
+
+ mov bh,dh	
+ mov bl,ds:byte ptr[1+esi]	
+
+ add edx,ebp	
+ mov ch,dh	
+
+ mov al,ds:byte ptr[12345678h+ebx]	
+LBPatch30:	
+ mov edx,ds:dword ptr[_sourcetstep]	
+
+ mov ds:byte ptr[1+edi],al	
+ mov al,ds:byte ptr[12345678h+ecx]	
+LBPatch31:	
+
+ mov ds:byte ptr[edi],al	
+ mov ebp,ds:dword ptr[_surfrowbytes]	
+
+ add esi,edx	
+ add edi,ebp	
+
+;			if (pbasesource >= r_sourcemax)
+;				pbasesource -= stepback;
+
+ cmp esi,ds:dword ptr[_r_sourcemax]	
+ jb LSkip_mip3	
+ sub esi,ds:dword ptr[_r_stepback]	
+LSkip_mip3:	
+
+ mov ebx,ds:dword ptr[_r_lightptr]	
+ dec ds:dword ptr[sb_v]	
+
+ jnz Lv_loop_mip3	
+
+ pop ebx	; restore register variables
+ pop esi	
+ pop edi	
+ pop ebp	; restore the caller's stack frame
+ ret	
+
+
+ public _R_Surf8End	
+_R_Surf8End:	
+
+;----------------------------------------------------------------------
+; Code patching routines
+;----------------------------------------------------------------------
+_TEXT ENDS
+_DATA SEGMENT	
+
+ align 4	
+LPatchTable8:	
+ dd LBPatch0-4	
+ dd LBPatch1-4	
+ dd LBPatch2-4	
+ dd LBPatch3-4	
+ dd LBPatch4-4	
+ dd LBPatch5-4	
+ dd LBPatch6-4	
+ dd LBPatch7-4	
+ dd LBPatch8-4	
+ dd LBPatch9-4	
+ dd LBPatch10-4	
+ dd LBPatch11-4	
+ dd LBPatch12-4	
+ dd LBPatch13-4	
+ dd LBPatch14-4	
+ dd LBPatch15-4	
+ dd LBPatch16-4	
+ dd LBPatch17-4	
+ dd LBPatch18-4	
+ dd LBPatch19-4	
+ dd LBPatch20-4	
+ dd LBPatch21-4	
+ dd LBPatch22-4	
+ dd LBPatch23-4	
+ dd LBPatch24-4	
+ dd LBPatch25-4	
+ dd LBPatch26-4	
+ dd LBPatch27-4	
+ dd LBPatch28-4	
+ dd LBPatch29-4	
+ dd LBPatch30-4	
+ dd LBPatch31-4	
+
+_DATA ENDS
+_TEXT SEGMENT	
+
+ align 4	
+ public _R_Surf8Patch	
+_R_Surf8Patch:	
+ push ebx	
+
+ mov eax,ds:dword ptr[_colormap]	
+ mov ebx,offset LPatchTable8
+ mov ecx,32	
+LPatchLoop8:	
+ mov edx,ds:dword ptr[ebx]	
+ add ebx,4	
+ mov ds:dword ptr[edx],eax	
+ dec ecx	
+ jnz LPatchLoop8	
+
+ pop ebx	
+
+ ret	
+
+_TEXT ENDS
+endif	;id386
+
+ END
+
--- /dev/null
+++ b/ref_soft/r_varsa.asm
@@ -1,0 +1,220 @@
+ .386P
+ .model FLAT
+;
+; d_varsa.s
+;
+
+include qasm.inc
+include d_if.inc
+
+if	id386
+
+_DATA SEGMENT	
+
+;-------------------------------------------------------
+; ASM-only variables
+;-------------------------------------------------------
+ public float_1, float_particle_z_clip, float_point5	
+ public float_minus_1, float_0	
+float_0 dd 0.0	
+float_1 dd 1.0	
+float_minus_1 dd -1.0	
+float_particle_z_clip dd PARTICLE_Z_CLIP	
+float_point5 dd 0.5	
+
+ public fp_16, fp_64k, fp_1m, fp_64kx64k	
+ public fp_1m_minus_1	
+ public fp_8	
+fp_1m dd 1048576.0	
+fp_1m_minus_1 dd 1048575.0	
+fp_64k dd 65536.0	
+fp_8 dd 8.0	
+fp_16 dd 16.0	
+fp_64kx64k dd 04f000000h	; (float)0x8000*0x10000
+
+
+ public FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd	
+FloatZero dd 0	
+Float2ToThe31nd dd 04f000000h	
+FloatMinus2ToThe31nd dd 0cf000000h	
+
+ public _r_bmodelactive	
+_r_bmodelactive dd 0	
+
+
+;-------------------------------------------------------
+; global refresh variables
+;-------------------------------------------------------
+
+; FIXME: put all refresh variables into one contiguous block. Make into one
+; big structure, like cl or sv?
+
+ align 4	
+ public _d_sdivzstepu	
+ public _d_tdivzstepu	
+ public _d_zistepu	
+ public _d_sdivzstepv	
+ public _d_tdivzstepv	
+ public _d_zistepv	
+ public _d_sdivzorigin	
+ public _d_tdivzorigin	
+ public _d_ziorigin	
+_d_sdivzstepu dd 0	
+_d_tdivzstepu dd 0	
+_d_zistepu dd 0	
+_d_sdivzstepv dd 0	
+_d_tdivzstepv dd 0	
+_d_zistepv dd 0	
+_d_sdivzorigin dd 0	
+_d_tdivzorigin dd 0	
+_d_ziorigin dd 0	
+
+ public _sadjust	
+ public _tadjust	
+ public _bbextents	
+ public _bbextentt	
+_sadjust dd 0	
+_tadjust dd 0	
+_bbextents dd 0	
+_bbextentt dd 0	
+
+ public _cacheblock	
+ public _d_viewbuffer	
+ public _cachewidth	
+ public _d_pzbuffer	
+ public _d_zrowbytes	
+ public _d_zwidth	
+_cacheblock dd 0	
+_cachewidth dd 0	
+_d_viewbuffer dd 0	
+_d_pzbuffer dd 0	
+_d_zrowbytes dd 0	
+_d_zwidth dd 0	
+
+
+;-------------------------------------------------------
+; ASM-only variables
+;-------------------------------------------------------
+ public izi	
+izi dd 0	
+
+ public pbase, s, t, sfracf, tfracf, snext, tnext	
+ public spancountminus1, zi16stepu, sdivz16stepu, tdivz16stepu	
+ public zi8stepu, sdivz8stepu, tdivz8stepu, pz	
+s dd 0	
+t dd 0	
+snext dd 0	
+tnext dd 0	
+sfracf dd 0	
+tfracf dd 0	
+pbase dd 0	
+zi8stepu dd 0	
+sdivz8stepu dd 0	
+tdivz8stepu dd 0	
+zi16stepu dd 0	
+sdivz16stepu dd 0	
+tdivz16stepu dd 0	
+spancountminus1 dd 0	
+pz dd 0	
+
+ public izistep	
+izistep dd 0	
+
+;-------------------------------------------------------
+; local variables for d_draw16.s
+;-------------------------------------------------------
+
+ public reciprocal_table_16, entryvec_table_16	
+; 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13,
+; 1/14, and 1/15 in 0.32 form
+reciprocal_table_16 dd 040000000h, 02aaaaaaah, 020000000h	
+ dd 019999999h, 015555555h, 012492492h	
+ dd 010000000h, 0e38e38eh, 0ccccccch, 0ba2e8bah	
+ dd 0aaaaaaah, 09d89d89h, 09249249h, 08888888h	
+
+ externdef Entry2_16:dword	
+ externdef Entry3_16:dword	
+ externdef Entry4_16:dword	
+ externdef Entry5_16:dword	
+ externdef Entry6_16:dword	
+ externdef Entry7_16:dword	
+ externdef Entry8_16:dword	
+ externdef Entry9_16:dword	
+ externdef Entry10_16:dword	
+ externdef Entry11_16:dword	
+ externdef Entry12_16:dword	
+ externdef Entry13_16:dword	
+ externdef Entry14_16:dword	
+ externdef Entry15_16:dword	
+ externdef Entry16_16:dword	
+
+entryvec_table_16 dd 0, Entry2_16, Entry3_16, Entry4_16	
+ dd Entry5_16, Entry6_16, Entry7_16, Entry8_16	
+ dd Entry9_16, Entry10_16, Entry11_16, Entry12_16	
+ dd Entry13_16, Entry14_16, Entry15_16, Entry16_16	
+
+;-------------------------------------------------------
+; local variables for d_parta.s
+;-------------------------------------------------------
+ public DP_Count, DP_u, DP_v, DP_32768, DP_Color, DP_Pix
+DP_Count dd 0	
+DP_u dd 0	
+DP_v dd 0	
+DP_32768 dd 32768.0	
+DP_Color dd 0	
+DP_Pix dd 0	
+
+
+;externdef DP_1x1:dword	
+;externdef DP_2x2:dword	
+;externdef DP_3x3:dword	
+;externdef DP_4x4:dword	
+
+;DP_EntryTable dd DP_1x1, DP_2x2, DP_3x3, DP_4x4	
+
+;
+; advancetable is 8 bytes, but points to the middle of that range so negative
+; offsets will work
+;
+ public advancetable, sstep, tstep, pspantemp, counttemp, jumptemp	
+advancetable dd 0, 0	
+sstep dd 0	
+tstep dd 0	
+
+pspantemp dd 0	
+counttemp dd 0	
+jumptemp dd 0	
+
+; 1/2, 1/3, 1/4, 1/5, 1/6, and 1/7 in 0.32 form
+; public reciprocal_table, entryvec_table	
+reciprocal_table dd 040000000h, 02aaaaaaah, 020000000h	
+ dd 019999999h, 015555555h, 012492492h	
+
+
+; externdef Entry2_8:dword	
+; externdef Entry3_8:dword	
+; externdef Entry4_8:dword	
+; externdef Entry5_8:dword	
+; externdef Entry6_8:dword	
+; externdef Entry7_8:dword	
+; externdef Entry8_8:dword	
+
+;entryvec_table dd 0, Entry2_8, Entry3_8, Entry4_8	
+; dd Entry5_8, Entry6_8, Entry7_8, Entry8_8	
+
+ externdef Spr8Entry2_8:dword	
+ externdef Spr8Entry3_8:dword	
+ externdef Spr8Entry4_8:dword	
+ externdef Spr8Entry5_8:dword	
+ externdef Spr8Entry6_8:dword	
+ externdef Spr8Entry7_8:dword	
+ externdef Spr8Entry8_8:dword	
+
+ public spr8entryvec_table	
+spr8entryvec_table dd 0, Spr8Entry2_8, Spr8Entry3_8, Spr8Entry4_8	
+ dd Spr8Entry5_8, Spr8Entry6_8, Spr8Entry7_8, Spr8Entry8_8	
+
+
+_DATA ENDS
+endif	; id386
+ END
--- /dev/null
+++ b/ref_soft/rand1k.h
@@ -1,0 +1,123 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// 1K random numbers in the range 0-255
+0, 144, 49, 207, 149, 122, 89, 229, 210, 191,
+44, 219, 181, 131, 77, 3, 23, 93, 37, 42,
+253, 114, 30, 1, 2, 96, 136, 146, 154, 155,
+42, 169, 115, 90, 14, 155, 200, 205, 133, 77,
+224, 186, 244, 236, 138, 36, 118, 60, 220, 53,
+199, 215, 255, 255, 156, 100, 68, 76, 215, 6,
+96, 23, 173, 14, 2, 235, 70, 69, 150, 176,
+214, 185, 124, 52, 190, 119, 117, 242, 190, 27,
+153, 98, 188, 155, 146, 92, 38, 57, 108, 205,
+132, 253, 192, 88, 43, 168, 125, 16, 179, 129,
+37, 243, 36, 231, 177, 77, 109, 18, 247, 174,
+39, 224, 210, 149, 48, 45, 209, 121, 39, 129,
+187, 103, 71, 145, 174, 193, 184, 121, 31, 94,
+213, 8, 132, 169, 109, 26, 243, 235, 140, 88,
+120, 95, 216, 81, 116, 69, 251, 76, 189, 145,
+50, 194, 214, 101, 128, 227, 7, 254, 146, 12,
+136, 49, 215, 160, 168, 50, 215, 31, 28, 190,
+80, 240, 73, 86, 35, 187, 213, 181, 153, 191,
+64, 36, 0, 15, 206, 218, 53, 29, 141, 3,
+29, 116, 192, 175, 139, 18, 111, 51, 178, 74,
+111, 59, 147, 136, 160, 41, 129, 246, 178, 236,
+48, 86, 45, 254, 117, 255, 24, 160, 24, 112,
+238, 12, 229, 74, 58, 196, 105, 51, 160, 154,
+115, 119, 153, 162, 218, 212, 159, 184, 144, 96,
+47, 188, 142, 231, 62, 48, 154, 178, 149, 89,
+126, 20, 189, 156, 158, 176, 205, 38, 147, 222,
+233, 157, 186, 11, 170, 249, 80, 145, 78, 44,
+27, 222, 217, 190, 39, 83, 20, 19, 164, 209,
+139, 114, 104, 76, 119, 128, 39, 82, 188, 80,
+211, 245, 223, 185, 76, 241, 32, 16, 200, 134,
+156, 244, 18, 224, 167, 82, 26, 129, 58, 74,
+235, 141, 169, 29, 126, 97, 127, 203, 130, 97,
+176, 136, 155, 101, 1, 181, 25, 159, 220, 125,
+191, 127, 97, 201, 141, 91, 244, 161, 45, 95,
+33, 190, 243, 156, 7, 84, 14, 163, 33, 216,
+221, 152, 184, 218, 3, 32, 181, 157, 55, 16,
+43, 159, 87, 81, 94, 169, 205, 206, 134, 156,
+204, 230, 37, 161, 103, 64, 34, 218, 16, 109,
+146, 77, 140, 57, 79, 28, 206, 34, 72, 201,
+229, 202, 190, 157, 92, 219, 58, 221, 58, 63,
+138, 252, 13, 20, 134, 109, 24, 66, 228, 59,
+37, 32, 238, 20, 12, 15, 86, 234, 102, 110,
+242, 214, 136, 215, 177, 101, 66, 1, 134, 244,
+102, 61, 149, 65, 175, 241, 111, 227, 1, 240,
+153, 201, 147, 36, 56, 98, 1, 106, 21, 168,
+218, 16, 207, 169, 177, 205, 135, 175, 36, 176,
+186, 199, 7, 222, 164, 180, 21, 141, 242, 15,
+70, 37, 251, 158, 74, 236, 94, 177, 55, 39,
+61, 133, 230, 27, 231, 113, 20, 200, 43, 249,
+198, 222, 53, 116, 0, 192, 29, 103, 79, 254,
+9, 64, 48, 63, 39, 158, 226, 240, 50, 199,
+165, 168, 232, 116, 235, 170, 38, 162, 145, 108,
+241, 138, 148, 137, 65, 101, 89, 9, 203, 50,
+17, 99, 151, 18, 50, 39, 164, 116, 154, 178,
+112, 175, 101, 213, 151, 51, 243, 224, 100, 252,
+47, 229, 147, 113, 160, 181, 12, 73, 66, 104,
+229, 181, 186, 229, 100, 101, 231, 79, 99, 146,
+90, 187, 190, 188, 189, 35, 51, 69, 174, 233,
+94, 132, 28, 232, 51, 132, 167, 112, 176, 23,
+20, 19, 7, 90, 78, 178, 36, 101, 17, 172,
+185, 50, 177, 157, 167, 139, 25, 139, 12, 249,
+118, 248, 186, 135, 174, 177, 95, 99, 12, 207,
+43, 15, 79, 200, 54, 82, 124, 2, 112, 130,
+155, 194, 102, 89, 215, 241, 159, 255, 13, 144,
+221, 99, 78, 72, 6, 156, 100, 4, 7, 116,
+219, 239, 102, 186, 156, 206, 224, 149, 152, 20,
+203, 118, 151, 150, 145, 208, 172, 87, 2, 68,
+87, 59, 197, 95, 222, 29, 185, 161, 228, 46,
+137, 230, 199, 247, 50, 230, 204, 244, 217, 227,
+160, 47, 157, 67, 64, 187, 201, 43, 182, 123,
+20, 206, 218, 31, 78, 146, 121, 195, 49, 186,
+254, 3, 165, 177, 44, 18, 70, 173, 214, 142,
+95, 199, 59, 163, 59, 52, 248, 72, 5, 196,
+38, 12, 2, 89, 164, 87, 106, 106, 23, 139,
+179, 86, 168, 224, 137, 145, 13, 119, 66, 109,
+221, 124, 22, 144, 181, 199, 221, 217, 75, 221,
+165, 191, 212, 195, 223, 232, 233, 133, 112, 27,
+90, 210, 109, 43, 0, 168, 198, 16, 22, 98,
+175, 206, 39, 36, 12, 88, 4, 250, 165, 13,
+234, 163, 110, 5, 62, 100, 167, 200, 5, 211,
+35, 162, 140, 251, 118, 54, 76, 200, 87, 123,
+155, 26, 252, 193, 38, 116, 182, 255, 198, 164,
+159, 242, 176, 74, 145, 74, 140, 182, 63, 139,
+126, 243, 171, 195, 159, 114, 204, 190, 253, 52,
+161, 232, 151, 235, 129, 125, 115, 227, 240, 46,
+64, 51, 187, 240, 160, 10, 164, 8, 142, 139,
+114, 15, 254, 32, 153, 12, 44, 169, 85, 80,
+167, 105, 109, 56, 173, 42, 127, 129, 205, 111,
+1, 86, 96, 32, 211, 187, 228, 164, 166, 131,
+187, 188, 245, 119, 92, 28, 231, 210, 116, 27,
+222, 194, 10, 106, 239, 17, 42, 54, 29, 151,
+30, 158, 148, 176, 187, 234, 171, 76, 207, 96,
+255, 197, 52, 43, 99, 46, 148, 50, 245, 48,
+97, 77, 30, 50, 11, 197, 194, 225, 0, 114,
+109, 205, 118, 126, 191, 61, 143, 23, 236, 228,
+219, 15, 125, 161, 191, 193, 65, 232, 202, 51,
+141, 13, 133, 202, 180, 6, 187, 141, 234, 224,
+204, 78, 101, 123, 13, 166, 0, 196, 193, 56,
+39, 14, 171, 8, 88, 178, 204, 111, 251, 162,
+75, 122, 223, 20, 25, 36, 36, 235, 79, 95,
+208, 11, 208, 61, 229, 65, 68, 53, 58, 216,
+223, 227, 216, 155, 10, 44, 47, 91, 115, 47,
+228, 159, 139, 233
--- /dev/null
+++ b/ref_soft/ref_soft.001
@@ -1,0 +1,1498 @@
+# Microsoft Developer Studio Project File - Name="ref_soft" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=ref_soft - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_soft.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_soft.mak" CFG="ref_soft - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ref_soft - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Debug Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Release Alpha" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\ref_soft"
+# PROP BASE Intermediate_Dir ".\ref_soft"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386
+# SUBTRACT LINK32 /debug
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\ref_soft"
+# PROP BASE Intermediate_Dir ".\ref_soft"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /nodefaultlib:"libc"
+# SUBTRACT LINK32 /profile /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug Alpha"
+# PROP BASE Intermediate_Dir "Debug Alpha"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA /nodefaultlib:"libc"
+# SUBTRACT BASE LINK32 /nodefaultlib
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA /nodefaultlib:"libc"
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ref_soft"
+# PROP BASE Intermediate_Dir "ref_soft"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Z<none> /Fr
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# SUBTRACT LINK32 /debug
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ref_soft - Win32 Release"
+# Name "ref_soft - Win32 Debug"
+# Name "ref_soft - Win32 Debug Alpha"
+# Name "ref_soft - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=..\game\q_shared.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\q_shwin.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_aclip.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_ACL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_ACL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_ACL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_aclipa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_aclipa.asm
+InputName=r_aclipa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_aclipa.asm
+InputName=r_aclipa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_alias.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_ALI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_ALI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_ALI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_bsp.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_BSP=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_BSP=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_BSP=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_draw.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_DRA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_DRA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_DRA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_draw16.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_draw16.asm
+InputName=r_draw16
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_draw16.asm
+InputName=r_draw16
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_drawa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_drawa.asm
+InputName=r_drawa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_drawa.asm
+InputName=r_drawa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_edge.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_EDG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_EDG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_EDG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_edgea.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_edgea.asm
+InputName=r_edgea
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_edgea.asm
+InputName=r_edgea
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_image.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_IMA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_IMA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_IMA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_light.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_LIG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_LIG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_LIG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_main.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_MAI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_MAI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_MAI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_misc.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_MIS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_MIS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_MIS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_model.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_MOD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_MOD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_MOD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_part.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_PAR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_PAR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_PAR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_poly.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_POL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_POL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_POL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_polysa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_polysa.asm
+InputName=r_polysa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_polysa.asm
+InputName=r_polysa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_polyse.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_POLY=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\adivtab.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	".\rand1k.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_POLY=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\adivtab.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	".\rand1k.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_POLY=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\adivtab.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	".\rand1k.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_rast.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_RAS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_RAS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_RAS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_scan.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_SCA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_SCA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_SCA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_scana.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_scana.asm
+InputName=r_scana
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_scana.asm
+InputName=r_scana
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_spr8.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_spr8.asm
+InputName=r_spr8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_spr8.asm
+InputName=r_spr8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_sprite.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_SPR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_SPR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_SPR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_surf.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_SUR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_SUR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_SUR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_surf8.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_surf8.asm
+InputName=r_surf8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_surf8.asm
+InputName=r_surf8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_varsa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_varsa.asm
+InputName=r_varsa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_varsa.asm
+InputName=r_varsa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_ddraw.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_RW_DD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_RW_DD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_RW_DD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_dib.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_RW_DI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_RW_DI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_RW_DI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_imp.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_RW_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	"..\win32\winquake.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_RW_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	"..\win32\winquake.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_RW_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	"..\win32\winquake.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\adivtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\anorms.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\game\q_shared.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qcommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rand1k.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\ref.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_win.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\winquake.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\ref_soft.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/ref_soft/ref_soft.def
@@ -1,0 +1,2 @@
+EXPORTS
+	GetRefAPI
--- /dev/null
+++ b/ref_soft/ref_soft.dsp
@@ -1,0 +1,1496 @@
+# Microsoft Developer Studio Project File - Name="ref_soft" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=ref_soft - Win32 Debug Alpha
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_soft.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "ref_soft.mak" CFG="ref_soft - Win32 Debug Alpha"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "ref_soft - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Debug Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "ref_soft - Win32 Release Alpha" (based on "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\ref_soft"
+# PROP BASE Intermediate_Dir ".\ref_soft"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\release"
+# PROP Intermediate_Dir ".\release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386
+# SUBTRACT LINK32 /debug
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\ref_soft"
+# PROP BASE Intermediate_Dir ".\ref_soft"
+# PROP BASE Target_Dir "."
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\debug"
+# PROP Intermediate_Dir ".\debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir "."
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /nodefaultlib:"libc"
+# SUBTRACT LINK32 /profile /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug Alpha"
+# PROP BASE Intermediate_Dir "Debug Alpha"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\DebugAxp"
+# PROP Intermediate_Dir ".\DebugAxp"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MTd /Gt0 /W3 /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA /nodefaultlib:"libc"
+# SUBTRACT BASE LINK32 /nodefaultlib
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:ALPHA /nodefaultlib:"libc"
+# SUBTRACT LINK32 /nodefaultlib
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ref_soft"
+# PROP BASE Intermediate_Dir "ref_soft"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\ReleaseAXP"
+# PROP Intermediate_Dir ".\ReleaseAXP"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /QA21164 /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /YX /FD /QAieee1 /c
+# SUBTRACT CPP /Z<none> /Fr
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /machine:ALPHA
+# SUBTRACT LINK32 /debug
+
+!ENDIF 
+
+# Begin Target
+
+# Name "ref_soft - Win32 Release"
+# Name "ref_soft - Win32 Debug"
+# Name "ref_soft - Win32 Debug Alpha"
+# Name "ref_soft - Win32 Release Alpha"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=..\game\q_shared.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_Q_SHA=\
+	"..\game\q_shared.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\q_shwin.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_Q_SHW=\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\winquake.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_aclip.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_ACL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_ACL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_ACL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_aclipa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_aclipa.asm
+InputName=r_aclipa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_aclipa.asm
+InputName=r_aclipa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_alias.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_ALI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_ALI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_ALI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\anorms.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_bsp.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_BSP=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_BSP=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_BSP=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_draw.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_DRA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_DRA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_DRA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_draw16.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_draw16.asm
+InputName=r_draw16
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_draw16.asm
+InputName=r_draw16
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_drawa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_drawa.asm
+InputName=r_drawa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_drawa.asm
+InputName=r_drawa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_edge.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_EDG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_EDG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_EDG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_edgea.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_edgea.asm
+InputName=r_edgea
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_edgea.asm
+InputName=r_edgea
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_image.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_IMA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_IMA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_IMA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_light.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_LIG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_LIG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_LIG=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_main.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_MAI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_MAI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_MAI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_misc.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_MIS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_MIS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_MIS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_model.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_MOD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_MOD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_MOD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_part.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_PAR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_PAR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_PAR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_poly.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_POL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_POL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_POL=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_polysa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_polysa.asm
+InputName=r_polysa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_polysa.asm
+InputName=r_polysa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_polyse.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_POLY=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\adivtab.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	".\rand1k.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_POLY=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\adivtab.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	".\rand1k.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_POLY=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\adivtab.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	".\rand1k.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_rast.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_RAS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_RAS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_RAS=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_scan.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_SCA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_SCA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_SCA=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_scana.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_scana.asm
+InputName=r_scana
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_scana.asm
+InputName=r_scana
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_spr8.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_spr8.asm
+InputName=r_spr8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_spr8.asm
+InputName=r_spr8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_sprite.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_SPR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_SPR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_SPR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_surf.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_R_SUR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_R_SUR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_R_SUR=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_surf8.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_surf8.asm
+InputName=r_surf8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_surf8.asm
+InputName=r_surf8
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_varsa.asm
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\..\release
+InputPath=.\r_varsa.asm
+InputName=r_varsa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\..\debug
+InputPath=.\r_varsa.asm
+InputName=r_varsa
+
+"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(InputPath)
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_ddraw.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_RW_DD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_RW_DD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_RW_DD=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_dib.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_RW_DI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_RW_DI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_RW_DI=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_imp.c
+
+!IF  "$(CFG)" == "ref_soft - Win32 Release"
+
+DEP_CPP_RW_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	"..\win32\winquake.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Debug Alpha"
+
+DEP_CPP_RW_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	"..\win32\winquake.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ELSEIF  "$(CFG)" == "ref_soft - Win32 Release Alpha"
+
+DEP_CPP_RW_IM=\
+	"..\client\ref.h"\
+	"..\game\q_shared.h"\
+	"..\qcommon\qcommon.h"\
+	"..\qcommon\qfiles.h"\
+	"..\win32\rw_win.h"\
+	"..\win32\winquake.h"\
+	".\r_local.h"\
+	".\r_model.h"\
+	
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\adivtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\anorms.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\game\q_shared.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qcommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\qcommon\qfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_local.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\r_model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rand1k.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\client\ref.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\rw_win.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32\winquake.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\ref_soft.def
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/ref_soft/ref_soft.plg
@@ -1,0 +1,17 @@
+--------------------Configuration: ref_soft - Win32 Release Alpha--------------------
+Begining build with project "G:\quake2\code\ref_soft\ref_soft.dsp", at root.
+Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library)
+
+Project's tools are:
+			"OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
+			"C/C++ Compiler for Alpha" with flags "/nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/ref_soft.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /FD /QAieee1 /c "
+			"Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" "
+			"Browser Database Maker" with flags "/nologo /o"..\ReleaseAXP/ref_soft.bsc" "
+			"COFF Linker for Alpha" with flags "kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/ref_soft.pdb" /debug /machine:ALPHA /def:".\ref_soft.def" /out:"..\ReleaseAXP/ref_soft.dll" /implib:"..\ReleaseAXP/ref_soft.lib" "
+			"Custom Build" with flags ""
+			"<Component 0xa>" with flags ""
+
+
+
+
+ref_soft.dll - 0 error(s), 0 warning(s)
--- /dev/null
+++ b/rhapsody/in_next.m
@@ -1,0 +1,332 @@
+// in_next.m
+
+#import <AppKit/AppKit.h>
+#import <drivers/event_status_driver.h>
+#include "../client/client.h"
+
+float	mousex, mousey;
+
+float	mouse_center_x = 160;
+float	mouse_center_y = 100;
+
+void PSsetmouse (float x, float y);
+void PSshowcursor (void);
+void PShidecursor (void);
+void PScurrentmouse (int win, float *x, float *y);
+
+extern	NSView	*vid_view_i;
+extern	NSWindow	*vid_window_i;
+
+qboolean	mlooking;
+qboolean	mouseinitialized;
+int		mouse_buttons;
+int		mouse_oldbuttonstate;
+int		mouseactive;
+int		mousereset;
+int		mx_accum, my_accum;
+int		window_center_x, window_center_y;
+int		old_mouse_x, old_mouse_y;
+
+cvar_t	in_mouse = {"in_mouse", "0", CVAR_ARCHIVE};
+cvar_t	m_filter = {"m_filter", "0", CVAR_ARCHIVE};
+cvar_t	freelook = {"in_freelook", "0", CVAR_ARCHIVE};
+
+
+/*
+===========
+IN_ActivateMouse
+
+Called when the window gains focus or changes in some way
+===========
+*/
+void IN_ActivateMouse (void)
+{
+    NSRect	r;
+  
+        if (!mouseinitialized)
+                return;
+        if (!in_mouse.value)
+                return;
+
+        r = [vid_window_i frame];
+        window_center_x = r.size.width / 2;
+        window_center_y = r.size.height / 2;
+
+        if (!mouseactive)
+            PShidecursor ();
+ 
+        mouseactive = true;
+        mousereset = true;
+}
+
+
+/*
+===========
+IN_DeactivateMouse
+
+Called when the window loses focus
+===========
+*/
+void IN_DeactivateMouse (void)
+{
+        if (!mouseinitialized)
+                return;
+
+    if (mouseactive)
+        PSshowcursor ();
+
+    mouseactive = false;
+}
+
+
+/*
+===========
+IN_StartupMouse
+===========
+*/
+void IN_StartupMouse (void)
+{
+        if ( COM_CheckParm ("-nomouse") ) 
+                return; 
+
+        mouseinitialized = true;
+
+        mouse_buttons = 3;
+
+        IN_ActivateMouse ();
+}
+
+/*
+===========
+IN_MouseEvent
+===========
+*/
+void IN_MouseEvent (int mstate)
+{
+        int		i;
+
+        if (!mouseactive)
+                return;
+
+// perform button actions
+        for (i=0 ; i<mouse_buttons ; i++)
+        {
+                if ( (mstate & (1<<i)) &&
+                        !(mouse_oldbuttonstate & (1<<i)) )
+                {
+                        Key_Event (K_MOUSE1 + i, true);
+                }
+
+                if ( !(mstate & (1<<i)) &&
+                        (mouse_oldbuttonstate & (1<<i)) )
+                {
+                                Key_Event (K_MOUSE1 + i, false);
+                }
+        }	
+
+        mouse_oldbuttonstate = mstate;
+}
+
+
+
+/*
+===========
+IN_Accumulate
+===========
+*/
+void IN_Accumulate (void)
+{
+        int		dx, dy;
+        static int		old_x, old_y;
+
+        if (!mouseinitialized)
+                return;
+
+        if (in_mouse.modified)
+        {
+            in_mouse.modified = false;
+            IN_DeactivateMouse ();
+            IN_ActivateMouse ();
+        }
+
+        if (!mouseactive)
+                return;
+
+//       [vid_view_i lockFocus];
+
+        if (mousereset)
+        {	// we haven't centered cursor yet
+                mousereset = false;
+        }
+        else
+        {
+	 NSPoint	p;
+
+            PScurrentmouse ([vid_window_i windowNumber], &mousex, &mousey);
+
+		p.x = mousex;
+		p.y = mousey;
+		p = [vid_view_i convertPoint:p fromView: nil];
+
+            mousex = p.x;
+            mousey = p.y;
+            
+            dx = mousex - old_x;
+            dy = old_y - mousey;
+
+                if (!dx && !dy)
+                        return;
+                mx_accum += dx;
+                my_accum += dy;
+        }
+
+        // force the mouse to the center, so there's room to move
+        PSsetmouse (window_center_x, window_center_y);
+        PScurrentmouse ([vid_window_i windowNumber], &mousex, &mousey);
+//        PSsetmouse (window_center_x, window_center_y);
+        old_x = window_center_x;
+        old_y = window_center_y;
+
+//        [vid_view_i unlockFocus];
+}
+
+
+/*
+===========
+IN_MouseMove
+===========
+*/
+void IN_MouseMove (usercmd_t *cmd)
+{
+        int		mx, my;
+	int		mouse_x, mouse_y;
+       
+        IN_Accumulate ();
+
+        mx = mx_accum;
+        my = my_accum;
+
+        mx_accum = 0;
+        my_accum = 0;
+
+        if (m_filter.value)
+        {
+                mouse_x = (mx + old_mouse_x) * 0.5;
+                mouse_y = (my + old_mouse_y) * 0.5;
+        }
+        else
+        {
+                mouse_x = mx;
+                mouse_y = my;
+        }
+
+        old_mouse_x = mx;
+        old_mouse_y = my;
+
+        if (!mx && !my)
+                return;
+
+        if (!mouseactive)
+                return;
+
+        mouse_x *= sensitivity.value;
+        mouse_y *= sensitivity.value;
+
+// add mouse X/Y movement to cmd
+        if ( (in_strafe.state & 1) || (lookstrafe.value && mlooking ))
+                cmd->sidemove += m_side.value * mouse_x;
+        else
+                cl.viewangles[YAW] -= m_yaw.value * mouse_x;
+
+        if ( (mlooking || freelook.value) && !(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
+        {
+                cmd->forwardmove -= m_forward.value * mouse_y;
+        }
+
+}
+
+void IN_ShowMouse (void)
+{
+    PSshowcursor ();
+}
+
+void IN_HideMouse (void)
+{
+    PShidecursor ();
+}
+
+NXEventHandle	eventhandle;
+NXMouseScaling	oldscaling, newscaling;
+NXMouseButton	oldbutton;
+
+/*
+ =============
+ IN_Init
+ =============
+ */
+void IN_Init (void)
+{
+    Cvar_RegisterVariable (&in_mouse);
+    Cvar_RegisterVariable (&m_filter);
+    Cvar_RegisterVariable (&freelook);
+
+    Cmd_AddCommand ("showmouse", IN_ShowMouse);
+    Cmd_AddCommand ("hidemouse", IN_HideMouse);
+    
+    IN_StartupMouse ();
+
+    // open the event status driver
+    eventhandle = NXOpenEventStatus();
+    NXGetMouseScaling (eventhandle, &oldscaling);
+    NXSetMouseScaling (eventhandle, &newscaling);
+    oldbutton = NXMouseButtonEnabled (eventhandle);
+    NXEnableMouseButton (eventhandle, 2);
+}
+
+/*
+ =============
+ IN_Shutdown
+ =============
+ */
+void IN_Shutdown (void)
+{
+    IN_DeactivateMouse ();
+
+    // put mouse scaling back the way it was
+    NXSetMouseScaling (eventhandle, &oldscaling);
+    NXEnableMouseButton (eventhandle, oldbutton);
+    NXCloseEventStatus (eventhandle);
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+    IN_MouseMove (cmd);
+}
+
+void IN_Commands (void)
+{
+}
+
+
+/*
+=========================================================================
+
+VIEW CENTERING
+
+=========================================================================
+*/
+
+void V_StopPitchDrift (void)
+{
+	cl.laststop = cl.time;
+	cl.nodrift = true;
+	cl.pitchvel = 0;
+}
--- /dev/null
+++ b/rhapsody/makefile.bak
@@ -1,0 +1,63 @@
+
+CFLAGS = -O -g -DGAME_HARD_LINKED -DREF_HARD_LINKED
+LDFLAGS = -sectcreate __ICON __header quake2.iconheader -segprot __ICON r r -sectcreate __ICON app quake2.tiff -framework AppKit -framework Foundation
+EXE	= quake2
+TARGETS	= $(EXE)
+
+all: $(TARGETS)
+
+#----------------------------------------------------------------------
+
+SERVERFILES = sv_ccmds.o sv_ents.o sv_game.o sv_init.o sv_main.o sv_send.o sv_user.o sv_world.o
+
+GAMEFILES = g_ai.o g_cmds.o g_combat.o g_func.o g_items.o g_main.o g_misc.o g_monster.o g_phys.o g_save.o g_spawn.o g_target.o g_trigger.o g_utils.o g_weapon.o g_turret.o m_actor.o m_berserk.o m_boss2.o m_boss3.o m_boss31.o m_boss32.o m_brain.o m_chick.o m_flipper.o m_float.o m_flyer.o m_gladiator.o m_gunner.o m_hover.o m_infantry.o m_insane.o m_medic.o m_move.o m_mutant.o m_parasite.o m_soldier.o m_supertank.o m_tank.o p_client.o p_hud.o p_trail.o p_view.o p_weapon.o
+
+CLIENTFILES = cl_ents.o cl_fx.o cl_input.o cl_inv.o cl_main.o cl_parse.o cl_pred.o cl_scrn.o cl_cin.o cl_tent.o cl_view.o console.o keys.o menu.o qmenu.o snd_dma.o snd_mem.o snd_mix.o
+
+# commonfiles are used by both client and server
+COMMONFILES = m_flash.o cmd.o cmodel.o common.o cvar.o files.o md4.o net_chan.o net_udp.o pmove.o
+
+REFGLFILES = gl_draw.o gl_light.o gl_mesh.o gl_model.o gl_rmain.o gl_rmisc.o gl_rsurf.o gl_warp.o gl_image.o
+
+REFSOFTFILES = r_aclip.o r_alias.o r_bsp.o r_draw.o r_edge.o r_image.o r_light.o r_main.o r_misc.o r_model.o r_part.o r_polyse.o r_poly.o r_rast.o r_scan.o r_sprite.o r_surf.o
+
+# sharedfiles are included in EVERY dll
+SHAREDFILES = q_shared.o
+
+IRIXFILES = cd_sgi.o glx_imp.o qgl_sgi.o sys_sgi.o vid_sgi.o in_sgi.o snddma_null.o
+
+RHAPFILES = cd_null.o in_null.o snddma_null.o sys_rhap.o vid_null.o swimp_rhap.o
+
+NULLFILES = cd_null.o in_null.o snddma_null.o sys_null.o vid_null.o swimp_null.o
+
+#----------------------------------------------------------------------
+
+FILES = $(SERVERFILES) $(GAMEFILES) $(COMMONFILES) $(CLIENTFILES) $(REFSOFTFILES) $(SHAREDFILES) $(RHAPFILES)
+
+$(EXE) : $(FILES)
+	cc -o $(EXE) $(FILES) $(LDFLAGS)
+
+clean:
+	rm -f $(EXE) $(FILES)
+
+#----------------------------------------------------------------------
+
+# gnumake pattern rules are so cool!
+
+%.o : ../game/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../qcommon/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../client/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../server/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../ref_soft/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../ref_gl/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../null/%.c
+	cc $(CFLAGS) -c -o $@ $?
+%.o : ../rhapsody/%.m
+	cc $(CFLAGS) -c -o $@ $?
+
--- /dev/null
+++ b/rhapsody/notes.txt
@@ -1,0 +1,34 @@
+f1
+
+not calling back to set vid size after sw_mode change?
+
+do vid_xpos / ypos creep because of frames?
+
+fix fullscreen fallback bug
+
+nsping
+
+icon
+
+don't make sys_error varargs
+
+cvar_stvalue in ref????
+
+subframe event timing information
+
+swimp init / swimp_initgraphics?
+
+SWimp_SetMode shouldn't call
+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+subclass window instead of view?
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine.  A NULL palette means
+** to use the existing palette.  The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+
+do we ever pass a NULL palette?
--- /dev/null
+++ b/rhapsody/pb.project
@@ -1,0 +1,17 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (Foundation.framework); 
+        OTHER_LINKED = (QuakeWorld_main.m); 
+        OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, m.template, h.template); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(NEXT_ROOT)/NextDeveloper/Makefiles/pb_makefiles"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/NextDeveloper/bin/make; 
+    PROJECTNAME = QuakeWorld; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.6; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/NextDeveloper/Executables/make; 
+}
--- /dev/null
+++ b/rhapsody/quake2.iconheader
@@ -1,0 +1,2 @@
+F	test.app	test	app
+F	test	test	app
binary files /dev/null b/rhapsody/quake2.tiff differ
--- /dev/null
+++ b/rhapsody/r_next.m
@@ -1,0 +1,735 @@
+
+#import <AppKit/AppKit.h>
+#include "../ref_soft/r_local.h"
+
+/*
+====================================================================
+
+ OPENSTEP specific stuff
+
+====================================================================
+*/
+
+@interface QuakeView : NSView
+@end
+
+NSWindow	*vid_window_i;
+QuakeView	*vid_view_i;
+
+unsigned	*buffernative;
+
+//===========================================================
+
+
+int Draw_SetResolution (void);
+
+#define	TYPE_FULLSCREEN	0
+#define	TYPE_WINDOWED	1
+#define	TYPE_STRETCHED	2
+
+#define	NUM_RESOLUTIONS		7
+int	resolutions[NUM_RESOLUTIONS][2] = { 
+	{320,200}, {320,240}, {400,300}, {512,384}, {640,480}, {800,600}, {1024,768} };
+
+qboolean	available[NUM_RESOLUTIONS][3];
+int			mode_res = 0, mode_type = TYPE_WINDOWED;
+
+byte		gammatable[256];	// palette is sent through this
+unsigned       	current_palette[256];
+unsigned       	gamma_palette[256];
+
+int			cursor_res, cursor_type;
+
+cvar_t		*vid_x;
+cvar_t		*vid_y;
+cvar_t		*vid_mode;
+cvar_t		*vid_stretched;
+cvar_t		*vid_fullscreen;
+cvar_t		*draw_gamma;
+
+void Draw_BuildGammaTable (void);
+
+/*
+====================================================================
+
+MENU INTERACTION
+
+====================================================================
+*/
+
+void FindModes (void)
+{
+	if (mode_res < 0 || mode_res >= NUM_RESOLUTIONS)
+		mode_res = 0;
+	if (mode_type < 0 || mode_type > 3)
+		mode_type = 1;
+
+}
+
+void RM_Print (int x, int y, char *s)
+{
+	while (*s)
+	{
+		Draw_Char (x, y, (*s)+128);
+		s++;
+		x += 8;
+	}
+}
+
+/*
+================
+Draw_MenuDraw
+================
+*/
+void Draw_MenuDraw (void)
+{
+	int		i, j;
+	int		y;
+	char	string[32];
+
+	Draw_Pic ( 4, 4, "vidmodes");
+
+	RM_Print (80, 32, "fullscreen windowed stretched");
+	RM_Print (80, 40, "---------- -------- ---------");
+	y = 50;
+
+	// draw background behind selected mode
+	Draw_Fill ( (mode_type+1)*80, y+(mode_res)*10, 40,10, 8);
+
+	// draw available grid
+	for (i=0 ; i<NUM_RESOLUTIONS ; i++, y+= 10)
+	{
+		sprintf (string, "%ix%i", resolutions[i][0], resolutions[i][1]);
+		RM_Print (0, y, string);
+		for (j=0 ; j<3 ; j++)
+			if (available[i][j])
+				RM_Print ( 80 + j*80, y, "*");
+	}
+
+	// draw the cursor
+	Draw_Char (80 + cursor_type*80, 50 + cursor_res*10, 128 + 12+((int)(r_newrefdef.time*4)&1));
+}
+
+
+#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
+
+/*
+================
+Draw_MenuKey
+================
+*/
+void Draw_MenuKey (int key)
+{
+	switch (key)
+	{
+	case K_LEFTARROW:
+		cursor_type--;
+		if (cursor_type < 0)
+			cursor_type = 2;
+		break;
+
+	case K_RIGHTARROW:
+		cursor_type++;
+		if (cursor_type > 2)
+			cursor_type = 0;
+		break;
+
+	case K_UPARROW:
+		cursor_res--;
+		if (cursor_res < 0)
+			cursor_res = NUM_RESOLUTIONS-1;
+		break;
+
+	case K_DOWNARROW:
+		cursor_res++;
+		if (cursor_res >= NUM_RESOLUTIONS)
+			cursor_res = 0;
+		break;
+
+	case K_ENTER:
+		ri.Cmd_ExecuteText (EXEC_NOW, va("vid_mode %i", cursor_res));
+		switch (cursor_type)
+                {
+                    case TYPE_FULLSCREEN:
+                        ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 1");
+                        ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 0");
+                        break;
+                    case TYPE_WINDOWED:
+                        ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 0");
+                        ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 0");
+                        break;
+                    case TYPE_STRETCHED:
+                        ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 0");
+                        ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 1");
+                        break;
+		}
+                    
+		mode_res = cursor_res;
+		mode_type = cursor_type;
+		Draw_SetResolution ();
+		break;
+
+	default:
+		break;
+	}
+}
+
+//===========================================================
+
+
+/*
+================
+Draw_SetResolution
+
+The vid structure will be filled in on return
+Also allocates the z buffer and surface cache
+================
+*/
+int Draw_SetResolution (void)
+{
+    NSRect	content;
+    
+	if (vid_mode->value < 0)
+		ri.Cmd_ExecuteText (EXEC_NOW, "vid_mode 0");
+	if (vid_mode->value >= NUM_RESOLUTIONS)
+		ri.Cmd_ExecuteText (EXEC_NOW, va("vid_mode %i", NUM_RESOLUTIONS-1));
+
+	vid_mode->modified = false;
+        vid_fullscreen->modified = false;
+        vid_stretched->modified = false;
+
+        // free nativebuffer
+        if (buffernative)
+        {
+            free (buffernative);
+            buffernative = NULL;
+        }
+        
+	// free z buffer
+	if (d_pzbuffer)
+	{
+		free (d_pzbuffer);
+		d_pzbuffer = NULL;
+	}
+	// free surface cache
+	if (sc_base)
+	{
+		D_FlushCaches ();
+		free (sc_base);
+		sc_base = NULL;
+	}
+
+        vid.width = resolutions[(int)(vid_mode->value)][0];
+	vid.height = resolutions[(int)(vid_mode->value)][1];
+
+	vid.win_width = vid.width;
+	vid.win_height = vid.height;
+	if (vid_stretched->value)
+	{
+		vid.win_width <<= 1;
+		vid.win_height <<= 1;
+	}
+
+	vid.aspect = 1;
+	vid.buffer = malloc (vid.width*vid.height);
+	vid.rowbytes = vid.width;
+        d_pzbuffer = malloc(vid.width*vid.height*2);
+        buffernative = malloc(vid.width*vid.height*4);
+
+	D_InitCaches ();
+
+	Sys_SetPalette ((byte *)d_8to24table);
+
+        if (vid_view_i)
+            [vid_view_i unlockFocus];
+        if (vid_window_i)
+            [vid_window_i close];
+//
+// open a window
+//
+        content = NSMakeRect (vid_x->value,vid_y->value,vid.win_width, vid.win_height);
+   vid_window_i = [[NSWindow alloc]
+                       initWithContentRect:	content
+                                 styleMask:	NSTitledWindowMask
+                                   backing:	NSBackingStoreRetained
+                            	defer:	NO
+       ];
+
+   [vid_window_i setDelegate: vid_window_i];
+   [vid_window_i display];
+   [NSApp activateIgnoringOtherApps: YES];
+   [vid_window_i makeKeyAndOrderFront: nil];
+
+//   NSPing ();
+
+   content.origin.x = content.origin.y = 0;
+   vid_view_i = [[QuakeView alloc] initWithFrame: content];
+   [vid_window_i setContentView: vid_view_i];
+   [vid_window_i makeFirstResponder: vid_view_i];
+   [vid_window_i setDelegate: vid_view_i];
+
+//   [vid_window_i addToEventMask: NS_FLAGSCHANGEDMASK];
+   [vid_window_i setTitle: @"Bitmap Quake Console"];
+ 	[vid_window_i makeKeyAndOrderFront: nil];
+        
+   // leave focus locked forever
+   [vid_view_i lockFocus];
+   
+	ri.VID_SetSize (vid.width, vid.height);
+
+	return 0;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+Draw_Init
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+int Draw_Init (void *window)
+{
+    [NSApplication sharedApplication];
+	[NSApp finishLaunching];
+  
+	ri.Con_Printf (PRINT_ALL, "refresh version: "REF_VERSION"\n");
+
+	vid_x = ri.Cvar_Get ("vid_x", "0", CVAR_ARCHIVE);
+	vid_y = ri.Cvar_Get ("vid_y", "0", CVAR_ARCHIVE);
+	vid_mode = ri.Cvar_Get ("vid_mode", "0", CVAR_ARCHIVE);
+        vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
+        vid_stretched = ri.Cvar_Get ("vid_stretched", "0", CVAR_ARCHIVE);
+	draw_gamma = ri.Cvar_Get ("gamma", "1", CVAR_ARCHIVE);
+
+        Draw_GetPalette ();
+
+	Draw_BuildGammaTable ();
+
+	// get the lighting colormap
+	ri.FS_LoadFile ("gfx/colormap.lmp", (void **)&vid.colormap);
+	if (!vid.colormap)
+	{
+		ri.Con_Printf (PRINT_ALL, "ERROR: Couldn't load gfx/colormap.lmp");
+		return -1;
+	}
+
+	Draw_SetResolution ();
+
+	R_Init ();
+
+	return 0;
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+Draw_Shutdown
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void Draw_Shutdown (void)
+{
+   R_Shutdown ();
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+Draw_BuildGammaTable
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void Draw_BuildGammaTable (void)
+{
+	int		i, inf;
+	float	g;
+
+	draw_gamma->modified = false;
+	g = draw_gamma->value;
+
+	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;
+	}
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+Draw_BeginFram
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void Draw_BeginFrame (void)
+{
+	if (vid_mode->modified || vid_fullscreen->modified
+     	|| vid_stretched->modified)
+		Draw_SetResolution ();
+
+	if (draw_gamma->modified)
+	{
+		Draw_BuildGammaTable ();
+		Sys_SetPalette ((byte *)current_palette);
+	}
+
+//	MGL_beginDirectAccess();
+//	vid.buffer = mgldc->surface;
+//	vid.rowbytes = mgldc->mi.bytesPerLine;
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+Draw_EndFrame
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void Draw_EndFrame (void)
+{
+	int		i, c;
+	int		bps, spp, bpp, bpr;
+        unsigned char	*planes[5];
+        NSRect			bounds;
+
+	// translate to 24 bit color
+        c = vid.width*vid.height;
+	for (i=0 ; i<c ; i++)
+		buffernative[i] = gamma_palette[vid.buffer[i]];
+        
+     bps = 8;
+     spp = 3;
+     bpp = 32;
+     bpr = vid.width * 4;
+     planes[0] = (unsigned char *)buffernative;
+
+    bounds = [vid_view_i bounds];
+
+    NSDrawBitmap(
+                bounds,
+                vid.width,
+                vid.height,
+                bps,
+                spp,
+                bpp,
+                bpr,
+                NO,
+                NO,
+                 @"NSDeviceRGBColorSpace",
+                planes
+                );
+}
+
+
+//===============================================================================
+
+#define	HUNK_MAGIC	0xffaffaff
+typedef struct
+{
+    int		magic;
+    int		length;
+    int		pad[6];
+} hunkheader_t;
+
+hunkheader_t	*membase;
+int		maxsize;
+int		cursize;
+
+void *Hunk_Begin (void)
+{
+    kern_return_t	r;
+
+// reserve a huge chunk of memory, but don't commit any yet
+    maxsize = 16*1024*1024;
+    cursize = 0;
+    membase = NULL;
+    r = vm_allocate(task_self(), (vm_address_t *)&membase, maxsize, 1);
+    if (!membase || r != KERN_SUCCESS)
+            ri.Sys_Error (ERR_FATAL,"vm_allocate failed");
+    membase->magic = HUNK_MAGIC;
+    membase->length = maxsize;
+    cursize = 32;
+    return (void *)((byte *)membase + cursize);
+}
+
+void *Hunk_Alloc (int size)
+{
+	// round to cacheline
+	size = (size+31)&~31;
+	
+	cursize += size;
+
+        if (cursize > maxsize)
+            ri.Sys_Error (ERR_DROP, "Hunk_Alloc overflow");
+
+        memset ((byte *)membase+cursize-size,0,size);
+
+        return (void *)((byte *)membase+cursize-size);
+}
+
+int Hunk_End (void)
+{
+    kern_return_t	r;
+    
+    // round to pagesize
+    cursize = (cursize+vm_page_size)&~(vm_page_size-1);
+    membase->length = cursize;
+    r = vm_deallocate(task_self(),
+                  (vm_address_t)((byte *)membase + cursize),
+                  maxsize - cursize);
+    if ( r != KERN_SUCCESS )
+        ri.Sys_Error (ERR_DROP, "vm_deallocate failed");
+    return cursize;
+}
+
+void Hunk_Free (void *base)
+{
+    hunkheader_t	*h;
+    kern_return_t	r;
+    
+    h = ((hunkheader_t *)base) - 1;
+    if (h->magic != HUNK_MAGIC)
+        ri.Sys_Error (ERR_FATAL, "Hunk_Free: bad magic");
+
+    r = vm_deallocate(task_self(), (vm_address_t)h, h->length);
+    if ( r != KERN_SUCCESS )
+        ri.Sys_Error (ERR_DROP, "vm_deallocate failed");
+}
+
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+}
+
+
+/*
+================
+Sys_SetPalette
+================
+*/
+void Sys_SetPalette (byte *palette)
+{
+	byte	*p;
+	int		i;
+
+        memcpy (current_palette, palette, sizeof(current_palette));
+        p = (byte *)gamma_palette;
+	// gamma correct and byte swap
+	for (i=0 ; i<256 ; i++, p+=4, palette+=4)
+	{
+		p[0] = gammatable[palette[0]];
+		p[1] = gammatable[palette[1]];
+		p[2] = gammatable[palette[2]];
+                p[3] = 0xff;
+	}
+
+}
+
+
+/*
+ ==========================================================================
+
+ NEXTSTEP VIEW CLASS
+
+ ==========================================================================
+ */
+#include "../client/keys.h"
+
+void IN_ActivateMouse (void);
+void IN_DeactivateMouse (void);
+
+@implementation QuakeView
+
+-(BOOL) acceptsFirstResponder
+{
+    return YES;
+}
+
+- (void)windowDidMove: (NSNotification *)note
+{
+    NSRect	r;
+
+    r = [vid_window_i frame];
+    ri.Cmd_ExecuteText (EXEC_NOW, va("vid_x %i", (int)r.origin.x+1));
+    ri.Cmd_ExecuteText (EXEC_NOW, va("vid_y %i", (int)r.origin.y+1));    
+}
+
+- (void)becomeKeyWindow
+{
+    IN_ActivateMouse ();
+}
+
+- (void)resignKeyWindow
+{
+    IN_DeactivateMouse ();
+}
+
+
+typedef struct
+{
+    int		source, dest;
+} keymap_t;
+
+keymap_t keymaps[] =
+{
+    {103, K_RIGHTARROW},
+    {102, K_LEFTARROW},
+    {100, K_UPARROW},
+    {101, K_DOWNARROW},
+
+    {59, K_F1},
+    {60, K_F2},
+    {61, K_F3},
+    {62, K_F4},
+    {63, K_F5},
+    {64, K_F6},
+    {65, K_F7},
+    {66, K_F8},
+    {67, K_F9},
+    {68, K_F10},
+    {87, K_F11},
+    {88, K_F12},
+
+    {-1,-1}
+};
+
+keymap_t flagmaps[] =
+{
+    {NSShiftKeyMask, K_SHIFT},
+    {NSControlKeyMask, K_CTRL},
+    {NSAlternateKeyMask, K_ALT},
+    {NSCommandKeyMask, K_ALT},
+
+    {-1,-1}
+};
+
+- (void)mouseDown:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE1, true);
+}
+- (void)mouseUp:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE1, false);
+}
+- (void)rightMouseDown:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE2, true);
+}
+- (void)rightMouseUp:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE2, false);
+}
+
+
+/*
+ ===================
+ keyboard methods
+ ===================
+ */
+- (void)keyDown:(NSEvent *)theEvent
+{
+    int	ch;
+    keymap_t	*km;
+
+//    PSobscurecursor ();
+
+// check for non-ascii first
+    ch = [theEvent keyCode];
+    for (km=keymaps;km->source!=-1;km++)
+        if (ch == km->source)
+        {
+            Key_Event (km->dest, true);
+            return;
+        }
+
+            ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
+    if (ch >= 'A' && ch <= 'Z')
+        ch += 'a' - 'A';
+    if (ch>=256)
+        return;
+
+    Key_Event (ch, true);
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent
+{
+    static int	oldflags;
+    int		newflags;
+    int		delta;
+    keymap_t	*km;
+    int		i;
+
+//    PSobscurecursor ();
+    newflags = [theEvent modifierFlags];
+    delta = newflags ^ oldflags;
+    for (i=0 ; i<32 ; i++)
+    {
+        if ( !(delta & (1<<i)))
+            continue;
+        // changed
+        for (km=flagmaps;km->source!=-1;km++)
+            if ( (1<<i) == km->source)
+            {
+                if (newflags & (1<<i))
+                    Key_Event (km->dest, true);
+                else
+                    Key_Event (km->dest, false);
+            }
+
+    }
+
+        oldflags = newflags;
+}
+
+
+- (void)keyUp:(NSEvent *)theEvent
+{
+    int	ch;
+    keymap_t	*km;
+
+ // check for non-ascii first
+    ch = [theEvent keyCode];
+    for (km=keymaps;km->source!=-1;km++)
+        if (ch == km->source)
+        {
+            Key_Event (km->dest, false);
+            return;
+        }
+
+            ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
+    if (ch >= 'A' && ch <= 'Z')
+        ch += 'a' - 'A';
+    if (ch>=256)
+        return;
+    Key_Event (ch, false);
+}
+
+@end
+
+
--- /dev/null
+++ b/rhapsody/rhapqw.txt
@@ -1,0 +1,36 @@
+Put this QuakeWorld executable in a directory with the registered quake and QuakeWorld files.  You should be able to launch it from the workspace or the command line.
+
+The sound is a bit lagged and will likely drift on longer games, because I am using the system timer to calculate sample position.  This will need to be fixed at some point.
+
+There is no assembly language in yet, and it is still just using DPS to draw, so it isn't real fast yet.  Run it on a ppro with a write combining video driver.
+
+If you ever lose your mouse cursor inapropriately due to the game messing up, if you can restart QuakeWorld, you can type "showmouse" to bump the visibility counter by one. 
+
+You should eb able to connect to any QuakeWorld server, but you will have to do it with manual connect commands at the console, because we don't have either qspy or a browser plugin (yet) for openstep to find servers.
+
+Because the configuration ranges are different than windows, things like sensitivity and volume will need to be specified at the console.
+
+Some typical values (all of these should be saved automatically in the config file):
+
+vid_mode 1
+Sets 320*240 resolution.  320*200 (vid_mode 0) is somewhat faster, but looks scrunched at some desktop resolutions.
+
+vid_stretched 1
+Sets pixel doubling.  Slower, of cource.
+
+snd_mixahead 0.2
+Because this isn't very fast yet, you probably want to increase the mixahead from 0.1 so the sound doesn't break up.
+
+volume 0.15
+The default 0.7 is VERY loud on my system.  I don't know what it will be like on other systems.
+
+gamma 1.4
+Because openstep desktops are typically gamma corrected, the game will look washed out with default settings.  Geater than 1.0 gets darker, less than gets brighter.
+
+sensitivity 20
+The normal slider range probably doesn't give enough speed for most people.
+
+in_mouse 0
+The mouse is normally grabbed for controlling the game.  Setting this to 0 will give the mouse back to the desktop.
+
+
--- /dev/null
+++ b/rhapsody/snd_next.m
@@ -1,0 +1,2151 @@
+
+#import <servers/netname.h>
+#import <libc.h>
+
+#include "../client/client.h"
+
+double	snd_basetime;
+port_t devPort;
+
+extern	port_t	task_self_;
+#define	task_self()	task_self_
+
+//========================================================================
+
+#ifndef	_ntsoundNTSound
+#define	_ntsoundNTSound
+
+/* Module NTSound */
+
+#include <mach/kern_return.h>
+#include <mach/port.h>
+#include <mach/message.h>
+
+#ifndef	mig_external
+#define mig_external extern
+#endif
+
+#include <mach/std_types.h>
+#include <mach/mach_types.h>
+typedef short *sound_data_t;
+
+#define NTSOUNDNAME "NEXTIME_Sound"
+
+/* Routine ntsoundAcquire */
+mig_external kern_return_t ntsoundAcquire (
+        port_t kern_serv_port,
+        port_t owner_port,
+        vm_offset_t *dmaAddress,
+        int *dmaSize,
+        int *success);
+
+/* Routine ntsoundRelease */
+mig_external kern_return_t ntsoundRelease (
+        port_t kern_serv_port,
+        port_t owner_port);
+
+/* Routine ntsoundStart */
+mig_external kern_return_t ntsoundStart (
+        port_t kern_serv_port,
+        port_t owner_port);
+
+/* Routine ntsoundStop */
+mig_external kern_return_t ntsoundStop (
+        port_t kern_serv_port,
+        port_t owner_port);
+
+/* Routine ntsoundConfig */
+mig_external kern_return_t ntsoundConfig (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int channelCount,
+        int samplingRate,
+        int encoding,
+        int useInterrupts);
+
+/* Routine ntsoundBytesProcessed */
+mig_external kern_return_t ntsoundBytesProcessed (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int *byte_count);
+
+/* Routine ntsoundDMACount */
+mig_external kern_return_t ntsoundDMACount (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int *dma_count);
+
+/* Routine ntsoundInterruptCount */
+mig_external kern_return_t ntsoundInterruptCount (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int *irq_count);
+
+/* Routine ntsoundWrite */
+mig_external kern_return_t ntsoundWrite (
+        port_t kern_serv_port,
+        port_t owner_port,
+        sound_data_t data,
+        unsigned int dataCnt,
+        int *actual_count);
+
+/* Routine ntsoundSetVolume */
+mig_external kern_return_t ntsoundSetVolume (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int value);
+
+/* Routine ntsoundWireRange */
+mig_external kern_return_t ntsoundWireRange (
+        port_t device_port,
+        port_t token,
+        port_t task,
+        vm_offset_t addr,
+        vm_size_t size,
+        boolean_t wire);
+
+#endif	_ntsoundNTSound
+
+//========================================================================
+
+extern	port_t	name_server_port;
+
+#define NX_SoundDeviceParameterKeyBase		0
+#define NX_SoundDeviceParameterValueBase	200
+#define NX_SoundStreamParameterKeyBase		400
+#define NX_SoundStreamParameterValueBase	600
+#define NX_SoundParameterTagMax			799
+
+typedef enum _NXSoundParameterTag {
+   NX_SoundDeviceBufferSize = NX_SoundDeviceParameterKeyBase,
+   NX_SoundDeviceBufferCount,
+   NX_SoundDeviceDetectPeaks,
+   NX_SoundDeviceRampUp,
+   NX_SoundDeviceRampDown,
+   NX_SoundDeviceInsertZeros,
+   NX_SoundDeviceDeemphasize,
+   NX_SoundDeviceMuteSpeaker,
+   NX_SoundDeviceMuteHeadphone,
+   NX_SoundDeviceMuteLineOut,
+   NX_SoundDeviceOutputLoudness,
+   NX_SoundDeviceOutputAttenuationStereo,
+   NX_SoundDeviceOutputAttenuationLeft,
+   NX_SoundDeviceOutputAttenuationRight,
+   NX_SoundDeviceAnalogInputSource,
+   NX_SoundDeviceMonitorAttenuation,
+   NX_SoundDeviceInputGainStereo,
+   NX_SoundDeviceInputGainLeft,
+   NX_SoundDeviceInputGainRight,
+
+   NX_SoundDeviceAnalogInputSource_Microphone
+       = NX_SoundDeviceParameterValueBase,
+   NX_SoundDeviceAnalogInputSource_LineIn,
+
+   NX_SoundStreamDataEncoding = NX_SoundStreamParameterKeyBase,
+   NX_SoundStreamSamplingRate,
+   NX_SoundStreamChannelCount,
+   NX_SoundStreamHighWaterMark,
+   NX_SoundStreamLowWaterMark,
+   NX_SoundStreamSource,
+   NX_SoundStreamSink,
+   NX_SoundStreamDetectPeaks,
+   NX_SoundStreamGainStereo,
+   NX_SoundStreamGainLeft,
+   NX_SoundStreamGainRight,
+
+   NX_SoundStreamDataEncoding_Linear16 = NX_SoundStreamParameterValueBase,
+   NX_SoundStreamDataEncoding_Linear8,
+   NX_SoundStreamDataEncoding_Mulaw8,
+   NX_SoundStreamDataEncoding_Alaw8,
+   NX_SoundStreamDataEncoding_AES,
+   NX_SoundStreamSource_Analog,
+   NX_SoundStreamSource_AES,
+   NX_SoundStreamSink_Analog,
+   NX_SoundStreamSink_AES
+} NXSoundParameterTag;
+
+//========================================================================
+
+//#include "NTSound.h"
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mig_errors.h>
+#include <mach/msg_type.h>
+#if	!defined(KERNEL) && !defined(MIG_NO_STRINGS)
+#include <strings.h>
+#endif
+/* LINTLIBRARY */
+
+extern port_t mig_get_reply_port();
+extern void mig_dealloc_reply_port();
+
+#ifndef	mig_internal
+#define	mig_internal	static
+#endif
+
+#ifndef	TypeCheck
+#define	TypeCheck 1
+#endif
+
+#ifndef	UseExternRCSId
+#ifdef	hc
+#define	UseExternRCSId		1
+#endif
+#endif
+
+#ifndef	UseStaticMsgType
+#if	!defined(hc) || defined(__STDC__)
+#define	UseStaticMsgType	1
+#endif
+#endif
+
+#define msg_request_port	msg_remote_port
+#define msg_reply_port		msg_local_port
+
+
+/* Routine Acquire */
+mig_external kern_return_t ntsoundAcquire (
+        port_t kern_serv_port,
+        port_t owner_port,
+        vm_offset_t *dmaAddress,
+        int *dmaSize,
+        int *success)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+                msg_type_t dmaAddressType;
+                vm_offset_t dmaAddress;
+                msg_type_t dmaSizeType;
+                int dmaSize;
+                msg_type_t successType;
+                int success;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t dmaAddressCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t dmaSizeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t successCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1008;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1108)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 56) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->dmaAddressType != * (int *) &dmaAddressCheck)
+#else	UseStaticMsgType
+        if ((OutP->dmaAddressType.msg_type_inline != TRUE) ||
+            (OutP->dmaAddressType.msg_type_longform != FALSE) ||
+            (OutP->dmaAddressType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->dmaAddressType.msg_type_number != 1) ||
+            (OutP->dmaAddressType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *dmaAddress /* dmaAddress */ = /* *dmaAddress */ OutP->dmaAddress;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->dmaSizeType != * (int *) &dmaSizeCheck)
+#else	UseStaticMsgType
+        if ((OutP->dmaSizeType.msg_type_inline != TRUE) ||
+            (OutP->dmaSizeType.msg_type_longform != FALSE) ||
+            (OutP->dmaSizeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->dmaSizeType.msg_type_number != 1) ||
+            (OutP->dmaSizeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *dmaSize /* dmaSize */ = /* *dmaSize */ OutP->dmaSize;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->successType != * (int *) &successCheck)
+#else	UseStaticMsgType
+        if ((OutP->successType.msg_type_inline != TRUE) ||
+            (OutP->successType.msg_type_longform != FALSE) ||
+            (OutP->successType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->successType.msg_type_number != 1) ||
+            (OutP->successType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *success /* success */ = /* *success */ OutP->success;
+
+        return OutP->RetCode;
+}
+
+/* Routine Release */
+mig_external kern_return_t ntsoundRelease (
+        port_t kern_serv_port,
+        port_t owner_port)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1009;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1109)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 32) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+        return OutP->RetCode;
+}
+
+/* Routine Start */
+mig_external kern_return_t ntsoundStart (
+        port_t kern_serv_port,
+        port_t owner_port)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1010;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1110)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 32) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+        return OutP->RetCode;
+}
+
+/* Routine Stop */
+mig_external kern_return_t ntsoundStop (
+        port_t kern_serv_port,
+        port_t owner_port)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1011;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1111)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 32) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+        return OutP->RetCode;
+}
+
+/* Routine Config */
+mig_external kern_return_t ntsoundConfig (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int channelCount,
+        int samplingRate,
+        int encoding,
+        int useInterrupts)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+                msg_type_t channelCountType;
+                int channelCount;
+                msg_type_t samplingRateType;
+                int samplingRate;
+                msg_type_t encodingType;
+                int encoding;
+                msg_type_t useInterruptsType;
+                int useInterrupts;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 64;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t channelCountType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t samplingRateType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t encodingType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t useInterruptsType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+#if	UseStaticMsgType
+        InP->channelCountType = channelCountType;
+#else	UseStaticMsgType
+        InP->channelCountType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->channelCountType.msg_type_size = 32;
+        InP->channelCountType.msg_type_number = 1;
+        InP->channelCountType.msg_type_inline = TRUE;
+        InP->channelCountType.msg_type_longform = FALSE;
+        InP->channelCountType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->channelCount /* channelCount */ = /* channelCount */ channelCount;
+
+#if	UseStaticMsgType
+        InP->samplingRateType = samplingRateType;
+#else	UseStaticMsgType
+        InP->samplingRateType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->samplingRateType.msg_type_size = 32;
+        InP->samplingRateType.msg_type_number = 1;
+        InP->samplingRateType.msg_type_inline = TRUE;
+        InP->samplingRateType.msg_type_longform = FALSE;
+        InP->samplingRateType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->samplingRate /* samplingRate */ = /* samplingRate */ samplingRate;
+
+#if	UseStaticMsgType
+        InP->encodingType = encodingType;
+#else	UseStaticMsgType
+        InP->encodingType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->encodingType.msg_type_size = 32;
+        InP->encodingType.msg_type_number = 1;
+        InP->encodingType.msg_type_inline = TRUE;
+        InP->encodingType.msg_type_longform = FALSE;
+        InP->encodingType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->encoding /* encoding */ = /* encoding */ encoding;
+
+#if	UseStaticMsgType
+        InP->useInterruptsType = useInterruptsType;
+#else	UseStaticMsgType
+        InP->useInterruptsType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->useInterruptsType.msg_type_size = 32;
+        InP->useInterruptsType.msg_type_number = 1;
+        InP->useInterruptsType.msg_type_inline = TRUE;
+        InP->useInterruptsType.msg_type_longform = FALSE;
+        InP->useInterruptsType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->useInterrupts /* useInterrupts */ = /* useInterrupts */ useInterrupts;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1012;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1112)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 32) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+        return OutP->RetCode;
+}
+
+/* Routine BytesProcessed */
+mig_external kern_return_t ntsoundBytesProcessed (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int *byte_count)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+                msg_type_t byte_countType;
+                int byte_count;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t byte_countCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1013;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1113)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 40) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->byte_countType != * (int *) &byte_countCheck)
+#else	UseStaticMsgType
+        if ((OutP->byte_countType.msg_type_inline != TRUE) ||
+            (OutP->byte_countType.msg_type_longform != FALSE) ||
+            (OutP->byte_countType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->byte_countType.msg_type_number != 1) ||
+            (OutP->byte_countType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *byte_count /* byte_count */ = /* *byte_count */ OutP->byte_count;
+
+        return OutP->RetCode;
+}
+
+/* Routine DMACount */
+mig_external kern_return_t ntsoundDMACount (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int *dma_count)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+                msg_type_t dma_countType;
+                int dma_count;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t dma_countCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1014;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1114)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 40) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->dma_countType != * (int *) &dma_countCheck)
+#else	UseStaticMsgType
+        if ((OutP->dma_countType.msg_type_inline != TRUE) ||
+            (OutP->dma_countType.msg_type_longform != FALSE) ||
+            (OutP->dma_countType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->dma_countType.msg_type_number != 1) ||
+            (OutP->dma_countType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *dma_count /* dma_count */ = /* *dma_count */ OutP->dma_count;
+
+        return OutP->RetCode;
+}
+
+/* Routine InterruptCount */
+mig_external kern_return_t ntsoundInterruptCount (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int *irq_count)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+                msg_type_t irq_countType;
+                int irq_count;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 32;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t irq_countCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1015;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1115)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 40) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->irq_countType != * (int *) &irq_countCheck)
+#else	UseStaticMsgType
+        if ((OutP->irq_countType.msg_type_inline != TRUE) ||
+            (OutP->irq_countType.msg_type_longform != FALSE) ||
+            (OutP->irq_countType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->irq_countType.msg_type_number != 1) ||
+            (OutP->irq_countType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *irq_count /* irq_count */ = /* *irq_count */ OutP->irq_count;
+
+        return OutP->RetCode;
+}
+
+/* Routine Write */
+mig_external kern_return_t ntsoundWrite (
+        port_t kern_serv_port,
+        port_t owner_port,
+        sound_data_t data,
+        unsigned int dataCnt,
+        int *actual_count)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+                msg_type_long_t dataType;
+                short data[7000];
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+                msg_type_t actual_countType;
+                int actual_count;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 44;
+        /* Maximum request size 14044 */
+        unsigned int msg_size_delta;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_long_t dataType = {
+        {
+                /* msg_type_name = */		0,
+                /* msg_type_size = */		0,
+                /* msg_type_number = */		0,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	TRUE,
+                /* msg_type_deallocate = */	FALSE,
+        },
+                /* msg_type_long_name = */	MSG_TYPE_INTEGER_16,
+                /* msg_type_long_size = */	16,
+                /* msg_type_long_number = */	7000,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t actual_countCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+#if	UseStaticMsgType
+        InP->dataType = dataType;
+#else	UseStaticMsgType
+        InP->dataType.msg_type_long_name = MSG_TYPE_INTEGER_16;
+        InP->dataType.msg_type_long_size = 16;
+        InP->dataType.msg_type_header.msg_type_inline = TRUE;
+        InP->dataType.msg_type_header.msg_type_longform = TRUE;
+        InP->dataType.msg_type_header.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        if (dataCnt > 7000)
+                return MIG_ARRAY_TOO_LARGE;
+        bcopy((char *) data, (char *) InP->data, 2 * dataCnt);
+
+        InP->dataType.msg_type_long_number /* dataCnt */ = /* dataType.msg_type_long_number */ dataCnt;
+
+        msg_size_delta = (2 * dataCnt + 3) & ~3;
+        msg_size += msg_size_delta;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1016;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1116)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 40) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->actual_countType != * (int *) &actual_countCheck)
+#else	UseStaticMsgType
+        if ((OutP->actual_countType.msg_type_inline != TRUE) ||
+            (OutP->actual_countType.msg_type_longform != FALSE) ||
+            (OutP->actual_countType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->actual_countType.msg_type_number != 1) ||
+            (OutP->actual_countType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        *actual_count /* actual_count */ = /* *actual_count */ OutP->actual_count;
+
+        return OutP->RetCode;
+}
+
+/* Routine SetVolume */
+mig_external kern_return_t ntsoundSetVolume (
+        port_t kern_serv_port,
+        port_t owner_port,
+        int value)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t owner_portType;
+                port_t owner_port;
+                msg_type_t valueType;
+                int value;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 40;
+
+#if	UseStaticMsgType
+        static const msg_type_t owner_portType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t valueType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->owner_portType = owner_portType;
+#else	UseStaticMsgType
+        InP->owner_portType.msg_type_name = MSG_TYPE_PORT;
+        InP->owner_portType.msg_type_size = 32;
+        InP->owner_portType.msg_type_number = 1;
+        InP->owner_portType.msg_type_inline = TRUE;
+        InP->owner_portType.msg_type_longform = FALSE;
+        InP->owner_portType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->owner_port /* owner_port */ = /* owner_port */ owner_port;
+
+#if	UseStaticMsgType
+        InP->valueType = valueType;
+#else	UseStaticMsgType
+        InP->valueType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->valueType.msg_type_size = 32;
+        InP->valueType.msg_type_number = 1;
+        InP->valueType.msg_type_inline = TRUE;
+        InP->valueType.msg_type_longform = FALSE;
+        InP->valueType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->value /* value */ = /* value */ value;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = kern_serv_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1017;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1117)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 32) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+        return OutP->RetCode;
+}
+
+/* Routine WireRange */
+mig_external kern_return_t ntsoundWireRange (
+        port_t device_port,
+        port_t token,
+        port_t task,
+        vm_offset_t addr,
+        vm_size_t size,
+        boolean_t wire)
+{
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t tokenType;
+                port_t token;
+                msg_type_t taskType;
+                port_t task;
+                msg_type_t addrType;
+                vm_offset_t addr;
+                msg_type_t sizeType;
+                vm_size_t size;
+                msg_type_t wireType;
+                boolean_t wire;
+        } Request;
+
+        typedef struct {
+                msg_header_t Head;
+                msg_type_t RetCodeType;
+                kern_return_t RetCode;
+        } Reply;
+
+        union {
+                Request In;
+                Reply Out;
+        } Mess;
+
+        register Request *InP = &Mess.In;
+        register Reply *OutP = &Mess.Out;
+
+        msg_return_t msg_result;
+
+#if	TypeCheck
+        boolean_t msg_simple;
+#endif	TypeCheck
+
+        unsigned int msg_size = 64;
+
+#if	UseStaticMsgType
+        static const msg_type_t tokenType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t taskType = {
+                /* msg_type_name = */		MSG_TYPE_PORT,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t addrType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t sizeType = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t wireType = {
+                /* msg_type_name = */		MSG_TYPE_BOOLEAN,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0,
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        static const msg_type_t RetCodeCheck = {
+                /* msg_type_name = */		MSG_TYPE_INTEGER_32,
+                /* msg_type_size = */		32,
+                /* msg_type_number = */		1,
+                /* msg_type_inline = */		TRUE,
+                /* msg_type_longform = */	FALSE,
+                /* msg_type_deallocate = */	FALSE,
+                /* msg_type_unused = */		0
+        };
+#endif	UseStaticMsgType
+
+#if	UseStaticMsgType
+        InP->tokenType = tokenType;
+#else	UseStaticMsgType
+        InP->tokenType.msg_type_name = MSG_TYPE_PORT;
+        InP->tokenType.msg_type_size = 32;
+        InP->tokenType.msg_type_number = 1;
+        InP->tokenType.msg_type_inline = TRUE;
+        InP->tokenType.msg_type_longform = FALSE;
+        InP->tokenType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->token /* token */ = /* token */ token;
+
+#if	UseStaticMsgType
+        InP->taskType = taskType;
+#else	UseStaticMsgType
+        InP->taskType.msg_type_name = MSG_TYPE_PORT;
+        InP->taskType.msg_type_size = 32;
+        InP->taskType.msg_type_number = 1;
+        InP->taskType.msg_type_inline = TRUE;
+        InP->taskType.msg_type_longform = FALSE;
+        InP->taskType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->task /* task */ = /* task */ task;
+
+#if	UseStaticMsgType
+        InP->addrType = addrType;
+#else	UseStaticMsgType
+        InP->addrType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->addrType.msg_type_size = 32;
+        InP->addrType.msg_type_number = 1;
+        InP->addrType.msg_type_inline = TRUE;
+        InP->addrType.msg_type_longform = FALSE;
+        InP->addrType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->addr /* addr */ = /* addr */ addr;
+
+#if	UseStaticMsgType
+        InP->sizeType = sizeType;
+#else	UseStaticMsgType
+        InP->sizeType.msg_type_name = MSG_TYPE_INTEGER_32;
+        InP->sizeType.msg_type_size = 32;
+        InP->sizeType.msg_type_number = 1;
+        InP->sizeType.msg_type_inline = TRUE;
+        InP->sizeType.msg_type_longform = FALSE;
+        InP->sizeType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->size /* size */ = /* size */ size;
+
+#if	UseStaticMsgType
+        InP->wireType = wireType;
+#else	UseStaticMsgType
+        InP->wireType.msg_type_name = MSG_TYPE_BOOLEAN;
+        InP->wireType.msg_type_size = 32;
+        InP->wireType.msg_type_number = 1;
+        InP->wireType.msg_type_inline = TRUE;
+        InP->wireType.msg_type_longform = FALSE;
+        InP->wireType.msg_type_deallocate = FALSE;
+#endif	UseStaticMsgType
+
+        InP->wire /* wire */ = /* wire */ wire;
+
+        InP->Head.msg_simple = FALSE;
+        InP->Head.msg_size = msg_size;
+        InP->Head.msg_type = MSG_TYPE_NORMAL | MSG_TYPE_RPC;
+        InP->Head.msg_request_port = device_port;
+        InP->Head.msg_reply_port = mig_get_reply_port();
+        InP->Head.msg_id = 1018;
+
+        msg_result = msg_rpc(&InP->Head, MSG_OPTION_NONE, sizeof(Reply), 0, 0);
+        if (msg_result != RPC_SUCCESS) {
+                if (msg_result == RCV_INVALID_PORT)
+                        mig_dealloc_reply_port();
+                return msg_result;
+        }
+
+#if	TypeCheck
+        msg_size = OutP->Head.msg_size;
+        msg_simple = OutP->Head.msg_simple;
+#endif	TypeCheck
+
+        if (OutP->Head.msg_id != 1118)
+                return MIG_REPLY_MISMATCH;
+
+#if	TypeCheck
+        if (((msg_size != 32) || (msg_simple != TRUE)) &&
+            ((msg_size != sizeof(death_pill_t)) ||
+             (msg_simple != TRUE) ||
+             (OutP->RetCode == KERN_SUCCESS)))
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+#if	TypeCheck
+#if	UseStaticMsgType
+        if (* (int *) &OutP->RetCodeType != * (int *) &RetCodeCheck)
+#else	UseStaticMsgType
+        if ((OutP->RetCodeType.msg_type_inline != TRUE) ||
+            (OutP->RetCodeType.msg_type_longform != FALSE) ||
+            (OutP->RetCodeType.msg_type_name != MSG_TYPE_INTEGER_32) ||
+            (OutP->RetCodeType.msg_type_number != 1) ||
+            (OutP->RetCodeType.msg_type_size != 32))
+#endif	UseStaticMsgType
+                return MIG_TYPE_ERROR;
+#endif	TypeCheck
+
+        if (OutP->RetCode != KERN_SUCCESS)
+                return OutP->RetCode;
+
+        return OutP->RetCode;
+}
+
+
+//========================================================================
+
+/*
+==================
+SNDDMA_Init
+
+Try to find a sound device to mix for.
+Returns false if nothing is found.
+==================
+*/
+qboolean SNDDMA_Init(void)
+{
+    int		err;
+    int		i;
+	byte	*buf;
+        int	bufsize;
+  	int	progress, oldprogress;
+        
+    shm = &sn;
+    shm->channels = 2;
+    shm->samplebits = 16;
+    shm->speed = 11025;
+
+    err = netname_look_up(name_server_port,"", NTSOUNDNAME,&devPort);
+    if (err)
+    {
+        Com_Printf("SNDDMA_Init: Cannot access theater driver\n");
+        return false;
+    }
+
+    err = ntsoundAcquire(devPort,task_self(),(vm_offset_t *)&buf,&bufsize,&i);
+    if (err || !i)
+    {
+        Com_Printf("SNDDMA_Init: Sound driver is busy or messed up\n");
+        return false;
+    }
+
+    err = ntsoundConfig(devPort,task_self(),shm->channels,(int)shm->speed,
+                        NX_SoundStreamDataEncoding_Linear16, 1);
+    if (err)
+    {
+        Com_Printf("SNDDMA_Init: ntsoundConfig error: %d\n",err);
+        return false;
+    }
+    else
+        Com_Printf("SNDDMA_Init: Configured for %d Hz, %d channels\n"
+                   ,(int)shm->speed,shm->channels);
+ //   printf ("buf: 0x%x\n", buf);
+ //   printf ("bufsize: %d\n", bufsize);
+
+    bzero(buf,bufsize);
+
+//   ntsoundSetVolume(devPort,task_self(),5);
+   ntsoundStart(devPort,task_self());
+
+   shm->soundalive = true;
+   shm->splitbuffer = false;
+   shm->samples = bufsize/(shm->samplebits/8);
+   shm->samplepos = 0;
+   shm->submission_chunk = 1;
+   shm->buffer = buf;
+
+   //
+   // find a buffer crossing point for pos testing
+   //
+   
+   ntsoundBytesProcessed(devPort,task_self(),&oldprogress);
+   do
+       {
+       ntsoundBytesProcessed(devPort,task_self(),&progress);
+     } while (progress == oldprogress);
+   snd_basetime = Sys_DoubleTime() - progress/(11025*2);
+ 
+   return true;
+}
+
+/*
+==============
+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		progress;
+
+#if 0
+    ntsoundBytesProcessed(devPort,task_self(),&progress);
+//    ntsoundDMACount(devPort,task_self(),&progress);
+
+//printf ("(%i / %f) ", progress, (float)(Sys_DoubleTime ()));
+    progress += 2048;
+    progress >>= 1;
+#else
+    
+ progress = (Sys_DoubleTime() - snd_basetime)*11025*2;
+ progress += 8192;
+ progress &= ~1;
+#endif
+ 
+    progress &= (shm->samples-1);
+
+    return progress;
+}
+
+
+/*
+==============
+SNDDMA_Submit
+
+Reset the sound device for exiting
+===============
+*/
+void SNDDMA_Submit(void)
+{
+}
+
+/*
+==============
+SNDDMA_Shutdown
+
+Reset the sound device for exiting
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+    ntsoundStop(devPort,task_self());
+    ntsoundRelease(devPort,task_self());
+}
+
--- /dev/null
+++ b/rhapsody/swimp_rhap.m
@@ -1,0 +1,580 @@
+#import <AppKit/AppKit.h>
+#import <Interceptor/NSDirectScreen.h>
+#import <AppKit/NSColor.h>
+#include "../ref_soft/r_local.h"
+
+@interface QuakeView : NSView
+@end
+
+NSWindow	*vid_window_i;
+QuakeView	*vid_view_i;
+NSDirectScreen *vid_screen;
+byte		*vid_buffer;		// real framebuffer
+int			vid_rowbytes;		// framebuffer rowbytes
+
+unsigned	*buffernative;		// 24 bit off-screen back buffer for window
+unsigned	swimp_palette[256];
+
+typedef enum {
+    rhap_shutdown,
+    rhap_windowed,
+    rhap_fullscreen
+} rhapMode_t;
+
+rhapMode_t	rhap_mode;
+
+/*
+=======================================================================
+
+FULLSCREEN
+
+=======================================================================
+*/
+
+/*
+** InitFullscreen
+*/
+rserr_t InitFullscreen (int width, int height)
+{
+    NSDictionary *mode, *bestMode;
+    int			modeWidth, bestWidth;
+    int			modeHeight, bestHeight;
+	NSArray		*modes;
+    int			i;
+	NSString	*string;
+
+    
+    vid_screen = [[NSDirectScreen alloc] initWithScreen:[NSScreen mainScreen]];
+
+    // search for an apropriate mode
+    modes = [vid_screen availableDisplayModes];
+    bestMode = NULL;
+    bestWidth = 99999;
+    bestHeight = 99999;
+   	for (i=0 ; i<[modes count] ; i++) {
+        mode = [modes objectAtIndex: i];
+        string = [mode objectForKey: @"NSDirectScreenPixelEncoding"];
+        if ( ![string isEqualToString: @"PPPPPPPP"] )
+            continue;	// only look at paletted modes
+        modeWidth = [[mode objectForKey: @"NSDirectScreenWidth"] intValue];
+        modeHeight = [[mode objectForKey: @"NSDirectScreenHeight"] intValue];
+        if (modeWidth < width || modeHeight < height)
+            continue;
+        if (modeWidth < bestWidth) {
+            bestWidth = modeWidth;
+            bestHeight = modeHeight;
+            bestMode = mode;
+        }
+    } 
+
+    // if there wasn't any paletted mode of that res or greater, fail
+    if (!bestMode)
+        return rserr_invalid_fullscreen;
+
+	ri.Con_Printf (PRINT_ALL, "SheildDisplay\n");
+    [vid_screen shieldDisplay];
+
+    // hide the cursor in all fullscreen modes
+    [NSCursor hide];
+    
+    vid_window_i = [vid_screen shieldingWindow];
+
+    ri.Con_Printf (PRINT_ALL, "switchToDisplayMode\n");
+    [vid_screen switchToDisplayMode:bestMode];
+//    [vid_screen fadeDisplayOutToColor:[NSColor blackColor]];
+//    [vid_screen fadeDisplayInFromColor:[NSColor blackColor]];
+
+	vid_buffer = [vid_screen data];
+	vid_rowbytes = [vid_screen bytesPerRow];
+
+    return rserr_ok;
+}
+
+void ShutdownFullscreen (void)
+{
+	[vid_screen dealloc];
+	[NSCursor unhide];
+}
+
+void SetPaletteFullscreen (const unsigned char *palette) {
+#if 0
+    byte	*p;
+    int		i;
+	NSDirectPalette		*pal;
+
+    pal = [NSDirectPalette init];
+    for (i=0 ; i<256 ; i++)
+        [pal setRed: palette[0]*(1.0/255)
+              green:  palette[1]*(1.0/255)
+               blue:  palette[2]*(1.0/255)
+            atIndex: i];
+	[vid_screen setPalette: pal];
+    [pal release];
+#endif
+}
+
+
+
+void BlitFullscreen (void)
+{
+	int		i, j;
+	int		w;
+	int		*dest, *source;
+
+	w = vid.width>>2;
+
+    source = (int *)vid.buffer;		// off-screen buffer
+    dest = (int *)vid_buffer;		// directly on screen
+    for (j=0 ; j<vid.height ; j++
+         , source += (vid.rowbytes>>2), dest += (vid_rowbytes>>2)  ) {
+        for (i=0 ; i<w ; i++ ) {
+            dest[i] = source[i];            
+        }
+ 	}
+}
+
+/*
+=======================================================================
+
+WINDOWED
+
+=======================================================================
+*/
+
+/*
+** InitWindowed
+*/
+rserr_t InitWindowed (int width, int height)
+{
+    rserr_t retval = rserr_ok;
+    NSRect	content;
+    cvar_t	*vid_xpos;
+    cvar_t	*vid_ypos;
+
+    //
+    // open a window
+    //
+    vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
+    vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
+
+    content = NSMakeRect (vid_xpos->value,vid_ypos->value, width, height);
+    vid_window_i = [[NSWindow alloc]
+                initWithContentRect:	content
+                            styleMask:	NSTitledWindowMask
+                            backing:	NSBackingStoreRetained
+                            defer:	NO
+    ];
+
+//    [vid_window_i addToEventMask: NS_FLAGSCHANGEDMASK];
+    [vid_window_i setTitle: @"Quake2"];
+
+    buffernative = malloc(width * height * 4);
+
+    return retval;
+}
+
+void ShutdownWindowed (void)
+{
+    if (vid_window_i)
+    {
+        [vid_window_i release];
+        vid_window_i = NULL;
+    }
+    if (buffernative)
+    {
+        free (buffernative);
+        buffernative = NULL;
+    }
+}
+
+void SetPaletteWindowed (const unsigned char *palette) {
+    byte	*p;
+    int		i;
+
+    p = (byte *)swimp_palette;
+    for (i=0 ; i<256 ; i++, p+=4, palette+=4)
+    {
+        p[0] = palette[0];
+       	p[1] = palette[1];
+        p[2] = palette[2];
+        p[3] = 0xff;
+    }
+}
+
+
+void BlitWindowed (void)
+{
+    int		i, c;
+    int		bps, spp, bpp, bpr;
+    unsigned char	*planes[5];
+    NSRect			bounds;
+
+    if (!vid_view_i)
+        return;
+
+    // translate to 24 bit color
+    c = vid.width*vid.height;
+    for (i=0 ; i<c ; i++)
+        buffernative[i] = swimp_palette[vid.buffer[i]];
+
+     bps = 8;
+     spp = 3;
+     bpp = 32;
+     bpr = vid.width * 4;
+     planes[0] = (unsigned char *)buffernative;
+
+    bounds = [vid_view_i bounds];
+
+    [vid_view_i lockFocus];
+
+    NSDrawBitmap(
+                bounds,
+                vid.width,
+                vid.height,
+                bps,
+                spp,
+                bpp,
+                bpr,
+                NO,
+                NO,
+                 @"NSDeviceRGBColorSpace",
+                planes
+                );
+
+    [vid_view_i unlockFocus];
+	PSWait ();
+}
+
+
+//======================================================================
+
+/*
+** RW_IMP.C
+**
+** This file contains ALL Win32 specific stuff having to do with the
+** software refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** SWimp_EndFrame
+** SWimp_Init
+** SWimp_SetPalette
+** SWimp_Shutdown
+*/
+
+
+/*
+** SWimp_Init
+**
+** This routine is responsible for initializing the implementation
+** specific stuff in a software rendering subsystem.
+*/
+int SWimp_Init( void *hInstance, void *wndProc )
+{
+    if (!NSApp)
+    {
+        [NSApplication sharedApplication];
+        [NSApp finishLaunching];
+    }
+
+    return true;
+}
+
+
+/*
+** SWimp_SetMode
+*/
+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen)
+{
+    const char 	*win_fs[] = { "W", "FS" };
+    NSRect		content;
+	rserr_t		ret;
+    
+    // free resources in use
+    SWimp_Shutdown ();
+
+    ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
+
+    if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
+    {
+        ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+        return rserr_invalid_mode;
+    }
+
+    ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] );
+
+    vid.buffer = malloc(*pwidth * *pheight);
+	vid.rowbytes = *pwidth;
+
+    if (fullscreen) {
+        rhap_mode = rhap_fullscreen;
+        ret = InitFullscreen (*pwidth, *pheight);        
+    } else {
+        rhap_mode = rhap_windowed;
+        ret = InitWindowed (*pwidth, *pheight);
+    }
+
+    if (ret != rserr_ok) {
+        SWimp_Shutdown ();
+        return ret;       
+    }
+    
+    /*
+     ** the view is identical in windowed and fullscreen modes
+     */
+    content.origin.x = content.origin.y = 0;
+    content.size.width = *pwidth;
+    content.size.height = *pheight;
+    vid_view_i = [[QuakeView alloc] initWithFrame: content];
+    [vid_window_i setContentView: vid_view_i];
+    [vid_window_i makeFirstResponder: vid_view_i];
+    [vid_window_i setDelegate: vid_view_i];
+
+    [NSApp activateIgnoringOtherApps: YES];
+    [vid_window_i makeKeyAndOrderFront: nil];
+    [vid_window_i display];
+
+	return ret;
+}
+
+/*
+** SWimp_Shutdown
+**
+** System specific graphics subsystem shutdown routine
+*/
+void SWimp_Shutdown( void )
+{
+    if (rhap_mode == rhap_windowed)
+        ShutdownWindowed ();
+    else if (rhap_mode == rhap_fullscreen)
+        ShutdownFullscreen ();
+
+    rhap_mode = rhap_shutdown;
+
+    if (vid.buffer)
+    {
+        free (vid.buffer);
+        vid.buffer = NULL;
+    }
+}
+
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine.  A NULL palette means
+** to use the existing palette.  The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+void SWimp_SetPalette( const unsigned char *palette )
+{
+    if (rhap_mode == rhap_windowed)
+        SetPaletteWindowed (palette);
+    else if (rhap_mode == rhap_fullscreen)
+        SetPaletteFullscreen (palette);
+}
+
+
+/*
+** SWimp_EndFrame
+**
+** This does an implementation specific copy from the backbuffer to the
+** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
+** on whether we're using DIB sections/GDI or DDRAW.
+*/
+void SWimp_EndFrame (void)
+{
+    if (rhap_mode == rhap_windowed)
+        BlitWindowed ();
+    else if (rhap_mode == rhap_fullscreen)
+        BlitFullscreen ();
+}
+
+
+/*
+** SWimp_AppActivate
+*/
+void SWimp_AppActivate( qboolean active )
+{
+}
+
+
+/*
+ ==========================================================================
+
+ NEXTSTEP VIEW CLASS
+
+ ==========================================================================
+ */
+#include "../client/keys.h"
+
+void IN_ActivateMouse (void);
+void IN_DeactivateMouse (void);
+
+@implementation QuakeView
+
+-(BOOL) acceptsFirstResponder
+{
+    return YES;
+}
+
+- (void)windowDidMove: (NSNotification *)note
+{
+    NSRect	r;
+
+    r = [vid_window_i frame];
+    ri.Cmd_ExecuteText (EXEC_NOW, va("vid_xpos %i", (int)r.origin.x+1));
+    ri.Cmd_ExecuteText (EXEC_NOW, va("vid_ypos %i", (int)r.origin.y+1));
+}
+
+- (void)becomeKeyWindow
+{
+    IN_ActivateMouse ();
+}
+
+- (void)resignKeyWindow
+{
+    IN_DeactivateMouse ();
+}
+
+
+typedef struct
+{
+    int		source, dest;
+} keymap_t;
+
+keymap_t keymaps[] =
+{
+    {0xf703, K_RIGHTARROW},
+	{0xf702, K_LEFTARROW},
+	{0xf700, K_UPARROW},
+	{0xf701, K_DOWNARROW},
+
+	{0xf704, K_F1},
+	{0xf705, K_F2},
+	{0xf706, K_F3},
+	{0xf707, K_F4},
+	{0xf708, K_F5},
+	{0xf709, K_F6},
+	{0xf70a, K_F7},
+	{0xf70b, K_F8},
+	{0xf70c, K_F9},
+	{0xf70d, K_F10},
+	{0xf70e, K_F11},
+	{0xf70f, K_F12},
+
+    {-1,-1}
+};
+
+keymap_t flagmaps[] =
+{
+    {NSShiftKeyMask, K_SHIFT},
+    {NSControlKeyMask, K_CTRL},
+    {NSAlternateKeyMask, K_ALT},
+    {NSCommandKeyMask, K_ALT},
+
+    {-1,-1}
+};
+
+- (void)mouseDown:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE1, true, 0);
+}
+- (void)mouseUp:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE1, false, 0);
+}
+- (void)rightMouseDown:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE2, true, 0);
+}
+- (void)rightMouseUp:(NSEvent *)theEvent
+{
+    Key_Event (K_MOUSE2, false, 0);
+}
+
+
+/*
+ ===================
+ keyboard methods
+ ===================
+ */
+- (void)keyDown:(NSEvent *)theEvent
+{
+    int	ch;
+    keymap_t	*km;
+
+//    PSobscurecursor ();
+
+    ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
+// check for non-ascii first
+   for (km=keymaps;km->source!=-1;km++)
+       if (ch == km->source)
+       {
+           Key_Event (km->dest, true, 0);
+           return;
+       }
+
+    if (ch >= 'A' && ch <= 'Z')
+        ch += 'a' - 'A';
+    if (ch>=256)
+        return;
+
+    Key_Event (ch, true, 0);
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent
+{
+    static int	oldflags;
+    int		newflags;
+    int		delta;
+    keymap_t	*km;
+    int		i;
+
+//    PSobscurecursor ();
+    newflags = [theEvent modifierFlags];
+    delta = newflags ^ oldflags;
+    for (i=0 ; i<32 ; i++)
+    {
+        if ( !(delta & (1<<i)))
+            continue;
+        // changed
+        for (km=flagmaps;km->source!=-1;km++)
+            if ( (1<<i) == km->source)
+            {
+                if (newflags & (1<<i))
+                    Key_Event (km->dest, true, 0);
+                else
+                    Key_Event (km->dest, false, 0);
+            }
+
+    }
+
+        oldflags = newflags;
+}
+
+
+- (void)keyUp:(NSEvent *)theEvent
+{
+    int	ch;
+    keymap_t	*km;
+
+    ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
+
+	// check for non-ascii first
+   for (km=keymaps;km->source!=-1;km++)
+      if (ch == km->source)
+      {
+          Key_Event (km->dest, false, 0);
+          return;
+      }
+
+    if (ch >= 'A' && ch <= 'Z')
+        ch += 'a' - 'A';
+    if (ch>=256)
+        return;
+    Key_Event (ch, false, 0);
+}
+
+@end
+
+
--- /dev/null
+++ b/rhapsody/sys_rhap.m
@@ -1,0 +1,338 @@
+#include <libc.h>
+#import <AppKit/AppKit.h>
+#include "../qcommon/qcommon.h"
+
+int		curtime;
+int		sys_frame_time;
+
+void	Sys_UnloadGame (void)
+{
+}
+
+void *GetGameAPI (void *import);
+
+void	*Sys_GetGameAPI (void *parms)
+{
+	// we are hard-linked in, so no need to load anything
+    return GetGameAPI (parms);
+}
+
+void Sys_CopyProtect (void)
+{
+}
+
+char *Sys_GetClipboardData( void )
+{
+    return NULL;
+}
+
+
+//===========================================================================
+
+int		hunkcount;
+
+byte	*membase;
+int		hunkmaxsize;
+int		cursize;
+
+//#define	VIRTUAL_ALLOC
+
+void *Hunk_Begin (int maxsize)
+{
+    // reserve a huge chunk of memory, but don't commit any yet
+    cursize = 0;
+    hunkmaxsize = maxsize;
+#ifdef VIRTUAL_ALLOC
+    membase = VirtualAlloc (NULL, maxsize, MEM_RESERVE, PAGE_NOACCESS);
+#else
+    membase = malloc (maxsize);
+    memset (membase, 0, maxsize);
+#endif
+    if (!membase)
+        Sys_Error ("VirtualAlloc reserve failed");
+    return (void *)membase;
+}
+
+void *Hunk_Alloc (int size)
+{
+    void	*buf;
+
+    // round to cacheline
+    size = (size+31)&~31;
+
+#ifdef VIRTUAL_ALLOC
+    // commit pages as needed
+//	buf = VirtualAlloc (membase+cursize, size, MEM_COMMIT, PAGE_READWRITE);
+    buf = VirtualAlloc (membase, cursize+size, MEM_COMMIT, PAGE_READWRITE);
+    if (!buf)
+    {
+        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
+        Sys_Error ("VirtualAlloc commit failed.\n%s", buf);
+    }
+#endif
+    cursize += size;
+    if (cursize > hunkmaxsize)
+        Sys_Error ("Hunk_Alloc overflow");
+
+    return (void *)(membase+cursize-size);
+}
+
+int Hunk_End (void)
+{
+
+    // free the remaining unused virtual memory
+#if 0
+    void	*buf;
+
+    // write protect it
+    buf = VirtualAlloc (membase, cursize, MEM_COMMIT, PAGE_READONLY);
+    if (!buf)
+        Sys_Error ("VirtualAlloc commit failed");
+#endif
+
+    hunkcount++;
+//Com_Printf ("hunkcount: %i\n", hunkcount);
+    return cursize;
+}
+
+void Hunk_Free (void *base)
+{
+    if ( base )
+#ifdef VIRTUAL_ALLOC
+        VirtualFree (base, 0, MEM_RELEASE);
+#else
+        free (base);
+#endif
+
+    hunkcount--;
+}
+
+
+//===========================================================================
+
+
+void Sys_Mkdir (char *path)
+{
+	if (mkdir (path, 0777) != -1)
+		return;
+	if (errno != EEXIST)
+		Com_Error (ERR_FATAL, "mkdir %s: %s",path, strerror(errno)); 
+}
+
+char	*Sys_FindFirst (char *path, unsigned musthave, unsigned canthave)
+{
+    return NULL;
+}
+
+char	*Sys_FindNext (unsigned musthave, unsigned canthave)
+{
+    return NULL;
+}
+
+void	Sys_FindClose (void)
+{
+}
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int Sys_Milliseconds (void)
+{
+	struct timeval tp;
+	struct timezone tzp;
+	static int		secbase;
+
+	gettimeofday(&tp, &tzp);
+	
+	if (!secbase)
+	{
+		secbase = tp.tv_sec;
+		return tp.tv_usec/1000;
+	}
+	
+    curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
+
+    return curtime;
+}
+
+/*
+================
+Sys_Error
+================
+*/
+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);
+	printf ("Fatal error: %s\n",string);
+	
+	if (!NSApp)
+	{	// appkit isn't running, so don't try to pop up a panel
+		exit (1);
+	}
+        NSRunAlertPanel (@"Fatal error",[NSString stringWithCString: string]
+                         ,@"exit",NULL,NULL);
+	[NSApp terminate: NULL];
+        exit(1);
+}
+
+/*
+================
+Sys_Printf
+================
+*/
+void	Sys_ConsoleOutput (char *text)
+{
+	char		*t_p;
+	int			l, r;
+	
+	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;
+		}
+	}
+}
+
+/*
+================
+Sys_Quit
+================
+*/
+void Sys_Quit (void)
+{
+// change stdin to blocking
+	fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+
+	if (!NSApp)
+		exit (0);		// appkit isn't running
+
+        [NSApp terminate:nil];
+}
+
+
+/*
+================
+Sys_Init
+================
+*/
+void Sys_Init(void)
+{
+    moncontrol(0);	// turn off profiling except during real Quake work
+
+// change stdin to non blocking
+     fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);	
+}
+
+
+extern	NSWindow	*vid_window_i;
+
+void Sys_AppActivate (void)
+{
+    [vid_window_i makeKeyAndOrderFront: nil];
+}
+
+
+/*
+================
+Sys_SendKeyEvents
+
+service any pending appkit events
+================
+*/
+void Sys_SendKeyEvents (void)
+{
+	NSEvent	*event;
+	NSDate	*date;
+
+	date = [NSDate date];
+	do
+	{
+		event = [NSApp
+            nextEventMatchingMask: 	0xffffffff
+            untilDate:		date
+            inMode:			@"NSDefaultRunLoopMode"
+            dequeue:		YES];
+		if (event)
+			[NSApp	sendEvent: event];
+	} while (event);
+
+    // grab frame time 
+    sys_frame_time = Sys_Milliseconds();
+}
+
+
+/*
+================
+Sys_ConsoleInput
+
+Checks for a complete line of text typed in at the console, then forwards
+it to the host command processor
+================
+*/
+char *Sys_ConsoleInput (void)
+{
+	static char	text[256];
+	int		len;
+
+	len = read (0, text, sizeof(text));
+	if (len < 1)
+		return NULL;
+	text[len-1] = 0;	// rip off the /n and terminate
+	
+	return text;
+}
+
+
+/*
+=============
+main
+=============
+*/
+void main (int argc, char **argv)
+{
+    int		frame;
+    NSAutoreleasePool *pool;
+	int		oldtime, t;
+        
+    pool = [[NSAutoreleasePool alloc] init];
+        
+    Qcommon_Init (argc, argv);
+
+    [pool release];
+
+    oldtime = Sys_Milliseconds ();
+    while (1)
+    {
+        pool =[[NSAutoreleasePool alloc] init];
+
+        if (++frame > 10)
+            moncontrol(1);// profile only while we do each Quake frame
+
+		t = Sys_Milliseconds ();
+        Qcommon_Frame (t - oldtime);
+		oldtime = t;
+        moncontrol(0);
+
+        [pool release];
+    }
+}
+
--- /dev/null
+++ b/rhapsody/vid_next.m
@@ -1,0 +1,1789 @@
+// vid_next.m -- NEXTSTEP video driver
+
+#define	INTERCEPTOR
+
+#import <appkit/appkit.h>
+#import <string.h>
+#import "intercep.h"
+#include "quakedef.h"
+#include "d_local.h"
+
+int	BASEWIDTH = 320;
+int BASEHEIGHT = 200;
+
+void SetupBitmap (void);
+void SetupFramebuffer (void);
+void UpdateBitmap (void);
+void UpdateFramebuffer (vrect_t *vrect);
+void SetVideoEncoding (char *encoding);
+void Update8_1 (pixel_t *src, byte *dest, int width,
+		int height, int destrowbytes);
+void Update16_1 (pixel_t *src, unsigned short *dest, int width,
+		int height, int destrowbytes);
+void Update32_1 (pixel_t *src, unsigned *dest, int width,
+		int height, int destrowbytes);
+
+
+@interface QuakeView : View
+@end
+
+@interface FrameWindow:Window
+@end
+
+unsigned short	d_8to16table[256];	// not used in 8 bpp mode
+unsigned	d_8to24table[256];	// not used in 8 bpp mode
+
+
+/*
+==========================================================================
+
+						API FUNCTIONS
+
+==========================================================================
+*/
+
+typedef enum {disp_bitmap, disp_framebuffer}	display_t;
+
+pixel_t		*vid_buffer;
+pixel_t		*buffernative;
+unsigned	pcolormap[4][256];	// map from quake pixels to native pixels
+unsigned	pixbytesnative;
+unsigned	rowbytesnative;
+int			dither;
+
+int			drawdirect = 0;
+
+int			d_con_indirect = 0;
+
+display_t		vid_display;
+
+byte			vid_palette[768];	// saved for restarting vid system
+
+id				vid_window_i;
+id				vid_view_i;
+#ifdef INTERCEPTOR
+NXDirectBitmap	*vid_dbitmap_i;
+NXFramebuffer	*vid_framebuffer_i;
+#endif
+
+NXRect   		screenBounds;		// only valid in framebuffer mode
+
+int				vid_scale;
+
+char			*vid_encodingstring;
+
+int				vid_fullscreen;
+int				vid_screen;
+
+int				vid_high_hunk_mark;
+
+typedef enum
+{
+	enc_24_rgba,
+	enc_24_0rgb,
+	enc_24_rgb0,
+	enc_12_rgba,
+	enc_12_rgb0,
+	enc_15_0rgb,
+	enc_564,
+	enc_8_gray,
+	enc_8_rgb
+} vid_encoding_t;
+
+typedef struct
+{
+	char			*string;
+	int				pixelbytes;
+	void			(*colormap) (void);
+	vid_encoding_t	name;
+} vidtype_t;
+
+vid_encoding_t	vid_encoding;
+ 
+void	Table8 (void);
+void	Table15 (void);
+void	Table12 (void);
+void	Table12Swap (void);
+void	Table24 (void);
+void	Table24Swap (void);
+
+vidtype_t vid_encodingtable[]=
+{
+{"RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA",4, Table24Swap, enc_24_rgba},
+{"--------RRRRRRRRGGGGGGGGBBBBBBBB",4, Table24, enc_24_0rgb},
+{"RRRRRRRRGGGGGGGGBBBBBBBB--------",4, Table24Swap, enc_24_rgb0},
+{"RRRRGGGGBBBBAAAA",2, Table12Swap, enc_12_rgba},
+{"RRRRGGGGBBBB----",2, Table12, enc_12_rgb0},
+{"-RRRRRGGGGGBBBBB",2, Table15, enc_15_0rgb},
+{"WWWWWWWW",1, Table8, enc_8_gray},
+{"PPPPPPPP",1, Table8, enc_8_rgb},
+{NULL,0, 0, 0}
+};
+
+vidtype_t	*vid_type;
+void	InitNS8Bit (void);
+
+/*
+================
+D_BeginDirectRect
+================
+*/
+void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
+{
+// direct drawing of the "accessing disk" icon isn't supported under Nextstep
+}
+
+
+/*
+================
+D_EndDirectRect
+================
+*/
+void D_EndDirectRect (int x, int y, int width, int height)
+{
+// direct drawing of the "accessing disk" icon isn't supported under Nextstep
+}
+
+
+/*
+==============
+VID_Restart
+
+internal call only
+===============
+*/
+void VID_Restart (display_t mode, int scale)
+{
+	vid_display = mode;
+	vid_scale = scale;
+
+	[NXApp activateSelf:YES];
+
+	if (vid_display == disp_framebuffer)
+		SetupFramebuffer ();
+	else
+		SetupBitmap ();
+
+	vid.recalc_refdef = 1;
+}
+
+
+/*
+=================
+VID_Scale_f
+
+Keybinding command
+=================
+*/
+void VID_Scale_f (void)
+{
+	int		scale;
+	
+	if (Cmd_Argc () != 2)
+		return;
+		
+	scale = atoi (Cmd_Argv(1));
+	if (scale != 1 && scale != 2)
+	{
+		Con_Printf ("scale must be 1 or 2\n");
+		return;
+	}
+	VID_Shutdown ();
+	VID_Restart (vid_display, scale);
+}
+
+/*
+=================
+VID_Mode_f
+
+Keybinding command
+=================
+*/
+void VID_Mode_f (void)
+{
+	int		mode;
+
+	if (Cmd_Argc () != 2)
+		return;
+
+	mode = atoi (Cmd_Argv(1));
+
+	VID_Shutdown ();
+	if (mode == 0)
+	{
+		drawdirect = 0;
+		VID_Restart (disp_bitmap, vid_scale);
+	}
+	else if (mode == 1)
+	{
+		drawdirect = 0;
+		VID_Restart (disp_framebuffer, vid_scale);
+	}
+	else
+	{
+		drawdirect = 1;
+		VID_Restart (disp_framebuffer, vid_scale);
+	}
+}
+
+/*
+=================
+VID_Size_f
+
+Keybinding command
+=================
+*/
+void VID_Size_f (void)
+{	
+	if (Cmd_Argc () != 3)
+		return;
+
+	VID_Shutdown ();
+
+	BASEWIDTH = atoi (Cmd_Argv(1));
+	BASEHEIGHT = atoi (Cmd_Argv(2));
+
+	VID_Restart (vid_display, vid_scale);
+}
+
+/*
+================
+VID_Init
+================
+*/
+void	VID_Init (unsigned char *palette)
+{
+	InitNS8Bit ();			// fixed palette lookups
+	
+	Q_memcpy (vid_palette, palette, sizeof(vid_palette));
+
+	if (COM_CheckParm ("-bitmap"))
+		vid_display = disp_bitmap;
+	else
+		vid_display = disp_framebuffer;
+
+	if (COM_CheckParm ("-screen2"))
+		vid_screen = 1;
+	else
+		vid_screen = 0;
+
+	if (COM_CheckParm ("-direct"))
+		drawdirect = 1;
+	
+	Cmd_AddCommand ("vid_scale", VID_Scale_f);
+	Cmd_AddCommand ("vid_mode", VID_Mode_f);
+	Cmd_AddCommand ("vid_size", VID_Size_f);
+
+	vid.width = BASEWIDTH;
+	vid.height = BASEHEIGHT;
+	vid.aspect = 1.0;
+	vid.numpages = 1;
+	vid.colormap = host_colormap;
+	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
+	vid.maxwarpwidth = WARP_WIDTH;
+	vid.maxwarpheight = WARP_HEIGHT;
+
+	if (COM_CheckParm ("-scale2"))
+		vid_scale = 2;
+	else
+		vid_scale = 1;
+		
+    [Application new];
+
+	VID_Restart (vid_display, vid_scale);
+}
+
+
+/*
+================
+VID_Shutdown
+================
+*/
+void VID_Shutdown (void)
+{
+#ifdef INTERCEPTOR
+	if (vid_dbitmap_i)
+	{
+		[vid_dbitmap_i free];
+		vid_dbitmap_i = 0;
+	}
+	if (vid_framebuffer_i)
+	{
+		[vid_framebuffer_i free];
+		vid_framebuffer_i = 0;
+	}
+#endif
+	[vid_window_i close];
+	[vid_window_i free];
+}
+
+
+/*
+================
+VID_Update
+================
+*/
+void	VID_Update (vrect_t *rects)
+{
+	if (drawdirect)
+		return;
+
+	while (rects)
+	{
+		UpdateFramebuffer (rects);
+		rects = rects->pnext;
+	}
+
+	if (vid_display == disp_bitmap)
+		UpdateBitmap ();
+}
+
+
+/*
+================
+VID_SetPalette
+================
+*/
+void	VID_SetPalette (unsigned char *palette)
+{
+	Q_memcpy (vid_palette, palette, sizeof(vid_palette));
+	vid_type->colormap ();
+}
+
+
+/*
+================
+VID_ShiftPalette
+================
+*/
+void    VID_ShiftPalette (unsigned char *palette)
+{
+
+	VID_SetPalette (palette);
+}
+
+
+/*
+==========================================================================
+
+						NS STUFF
+
+==========================================================================
+*/
+
+
+/*
+=================
+SetVideoEncoding
+=================
+*/
+void SetVideoEncoding (char *encoding)
+{
+	vidtype_t			*type;
+
+	Sys_Printf ("SetVideoEncoding: %s\n",encoding);
+	vid_encodingstring = encoding;
+	
+	for (type = vid_encodingtable ; type->string ; type++)
+	{
+		if (strcmp(type->string, encoding) == 0)
+		{
+			pixbytesnative = type->pixelbytes;
+			vid_encoding = type->name;
+			type->colormap ();
+			vid_type = type;
+			return;
+		}
+	}
+	
+	Sys_Error ("Unsupported video encoding: %s\n",encoding);
+}
+
+/*
+=================
+AllocBuffers
+=================
+*/
+void AllocBuffers (qboolean withnative)
+{
+	int		surfcachesize;
+	void	*surfcache;
+	int		pixels;
+	int		pixbytes;
+	int		vid_buffersize;
+
+	if (vid_buffer)
+	{
+		D_FlushCaches ();
+		Hunk_FreeToHighMark (vid_high_hunk_mark);
+		vid_high_hunk_mark = 0;
+		vid_buffer = NULL;
+	}
+
+	pixels = vid.width * vid.height;
+
+	pixbytes = 1 +sizeof (*d_pzbuffer);
+	if (withnative)
+		pixbytes += pixbytesnative;
+		
+	surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
+	vid_buffersize = pixels * pixbytes + surfcachesize;
+
+	vid_high_hunk_mark = Hunk_HighMark ();
+	vid_buffer = Hunk_HighAllocName (vid_buffersize, "video");
+	if (!vid_buffer)
+		Sys_Error ("Couldn't alloc video buffers");
+
+	vid.buffer = vid_buffer;
+
+	d_pzbuffer = (unsigned short *)((byte *)vid_buffer + pixels);
+	surfcache = (byte *)d_pzbuffer + pixels * sizeof (*d_pzbuffer);
+	if (withnative)
+		buffernative = (byte *)surfcache + surfcachesize;
+
+	D_InitCaches (surfcache, surfcachesize);
+}
+
+/*
+=================
+SetupFramebuffer
+=================
+*/
+void SetupFramebuffer (void)
+{
+#ifdef INTERCEPTOR
+    int			windowNum;
+	NXRect		cont;
+	NXScreen	const *screens;
+	int			screencount;
+
+//
+// get the screen list
+//
+	[NXApp getScreens:&screens count:&screencount];
+
+//
+// create vid_framebuffer_i
+//
+    vid_framebuffer_i = [[NXFramebuffer alloc]
+		   initFromScreen:screens[vid_screen].screenNumber andMapIfPossible:YES];
+    [vid_framebuffer_i screenBounds:&screenBounds];
+
+	SetVideoEncoding ([vid_framebuffer_i pixelEncoding]);
+
+	buffernative = [vid_framebuffer_i data];
+	rowbytesnative = [vid_framebuffer_i bytesPerRow];
+
+//
+// create window
+//
+	if (vid_fullscreen)
+	{
+		vid.height = screenBounds.size.height / vid_scale;
+		vid.width = screenBounds.size.width / vid_scale;
+		cont.origin.x = 0;
+		cont.origin.y = 0;
+		cont.size.width = screenBounds.size.width;
+		cont.size.height = screenBounds.size.height;
+	}
+	else
+	{
+		buffernative = (unsigned char *)buffernative + 8 * rowbytesnative +
+				8 * pixbytesnative;
+		vid.width = BASEWIDTH;
+		vid.height = BASEHEIGHT;
+		cont.origin.x = 8;
+		cont.origin.y = screenBounds.size.height - (vid.height*vid_scale) - 8;
+		cont.size.width = vid.width * vid_scale;
+		cont.size.height = vid.height * vid_scale;
+	}
+
+    vid_window_i = [[FrameWindow alloc]
+		 initContent:		&cont
+		 style:				NX_PLAINSTYLE
+		 backing:			NX_NONRETAINED
+		 buttonMask:		0
+		 defer:				NO
+		 screen:			screens+vid_screen];
+    windowNum = [vid_window_i windowNum];
+    PSsetwindowlevel(40, windowNum);
+    PSsetautofill(YES, windowNum);
+    PSgsave();
+    PSwindowdeviceround(windowNum);
+    PSsetgray(NX_BLACK);
+    PSsetexposurecolor();
+    PSgrestore();
+
+//
+// create view
+//
+	vid_view_i = [[QuakeView alloc] initFrame: &screenBounds];
+	[[vid_window_i setContentView: vid_view_i] free];
+	[vid_window_i makeFirstResponder: vid_view_i];
+	[vid_window_i setDelegate: vid_view_i];	
+	[vid_window_i display];
+	[vid_window_i makeKeyAndOrderFront: nil];
+	NXPing ();
+
+	AllocBuffers (false);	// no native buffer
+
+	if (drawdirect)
+	{	// the direct drawing mode to NeXT colorspace
+		vid.buffer = buffernative;
+		vid.rowbytes = rowbytesnative;
+	}
+	else
+		vid.rowbytes = vid.width;
+
+	vid.conbuffer = vid.buffer;
+	vid.conrowbytes = vid.rowbytes;
+	vid.conwidth = vid.width;
+	vid.conheight = vid.height;
+#endif
+}
+
+/*
+=================
+SetupBitmap
+=================
+*/
+void SetupBitmap (void)
+{
+	int		depth;
+	NXRect	content;
+
+//
+// open a window
+//
+	NXSetRect (&content, 8,136, vid.width*vid_scale, vid.height*vid_scale);
+	vid_window_i = [[Window alloc]
+			initContent:	&content
+			style:			NX_RESIZEBARSTYLE
+			backing:		NX_RETAINED
+			buttonMask:		0
+			defer:			NO
+		];
+	[vid_window_i display];
+	[vid_window_i makeKeyAndOrderFront: nil];
+
+	NXPing ();
+
+	content.origin.x = content.origin.y = 0;
+	vid_view_i = [[QuakeView alloc] initFrame: &content];
+	[[vid_window_i setContentView: vid_view_i] free];
+	[vid_window_i makeFirstResponder: vid_view_i];
+	[vid_window_i setDelegate: vid_view_i];
+
+	[vid_window_i addToEventMask: NX_FLAGSCHANGEDMASK];
+
+//
+// find video info
+//
+    depth = [Window defaultDepthLimit];
+    switch (depth) {
+	case NX_EightBitGrayDepth:
+		SetVideoEncoding ("WWWWWWWW");
+	    break;
+	case NX_TwelveBitRGBDepth:
+		SetVideoEncoding ("RRRRGGGGBBBBAAAA");
+	    break;
+	default:
+	case NX_TwentyFourBitRGBDepth:
+		SetVideoEncoding ("RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA");
+	    break;
+//	default:	// 8 bit color shows up as an unknown...
+		Sys_Error ("Unsupported window depth");
+    }
+
+	[vid_window_i setTitle: "Bitmap Quake Console"];
+
+//
+// allocate memory for the back and translation buffers
+//
+	vid.rowbytes = vid.width;
+	rowbytesnative = vid.width * pixbytesnative;
+	
+	AllocBuffers (true);
+	
+	vid.conbuffer = vid.buffer;
+	vid.conrowbytes = vid.rowbytes;
+	vid.conwidth = vid.width;
+	vid.conheight = vid.height;
+}
+
+
+/*
+=================
+UpdateFramebuffer
+=================
+*/
+void UpdateFramebuffer (vrect_t *vrect)
+{
+	byte		*psourcebase;
+	byte		*pdestbase;
+	int			scale;
+	
+	psourcebase = vid.buffer + vrect->x + vrect->y * vid.rowbytes;
+
+	if (vid_display == disp_bitmap)
+		scale = 1;		// let NS do the scaling
+	else
+		scale = vid_scale;
+		
+	pdestbase = buffernative + scale *
+			(vrect->x * pixbytesnative + vrect->y * rowbytesnative);
+
+//
+// translate from ideal to native (except 8 bpp direct) and copy to screen
+//
+
+	if (pixbytesnative == 1)
+		Update8_1 (psourcebase, pdestbase, vrect->width, vrect->height,
+				rowbytesnative);
+	else if (pixbytesnative == 2)
+		Update16_1 (psourcebase, (unsigned short *)pdestbase, vrect->width, vrect->height,
+				rowbytesnative);
+	else
+		Update32_1 (psourcebase, (unsigned *)pdestbase, vrect->width, vrect->height,
+				rowbytesnative);
+}
+
+
+/*
+=================
+UpdateBitmap
+=================
+*/
+void UpdateBitmap (void)
+{
+	unsigned char	*planes[5];
+	NXRect			bounds;
+	int				bpp, spp, bps, bpr, colorspace;
+
+//
+// flush the screen with an image call
+// 
+	if (pixbytesnative == 1)
+	{
+		bps = 8;
+		spp = 1;
+		bpp = 8;
+		bpr = vid.width;
+		colorspace = NX_OneIsWhiteColorSpace;
+		planes[0] = vid.buffer;
+	}
+	else if (pixbytesnative == 2)
+	{
+		bps = 4;
+		spp = 3;
+		bpp = 16;
+		bpr = vid.width * 2;
+		colorspace = NX_RGBColorSpace;
+		planes[0] = buffernative;
+	}
+	else
+	{
+		bps = 8;
+		spp = 3;
+		bpp = 32;
+		bpr = vid.width * 4;
+		colorspace = NX_RGBColorSpace;
+		planes[0] = buffernative;
+	}
+
+	[vid_view_i getBounds: &bounds];
+	[vid_view_i lockFocus];
+
+	NXDrawBitmap(
+		&bounds,  
+		vid.width, 
+		vid.height,
+		bps,
+		spp,
+		bpp,
+		bpr,
+		NO,
+		NO,
+		colorspace,
+		planes
+	);
+	
+	[vid_view_i unlockFocus];
+    NXPing ();	
+}
+
+
+
+/*
+==========================================================================
+
+					TRANSLATION TABLE BUILDING
+
+==========================================================================
+*/
+
+int	redramp[] = {0, 19, 59, 113, 178, 255, 300};
+int greenramp[] = {0, 11, 34,  66, 104, 149, 199, 255, 300};
+int blueramp[] = {0, 28, 84, 161, 255, 300};
+int greyramp[] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204,
+				   221, 238, 255, 300};
+
+byte	greytable[256];
+byte	redtable[256];
+byte	greentable[256];
+byte	bluetable[256];
+
+void FillTable (byte *table, int *ramp, int base)
+{
+	int		i, j, o;
+	
+	o = 0;
+	for (i=0 ; i<16 && o < 256; i++)
+	{
+		j = ramp[i];
+		for ( ; o<=j ; o++)
+			table[o] = base + i;
+	}
+}
+
+void	InitNS8Bit (void)
+{
+	FillTable (greytable, greyramp, 240);
+	FillTable (redtable, redramp, 0);
+	FillTable (greentable, greenramp, 0);
+	FillTable (bluetable, blueramp, 0);
+}
+
+
+byte ns8trans[256] =	// FIXME: dynamically calc this so palettes work
+{
+0,241,242,243,244,244,245,246,247,248,249,250,251,252,253,254,
+45,241,241,242,91,91,91,96,96,136,136,136,141,141,141,141,
+241,46,242,243,243,97,97,97,245,246,143,143,143,143,148,148,
+0,5,45,45,50,50,90,90,95,95,95,95,95,140,140,141,
+0,40,40,40,40,80,80,80,80,80,120,120,120,120,120,120,
+45,50,50,90,90,95,95,135,135,135,136,141,141,181,181,181,
+45,90,91,91,131,131,136,136,136,176,181,181,186,226,231,236,
+45,45,91,91,96,96,136,136,137,142,182,182,187,188,188,233,
+188,249,248,247,246,137,137,137,244,243,243,91,242,241,241,45,
+183,183,183,247,137,137,137,137,137,244,91,91,91,241,241,45,
+252,251,188,188,248,248,142,142,142,244,244,243,91,242,241,45,
+247,247,246,246,245,245,244,244,243,243,242,242,51,241,241,5,
+236,231,231,191,186,185,185,140,140,135,135,95,90,90,45,45,
+4,49,49,53,53,93,93,93,93,92,92,92,243,242,46,241,
+239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,
+239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,182
+};
+
+/*
+===================
+Table8
+===================
+*/
+void	Table8 (void)
+{
+	byte	*pal;
+	int		r,g,b,v;
+	int		i;
+	byte	*table;
+	
+	pal = vid_palette;
+	table = (byte *)pcolormap[0];
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		r = pal[0];
+		g = pal[1];
+		b = pal[2];
+		pal += 3;
+		
+// use the grey ramp if all indexes are close
+
+		if (r-g < 16 && r-g > -16 && r-b < 16 && r-b > -16)
+		{
+			v = (r+g+b)/3;
+			*table++ = greytable[v];
+			continue;
+		}
+		
+		r = redtable[r];
+		g = greentable[g];
+		b = bluetable[b];
+		
+// otherwise use the color cube
+		*table++ = r*(8*5) + g*5 + b;
+	}
+}
+
+/*
+===================
+Table24
+===================
+*/
+void	Table24 (void)
+{
+	byte	*pal;
+	int		r,g,b,v;
+	int		i;
+	unsigned	*table;
+	
+	
+//
+// 8 8 8 encoding
+//
+	pal = vid_palette;
+	table = (unsigned *)pcolormap[0];
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		r = pal[0];
+		g = pal[1];
+		b = pal[2];
+		pal += 3;
+		
+		v = (r<<16) + (g<<8) + b;
+		*table++ = v;
+	}
+}
+
+/*
+===================
+Table24Swap
+===================
+*/
+void	Table24Swap (void)
+{
+	byte	*pal;
+	int		r,g,b,v;
+	int		i;
+	unsigned	*table;
+
+//
+// 8 8 8 encoding
+//
+	pal = vid_palette;
+	table = (unsigned *)pcolormap[0];
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		r = pal[0];
+		g = pal[1];
+		b = pal[2];
+		pal += 3;
+		
+		v = (r<<24) + (g<<16) + (b<<8) /*+ 255*/;
+		v = NXSwapBigLongToHost (v);
+		*table++ = v;
+	}
+}
+
+
+/*
+===================
+Table15
+===================
+*/
+void	Table15 (void)
+{
+	byte			*pal;
+	int				r,g,b,v;
+	int				i, k;
+	unsigned char	*palette;
+	unsigned short	*table;
+	int				dadj;
+	int		ditheradjust[4] = {(1 << 9) * 3 / 8,
+									(1 << 9) * 5 / 8,
+									(1 << 9) * 7 / 8,
+									(1 << 9) * 1 / 8};
+	
+	palette = vid_palette;
+	table = (unsigned short *)pcolormap;
+	
+//
+// 5 5 5 encoding
+//
+	for (k=0 ; k<4 ; k++)
+	{
+		dadj = ditheradjust[k];
+
+		pal = vid_palette;
+
+		for (i=0 ; i<256 ; i++)
+		{
+		// shift 6 bits to get back to 0-255, & 3 more for 5 bit color
+		// FIXME: scale intensity levels properly
+			r = (pal[0] + dadj) >> 3;
+			g = (pal[1] + dadj) >> 3;
+			b = (pal[2] + dadj) >> 3;
+			pal += 3;
+
+			v = (r<<10) + (g<<5) + b;
+
+			*table++ = v;
+		}
+	}
+}
+
+/*
+===================
+Table12
+===================
+*/
+void	Table12 (void)
+{
+	byte			*pal;
+	int				r,g,b,v;
+	int				i, k;
+	unsigned short	*table;
+	int				dadj;
+	static int		ditheradjust[4] = {(1 << 9) * 3 / 8,
+									   (1 << 9) * 5 / 8,
+									   (1 << 9) * 7 / 8,
+									   (1 << 9) * 1 / 8};
+
+	table = (unsigned short *)pcolormap;
+		
+//
+// 4 4 4 encoding
+//
+	for (k=0 ; k<4 ; k++)
+	{
+		dadj = ditheradjust[k];
+
+		pal = vid_palette;
+
+		for (i=0 ; i<256 ; i++)
+		{
+		// shift 5 bits to get back to 0-255, & 4 more for 4 bit color
+		// FIXME: scale intensity levels properly
+			r = (pal[0] + dadj) >> 4;
+			g = (pal[1] + dadj) >> 4;
+			b = (pal[2] + dadj) >> 4;
+			pal += 3;
+
+			v = ((r<<12) + (g<<8) + (b<<4) /*+ 15*/);
+
+			*table++ = v;
+		}
+	}
+}
+
+/*
+===================
+Table12Swap
+===================
+*/
+void	Table12Swap (void)
+{
+	byte			*pal;
+	int				r,g,b,v;
+	int				i, k;
+	unsigned short	*table;
+	int				dadj;
+	static int		ditheradjust[4] = {(1 << 9) * 3 / 8,
+									   (1 << 9) * 5 / 8,
+									   (1 << 9) * 7 / 8,
+									   (1 << 9) * 1 / 8};
+
+	table = (unsigned short *)pcolormap;
+		
+//
+// 4 4 4 encoding
+//
+	for (k=0 ; k<4 ; k++)
+	{
+		dadj = ditheradjust[k];
+
+		pal = vid_palette;
+
+		for (i=0 ; i<256 ; i++)
+		{
+		// shift 5 bits to get back to 0-255, & 4 more for 4 bit color
+		// FIXME: scale intensity levels properly
+			r = (pal[0] + dadj) >> 4;
+			g = (pal[1] + dadj) >> 4;
+			b = (pal[2] + dadj) >> 4;
+			pal += 3;
+
+			v = ((r<<12) + (g<<8) + (b<<4) /*+ 15*/);
+			v = NXSwapBigShortToHost (v);
+
+			*table++ = v;
+		}
+	}
+}
+
+
+/*
+==========================================================================
+
+					GENERIC IMAGING FUNCTIONS
+
+==========================================================================
+*/
+
+/*
+===================
+Update8_1
+===================
+*/
+void Update8_1 (pixel_t *src, byte *dest, int width, int height,
+		int destrowbytes)
+{
+	int				x,y;
+	unsigned		rowdelta, srcdelta;
+	unsigned		xcount;
+	byte			*pdest;
+	int				xwidth;
+
+	pdest = dest;
+	
+	xcount = width >> 3;
+	srcdelta = vid.width - width;
+
+	xwidth = width - (xcount << 3);
+	if (xwidth)
+		Sys_Error ("Width not multiple of 8");
+
+	if ((vid_display == disp_framebuffer) && (vid_scale == 2))
+	{
+		int		nextrow = destrowbytes;
+
+	    rowdelta = destrowbytes - (width << 1)  + destrowbytes;
+
+		if (dither)
+		{
+			unsigned short	*psrc;
+
+			psrc = (unsigned short *)src;
+
+			for (y = height ; y ; y--)
+			{
+		    	for (x = xcount ; x ;x--)
+			    {
+					unsigned	temp;
+
+					temp = psrc[0];
+					pdest[0] = ((byte *)pcolormap[0])[temp];
+					pdest[1] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 1] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[1];
+					pdest[2] = ((byte *)pcolormap[0])[temp];
+					pdest[3] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 2] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 3] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[2];
+					pdest[4] = ((byte *)pcolormap[0])[temp];
+					pdest[5] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 4] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 5] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[3];
+					pdest[6] = ((byte *)pcolormap[0])[temp];
+					pdest[7] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 6] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 7] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[4];
+					pdest[8] = ((byte *)pcolormap[0])[temp];
+					pdest[9] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 8] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 9] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[5];
+					pdest[10] = ((byte *)pcolormap[0])[temp];
+					pdest[11] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 10] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 11] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[6];
+					pdest[12] = ((byte *)pcolormap[0])[temp];
+					pdest[13] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 12] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 13] = ((byte *)pcolormap[3])[temp];
+					temp = psrc[7];
+					pdest[14] = ((byte *)pcolormap[0])[temp];
+					pdest[15] = ((byte *)pcolormap[1])[temp];
+					pdest[nextrow + 14] = ((byte *)pcolormap[2])[temp];
+					pdest[nextrow + 15] = ((byte *)pcolormap[3])[temp];
+					pdest += 16; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+		}
+		else
+		{
+			byte	*psrc;
+
+			psrc = (byte *)src;
+
+			for (y = height ; y ; y--)
+			{
+				for (x = xcount ; x ;x--)
+		    	{
+					pdest[0] = pdest[1] = pdest[nextrow] =
+						pdest[nextrow + 1] = ((byte *)pcolormap[0])[psrc[0]];
+					pdest[2] = pdest[3] = pdest[nextrow + 2] =
+						pdest[nextrow + 3] = ((byte *)pcolormap[0])[psrc[1]];
+					pdest[4] = pdest[5] = pdest[nextrow + 4] =
+						pdest[nextrow + 5] = ((byte *)pcolormap[0])[psrc[2]];
+					pdest[6] = pdest[7] = pdest[nextrow + 6] =
+						pdest[nextrow + 7] = ((byte *)pcolormap[0])[psrc[3]];
+					pdest[8] = pdest[9] = pdest[nextrow + 8] =
+						pdest[nextrow + 9] = ((byte *)pcolormap[0])[psrc[4]];
+					pdest[10] = pdest[11] = pdest[nextrow + 10] =
+						pdest[nextrow + 11] = ((byte *)pcolormap[0])[psrc[5]];
+					pdest[12] = pdest[13] = pdest[nextrow + 12] =
+						pdest[nextrow + 13] = ((byte *)pcolormap[0])[psrc[6]];
+					pdest[14] = pdest[15] = pdest[nextrow + 14] =
+						pdest[nextrow + 15] = ((byte *)pcolormap[0])[psrc[7]];
+					pdest += 16; psrc += 8;
+		    	}
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+		}
+    }
+	else
+	{
+	    rowdelta = destrowbytes - width;
+
+		if (dither)
+		{
+			unsigned short	*psrc;
+
+			psrc = (unsigned short *)src;
+
+			for (y = height ; y>0 ; y -= 2)
+			{
+		    	for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = ((byte *)pcolormap[0])[psrc[0]];
+					pdest[1] = ((byte *)pcolormap[1])[psrc[1]];
+					pdest[2] = ((byte *)pcolormap[0])[psrc[2]];
+					pdest[3] = ((byte *)pcolormap[1])[psrc[3]];
+					pdest[4] = ((byte *)pcolormap[0])[psrc[4]];
+					pdest[5] = ((byte *)pcolormap[1])[psrc[5]];
+					pdest[6] = ((byte *)pcolormap[0])[psrc[6]];
+					pdest[7] = ((byte *)pcolormap[1])[psrc[7]];
+					pdest += 8; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+
+		    	for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = ((byte *)pcolormap[2])[psrc[0]];
+					pdest[1] = ((byte *)pcolormap[3])[psrc[1]];
+					pdest[2] = ((byte *)pcolormap[2])[psrc[2]];
+					pdest[3] = ((byte *)pcolormap[3])[psrc[3]];
+					pdest[4] = ((byte *)pcolormap[2])[psrc[4]];
+					pdest[5] = ((byte *)pcolormap[3])[psrc[5]];
+					pdest[6] = ((byte *)pcolormap[2])[psrc[6]];
+					pdest[7] = ((byte *)pcolormap[3])[psrc[7]];
+					pdest += 8; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+		}
+		else
+		{
+			byte	*psrc;
+
+			psrc = (byte *)src;
+//			srcdelta += width;
+//			rowdelta += width;
+
+			for (y = height ; y ; y--)
+			{
+		    	for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = ((byte *)pcolormap[0])[psrc[0]];
+					pdest[1] = ((byte *)pcolormap[0])[psrc[1]];
+					pdest[2] = ((byte *)pcolormap[0])[psrc[2]];
+					pdest[3] = ((byte *)pcolormap[0])[psrc[3]];
+					pdest[4] = ((byte *)pcolormap[0])[psrc[4]];
+					pdest[5] = ((byte *)pcolormap[0])[psrc[5]];
+					pdest[6] = ((byte *)pcolormap[0])[psrc[6]];
+					pdest[7] = ((byte *)pcolormap[0])[psrc[7]];
+					pdest += 8; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+		    }
+		}
+    }
+}
+
+
+/*
+===================
+Update16_1
+===================
+*/
+void Update16_1 (pixel_t *src, unsigned short *dest, int width,
+		int height, int destrowbytes)
+{
+	int				x,y;
+	unsigned		rowdelta, srcdelta;
+	unsigned		xcount;
+	pixel_t			*psrc;
+	unsigned short	*pdest;
+	int				xwidth;
+
+
+	psrc = src;
+	pdest = dest;
+	
+	xcount = width >> 3;
+	srcdelta = vid.width - width;
+
+	xwidth = width - (xcount << 3);
+	if (xwidth)
+		Sys_Error ("Width not multiple of 8");
+
+	if ((vid_display == disp_framebuffer) && (vid_scale == 2))
+	{
+		int		nextrow = destrowbytes >> 1;
+
+	    rowdelta = (destrowbytes - ((width << 1) << 1) + destrowbytes) >> 1;
+
+		if (dither)
+		{
+			for (y = height ; y ; y--)
+			{
+		    	for (x = xcount ; x ;x--)
+			    {
+					unsigned	temp;
+
+					temp = psrc[0];
+					pdest[0] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[1] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 1] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[1];
+					pdest[2] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[3] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 2] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 3] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[2];
+					pdest[4] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[5] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 4] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 5] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[3];
+					pdest[6] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[7] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 6] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 7] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[4];
+					pdest[8] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[9] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 8] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 9] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[5];
+					pdest[10] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[11] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 10] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 11] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[6];
+					pdest[12] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[13] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 12] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 13] = ((unsigned short *)pcolormap[3])[temp];
+					temp = psrc[7];
+					pdest[14] = ((unsigned short *)pcolormap[0])[temp];
+					pdest[15] = ((unsigned short *)pcolormap[1])[temp];
+					pdest[nextrow + 14] = ((unsigned short *)pcolormap[2])[temp];
+					pdest[nextrow + 15] = ((unsigned short *)pcolormap[3])[temp];
+					pdest += 16; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+		}
+		else
+		{
+			for (y = height ; y ; y--)
+			{
+			for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = pdest[1] = pdest[nextrow] =
+							pdest[nextrow + 1] = pcolormap[0][psrc[0]];
+					pdest[2] = pdest[3] = pdest[nextrow + 2] =
+							pdest[nextrow + 3] = pcolormap[0][psrc[1]];
+					pdest[4] = pdest[5] = pdest[nextrow + 4] =
+							pdest[nextrow + 5] = pcolormap[0][psrc[2]];
+					pdest[6] = pdest[7] = pdest[nextrow + 6] =
+							pdest[nextrow + 7] = pcolormap[0][psrc[3]];
+					pdest[8] = pdest[9] = pdest[nextrow + 8] =
+							pdest[nextrow + 9] = pcolormap[0][psrc[4]];
+					pdest[10] = pdest[11] = pdest[nextrow + 10] =
+							pdest[nextrow + 11] = pcolormap[0][psrc[5]];
+					pdest[12] = pdest[13] = pdest[nextrow + 12] =
+							pdest[nextrow + 13] = pcolormap[0][psrc[6]];
+					pdest[14] = pdest[15] = pdest[nextrow + 14] =
+							pdest[nextrow + 15] = pcolormap[0][psrc[7]];
+					pdest += 16; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+    	}
+	}
+	else
+	{
+	    rowdelta = (destrowbytes - (width<<1))>>1;
+
+		if (dither)
+		{
+			for (y = height ; y>0 ; y -= 2)
+			{
+		    	for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = ((unsigned short *)pcolormap[0])[psrc[0]];
+					pdest[1] = ((unsigned short *)pcolormap[1])[psrc[1]];
+					pdest[2] = ((unsigned short *)pcolormap[0])[psrc[2]];
+					pdest[3] = ((unsigned short *)pcolormap[1])[psrc[3]];
+					pdest[4] = ((unsigned short *)pcolormap[0])[psrc[4]];
+					pdest[5] = ((unsigned short *)pcolormap[1])[psrc[5]];
+					pdest[6] = ((unsigned short *)pcolormap[0])[psrc[6]];
+					pdest[7] = ((unsigned short *)pcolormap[1])[psrc[7]];
+					pdest += 8; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+
+		    	for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = ((unsigned short *)pcolormap[2])[psrc[0]];
+					pdest[1] = ((unsigned short *)pcolormap[3])[psrc[1]];
+					pdest[2] = ((unsigned short *)pcolormap[2])[psrc[2]];
+					pdest[3] = ((unsigned short *)pcolormap[3])[psrc[3]];
+					pdest[4] = ((unsigned short *)pcolormap[2])[psrc[4]];
+					pdest[5] = ((unsigned short *)pcolormap[3])[psrc[5]];
+					pdest[6] = ((unsigned short *)pcolormap[2])[psrc[6]];
+					pdest[7] = ((unsigned short *)pcolormap[3])[psrc[7]];
+					pdest += 8; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+		}
+		else
+		{
+			for (y = height ; y ; y--)
+			{
+			for (x = xcount ; x ;x--)
+			    {
+					pdest[0] = pcolormap[0][psrc[0]];
+					pdest[1] = pcolormap[0][psrc[1]];
+					pdest[2] = pcolormap[0][psrc[2]];
+					pdest[3] = pcolormap[0][psrc[3]];
+					pdest[4] = pcolormap[0][psrc[4]];
+					pdest[5] = pcolormap[0][psrc[5]];
+					pdest[6] = pcolormap[0][psrc[6]];
+					pdest[7] = pcolormap[0][psrc[7]];
+					pdest += 8; psrc += 8;
+			    }
+
+				psrc += srcdelta;
+			    pdest += rowdelta;
+			}
+    	}
+	}
+}
+
+
+/*
+===================
+Update32_1
+===================
+*/
+void Update32_1 (pixel_t *src, unsigned *dest, int width, int height,
+		int destrowbytes)
+{
+	int				x,y;
+	unsigned		rowdelta, srcdelta;
+	unsigned		xcount;
+	pixel_t			*psrc;
+	unsigned		*pdest;
+	int				xwidth;
+
+	psrc = src;
+	pdest = dest;
+
+	xcount = width >> 3;
+	srcdelta = vid.width - width;
+
+	xwidth = width - (xcount << 3);
+	if (xwidth)
+		Sys_Error ("Width not multiple of 8");
+
+	if ((vid_display == disp_framebuffer) && (vid_scale == 2))
+	{
+		int		nextrow = destrowbytes >> 2;
+
+	    rowdelta = ((destrowbytes - ((width << 1) << 2)) >> 2)  +
+				(destrowbytes >> 2);
+
+		for (y = height ; y ; y--)
+		{
+			for (x = xcount ; x ;x--)
+		    {
+				pdest[0] = pdest[1] = pdest[nextrow] =
+						pdest[nextrow + 1] = pcolormap[0][psrc[0]];
+				pdest[2] = pdest[3] = pdest[nextrow + 2] =
+						pdest[nextrow + 3] = pcolormap[0][psrc[1]];
+				pdest[4] = pdest[5] = pdest[nextrow + 4] =
+						pdest[nextrow + 5] = pcolormap[0][psrc[2]];
+				pdest[6] = pdest[7] = pdest[nextrow + 6] =
+						pdest[nextrow + 7] = pcolormap[0][psrc[3]];
+				pdest[8] = pdest[9] = pdest[nextrow + 8] =
+						pdest[nextrow + 9] = pcolormap[0][psrc[4]];
+				pdest[10] = pdest[11] = pdest[nextrow + 10] =
+						pdest[nextrow + 11] = pcolormap[0][psrc[5]];
+				pdest[12] = pdest[13] = pdest[nextrow + 12] =
+						pdest[nextrow + 13] = pcolormap[0][psrc[6]];
+				pdest[14] = pdest[15] = pdest[nextrow + 14] =
+						pdest[nextrow + 15] = pcolormap[0][psrc[7]];
+				pdest += 16; psrc += 8;
+		    }
+
+			psrc += srcdelta;
+		    pdest += rowdelta;
+		}
+    }
+	else
+	{
+	    rowdelta = (destrowbytes - (width<<2))>>2;
+
+		for (y = height ; y ; y--)
+		{
+			for (x = xcount ; x ;x--)
+		    {
+				pdest[0] = pcolormap[0][psrc[0]];
+				pdest[1] = pcolormap[0][psrc[1]];
+				pdest[2] = pcolormap[0][psrc[2]];
+				pdest[3] = pcolormap[0][psrc[3]];
+				pdest[4] = pcolormap[0][psrc[4]];
+				pdest[5] = pcolormap[0][psrc[5]];
+				pdest[6] = pcolormap[0][psrc[6]];
+				pdest[7] = pcolormap[0][psrc[7]];
+				pdest += 8; psrc += 8;
+		    }
+
+			psrc += srcdelta;
+		    pdest += rowdelta;
+		}
+	}
+}
+
+
+/*
+==========================================================================
+
+						NEXTSTEP VIEW CLASS
+
+==========================================================================
+*/
+
+
+@implementation QuakeView
+
+/*
+=================
+windowDidMove
+
+=================
+*/
+- windowDidMove:sender
+{
+    NXPoint	aPoint;
+    NXRect	winframe;
+
+    aPoint.x = aPoint.y = 0;
+    [self convertPoint:&aPoint toView:nil];
+    [window convertBaseToScreen: &aPoint];
+    [window getFrame: &winframe];
+
+    if ((int)aPoint.x & 7)
+    {
+	[window moveTo:winframe.origin.x - ((int)aPoint.x&7) 
+			:winframe.origin.y];
+	[window getFrame: &winframe];
+    }
+    return self;
+}
+
+- windowWillResize:sender toSize:(NXSize *)frameSize
+{
+	NXRect		fr, cont;
+	
+	fr.origin.x = fr.origin.y = 0;
+	fr.size = *frameSize;
+	
+	[Window getContentRect:&cont forFrameRect: &fr style:[window style]];
+
+	cont.size.width = (int)cont.size.width & ~15;
+	if (cont.size.width < 128)
+		cont.size.width = 128;
+	cont.size.height = (int)cont.size.height & ~3;
+	if (cont.size.height < 32)
+		cont.size.height = 32;
+
+	[Window getFrameRect:&fr forContentRect: &cont style:[window style]];
+
+	*frameSize = fr.size;
+	
+	return self;
+}
+
+- windowDidResize:sender
+{
+	if (vid_display == disp_framebuffer)
+		Sys_Error ("How the heck are you resizing a framebuffer window?!?");
+
+	vid.width = bounds.size.width/vid_scale;
+	vid.height = bounds.size.height/vid_scale;
+
+//
+// allocate memory for the back and translation buffers
+//
+	vid.rowbytes = vid.width;
+	rowbytesnative = vid.width * pixbytesnative;
+	
+	AllocBuffers (true);
+
+	vid.conbuffer = vid.buffer;
+	vid.conrowbytes = vid.rowbytes;
+	vid.conwidth = vid.width;
+	vid.conheight = vid.height;
+
+	vid.recalc_refdef = 1;
+
+	return self;
+}
+
+-(BOOL) acceptsFirstResponder
+{
+    return YES;
+}
+
+
+typedef struct
+{
+	int		source, dest;
+} keymap_t;
+
+keymap_t keymaps[] =
+{
+	{103, K_RIGHTARROW},
+	{102, K_LEFTARROW},
+	{100, K_UPARROW},
+	{101, K_DOWNARROW},
+	{111, K_PAUSE},
+
+	{59, K_F1},
+	{60, K_F2},
+	{61, K_F3},
+	{62, K_F4},
+	{63, K_F5},
+	{64, K_F6},
+	{65, K_F7},
+	{66, K_F8},
+	{67, K_F9},
+	{68, K_F10},
+	{87, K_F11},
+	{88, K_F12},
+	
+	{-1,-1}
+};
+
+keymap_t flagmaps[] =
+{
+	{NX_SHIFTMASK, K_SHIFT},
+	{NX_CONTROLMASK, K_CTRL},
+	{NX_ALTERNATEMASK, K_ALT},
+	{NX_COMMANDMASK, K_ALT},
+	
+	{-1,-1}
+};
+
+/*
+===================
+keyboard methods
+===================
+*/
+- keyDown:(NXEvent *)theEvent
+{
+    int	ch;
+	keymap_t	*km;
+	
+	PSobscurecursor ();
+
+// check for non-ascii first
+	ch = theEvent->data.key.keyCode;
+	for (km=keymaps;km->source!=-1;km++)
+		if (ch == km->source)
+		{
+			Key_Event (km->dest, true);
+			return self;
+		}
+
+    ch = theEvent->data.key.charCode;
+	if (ch >= 'A' && ch <= 'Z')
+		ch += 'a' - 'A';
+    if (ch>=256)
+		return self;
+		
+	Key_Event (ch, true);
+    return self;
+}
+
+- flagsChanged:(NXEvent *)theEvent
+{
+	static int	oldflags;
+    int		newflags;
+	int		delta;
+	keymap_t	*km;
+	int		i;
+	
+	PSobscurecursor ();
+    newflags = theEvent->flags;
+	delta = newflags ^ oldflags;
+	for (i=0 ; i<32 ; i++)
+	{
+		if ( !(delta & (1<<i)))
+			continue;
+	// changed
+		for (km=flagmaps;km->source!=-1;km++)
+			if ( (1<<i) == km->source)
+			{
+				if (newflags & (1<<i))
+					Key_Event (km->dest, true);
+				else
+					Key_Event (km->dest, false);
+			}
+
+	}
+	
+	oldflags = newflags;
+		
+    return self;
+}
+
+
+- keyUp:(NXEvent *)theEvent
+{
+    int	ch;
+ 	keymap_t	*km;
+  
+ // check for non-ascii first
+	ch = theEvent->data.key.keyCode;
+	for (km=keymaps;km->source!=-1;km++)
+		if (ch == km->source)
+		{
+			Key_Event (km->dest, false);
+			return self;
+		}
+
+   ch = theEvent->data.key.charCode;
+	if (ch >= 'A' && ch <= 'Z')
+		ch += 'a' - 'A';
+    if (ch>=256)
+		return self;
+	Key_Event (ch, false);
+    return self;
+}
+
+
+- tiffShot
+{
+	id			imagerep, image;
+	NXRect		r;
+	NXStream	*stream;
+	int			fd;
+	int    		i; 
+	char		tiffname[80]; 
+	
+	[vid_window_i getFrame: &r];
+	r.origin.x = r.origin.y = 0;
+	image = [[NXImage alloc] initSize: &r.size];
+	imagerep = [[NXCachedImageRep alloc] initFromWindow:vid_window_i rect:&r];
+	
+	[image lockFocus];
+	[imagerep draw];
+	[image unlockFocus];
+	
+// 
+// find a file name to save it to 
+// 
+	strcpy(tiffname,"quake00.tif");
+		
+	for (i=0 ; i<=99 ; i++) 
+	{ 
+		tiffname[5] = i/10 + '0'; 
+		tiffname[6] = i%10 + '0'; 
+		if (Sys_FileTime(tiffname) == -1)
+			break;	// file doesn't exist
+	} 
+	if (i==100) 
+		Sys_Error ("SCR_ScreenShot_f: Couldn't create a tiff"); 
+
+	fd = open (tiffname, O_RDWR|O_CREAT|O_TRUNC, 0666);
+	stream = NXOpenFile (fd, NX_READWRITE);
+	[image writeTIFF: stream];
+	NXClose (stream);
+	close (fd);
+	printf ("wrote %s\n", tiffname);
+
+	[image free];
+	[imagerep free];
+	return self;
+	
+}
+
+- screenShot: sender
+{
+	return [self tiffShot];
+}
+
+- setScaleFullScreen: sender
+{
+	VID_Shutdown ();
+	if (vid_fullscreen)
+	{
+		vid_fullscreen = 0;
+		VID_Restart (vid_display, vid_scale);
+	}
+	else
+	{
+		vid_fullscreen = 1;
+		VID_Restart (vid_display, vid_scale);
+	}
+	return self;
+}
+
+@end
+
+//============================================================================
+
+@implementation FrameWindow
+
+- windowExposed:(NXEvent *)theEvent
+{
+	return self;
+}
+
+@end
+
+
--- /dev/null
+++ b/server/server.h
@@ -1,0 +1,341 @@
+/*
+Copyright (C) 1997-2001 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
+
+
+//define	PARANOID			// speed sapping error checking
+
+#include "../qcommon/qcommon.h"
+#include "../game/game.h"
+
+//=============================================================================
+
+#define	MAX_MASTERS	8				// max recipients for heartbeat packets
+
+typedef enum {
+	ss_dead,			// no map loaded
+	ss_loading,			// spawning level edicts
+	ss_game,			// actively running
+	ss_cinematic,
+	ss_demo,
+	ss_pic
+} server_state_t;
+// some qc commands are only valid before the server has finished
+// initializing (precache commands, static sounds / objects, etc)
+
+typedef struct
+{
+	server_state_t	state;			// precache commands are only valid during load
+
+	qboolean	attractloop;		// running cinematics and demos for the local system only
+	qboolean	loadgame;			// client begins should reuse existing entity
+
+	unsigned	time;				// always sv.framenum * 100 msec
+	int			framenum;
+
+	char		name[MAX_QPATH];			// map name, or cinematic name
+	struct cmodel_s		*models[MAX_MODELS];
+
+	char		configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+	entity_state_t	baselines[MAX_EDICTS];
+
+	// the multicast buffer is used to send a message to a set of clients
+	// it is only used to marshall data until SV_Multicast is called
+	sizebuf_t	multicast;
+	byte		multicast_buf[MAX_MSGLEN];
+
+	// demo server information
+	FILE		*demofile;
+	qboolean	timedemo;		// don't time sync
+} server_t;
+
+#define EDICT_NUM(n) ((edict_t *)((byte *)ge->edicts + ge->edict_size*(n)))
+#define NUM_FOR_EDICT(e) ( ((byte *)(e)-(byte *)ge->edicts ) / ge->edict_size)
+
+
+typedef enum
+{
+	cs_free,		// can be reused for a new connection
+	cs_zombie,		// client has been disconnected, but don't reuse
+					// connection for a couple seconds
+	cs_connected,	// has been assigned to a client_t, but not in game yet
+	cs_spawned		// client is fully in game
+} client_state_t;
+
+typedef struct
+{
+	int					areabytes;
+	byte				areabits[MAX_MAP_AREAS/8];		// portalarea visibility bits
+	player_state_t		ps;
+	int					num_entities;
+	int					first_entity;		// into the circular sv_packet_entities[]
+	int					senttime;			// for ping calculations
+} client_frame_t;
+
+#define	LATENCY_COUNTS	16
+#define	RATE_MESSAGES	10
+
+typedef struct client_s
+{
+	client_state_t	state;
+
+	char			userinfo[MAX_INFO_STRING];		// name, etc
+
+	int				lastframe;			// for delta compression
+	usercmd_t		lastcmd;			// for filling in big drops
+
+	int				commandMsec;		// every seconds this is reset, if user
+										// commands exhaust it, assume time cheating
+
+	int				frame_latency[LATENCY_COUNTS];
+	int				ping;
+
+	int				message_size[RATE_MESSAGES];	// used to rate drop packets
+	int				rate;
+	int				surpressCount;		// number of messages rate supressed
+
+	edict_t			*edict;				// EDICT_NUM(clientnum+1)
+	char			name[32];			// extracted from userinfo, high bits masked
+	int				messagelevel;		// for filtering printed messages
+
+	// The datagram is written to by sound calls, prints, temp ents, etc.
+	// It can be harmlessly overflowed.
+	sizebuf_t		datagram;
+	byte			datagram_buf[MAX_MSGLEN];
+
+	client_frame_t	frames[UPDATE_BACKUP];	// updates can be delta'd from here
+
+	byte			*download;			// file being downloaded
+	int				downloadsize;		// total bytes (can't use EOF because of paks)
+	int				downloadcount;		// bytes sent
+
+	int				lastmessage;		// sv.framenum when packet was last received
+	int				lastconnect;
+
+	int				challenge;			// challenge of this user, randomly generated
+
+	netchan_t		netchan;
+} client_t;
+
+// a client can leave the server in one of four ways:
+// dropping properly by quiting or disconnecting
+// timing out if no valid messages are received for timeout.value seconds
+// getting kicked off by the server operator
+// a program error, like an overflowed reliable buffer
+
+//=============================================================================
+
+// MAX_CHALLENGES is made large to prevent a denial
+// of service attack that could cycle all of them
+// out before legitimate users connected
+#define	MAX_CHALLENGES	1024
+
+typedef struct
+{
+	netadr_t	adr;
+	int			challenge;
+	int			time;
+} challenge_t;
+
+
+typedef struct
+{
+	qboolean	initialized;				// sv_init has completed
+	int			realtime;					// always increasing, no clamping, etc
+
+	char		mapcmd[MAX_TOKEN_CHARS];	// ie: *intro.cin+base 
+
+	int			spawncount;					// incremented each server start
+											// used to check late spawns
+
+	client_t	*clients;					// [maxclients->value];
+	int			num_client_entities;		// maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES
+	int			next_client_entities;		// next client_entity to use
+	entity_state_t	*client_entities;		// [num_client_entities]
+
+	int			last_heartbeat;
+
+	challenge_t	challenges[MAX_CHALLENGES];	// to prevent invalid IPs from connecting
+
+	// serverrecord values
+	FILE		*demofile;
+	sizebuf_t	demo_multicast;
+	byte		demo_multicast_buf[MAX_MSGLEN];
+} server_static_t;
+
+//=============================================================================
+
+extern	netadr_t	net_from;
+extern	sizebuf_t	net_message;
+
+extern	netadr_t	master_adr[MAX_MASTERS];	// address of the master server
+
+extern	server_static_t	svs;				// persistant server info
+extern	server_t		sv;					// local server
+
+extern	cvar_t		*sv_paused;
+extern	cvar_t		*maxclients;
+extern	cvar_t		*sv_noreload;			// don't reload level state when reentering
+extern	cvar_t		*sv_airaccelerate;		// don't reload level state when reentering
+											// development tool
+extern	cvar_t		*sv_enforcetime;
+
+extern	client_t	*sv_client;
+extern	edict_t		*sv_player;
+
+//===========================================================
+
+//
+// sv_main.c
+//
+void SV_FinalMessage (char *message, qboolean reconnect);
+void SV_DropClient (client_t *drop);
+
+int SV_ModelIndex (char *name);
+int SV_SoundIndex (char *name);
+int SV_ImageIndex (char *name);
+
+void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
+
+void SV_ExecuteUserCommand (char *s);
+void SV_InitOperatorCommands (void);
+
+void SV_SendServerinfo (client_t *client);
+void SV_UserinfoChanged (client_t *cl);
+
+
+void Master_Heartbeat (void);
+void Master_Packet (void);
+
+//
+// sv_init.c
+//
+void SV_InitGame (void);
+void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame);
+
+
+//
+// sv_phys.c
+//
+void SV_PrepWorldFrame (void);
+
+//
+// sv_send.c
+//
+typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t;
+#define	SV_OUTPUTBUF_LENGTH	(MAX_MSGLEN - 16)
+
+extern	char	sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+
+void SV_FlushRedirect (int sv_redirected, char *outputbuf);
+
+void SV_DemoCompleted (void);
+void SV_SendClientMessages (void);
+
+void SV_Multicast (vec3_t origin, multicast_t to);
+void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
+					int soundindex, float volume,
+					float attenuation, float timeofs);
+void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...);
+void SV_BroadcastPrintf (int level, char *fmt, ...);
+void SV_BroadcastCommand (char *fmt, ...);
+
+//
+// sv_user.c
+//
+void SV_Nextserver (void);
+void SV_ExecuteClientMessage (client_t *cl);
+
+//
+// sv_ccmds.c
+//
+void SV_ReadLevelFile (void);
+void SV_Status_f (void);
+
+//
+// sv_ents.c
+//
+void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg);
+void SV_RecordDemoMessage (void);
+void SV_BuildClientFrame (client_t *client);
+
+
+void SV_Error (char *error, ...);
+
+//
+// sv_game.c
+//
+extern	game_export_t	*ge;
+
+void SV_InitGameProgs (void);
+void SV_ShutdownGameProgs (void);
+void SV_InitEdict (edict_t *e);
+
+
+
+//============================================================
+
+//
+// high level object sorting to reduce interaction tests
+//
+
+void SV_ClearWorld (void);
+// called after the world model has been loaded, before linking any entities
+
+void SV_UnlinkEdict (edict_t *ent);
+// call before removing an entity, and before trying to move one,
+// so it doesn't clip against itself
+
+void SV_LinkEdict (edict_t *ent);
+// Needs to be called any time an entity changes origin, mins, maxs,
+// or solid.  Automatically unlinks if needed.
+// sets ent->v.absmin and ent->v.absmax
+// sets ent->leafnums[] for pvs determination even if the entity
+// is not solid
+
+int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
+// fills in a table of edict pointers with edicts that have bounding boxes
+// that intersect the given area.  It is possible for a non-axial bmodel
+// to be returned that doesn't actually intersect the area on an exact
+// test.
+// returns the number of pointers filled in
+// ??? does this always return the world?
+
+//===================================================================
+
+//
+// functions that interact with everything apropriate
+//
+int SV_PointContents (vec3_t p);
+// returns the CONTENTS_* value from the world at the given point.
+// Quake 2 extends this to also check entities, to allow moving liquids
+
+
+trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask);
+// mins and maxs are relative
+
+// if the entire move stays in a solid volume, trace.allsolid will be set,
+// trace.startsolid will be set, and trace.fraction will be 0
+
+// if the starting point is in a solid, it will be allowed to move out
+// to an open area
+
+// passedict is explicitly excluded from clipping checks (normally NULL)
+
--- /dev/null
+++ b/server/sv_ccmds.c
@@ -1,0 +1,1050 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+/*
+===============================================================================
+
+OPERATOR CONSOLE ONLY COMMANDS
+
+These commands can only be entered from stdin or by a remote operator datagram
+===============================================================================
+*/
+
+/*
+====================
+SV_SetMaster_f
+
+Specify a list of master servers
+====================
+*/
+void SV_SetMaster_f (void)
+{
+	int		i, slot;
+
+	// only dedicated servers send heartbeats
+	if (!dedicated->value)
+	{
+		Com_Printf ("Only dedicated servers use masters.\n");
+		return;
+	}
+
+	// make sure the server is listed public
+	Cvar_Set ("public", "1");
+
+	for (i=1 ; i<MAX_MASTERS ; i++)
+		memset (&master_adr[i], 0, sizeof(master_adr[i]));
+
+	slot = 1;		// slot 0 will always contain the id master
+	for (i=1 ; i<Cmd_Argc() ; i++)
+	{
+		if (slot == MAX_MASTERS)
+			break;
+
+		if (!NET_StringToAdr (Cmd_Argv(i), &master_adr[i]))
+		{
+			Com_Printf ("Bad address: %s\n", Cmd_Argv(i));
+			continue;
+		}
+		if (master_adr[slot].port == 0)
+			master_adr[slot].port = BigShort (PORT_MASTER);
+
+		Com_Printf ("Master server at %s\n", NET_AdrToString (master_adr[slot]));
+
+		Com_Printf ("Sending a ping.\n");
+
+		Netchan_OutOfBandPrint (NS_SERVER, master_adr[slot], "ping");
+
+		slot++;
+	}
+
+	svs.last_heartbeat = -9999999;
+}
+
+
+
+/*
+==================
+SV_SetPlayer
+
+Sets sv_client and sv_player to the player with idnum Cmd_Argv(1)
+==================
+*/
+qboolean SV_SetPlayer (void)
+{
+	client_t	*cl;
+	int			i;
+	int			idnum;
+	char		*s;
+
+	if (Cmd_Argc() < 2)
+		return false;
+
+	s = Cmd_Argv(1);
+
+	// numeric values are just slot numbers
+	if (s[0] >= '0' && s[0] <= '9')
+	{
+		idnum = atoi(Cmd_Argv(1));
+		if (idnum < 0 || idnum >= maxclients->value)
+		{
+			Com_Printf ("Bad client slot: %i\n", idnum);
+			return false;
+		}
+
+		sv_client = &svs.clients[idnum];
+		sv_player = sv_client->edict;
+		if (!sv_client->state)
+		{
+			Com_Printf ("Client %i is not active\n", idnum);
+			return false;
+		}
+		return true;
+	}
+
+	// check for a name match
+	for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+	{
+		if (!cl->state)
+			continue;
+		if (!strcmp(cl->name, s))
+		{
+			sv_client = cl;
+			sv_player = sv_client->edict;
+			return true;
+		}
+	}
+
+	Com_Printf ("Userid %s is not on the server\n", s);
+	return false;
+}
+
+
+/*
+===============================================================================
+
+SAVEGAME FILES
+
+===============================================================================
+*/
+
+/*
+=====================
+SV_WipeSavegame
+
+Delete save/<XXX>/
+=====================
+*/
+void SV_WipeSavegame (char *savename)
+{
+	char	name[MAX_OSPATH];
+	char	*s;
+
+	Com_DPrintf("SV_WipeSaveGame(%s)\n", savename);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename);
+	remove (name);
+	Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename);
+	remove (name);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename);
+	s = Sys_FindFirst( name, 0, 0 );
+	while (s)
+	{
+		remove (s);
+		s = Sys_FindNext( 0, 0 );
+	}
+	Sys_FindClose ();
+	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename);
+	s = Sys_FindFirst(name, 0, 0 );
+	while (s)
+	{
+		remove (s);
+		s = Sys_FindNext( 0, 0 );
+	}
+	Sys_FindClose ();
+}
+
+
+/*
+================
+CopyFile
+================
+*/
+void CopyFile (char *src, char *dst)
+{
+	FILE	*f1, *f2;
+	int		l;
+	byte	buffer[65536];
+
+	Com_DPrintf ("CopyFile (%s, %s)\n", src, dst);
+
+	f1 = fopen (src, "rb");
+	if (!f1)
+		return;
+	f2 = fopen (dst, "wb");
+	if (!f2)
+	{
+		fclose (f1);
+		return;
+	}
+
+	while (1)
+	{
+		l = fread (buffer, 1, sizeof(buffer), f1);
+		if (!l)
+			break;
+		fwrite (buffer, 1, l, f2);
+	}
+
+	fclose (f1);
+	fclose (f2);
+}
+
+
+/*
+================
+SV_CopySaveGame
+================
+*/
+void SV_CopySaveGame (char *src, char *dst)
+{
+	char	name[MAX_OSPATH], name2[MAX_OSPATH];
+	int		l, len;
+	char	*found;
+
+	Com_DPrintf("SV_CopySaveGame(%s, %s)\n", src, dst);
+
+	SV_WipeSavegame (dst);
+
+	// copy the savegame over
+	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), src);
+	Com_sprintf (name2, sizeof(name2), "%s/save/%s/server.ssv", FS_Gamedir(), dst);
+	FS_CreatePath (name2);
+	CopyFile (name, name2);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir(), src);
+	Com_sprintf (name2, sizeof(name2), "%s/save/%s/game.ssv", FS_Gamedir(), dst);
+	CopyFile (name, name2);
+
+	Com_sprintf (name, sizeof(name), "%s/save/%s/", FS_Gamedir(), src);
+	len = strlen(name);
+	Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir(), src);
+	found = Sys_FindFirst(name, 0, 0 );
+	while (found)
+	{
+		strcpy (name+len, found+len);
+
+		Com_sprintf (name2, sizeof(name2), "%s/save/%s/%s", FS_Gamedir(), dst, found+len);
+		CopyFile (name, name2);
+
+		// change sav to sv2
+		l = strlen(name);
+		strcpy (name+l-3, "sv2");
+		l = strlen(name2);
+		strcpy (name2+l-3, "sv2");
+		CopyFile (name, name2);
+
+		found = Sys_FindNext( 0, 0 );
+	}
+	Sys_FindClose ();
+}
+
+
+/*
+==============
+SV_WriteLevelFile
+
+==============
+*/
+void SV_WriteLevelFile (void)
+{
+	char	name[MAX_OSPATH];
+	FILE	*f;
+
+	Com_DPrintf("SV_WriteLevelFile()\n");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
+	f = fopen(name, "wb");
+	if (!f)
+	{
+		Com_Printf ("Failed to open %s\n", name);
+		return;
+	}
+	fwrite (sv.configstrings, sizeof(sv.configstrings), 1, f);
+	CM_WritePortalState (f);
+	fclose (f);
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+	ge->WriteLevel (name);
+}
+
+/*
+==============
+SV_ReadLevelFile
+
+==============
+*/
+void SV_ReadLevelFile (void)
+{
+	char	name[MAX_OSPATH];
+	FILE	*f;
+
+	Com_DPrintf("SV_ReadLevelFile()\n");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
+	f = fopen(name, "rb");
+	if (!f)
+	{
+		Com_Printf ("Failed to open %s\n", name);
+		return;
+	}
+	FS_Read (sv.configstrings, sizeof(sv.configstrings), f);
+	CM_ReadPortalState (f);
+	fclose (f);
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+	ge->ReadLevel (name);
+}
+
+/*
+==============
+SV_WriteServerFile
+
+==============
+*/
+void SV_WriteServerFile (qboolean autosave)
+{
+	FILE	*f;
+	cvar_t	*var;
+	char	name[MAX_OSPATH], string[128];
+	char	comment[32];
+	time_t	aclock;
+	struct tm	*newtime;
+
+	Com_DPrintf("SV_WriteServerFile(%s)\n", autosave ? "true" : "false");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
+	f = fopen (name, "wb");
+	if (!f)
+	{
+		Com_Printf ("Couldn't write %s\n", name);
+		return;
+	}
+	// write the comment field
+	memset (comment, 0, sizeof(comment));
+
+	if (!autosave)
+	{
+		time (&aclock);
+		newtime = localtime (&aclock);
+		Com_sprintf (comment,sizeof(comment), "%2i:%i%i %2i/%2i  ", newtime->tm_hour
+			, newtime->tm_min/10, newtime->tm_min%10,
+			newtime->tm_mon+1, newtime->tm_mday);
+		strncat (comment, sv.configstrings[CS_NAME], sizeof(comment)-1-strlen(comment) );
+	}
+	else
+	{	// autosaved
+		Com_sprintf (comment, sizeof(comment), "ENTERING %s", sv.configstrings[CS_NAME]);
+	}
+
+	fwrite (comment, 1, sizeof(comment), f);
+
+	// write the mapcmd
+	fwrite (svs.mapcmd, 1, sizeof(svs.mapcmd), f);
+
+	// write all CVAR_LATCH cvars
+	// these will be things like coop, skill, deathmatch, etc
+	for (var = cvar_vars ; var ; var=var->next)
+	{
+		if (!(var->flags & CVAR_LATCH))
+			continue;
+		if (strlen(var->name) >= sizeof(name)-1
+			|| strlen(var->string) >= sizeof(string)-1)
+		{
+			Com_Printf ("Cvar too long: %s = %s\n", var->name, var->string);
+			continue;
+		}
+		memset (name, 0, sizeof(name));
+		memset (string, 0, sizeof(string));
+		strcpy (name, var->name);
+		strcpy (string, var->string);
+		fwrite (name, 1, sizeof(name), f);
+		fwrite (string, 1, sizeof(string), f);
+	}
+
+	fclose (f);
+
+	// write game state
+	Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
+	ge->WriteGame (name, autosave);
+}
+
+/*
+==============
+SV_ReadServerFile
+
+==============
+*/
+void SV_ReadServerFile (void)
+{
+	FILE	*f;
+	char	name[MAX_OSPATH], string[128];
+	char	comment[32];
+	char	mapcmd[MAX_TOKEN_CHARS];
+
+	Com_DPrintf("SV_ReadServerFile()\n");
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
+	f = fopen (name, "rb");
+	if (!f)
+	{
+		Com_Printf ("Couldn't read %s\n", name);
+		return;
+	}
+	// read the comment field
+	FS_Read (comment, sizeof(comment), f);
+
+	// read the mapcmd
+	FS_Read (mapcmd, sizeof(mapcmd), f);
+
+	// read all CVAR_LATCH cvars
+	// these will be things like coop, skill, deathmatch, etc
+	while (1)
+	{
+		if (!fread (name, 1, sizeof(name), f))
+			break;
+		FS_Read (string, sizeof(string), f);
+		Com_DPrintf ("Set %s = %s\n", name, string);
+		Cvar_ForceSet (name, string);
+	}
+
+	fclose (f);
+
+	// start a new game fresh with new cvars
+	SV_InitGame ();
+
+	strcpy (svs.mapcmd, mapcmd);
+
+	// read game state
+	Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
+	ge->ReadGame (name);
+}
+
+
+//=========================================================
+
+
+
+
+/*
+==================
+SV_DemoMap_f
+
+Puts the server in demo mode on a specific map/cinematic
+==================
+*/
+void SV_DemoMap_f (void)
+{
+	SV_Map (true, Cmd_Argv(1), false );
+}
+
+/*
+==================
+SV_GameMap_f
+
+Saves the state of the map just being exited and goes to a new map.
+
+If the initial character of the map string is '*', the next map is
+in a new unit, so the current savegame directory is cleared of
+map files.
+
+Example:
+
+*inter.cin+jail
+
+Clears the archived maps, plays the inter.cin cinematic, then
+goes to map jail.bsp.
+==================
+*/
+void SV_GameMap_f (void)
+{
+	char		*map;
+	int			i;
+	client_t	*cl;
+	qboolean	*savedInuse;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("USAGE: gamemap <map>\n");
+		return;
+	}
+
+	Com_DPrintf("SV_GameMap(%s)\n", Cmd_Argv(1));
+
+	FS_CreatePath (va("%s/save/current/", FS_Gamedir()));
+
+	// check for clearing the current savegame
+	map = Cmd_Argv(1);
+	if (map[0] == '*')
+	{
+		// wipe all the *.sav files
+		SV_WipeSavegame ("current");
+	}
+	else
+	{	// save the map just exited
+		if (sv.state == ss_game)
+		{
+			// clear all the client inuse flags before saving so that
+			// when the level is re-entered, the clients will spawn
+			// at spawn points instead of occupying body shells
+			savedInuse = malloc(maxclients->value * sizeof(qboolean));
+			for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+			{
+				savedInuse[i] = cl->edict->inuse;
+				cl->edict->inuse = false;
+			}
+
+			SV_WriteLevelFile ();
+
+			// we must restore these for clients to transfer over correctly
+			for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+				cl->edict->inuse = savedInuse[i];
+			free (savedInuse);
+		}
+	}
+
+	// start up the next map
+	SV_Map (false, Cmd_Argv(1), false );
+
+	// archive server state
+	strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
+
+	// copy off the level to the autosave slot
+	if (!dedicated->value)
+	{
+		SV_WriteServerFile (true);
+		SV_CopySaveGame ("current", "save0");
+	}
+}
+
+/*
+==================
+SV_Map_f
+
+Goes directly to a given map without any savegame archiving.
+For development work
+==================
+*/
+void SV_Map_f (void)
+{
+	char	*map;
+	char	expanded[MAX_QPATH];
+
+	// if not a pcx, demo, or cinematic, check to make sure the level exists
+	map = Cmd_Argv(1);
+	if (!strstr (map, "."))
+	{
+		Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
+		if (FS_LoadFile (expanded, NULL) == -1)
+		{
+			Com_Printf ("Can't find %s\n", expanded);
+			return;
+		}
+	}
+
+	sv.state = ss_dead;		// don't save current level when changing
+	SV_WipeSavegame("current");
+	SV_GameMap_f ();
+}
+
+/*
+=====================================================================
+
+  SAVEGAMES
+
+=====================================================================
+*/
+
+
+/*
+==============
+SV_Loadgame_f
+
+==============
+*/
+void SV_Loadgame_f (void)
+{
+	char	name[MAX_OSPATH];
+	FILE	*f;
+	char	*dir;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("USAGE: loadgame <directory>\n");
+		return;
+	}
+
+	Com_Printf ("Loading game...\n");
+
+	dir = Cmd_Argv(1);
+	if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
+	{
+		Com_Printf ("Bad savedir.\n");
+	}
+
+	// make sure the server.ssv file exists
+	Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv(1));
+	f = fopen (name, "rb");
+	if (!f)
+	{
+		Com_Printf ("No such savegame: %s\n", name);
+		return;
+	}
+	fclose (f);
+
+	SV_CopySaveGame (Cmd_Argv(1), "current");
+
+	SV_ReadServerFile ();
+
+	// go to the map
+	sv.state = ss_dead;		// don't save current level when changing
+	SV_Map (false, svs.mapcmd, true);
+}
+
+
+
+/*
+==============
+SV_Savegame_f
+
+==============
+*/
+void SV_Savegame_f (void)
+{
+	char	*dir;
+
+	if (sv.state != ss_game)
+	{
+		Com_Printf ("You must be in a game to save.\n");
+		return;
+	}
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("USAGE: savegame <directory>\n");
+		return;
+	}
+
+	if (Cvar_VariableValue("deathmatch"))
+	{
+		Com_Printf ("Can't savegame in a deathmatch\n");
+		return;
+	}
+
+	if (!strcmp (Cmd_Argv(1), "current"))
+	{
+		Com_Printf ("Can't save to 'current'\n");
+		return;
+	}
+
+	if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0)
+	{
+		Com_Printf ("\nCan't savegame while dead!\n");
+		return;
+	}
+
+	dir = Cmd_Argv(1);
+	if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
+	{
+		Com_Printf ("Bad savedir.\n");
+	}
+
+	Com_Printf ("Saving game...\n");
+
+	// archive current level, including all client edicts.
+	// when the level is reloaded, they will be shells awaiting
+	// a connecting client
+	SV_WriteLevelFile ();
+
+	// save server state
+	SV_WriteServerFile (false);
+
+	// copy it off
+	SV_CopySaveGame ("current", dir);
+
+	Com_Printf ("Done.\n");
+}
+
+//===============================================================
+
+/*
+==================
+SV_Kick_f
+
+Kick a user off of the server
+==================
+*/
+void SV_Kick_f (void)
+{
+	if (!svs.initialized)
+	{
+		Com_Printf ("No server running.\n");
+		return;
+	}
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("Usage: kick <userid>\n");
+		return;
+	}
+
+	if (!SV_SetPlayer ())
+		return;
+
+	SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", sv_client->name);
+	// print directly, because the dropped client won't get the
+	// SV_BroadcastPrintf message
+	SV_ClientPrintf (sv_client, PRINT_HIGH, "You were kicked from the game\n");
+	SV_DropClient (sv_client);
+	sv_client->lastmessage = svs.realtime;	// min case there is a funny zombie
+}
+
+
+/*
+================
+SV_Status_f
+================
+*/
+void SV_Status_f (void)
+{
+	int			i, j, l;
+	client_t	*cl;
+	char		*s;
+	int			ping;
+	if (!svs.clients)
+	{
+		Com_Printf ("No server running.\n");
+		return;
+	}
+	Com_Printf ("map              : %s\n", sv.name);
+
+	Com_Printf ("num score ping name            lastmsg address               qport \n");
+	Com_Printf ("--- ----- ---- --------------- ------- --------------------- ------\n");
+	for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+	{
+		if (!cl->state)
+			continue;
+		Com_Printf ("%3i ", i);
+		Com_Printf ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]);
+
+		if (cl->state == cs_connected)
+			Com_Printf ("CNCT ");
+		else if (cl->state == cs_zombie)
+			Com_Printf ("ZMBI ");
+		else
+		{
+			ping = cl->ping < 9999 ? cl->ping : 9999;
+			Com_Printf ("%4i ", ping);
+		}
+
+		Com_Printf ("%s", cl->name);
+		l = 16 - strlen(cl->name);
+		for (j=0 ; j<l ; j++)
+			Com_Printf (" ");
+
+		Com_Printf ("%7i ", svs.realtime - cl->lastmessage );
+
+		s = NET_AdrToString ( cl->netchan.remote_address);
+		Com_Printf ("%s", s);
+		l = 22 - strlen(s);
+		for (j=0 ; j<l ; j++)
+			Com_Printf (" ");
+		
+		Com_Printf ("%5i", cl->netchan.qport);
+
+		Com_Printf ("\n");
+	}
+	Com_Printf ("\n");
+}
+
+/*
+==================
+SV_ConSay_f
+==================
+*/
+void SV_ConSay_f(void)
+{
+	client_t *client;
+	int		j;
+	char	*p;
+	char	text[1024];
+
+	if (Cmd_Argc () < 2)
+		return;
+
+	strcpy (text, "console: ");
+	p = Cmd_Args();
+
+	if (*p == '"')
+	{
+		p++;
+		p[strlen(p)-1] = 0;
+	}
+
+	strcat(text, p);
+
+	for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
+	{
+		if (client->state != cs_spawned)
+			continue;
+		SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
+	}
+}
+
+
+/*
+==================
+SV_Heartbeat_f
+==================
+*/
+void SV_Heartbeat_f (void)
+{
+	svs.last_heartbeat = -9999999;
+}
+
+
+/*
+===========
+SV_Serverinfo_f
+
+  Examine or change the serverinfo string
+===========
+*/
+void SV_Serverinfo_f (void)
+{
+	Com_Printf ("Server info settings:\n");
+	Info_Print (Cvar_Serverinfo());
+}
+
+
+/*
+===========
+SV_DumpUser_f
+
+Examine all a users info strings
+===========
+*/
+void SV_DumpUser_f (void)
+{
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("Usage: info <userid>\n");
+		return;
+	}
+
+	if (!SV_SetPlayer ())
+		return;
+
+	Com_Printf ("userinfo\n");
+	Com_Printf ("--------\n");
+	Info_Print (sv_client->userinfo);
+
+}
+
+
+/*
+==============
+SV_ServerRecord_f
+
+Begins server demo recording.  Every entity and every message will be
+recorded, but no playerinfo will be stored.  Primarily for demo merging.
+==============
+*/
+void SV_ServerRecord_f (void)
+{
+	char	name[MAX_OSPATH];
+	char	buf_data[32768];
+	sizebuf_t	buf;
+	int		len;
+	int		i;
+
+	if (Cmd_Argc() != 2)
+	{
+		Com_Printf ("serverrecord <demoname>\n");
+		return;
+	}
+
+	if (svs.demofile)
+	{
+		Com_Printf ("Already recording.\n");
+		return;
+	}
+
+	if (sv.state != ss_game)
+	{
+		Com_Printf ("You must be in a level to record.\n");
+		return;
+	}
+
+	//
+	// open the demo file
+	//
+	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
+
+	Com_Printf ("recording to %s.\n", name);
+	FS_CreatePath (name);
+	svs.demofile = fopen (name, "wb");
+	if (!svs.demofile)
+	{
+		Com_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+
+	// setup a buffer to catch all multicasts
+	SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
+
+	//
+	// write a single giant fake message with all the startup info
+	//
+	SZ_Init (&buf, buf_data, sizeof(buf_data));
+
+	//
+	// serverdata needs to go over for all types of servers
+	// to make sure the protocol is right, and to set the gamedir
+	//
+	// send the serverdata
+	MSG_WriteByte (&buf, svc_serverdata);
+	MSG_WriteLong (&buf, PROTOCOL_VERSION);
+	MSG_WriteLong (&buf, svs.spawncount);
+	// 2 means server demo
+	MSG_WriteByte (&buf, 2);	// demos are always attract loops
+	MSG_WriteString (&buf, Cvar_VariableString ("gamedir"));
+	MSG_WriteShort (&buf, -1);
+	// send full levelname
+	MSG_WriteString (&buf, sv.configstrings[CS_NAME]);
+
+	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+		if (sv.configstrings[i][0])
+		{
+			MSG_WriteByte (&buf, svc_configstring);
+			MSG_WriteShort (&buf, i);
+			MSG_WriteString (&buf, sv.configstrings[i]);
+		}
+
+	// write it to the demo file
+	Com_DPrintf ("signon message length: %i\n", buf.cursize);
+	len = LittleLong (buf.cursize);
+	fwrite (&len, 4, 1, svs.demofile);
+	fwrite (buf.data, buf.cursize, 1, svs.demofile);
+
+	// the rest of the demo file will be individual frames
+}
+
+
+/*
+==============
+SV_ServerStop_f
+
+Ends server demo recording
+==============
+*/
+void SV_ServerStop_f (void)
+{
+	if (!svs.demofile)
+	{
+		Com_Printf ("Not doing a serverrecord.\n");
+		return;
+	}
+	fclose (svs.demofile);
+	svs.demofile = NULL;
+	Com_Printf ("Recording completed.\n");
+}
+
+
+/*
+===============
+SV_KillServer_f
+
+Kick everyone off, possibly in preparation for a new game
+
+===============
+*/
+void SV_KillServer_f (void)
+{
+	if (!svs.initialized)
+		return;
+	SV_Shutdown ("Server was killed.\n", false);
+	NET_Config ( false );	// close network sockets
+}
+
+/*
+===============
+SV_ServerCommand_f
+
+Let the game dll handle a command
+===============
+*/
+void SV_ServerCommand_f (void)
+{
+	if (!ge)
+	{
+		Com_Printf ("No game loaded.\n");
+		return;
+	}
+
+	ge->ServerCommand();
+}
+
+//===========================================================
+
+/*
+==================
+SV_InitOperatorCommands
+==================
+*/
+void SV_InitOperatorCommands (void)
+{
+	Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
+	Cmd_AddCommand ("kick", SV_Kick_f);
+	Cmd_AddCommand ("status", SV_Status_f);
+	Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
+	Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
+
+	Cmd_AddCommand ("map", SV_Map_f);
+	Cmd_AddCommand ("demomap", SV_DemoMap_f);
+	Cmd_AddCommand ("gamemap", SV_GameMap_f);
+	Cmd_AddCommand ("setmaster", SV_SetMaster_f);
+
+	if ( dedicated->value )
+		Cmd_AddCommand ("say", SV_ConSay_f);
+
+	Cmd_AddCommand ("serverrecord", SV_ServerRecord_f);
+	Cmd_AddCommand ("serverstop", SV_ServerStop_f);
+
+	Cmd_AddCommand ("save", SV_Savegame_f);
+	Cmd_AddCommand ("load", SV_Loadgame_f);
+
+	Cmd_AddCommand ("killserver", SV_KillServer_f);
+
+	Cmd_AddCommand ("sv", SV_ServerCommand_f);
+}
+
--- /dev/null
+++ b/server/sv_ents.c
@@ -1,0 +1,727 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+/*
+=============================================================================
+
+Encode a client frame onto the network channel
+
+=============================================================================
+*/
+
+#if 0
+
+// because there can be a lot of projectiles, there is a special
+// network protocol for them
+#define	MAX_PROJECTILES		64
+edict_t	*projectiles[MAX_PROJECTILES];
+int		numprojs;
+cvar_t  *sv_projectiles;
+
+qboolean SV_AddProjectileUpdate (edict_t *ent)
+{
+	if (!sv_projectiles)
+		sv_projectiles = Cvar_Get("sv_projectiles", "1", 0);
+
+	if (!sv_projectiles->value)
+		return false;
+
+	if (!(ent->svflags & SVF_PROJECTILE))
+		return false;
+	if (numprojs == MAX_PROJECTILES)
+		return true;
+
+	projectiles[numprojs++] = ent;
+	return true;
+}
+
+void SV_EmitProjectileUpdate (sizebuf_t *msg)
+{
+	byte	bits[16];	// [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2]
+	int		n, i;
+	edict_t	*ent;
+	int		x, y, z, p, yaw;
+	int len;
+
+	if (!numprojs)
+		return;
+
+	MSG_WriteByte (msg, numprojs);
+
+	for (n=0 ; n<numprojs ; n++)
+	{
+		ent = projectiles[n];
+		x = (int)(ent->s.origin[0]+4096)>>1;
+		y = (int)(ent->s.origin[1]+4096)>>1;
+		z = (int)(ent->s.origin[2]+4096)>>1;
+		p = (int)(256*ent->s.angles[0]/360)&255;
+		yaw = (int)(256*ent->s.angles[1]/360)&255;
+
+		len = 0;
+		bits[len++] = x;
+		bits[len++] = (x>>8) | (y<<4);
+		bits[len++] = (y>>4);
+		bits[len++] = z;
+		bits[len++] = (z>>8);
+		if (ent->s.effects & EF_BLASTER)
+			bits[len-1] |= 64;
+
+		if (ent->s.old_origin[0] != ent->s.origin[0] ||
+			ent->s.old_origin[1] != ent->s.origin[1] ||
+			ent->s.old_origin[2] != ent->s.origin[2]) {
+			bits[len-1] |= 128;
+			x = (int)(ent->s.old_origin[0]+4096)>>1;
+			y = (int)(ent->s.old_origin[1]+4096)>>1;
+			z = (int)(ent->s.old_origin[2]+4096)>>1;
+			bits[len++] = x;
+			bits[len++] = (x>>8) | (y<<4);
+			bits[len++] = (y>>4);
+			bits[len++] = z;
+			bits[len++] = (z>>8);
+		}
+
+		bits[len++] = p;
+		bits[len++] = yaw;
+		bits[len++] = ent->s.modelindex;
+
+		bits[len++] = (ent->s.number & 0x7f);
+		if (ent->s.number > 255) {
+			bits[len-1] |= 128;
+			bits[len++] = (ent->s.number >> 7);
+		}
+
+		for (i=0 ; i<len ; i++)
+			MSG_WriteByte (msg, bits[i]);
+	}
+}
+#endif
+
+/*
+=============
+SV_EmitPacketEntities
+
+Writes a delta update of an entity_state_t list to the message.
+=============
+*/
+void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
+{
+	entity_state_t	*oldent, *newent;
+	int		oldindex, newindex;
+	int		oldnum, newnum;
+	int		from_num_entities;
+	int		bits;
+
+#if 0
+	if (numprojs)
+		MSG_WriteByte (msg, svc_packetentities2);
+	else
+#endif
+		MSG_WriteByte (msg, svc_packetentities);
+
+	if (!from)
+		from_num_entities = 0;
+	else
+		from_num_entities = from->num_entities;
+
+	newindex = 0;
+	oldindex = 0;
+	while (newindex < to->num_entities || oldindex < from_num_entities)
+	{
+		if (newindex >= to->num_entities)
+			newnum = 9999;
+		else
+		{
+			newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
+			newnum = newent->number;
+		}
+
+		if (oldindex >= from_num_entities)
+			oldnum = 9999;
+		else
+		{
+			oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
+			oldnum = oldent->number;
+		}
+
+		if (newnum == oldnum)
+		{	// delta update from old position
+			// because the force parm is false, this will not result
+			// in any bytes being emited if the entity has not changed at all
+			// note that players are always 'newentities', this updates their oldorigin always
+			// and prevents warping
+			MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
+			oldindex++;
+			newindex++;
+			continue;
+		}
+
+		if (newnum < oldnum)
+		{	// this is a new entity, send it from the baseline
+			MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
+			newindex++;
+			continue;
+		}
+
+		if (newnum > oldnum)
+		{	// the old entity isn't present in the new message
+			bits = U_REMOVE;
+			if (oldnum >= 256)
+				bits |= U_NUMBER16 | U_MOREBITS1;
+
+			MSG_WriteByte (msg,	bits&255 );
+			if (bits & 0x0000ff00)
+				MSG_WriteByte (msg,	(bits>>8)&255 );
+
+			if (bits & U_NUMBER16)
+				MSG_WriteShort (msg, oldnum);
+			else
+				MSG_WriteByte (msg, oldnum);
+
+			oldindex++;
+			continue;
+		}
+	}
+
+	MSG_WriteShort (msg, 0);	// end of packetentities
+
+#if 0
+	if (numprojs)
+		SV_EmitProjectileUpdate(msg);
+#endif
+}
+
+
+
+/*
+=============
+SV_WritePlayerstateToClient
+
+=============
+*/
+void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
+{
+	int				i;
+	int				pflags;
+	player_state_t	*ps, *ops;
+	player_state_t	dummy;
+	int				statbits;
+
+	ps = &to->ps;
+	if (!from)
+	{
+		memset (&dummy, 0, sizeof(dummy));
+		ops = &dummy;
+	}
+	else
+		ops = &from->ps;
+
+	//
+	// determine what needs to be sent
+	//
+	pflags = 0;
+
+	if (ps->pmove.pm_type != ops->pmove.pm_type)
+		pflags |= PS_M_TYPE;
+
+	if (ps->pmove.origin[0] != ops->pmove.origin[0]
+		|| ps->pmove.origin[1] != ops->pmove.origin[1]
+		|| ps->pmove.origin[2] != ops->pmove.origin[2] )
+		pflags |= PS_M_ORIGIN;
+
+	if (ps->pmove.velocity[0] != ops->pmove.velocity[0]
+		|| ps->pmove.velocity[1] != ops->pmove.velocity[1]
+		|| ps->pmove.velocity[2] != ops->pmove.velocity[2] )
+		pflags |= PS_M_VELOCITY;
+
+	if (ps->pmove.pm_time != ops->pmove.pm_time)
+		pflags |= PS_M_TIME;
+
+	if (ps->pmove.pm_flags != ops->pmove.pm_flags)
+		pflags |= PS_M_FLAGS;
+
+	if (ps->pmove.gravity != ops->pmove.gravity)
+		pflags |= PS_M_GRAVITY;
+
+	if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0]
+		|| ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1]
+		|| ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] )
+		pflags |= PS_M_DELTA_ANGLES;
+
+
+	if (ps->viewoffset[0] != ops->viewoffset[0]
+		|| ps->viewoffset[1] != ops->viewoffset[1]
+		|| ps->viewoffset[2] != ops->viewoffset[2] )
+		pflags |= PS_VIEWOFFSET;
+
+	if (ps->viewangles[0] != ops->viewangles[0]
+		|| ps->viewangles[1] != ops->viewangles[1]
+		|| ps->viewangles[2] != ops->viewangles[2] )
+		pflags |= PS_VIEWANGLES;
+
+	if (ps->kick_angles[0] != ops->kick_angles[0]
+		|| ps->kick_angles[1] != ops->kick_angles[1]
+		|| ps->kick_angles[2] != ops->kick_angles[2] )
+		pflags |= PS_KICKANGLES;
+
+	if (ps->blend[0] != ops->blend[0]
+		|| ps->blend[1] != ops->blend[1]
+		|| ps->blend[2] != ops->blend[2]
+		|| ps->blend[3] != ops->blend[3] )
+		pflags |= PS_BLEND;
+
+	if (ps->fov != ops->fov)
+		pflags |= PS_FOV;
+
+	if (ps->rdflags != ops->rdflags)
+		pflags |= PS_RDFLAGS;
+
+	if (ps->gunframe != ops->gunframe)
+		pflags |= PS_WEAPONFRAME;
+
+	pflags |= PS_WEAPONINDEX;
+
+	//
+	// write it
+	//
+	MSG_WriteByte (msg, svc_playerinfo);
+	MSG_WriteShort (msg, pflags);
+
+	//
+	// write the pmove_state_t
+	//
+	if (pflags & PS_M_TYPE)
+		MSG_WriteByte (msg, ps->pmove.pm_type);
+
+	if (pflags & PS_M_ORIGIN)
+	{
+		MSG_WriteShort (msg, ps->pmove.origin[0]);
+		MSG_WriteShort (msg, ps->pmove.origin[1]);
+		MSG_WriteShort (msg, ps->pmove.origin[2]);
+	}
+
+	if (pflags & PS_M_VELOCITY)
+	{
+		MSG_WriteShort (msg, ps->pmove.velocity[0]);
+		MSG_WriteShort (msg, ps->pmove.velocity[1]);
+		MSG_WriteShort (msg, ps->pmove.velocity[2]);
+	}
+
+	if (pflags & PS_M_TIME)
+		MSG_WriteByte (msg, ps->pmove.pm_time);
+
+	if (pflags & PS_M_FLAGS)
+		MSG_WriteByte (msg, ps->pmove.pm_flags);
+
+	if (pflags & PS_M_GRAVITY)
+		MSG_WriteShort (msg, ps->pmove.gravity);
+
+	if (pflags & PS_M_DELTA_ANGLES)
+	{
+		MSG_WriteShort (msg, ps->pmove.delta_angles[0]);
+		MSG_WriteShort (msg, ps->pmove.delta_angles[1]);
+		MSG_WriteShort (msg, ps->pmove.delta_angles[2]);
+	}
+
+	//
+	// write the rest of the player_state_t
+	//
+	if (pflags & PS_VIEWOFFSET)
+	{
+		MSG_WriteChar (msg, ps->viewoffset[0]*4);
+		MSG_WriteChar (msg, ps->viewoffset[1]*4);
+		MSG_WriteChar (msg, ps->viewoffset[2]*4);
+	}
+
+	if (pflags & PS_VIEWANGLES)
+	{
+		MSG_WriteAngle16 (msg, ps->viewangles[0]);
+		MSG_WriteAngle16 (msg, ps->viewangles[1]);
+		MSG_WriteAngle16 (msg, ps->viewangles[2]);
+	}
+
+	if (pflags & PS_KICKANGLES)
+	{
+		MSG_WriteChar (msg, ps->kick_angles[0]*4);
+		MSG_WriteChar (msg, ps->kick_angles[1]*4);
+		MSG_WriteChar (msg, ps->kick_angles[2]*4);
+	}
+
+	if (pflags & PS_WEAPONINDEX)
+	{
+		MSG_WriteByte (msg, ps->gunindex);
+	}
+
+	if (pflags & PS_WEAPONFRAME)
+	{
+		MSG_WriteByte (msg, ps->gunframe);
+		MSG_WriteChar (msg, ps->gunoffset[0]*4);
+		MSG_WriteChar (msg, ps->gunoffset[1]*4);
+		MSG_WriteChar (msg, ps->gunoffset[2]*4);
+		MSG_WriteChar (msg, ps->gunangles[0]*4);
+		MSG_WriteChar (msg, ps->gunangles[1]*4);
+		MSG_WriteChar (msg, ps->gunangles[2]*4);
+	}
+
+	if (pflags & PS_BLEND)
+	{
+		MSG_WriteByte (msg, ps->blend[0]*255);
+		MSG_WriteByte (msg, ps->blend[1]*255);
+		MSG_WriteByte (msg, ps->blend[2]*255);
+		MSG_WriteByte (msg, ps->blend[3]*255);
+	}
+	if (pflags & PS_FOV)
+		MSG_WriteByte (msg, ps->fov);
+	if (pflags & PS_RDFLAGS)
+		MSG_WriteByte (msg, ps->rdflags);
+
+	// send stats
+	statbits = 0;
+	for (i=0 ; i<MAX_STATS ; i++)
+		if (ps->stats[i] != ops->stats[i])
+			statbits |= 1<<i;
+	MSG_WriteLong (msg, statbits);
+	for (i=0 ; i<MAX_STATS ; i++)
+		if (statbits & (1<<i) )
+			MSG_WriteShort (msg, ps->stats[i]);
+}
+
+
+/*
+==================
+SV_WriteFrameToClient
+==================
+*/
+void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
+{
+	client_frame_t		*frame, *oldframe;
+	int					lastframe;
+
+//Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
+	// this is the frame we are creating
+	frame = &client->frames[sv.framenum & UPDATE_MASK];
+
+	if (client->lastframe <= 0)
+	{	// client is asking for a retransmit
+		oldframe = NULL;
+		lastframe = -1;
+	}
+	else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
+	{	// client hasn't gotten a good message through in a long time
+//		Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
+		oldframe = NULL;
+		lastframe = -1;
+	}
+	else
+	{	// we have a valid message to delta from
+		oldframe = &client->frames[client->lastframe & UPDATE_MASK];
+		lastframe = client->lastframe;
+	}
+
+	MSG_WriteByte (msg, svc_frame);
+	MSG_WriteLong (msg, sv.framenum);
+	MSG_WriteLong (msg, lastframe);	// what we are delta'ing from
+	MSG_WriteByte (msg, client->surpressCount);	// rate dropped packets
+	client->surpressCount = 0;
+
+	// send over the areabits
+	MSG_WriteByte (msg, frame->areabytes);
+	SZ_Write (msg, frame->areabits, frame->areabytes);
+
+	// delta encode the playerstate
+	SV_WritePlayerstateToClient (oldframe, frame, msg);
+
+	// delta encode the entities
+	SV_EmitPacketEntities (oldframe, frame, msg);
+}
+
+
+/*
+=============================================================================
+
+Build a client frame structure
+
+=============================================================================
+*/
+
+byte		fatpvs[65536/8];	// 32767 is MAX_MAP_LEAFS
+
+/*
+============
+SV_FatPVS
+
+The client will interpolate the view position,
+so we can't use a single PVS point
+===========
+*/
+void SV_FatPVS (vec3_t org)
+{
+	int		leafs[64];
+	int		i, j, count;
+	int		longs;
+	byte	*src;
+	vec3_t	mins, maxs;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		mins[i] = org[i] - 8;
+		maxs[i] = org[i] + 8;
+	}
+
+	count = CM_BoxLeafnums (mins, maxs, leafs, 64, NULL);
+	if (count < 1)
+		Com_Error (ERR_FATAL, "SV_FatPVS: count < 1");
+	longs = (CM_NumClusters()+31)>>5;
+
+	// convert leafs to clusters
+	for (i=0 ; i<count ; i++)
+		leafs[i] = CM_LeafCluster(leafs[i]);
+
+	memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
+	// or in all the other leaf bits
+	for (i=1 ; i<count ; i++)
+	{
+		for (j=0 ; j<i ; j++)
+			if (leafs[i] == leafs[j])
+				break;
+		if (j != i)
+			continue;		// already have the cluster we want
+		src = CM_ClusterPVS(leafs[i]);
+		for (j=0 ; j<longs ; j++)
+			((long *)fatpvs)[j] |= ((long *)src)[j];
+	}
+}
+
+
+/*
+=============
+SV_BuildClientFrame
+
+Decides which entities are going to be visible to the client, and
+copies off the playerstat and areabits.
+=============
+*/
+void SV_BuildClientFrame (client_t *client)
+{
+	int		e, i;
+	vec3_t	org;
+	edict_t	*ent;
+	edict_t	*clent;
+	client_frame_t	*frame;
+	entity_state_t	*state;
+	int		l;
+	int		clientarea, clientcluster;
+	int		leafnum;
+	int		c_fullsend;
+	byte	*clientphs;
+	byte	*bitvector;
+
+	clent = client->edict;
+	if (!clent->client)
+		return;		// not in game yet
+
+#if 0
+	numprojs = 0; // no projectiles yet
+#endif
+
+	// this is the frame we are creating
+	frame = &client->frames[sv.framenum & UPDATE_MASK];
+
+	frame->senttime = svs.realtime; // save it for ping calc later
+
+	// find the client's PVS
+	for (i=0 ; i<3 ; i++)
+		org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];
+
+	leafnum = CM_PointLeafnum (org);
+	clientarea = CM_LeafArea (leafnum);
+	clientcluster = CM_LeafCluster (leafnum);
+
+	// calculate the visible areas
+	frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea);
+
+	// grab the current player_state_t
+	frame->ps = clent->client->ps;
+
+
+	SV_FatPVS (org);
+	clientphs = CM_ClusterPHS (clientcluster);
+
+	// build up the list of visible entities
+	frame->num_entities = 0;
+	frame->first_entity = svs.next_client_entities;
+
+	c_fullsend = 0;
+
+	for (e=1 ; e<ge->num_edicts ; e++)
+	{
+		ent = EDICT_NUM(e);
+
+		// ignore ents without visible models
+		if (ent->svflags & SVF_NOCLIENT)
+			continue;
+
+		// ignore ents without visible models unless they have an effect
+		if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound
+			&& !ent->s.event)
+			continue;
+
+		// ignore if not touching a PV leaf
+		if (ent != clent)
+		{
+			// check area
+			if (!CM_AreasConnected (clientarea, ent->areanum))
+			{	// doors can legally straddle two areas, so
+				// we may need to check another one
+				if (!ent->areanum2
+					|| !CM_AreasConnected (clientarea, ent->areanum2))
+					continue;		// blocked by a door
+			}
+
+			// beams just check one point for PHS
+			if (ent->s.renderfx & RF_BEAM)
+			{
+				l = ent->clusternums[0];
+				if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
+					continue;
+			}
+			else
+			{
+				// FIXME: if an ent has a model and a sound, but isn't
+				// in the PVS, only the PHS, clear the model
+				if (ent->s.sound)
+				{
+					bitvector = fatpvs;	//clientphs;
+				}
+				else
+					bitvector = fatpvs;
+
+				if (ent->num_clusters == -1)
+				{	// too many leafs for individual check, go by headnode
+					if (!CM_HeadnodeVisible (ent->headnode, bitvector))
+						continue;
+					c_fullsend++;
+				}
+				else
+				{	// check individual leafs
+					for (i=0 ; i < ent->num_clusters ; i++)
+					{
+						l = ent->clusternums[i];
+						if (bitvector[l >> 3] & (1 << (l&7) ))
+							break;
+					}
+					if (i == ent->num_clusters)
+						continue;		// not visible
+				}
+
+				if (!ent->s.modelindex)
+				{	// don't send sounds if they will be attenuated away
+					vec3_t	delta;
+					float	len;
+
+					VectorSubtract (org, ent->s.origin, delta);
+					len = VectorLength (delta);
+					if (len > 400)
+						continue;
+				}
+			}
+		}
+
+#if 0
+		if (SV_AddProjectileUpdate(ent))
+			continue; // added as a special projectile
+#endif
+
+		// add it to the circular client_entities array
+		state = &svs.client_entities[svs.next_client_entities%svs.num_client_entities];
+		if (ent->s.number != e)
+		{
+			Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
+			ent->s.number = e;
+		}
+		*state = ent->s;
+
+		// don't mark players missiles as solid
+		if (ent->owner == client->edict)
+			state->solid = 0;
+
+		svs.next_client_entities++;
+		frame->num_entities++;
+	}
+}
+
+
+/*
+==================
+SV_RecordDemoMessage
+
+Save everything in the world out without deltas.
+Used for recording footage for merged or assembled demos
+==================
+*/
+void SV_RecordDemoMessage (void)
+{
+	int			e;
+	edict_t		*ent;
+	entity_state_t	nostate;
+	sizebuf_t	buf;
+	byte		buf_data[32768];
+	int			len;
+
+	if (!svs.demofile)
+		return;
+
+	memset (&nostate, 0, sizeof(nostate));
+	SZ_Init (&buf, buf_data, sizeof(buf_data));
+
+	// write a frame message that doesn't contain a player_state_t
+	MSG_WriteByte (&buf, svc_frame);
+	MSG_WriteLong (&buf, sv.framenum);
+
+	MSG_WriteByte (&buf, svc_packetentities);
+
+	e = 1;
+	ent = EDICT_NUM(e);
+	while (e < ge->num_edicts) 
+	{
+		// ignore ents without visible models unless they have an effect
+		if (ent->inuse &&
+			ent->s.number && 
+			(ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) && 
+			!(ent->svflags & SVF_NOCLIENT))
+			MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true);
+
+		e++;
+		ent = EDICT_NUM(e);
+	}
+
+	MSG_WriteShort (&buf, 0);		// end of packetentities
+
+	// now add the accumulated multicast information
+	SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
+	SZ_Clear (&svs.demo_multicast);
+
+	// now write the entire message to the file, prefixed by the length
+	len = LittleLong (buf.cursize);
+	fwrite (&len, 4, 1, svs.demofile);
+	fwrite (buf.data, buf.cursize, 1, svs.demofile);
+}
+
--- /dev/null
+++ b/server/sv_game.c
@@ -1,0 +1,396 @@
+/*
+Copyright (C) 1997-2001 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_game.c -- interface to the game dll
+
+#include "server.h"
+
+game_export_t	*ge;
+
+
+/*
+===============
+PF_Unicast
+
+Sends the contents of the mutlicast buffer to a single client
+===============
+*/
+void PF_Unicast (edict_t *ent, qboolean reliable)
+{
+	int		p;
+	client_t	*client;
+
+	if (!ent)
+		return;
+
+	p = NUM_FOR_EDICT(ent);
+	if (p < 1 || p > maxclients->value)
+		return;
+
+	client = svs.clients + (p-1);
+
+	if (reliable)
+		SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
+	else
+		SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
+
+	SZ_Clear (&sv.multicast);
+}
+
+
+/*
+===============
+PF_dprintf
+
+Debug print to server console
+===============
+*/
+void PF_dprintf (char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	Com_Printf ("%s", msg);
+}
+
+
+/*
+===============
+PF_cprintf
+
+Print to a single client
+===============
+*/
+void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	int			n;
+
+	if (ent)
+	{
+		n = NUM_FOR_EDICT(ent);
+		if (n < 1 || n > maxclients->value)
+			Com_Error (ERR_DROP, "cprintf to a non-client");
+	}
+
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	if (ent)
+		SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
+	else
+		Com_Printf ("%s", msg);
+}
+
+
+/*
+===============
+PF_centerprintf
+
+centerprint to a single client
+===============
+*/
+void PF_centerprintf (edict_t *ent, char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	int			n;
+	
+	n = NUM_FOR_EDICT(ent);
+	if (n < 1 || n > maxclients->value)
+		return;	// Com_Error (ERR_DROP, "centerprintf to a non-client");
+
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	MSG_WriteByte (&sv.multicast,svc_centerprint);
+	MSG_WriteString (&sv.multicast,msg);
+	PF_Unicast (ent, true);
+}
+
+
+/*
+===============
+PF_error
+
+Abort the server with a game error
+===============
+*/
+void PF_error (char *fmt, ...)
+{
+	char		msg[1024];
+	va_list		argptr;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg, fmt, argptr);
+	va_end (argptr);
+
+	Com_Error (ERR_DROP, "Game Error: %s", msg);
+}
+
+
+/*
+=================
+PF_setmodel
+
+Also sets mins and maxs for inline bmodels
+=================
+*/
+void PF_setmodel (edict_t *ent, char *name)
+{
+	int		i;
+	cmodel_t	*mod;
+
+	if (!name)
+		Com_Error (ERR_DROP, "PF_setmodel: NULL");
+
+	i = SV_ModelIndex (name);
+		
+//	ent->model = name;
+	ent->s.modelindex = i;
+
+// if it is an inline model, get the size information for it
+	if (name[0] == '*')
+	{
+		mod = CM_InlineModel (name);
+		VectorCopy (mod->mins, ent->mins);
+		VectorCopy (mod->maxs, ent->maxs);
+		SV_LinkEdict (ent);
+	}
+
+}
+
+/*
+===============
+PF_Configstring
+
+===============
+*/
+void PF_Configstring (int index, char *val)
+{
+	if (index < 0 || index >= MAX_CONFIGSTRINGS)
+		Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
+
+	if (!val)
+		val = "";
+
+	// change the string in sv
+	strcpy (sv.configstrings[index], val);
+	
+	if (sv.state != ss_loading)
+	{	// send the update to everyone
+		SZ_Clear (&sv.multicast);
+		MSG_WriteChar (&sv.multicast, svc_configstring);
+		MSG_WriteShort (&sv.multicast, index);
+		MSG_WriteString (&sv.multicast, val);
+
+		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
+	}
+}
+
+
+
+void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
+void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
+void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
+void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
+void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
+void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
+void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
+void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
+void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
+
+
+/*
+=================
+PF_inPVS
+
+Also checks portalareas so that doors block sight
+=================
+*/
+qboolean PF_inPVS (vec3_t p1, vec3_t p2)
+{
+	int		leafnum;
+	int		cluster;
+	int		area1, area2;
+	byte	*mask;
+
+	leafnum = CM_PointLeafnum (p1);
+	cluster = CM_LeafCluster (leafnum);
+	area1 = CM_LeafArea (leafnum);
+	mask = CM_ClusterPVS (cluster);
+
+	leafnum = CM_PointLeafnum (p2);
+	cluster = CM_LeafCluster (leafnum);
+	area2 = CM_LeafArea (leafnum);
+	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+		return false;
+	if (!CM_AreasConnected (area1, area2))
+		return false;		// a door blocks sight
+	return true;
+}
+
+
+/*
+=================
+PF_inPHS
+
+Also checks portalareas so that doors block sound
+=================
+*/
+qboolean PF_inPHS (vec3_t p1, vec3_t p2)
+{
+	int		leafnum;
+	int		cluster;
+	int		area1, area2;
+	byte	*mask;
+
+	leafnum = CM_PointLeafnum (p1);
+	cluster = CM_LeafCluster (leafnum);
+	area1 = CM_LeafArea (leafnum);
+	mask = CM_ClusterPHS (cluster);
+
+	leafnum = CM_PointLeafnum (p2);
+	cluster = CM_LeafCluster (leafnum);
+	area2 = CM_LeafArea (leafnum);
+	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+		return false;		// more than one bounce away
+	if (!CM_AreasConnected (area1, area2))
+		return false;		// a door blocks hearing
+
+	return true;
+}
+
+void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
+    float attenuation, float timeofs)
+{
+	if (!entity)
+		return;
+	SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
+}
+
+//==============================================
+
+/*
+===============
+SV_ShutdownGameProgs
+
+Called when either the entire server is being killed, or
+it is changing to a different game directory.
+===============
+*/
+void SV_ShutdownGameProgs (void)
+{
+	if (!ge)
+		return;
+	ge->Shutdown ();
+	Sys_UnloadGame ();
+	ge = NULL;
+}
+
+/*
+===============
+SV_InitGameProgs
+
+Init the game subsystem for a new map
+===============
+*/
+void SCR_DebugGraph (float value, int color);
+
+void SV_InitGameProgs (void)
+{
+	game_import_t	import;
+
+	// unload anything we have now
+	if (ge)
+		SV_ShutdownGameProgs ();
+
+
+	// load a new game dll
+	import.multicast = SV_Multicast;
+	import.unicast = PF_Unicast;
+	import.bprintf = SV_BroadcastPrintf;
+	import.dprintf = PF_dprintf;
+	import.cprintf = PF_cprintf;
+	import.centerprintf = PF_centerprintf;
+	import.error = PF_error;
+
+	import.linkentity = SV_LinkEdict;
+	import.unlinkentity = SV_UnlinkEdict;
+	import.BoxEdicts = SV_AreaEdicts;
+	import.trace = SV_Trace;
+	import.pointcontents = SV_PointContents;
+	import.setmodel = PF_setmodel;
+	import.inPVS = PF_inPVS;
+	import.inPHS = PF_inPHS;
+	import.Pmove = Pmove;
+
+	import.modelindex = SV_ModelIndex;
+	import.soundindex = SV_SoundIndex;
+	import.imageindex = SV_ImageIndex;
+
+	import.configstring = PF_Configstring;
+	import.sound = PF_StartSound;
+	import.positioned_sound = SV_StartSound;
+
+	import.WriteChar = PF_WriteChar;
+	import.WriteByte = PF_WriteByte;
+	import.WriteShort = PF_WriteShort;
+	import.WriteLong = PF_WriteLong;
+	import.WriteFloat = PF_WriteFloat;
+	import.WriteString = PF_WriteString;
+	import.WritePosition = PF_WritePos;
+	import.WriteDir = PF_WriteDir;
+	import.WriteAngle = PF_WriteAngle;
+
+	import.TagMalloc = Z_TagMalloc;
+	import.TagFree = Z_Free;
+	import.FreeTags = Z_FreeTags;
+
+	import.cvar = Cvar_Get;
+	import.cvar_set = Cvar_Set;
+	import.cvar_forceset = Cvar_ForceSet;
+
+	import.argc = Cmd_Argc;
+	import.argv = Cmd_Argv;
+	import.args = Cmd_Args;
+	import.AddCommandString = Cbuf_AddText;
+
+	import.DebugGraph = SCR_DebugGraph;
+	import.SetAreaPortalState = CM_SetAreaPortalState;
+	import.AreasConnected = CM_AreasConnected;
+
+	ge = (game_export_t *)Sys_GetGameAPI (&import);
+
+	if (!ge)
+		Com_Error (ERR_DROP, "failed to load game DLL");
+	if (ge->apiversion != GAME_API_VERSION)
+		Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
+		GAME_API_VERSION);
+
+	ge->Init ();
+}
+
--- /dev/null
+++ b/server/sv_init.c
@@ -1,0 +1,465 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+server_static_t	svs;				// persistant server info
+server_t		sv;					// local server
+
+/*
+================
+SV_FindIndex
+
+================
+*/
+int SV_FindIndex (char *name, int start, int max, qboolean create)
+{
+	int		i;
+	
+	if (!name || !name[0])
+		return 0;
+
+	for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
+		if (!strcmp(sv.configstrings[start+i], name))
+			return i;
+
+	if (!create)
+		return 0;
+
+	if (i == max)
+		Com_Error (ERR_DROP, "*Index: overflow");
+
+	strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
+
+	if (sv.state != ss_loading)
+	{	// send the update to everyone
+		SZ_Clear (&sv.multicast);
+		MSG_WriteChar (&sv.multicast, svc_configstring);
+		MSG_WriteShort (&sv.multicast, start+i);
+		MSG_WriteString (&sv.multicast, name);
+		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
+	}
+
+	return i;
+}
+
+
+int SV_ModelIndex (char *name)
+{
+	return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
+}
+
+int SV_SoundIndex (char *name)
+{
+	return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
+}
+
+int SV_ImageIndex (char *name)
+{
+	return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
+}
+
+
+/*
+================
+SV_CreateBaseline
+
+Entity baselines are used to compress the update messages
+to the clients -- only the fields that differ from the
+baseline will be transmitted
+================
+*/
+void SV_CreateBaseline (void)
+{
+	edict_t			*svent;
+	int				entnum;	
+
+	for (entnum = 1; entnum < ge->num_edicts ; entnum++)
+	{
+		svent = EDICT_NUM(entnum);
+		if (!svent->inuse)
+			continue;
+		if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
+			continue;
+		svent->s.number = entnum;
+
+		//
+		// take current state as baseline
+		//
+		VectorCopy (svent->s.origin, svent->s.old_origin);
+		sv.baselines[entnum] = svent->s;
+	}
+}
+
+
+/*
+=================
+SV_CheckForSavegame
+=================
+*/
+void SV_CheckForSavegame (void)
+{
+	char		name[MAX_OSPATH];
+	FILE		*f;
+	int			i;
+
+	if (sv_noreload->value)
+		return;
+
+	if (Cvar_VariableValue ("deathmatch"))
+		return;
+
+	Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+	f = fopen (name, "rb");
+	if (!f)
+		return;		// no savegame
+
+	fclose (f);
+
+	SV_ClearWorld ();
+
+	// get configstrings and areaportals
+	SV_ReadLevelFile ();
+
+	if (!sv.loadgame)
+	{	// coming back to a level after being in a different
+		// level, so run it for ten seconds
+
+		// rlava2 was sending too many lightstyles, and overflowing the
+		// reliable data. temporarily changing the server state to loading
+		// prevents these from being passed down.
+		server_state_t		previousState;		// PGM
+
+		previousState = sv.state;				// PGM
+		sv.state = ss_loading;					// PGM
+		for (i=0 ; i<100 ; i++)
+			ge->RunFrame ();
+
+		sv.state = previousState;				// PGM
+	}
+}
+
+
+/*
+================
+SV_SpawnServer
+
+Change the server to a new map, taking all connected
+clients along with it.
+
+================
+*/
+void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
+{
+	int			i;
+	unsigned	checksum;
+
+	if (attractloop)
+		Cvar_Set ("paused", "0");
+
+	Com_Printf ("------- Server Initialization -------\n");
+
+	Com_DPrintf ("SpawnServer: %s\n",server);
+	if (sv.demofile)
+		fclose (sv.demofile);
+
+	svs.spawncount++;		// any partially connected client will be
+							// restarted
+	sv.state = ss_dead;
+	Com_SetServerState (sv.state);
+
+	// wipe the entire per-level structure
+	memset (&sv, 0, sizeof(sv));
+	svs.realtime = 0;
+	sv.loadgame = loadgame;
+	sv.attractloop = attractloop;
+
+	// save name for levels that don't set message
+	strcpy (sv.configstrings[CS_NAME], server);
+	if (Cvar_VariableValue ("deathmatch"))
+	{
+		sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
+		pm_airaccelerate = sv_airaccelerate->value;
+	}
+	else
+	{
+		strcpy(sv.configstrings[CS_AIRACCEL], "0");
+		pm_airaccelerate = 0;
+	}
+
+	SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
+
+	strcpy (sv.name, server);
+
+	// leave slots at start for clients only
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		// needs to reconnect
+		if (svs.clients[i].state > cs_connected)
+			svs.clients[i].state = cs_connected;
+		svs.clients[i].lastframe = -1;
+	}
+
+	sv.time = 1000;
+	
+	strcpy (sv.name, server);
+	strcpy (sv.configstrings[CS_NAME], server);
+
+	if (serverstate != ss_game)
+	{
+		sv.models[1] = CM_LoadMap ("", false, &checksum);	// no real map
+	}
+	else
+	{
+		Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
+			"maps/%s.bsp", server);
+		sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
+	}
+	Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
+		"%i", checksum);
+
+	//
+	// clear physics interaction links
+	//
+	SV_ClearWorld ();
+	
+	for (i=1 ; i< CM_NumInlineModels() ; i++)
+	{
+		Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
+			"*%i", i);
+		sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
+	}
+
+	//
+	// spawn the rest of the entities on the map
+	//	
+
+	// precache and static commands can be issued during
+	// map initialization
+	sv.state = ss_loading;
+	Com_SetServerState (sv.state);
+
+	// load and spawn all other entities
+	ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
+
+	// run two frames to allow everything to settle
+	ge->RunFrame ();
+	ge->RunFrame ();
+
+	// all precaches are complete
+	sv.state = serverstate;
+	Com_SetServerState (sv.state);
+	
+	// create a baseline for more efficient communications
+	SV_CreateBaseline ();
+
+	// check for a savegame
+	SV_CheckForSavegame ();
+
+	// set serverinfo variable
+	Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
+
+	Com_Printf ("-------------------------------------\n");
+}
+
+/*
+==============
+SV_InitGame
+
+A brand new game has been started
+==============
+*/
+void SV_InitGame (void)
+{
+	int		i;
+	edict_t	*ent;
+	char	idmaster[32];
+
+	if (svs.initialized)
+	{
+		// cause any connected clients to reconnect
+		SV_Shutdown ("Server restarted\n", true);
+	}
+	else
+	{
+		// make sure the client is down
+		CL_Drop ();
+		SCR_BeginLoadingPlaque ();
+	}
+
+	// get any latched variable changes (maxclients, etc)
+	Cvar_GetLatchedVars ();
+
+	svs.initialized = true;
+
+	if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
+	{
+		Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
+		Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
+	}
+
+	// dedicated servers are can't be single player and are usually DM
+	// so unless they explicity set coop, force it to deathmatch
+	if (dedicated->value)
+	{
+		if (!Cvar_VariableValue ("coop"))
+			Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
+	}
+
+	// init clients
+	if (Cvar_VariableValue ("deathmatch"))
+	{
+		if (maxclients->value <= 1)
+			Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
+		else if (maxclients->value > MAX_CLIENTS)
+			Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
+	}
+	else if (Cvar_VariableValue ("coop"))
+	{
+		if (maxclients->value <= 1 || maxclients->value > 4)
+			Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
+#ifdef COPYPROTECT
+		if (!sv.attractloop && !dedicated->value)
+			Sys_CopyProtect ();
+#endif
+	}
+	else	// non-deathmatch, non-coop is one player
+	{
+		Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
+#ifdef COPYPROTECT
+		if (!sv.attractloop)
+			Sys_CopyProtect ();
+#endif
+	}
+
+	svs.spawncount = rand();
+	svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
+	svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
+	svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
+
+	// init network stuff
+	NET_Config ( (maxclients->value > 1) );
+
+	// heartbeats will always be sent to the id master
+	svs.last_heartbeat = -99999;		// send immediately
+	Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
+	NET_StringToAdr (idmaster, &master_adr[0]);
+
+	// init game
+	SV_InitGameProgs ();
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		ent = EDICT_NUM(i+1);
+		ent->s.number = i+1;
+		svs.clients[i].edict = ent;
+		memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
+	}
+}
+
+
+/*
+======================
+SV_Map
+
+  the full syntax is:
+
+  map [*]<map>$<startspot>+<nextserver>
+
+command from the console or progs.
+Map can also be a.cin, .pcx, or .dm2 file
+Nextserver is used to allow a cinematic to play, then proceed to
+another level:
+
+	map tram.cin+jail_e3
+======================
+*/
+void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
+{
+	char	level[MAX_QPATH];
+	char	*ch;
+	int		l;
+	char	spawnpoint[MAX_QPATH];
+
+	sv.loadgame = loadgame;
+	sv.attractloop = attractloop;
+
+	if (sv.state == ss_dead && !sv.loadgame)
+		SV_InitGame ();	// the game is just starting
+
+	strcpy (level, levelstring);
+
+	// if there is a + in the map, set nextserver to the remainder
+	ch = strstr(level, "+");
+	if (ch)
+	{
+		*ch = 0;
+			Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
+	}
+	else
+		Cvar_Set ("nextserver", "");
+
+	//ZOID special hack for end game screen in coop mode
+	if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx"))
+		Cvar_Set ("nextserver", "gamemap \"*base1\"");
+
+	// if there is a $, use the remainder as a spawnpoint
+	ch = strstr(level, "$");
+	if (ch)
+	{
+		*ch = 0;
+		strcpy (spawnpoint, ch+1);
+	}
+	else
+		spawnpoint[0] = 0;
+
+	// skip the end-of-unit flag if necessary
+	if (level[0] == '*')
+		strcpy (level, level+1);
+
+	l = strlen(level);
+	if (l > 4 && !strcmp (level+l-4, ".cin") )
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
+	}
+	else if (l > 4 && !strcmp (level+l-4, ".dm2") )
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
+	}
+	else if (l > 4 && !strcmp (level+l-4, ".pcx") )
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
+	}
+	else
+	{
+		SCR_BeginLoadingPlaque ();			// for local system
+		SV_BroadcastCommand ("changing\n");
+		SV_SendClientMessages ();
+		SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
+		Cbuf_CopyToDefer ();
+	}
+
+	SV_BroadcastCommand ("reconnect\n");
+}
--- /dev/null
+++ b/server/sv_main.c
@@ -1,0 +1,1055 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+netadr_t	master_adr[MAX_MASTERS];	// address of group servers
+
+client_t	*sv_client;			// current client
+
+cvar_t	*sv_paused;
+cvar_t	*sv_timedemo;
+
+cvar_t	*sv_enforcetime;
+
+cvar_t	*timeout;				// seconds without any message
+cvar_t	*zombietime;			// seconds to sink messages after disconnect
+
+cvar_t	*rcon_password;			// password for remote server commands
+
+cvar_t	*allow_download;
+cvar_t *allow_download_players;
+cvar_t *allow_download_models;
+cvar_t *allow_download_sounds;
+cvar_t *allow_download_maps;
+
+cvar_t *sv_airaccelerate;
+
+cvar_t	*sv_noreload;			// don't reload level state when reentering
+
+cvar_t	*maxclients;			// FIXME: rename sv_maxclients
+cvar_t	*sv_showclamp;
+
+cvar_t	*hostname;
+cvar_t	*public_server;			// should heartbeats be sent
+
+cvar_t	*sv_reconnect_limit;	// minimum seconds between connect messages
+
+void Master_Shutdown (void);
+
+
+//============================================================================
+
+
+/*
+=====================
+SV_DropClient
+
+Called when the player is totally leaving the server, either willingly
+or unwillingly.  This is NOT called if the entire server is quiting
+or crashing.
+=====================
+*/
+void SV_DropClient (client_t *drop)
+{
+	// add the disconnect
+	MSG_WriteByte (&drop->netchan.message, svc_disconnect);
+
+	if (drop->state == cs_spawned)
+	{
+		// call the prog function for removing a client
+		// this will remove the body, among other things
+		ge->ClientDisconnect (drop->edict);
+	}
+
+	if (drop->download)
+	{
+		FS_FreeFile (drop->download);
+		drop->download = NULL;
+	}
+
+	drop->state = cs_zombie;		// become free in a few seconds
+	drop->name[0] = 0;
+}
+
+
+
+/*
+==============================================================================
+
+CONNECTIONLESS COMMANDS
+
+==============================================================================
+*/
+
+/*
+===============
+SV_StatusString
+
+Builds the string that is sent as heartbeats and status replies
+===============
+*/
+char	*SV_StatusString (void)
+{
+	char	player[1024];
+	static char	status[MAX_MSGLEN - 16];
+	int		i;
+	client_t	*cl;
+	int		statusLength;
+	int		playerLength;
+
+	strcpy (status, Cvar_Serverinfo());
+	strcat (status, "\n");
+	statusLength = strlen(status);
+
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		cl = &svs.clients[i];
+		if (cl->state == cs_connected || cl->state == cs_spawned )
+		{
+			Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n", 
+				cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
+			playerLength = strlen(player);
+			if (statusLength + playerLength >= sizeof(status) )
+				break;		// can't hold any more
+			strcpy (status + statusLength, player);
+			statusLength += playerLength;
+		}
+	}
+
+	return status;
+}
+
+/*
+================
+SVC_Status
+
+Responds with all the info that qplug or qspy can see
+================
+*/
+void SVC_Status (void)
+{
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
+#if 0
+	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+	Com_Printf (SV_StatusString());
+	Com_EndRedirect ();
+#endif
+}
+
+/*
+================
+SVC_Ack
+
+================
+*/
+void SVC_Ack (void)
+{
+	Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
+}
+
+/*
+================
+SVC_Info
+
+Responds with short info for broadcast scans
+The second parameter should be the current protocol version number.
+================
+*/
+void SVC_Info (void)
+{
+	char	string[64];
+	int		i, count;
+	int		version;
+
+	if (maxclients->value == 1)
+		return;		// ignore in single player
+
+	version = atoi (Cmd_Argv(1));
+
+	if (version != PROTOCOL_VERSION)
+		Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
+	else
+	{
+		count = 0;
+		for (i=0 ; i<maxclients->value ; i++)
+			if (svs.clients[i].state >= cs_connected)
+				count++;
+
+		Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
+	}
+
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
+}
+
+/*
+================
+SVC_Ping
+
+Just responds with an acknowledgement
+================
+*/
+void SVC_Ping (void)
+{
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
+}
+
+
+/*
+=================
+SVC_GetChallenge
+
+Returns a challenge number that can be used
+in a subsequent client_connect command.
+We do this to prevent denial of service attacks that
+flood the server with invalid connection IPs.  With a
+challenge, they must give a valid IP address.
+=================
+*/
+void SVC_GetChallenge (void)
+{
+	int		i;
+	int		oldest;
+	int		oldestTime;
+
+	oldest = 0;
+	oldestTime = 0x7fffffff;
+
+	// see if we already have a challenge for this ip
+	for (i = 0 ; i < MAX_CHALLENGES ; i++)
+	{
+		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+			break;
+		if (svs.challenges[i].time < oldestTime)
+		{
+			oldestTime = svs.challenges[i].time;
+			oldest = i;
+		}
+	}
+
+	if (i == MAX_CHALLENGES)
+	{
+		// overwrite the oldest
+		svs.challenges[oldest].challenge = rand() & 0x7fff;
+		svs.challenges[oldest].adr = net_from;
+		svs.challenges[oldest].time = curtime;
+		i = oldest;
+	}
+
+	// send it back
+	Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
+}
+
+/*
+==================
+SVC_DirectConnect
+
+A connection request that did not come from the master
+==================
+*/
+void SVC_DirectConnect (void)
+{
+	char		userinfo[MAX_INFO_STRING];
+	netadr_t	adr;
+	int			i;
+	client_t	*cl, *newcl;
+	client_t	temp;
+	edict_t		*ent;
+	int			edictnum;
+	int			version;
+	int			qport;
+	int			challenge;
+
+	adr = net_from;
+
+	Com_DPrintf ("SVC_DirectConnect ()\n");
+
+	version = atoi(Cmd_Argv(1));
+	if (version != PROTOCOL_VERSION)
+	{
+		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
+		Com_DPrintf ("    rejected connect from version %i\n", version);
+		return;
+	}
+
+	qport = atoi(Cmd_Argv(2));
+
+	challenge = atoi(Cmd_Argv(3));
+
+	strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
+	userinfo[sizeof(userinfo) - 1] = 0;
+
+	// force the IP key/value pair so the game can filter based on ip
+	Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
+
+	// attractloop servers are ONLY for local clients
+	if (sv.attractloop)
+	{
+		if (!NET_IsLocalAddress (adr))
+		{
+			Com_Printf ("Remote connect in attract loop.  Ignored.\n");
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
+			return;
+		}
+	}
+
+	// see if the challenge is valid
+	if (!NET_IsLocalAddress (adr))
+	{
+		for (i=0 ; i<MAX_CHALLENGES ; i++)
+		{
+			if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+			{
+				if (challenge == svs.challenges[i].challenge)
+					break;		// good
+				Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
+				return;
+			}
+		}
+		if (i == MAX_CHALLENGES)
+		{
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
+			return;
+		}
+	}
+
+	newcl = &temp;
+	memset (newcl, 0, sizeof(client_t));
+
+	// if there is already a slot for this ip, reuse it
+	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+	{
+		if (cl->state == cs_free)
+			continue;
+		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
+			&& ( cl->netchan.qport == qport 
+			|| adr.port == cl->netchan.remote_address.port ) )
+		{
+			if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
+			{
+				Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
+				return;
+			}
+			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
+			newcl = cl;
+			goto gotnewcl;
+		}
+	}
+
+	// find a client slot
+	newcl = NULL;
+	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+	{
+		if (cl->state == cs_free)
+		{
+			newcl = cl;
+			break;
+		}
+	}
+	if (!newcl)
+	{
+		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
+		Com_DPrintf ("Rejected a connection.\n");
+		return;
+	}
+
+gotnewcl:	
+	// build a new connection
+	// accept the new client
+	// this is the only place a client_t is ever initialized
+	*newcl = temp;
+	sv_client = newcl;
+	edictnum = (newcl-svs.clients)+1;
+	ent = EDICT_NUM(edictnum);
+	newcl->edict = ent;
+	newcl->challenge = challenge; // save challenge for checksumming
+
+	// get the game a chance to reject this connection or modify the userinfo
+	if (!(ge->ClientConnect (ent, userinfo)))
+	{
+		if (*Info_ValueForKey (userinfo, "rejmsg")) 
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",  
+				Info_ValueForKey (userinfo, "rejmsg"));
+		else
+			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
+		Com_DPrintf ("Game rejected a connection.\n");
+		return;
+	}
+
+	// parse some info from the info strings
+	strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
+	SV_UserinfoChanged (newcl);
+
+	// send the connect packet to the client
+	Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
+
+	Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
+
+	newcl->state = cs_connected;
+	
+	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
+	newcl->datagram.allowoverflow = true;
+	newcl->lastmessage = svs.realtime;	// don't timeout
+	newcl->lastconnect = svs.realtime;
+}
+
+int Rcon_Validate (void)
+{
+	if (!strlen (rcon_password->string))
+		return 0;
+
+	if (strcmp (Cmd_Argv(1), rcon_password->string) )
+		return 0;
+
+	return 1;
+}
+
+/*
+===============
+SVC_RemoteCommand
+
+A client issued an rcon command.
+Shift down the remaining args
+Redirect all printfs
+===============
+*/
+void SVC_RemoteCommand (void)
+{
+	int		i;
+	char	remaining[1024];
+
+	i = Rcon_Validate ();
+
+	if (i == 0)
+		Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
+	else
+		Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
+
+	Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+
+	if (!Rcon_Validate ())
+	{
+		Com_Printf ("Bad rcon_password.\n");
+	}
+	else
+	{
+		remaining[0] = 0;
+
+		for (i=2 ; i<Cmd_Argc() ; i++)
+		{
+			strcat (remaining, Cmd_Argv(i) );
+			strcat (remaining, " ");
+		}
+
+		Cmd_ExecuteString (remaining);
+	}
+
+	Com_EndRedirect ();
+}
+
+/*
+=================
+SV_ConnectionlessPacket
+
+A connectionless packet has four leading 0xff
+characters to distinguish it from a game channel.
+Clients that are in the game can still send
+connectionless packets.
+=================
+*/
+void SV_ConnectionlessPacket (void)
+{
+	char	*s;
+	char	*c;
+
+	MSG_BeginReading (&net_message);
+	MSG_ReadLong (&net_message);		// skip the -1 marker
+
+	s = MSG_ReadStringLine (&net_message);
+
+	Cmd_TokenizeString (s, false);
+
+	c = Cmd_Argv(0);
+	Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
+
+	if (!strcmp(c, "ping"))
+		SVC_Ping ();
+	else if (!strcmp(c, "ack"))
+		SVC_Ack ();
+	else if (!strcmp(c,"status"))
+		SVC_Status ();
+	else if (!strcmp(c,"info"))
+		SVC_Info ();
+	else if (!strcmp(c,"getchallenge"))
+		SVC_GetChallenge ();
+	else if (!strcmp(c,"connect"))
+		SVC_DirectConnect ();
+	else if (!strcmp(c, "rcon"))
+		SVC_RemoteCommand ();
+	else
+		Com_Printf ("bad connectionless packet from %s:\n%s\n"
+		, NET_AdrToString (net_from), s);
+}
+
+
+//============================================================================
+
+/*
+===================
+SV_CalcPings
+
+Updates the cl->ping variables
+===================
+*/
+void SV_CalcPings (void)
+{
+	int			i, j;
+	client_t	*cl;
+	int			total, count;
+
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		cl = &svs.clients[i];
+		if (cl->state != cs_spawned )
+			continue;
+
+#if 0
+		if (cl->lastframe > 0)
+			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
+		else
+			cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
+#endif
+
+		total = 0;
+		count = 0;
+		for (j=0 ; j<LATENCY_COUNTS ; j++)
+		{
+			if (cl->frame_latency[j] > 0)
+			{
+				count++;
+				total += cl->frame_latency[j];
+			}
+		}
+		if (!count)
+			cl->ping = 0;
+		else
+#if 0
+			cl->ping = total*100/count - 100;
+#else
+			cl->ping = total / count;
+#endif
+
+		// let the game dll know about the ping
+		cl->edict->client->ping = cl->ping;
+	}
+}
+
+
+/*
+===================
+SV_GiveMsec
+
+Every few frames, gives all clients an allotment of milliseconds
+for their command moves.  If they exceed it, assume cheating.
+===================
+*/
+void SV_GiveMsec (void)
+{
+	int			i;
+	client_t	*cl;
+
+	if (sv.framenum & 15)
+		return;
+
+	for (i=0 ; i<maxclients->value ; i++)
+	{
+		cl = &svs.clients[i];
+		if (cl->state == cs_free )
+			continue;
+		
+		cl->commandMsec = 1800;		// 1600 + some slop
+	}
+}
+
+
+/*
+=================
+SV_ReadPackets
+=================
+*/
+void SV_ReadPackets (void)
+{
+	int			i;
+	client_t	*cl;
+	int			qport;
+
+	while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
+	{
+		// check for connectionless packet (0xffffffff) first
+		if (*(int *)net_message.data == -1)
+		{
+			SV_ConnectionlessPacket ();
+			continue;
+		}
+
+		// read the qport out of the message so we can fix up
+		// stupid address translating routers
+		MSG_BeginReading (&net_message);
+		MSG_ReadLong (&net_message);		// sequence number
+		MSG_ReadLong (&net_message);		// sequence number
+		qport = MSG_ReadShort (&net_message) & 0xffff;
+
+		// check for packets from connected clients
+		for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
+		{
+			if (cl->state == cs_free)
+				continue;
+			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
+				continue;
+			if (cl->netchan.qport != qport)
+				continue;
+			if (cl->netchan.remote_address.port != net_from.port)
+			{
+				Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
+				cl->netchan.remote_address.port = net_from.port;
+			}
+
+			if (Netchan_Process(&cl->netchan, &net_message))
+			{	// this is a valid, sequenced packet, so process it
+				if (cl->state != cs_zombie)
+				{
+					cl->lastmessage = svs.realtime;	// don't timeout
+					SV_ExecuteClientMessage (cl);
+				}
+			}
+			break;
+		}
+		
+		if (i != maxclients->value)
+			continue;
+	}
+}
+
+/*
+==================
+SV_CheckTimeouts
+
+If a packet has not been received from a client for timeout->value
+seconds, drop the conneciton.  Server frames are used instead of
+realtime to avoid dropping the local client while debugging.
+
+When a client is normally dropped, the client_t goes into a zombie state
+for a few seconds to make sure any final reliable message gets resent
+if necessary
+==================
+*/
+void SV_CheckTimeouts (void)
+{
+	int		i;
+	client_t	*cl;
+	int			droppoint;
+	int			zombiepoint;
+
+	droppoint = svs.realtime - 1000*timeout->value;
+	zombiepoint = svs.realtime - 1000*zombietime->value;
+
+	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+	{
+		// message times may be wrong across a changelevel
+		if (cl->lastmessage > svs.realtime)
+			cl->lastmessage = svs.realtime;
+
+		if (cl->state == cs_zombie
+		&& cl->lastmessage < zombiepoint)
+		{
+			cl->state = cs_free;	// can now be reused
+			continue;
+		}
+		if ( (cl->state == cs_connected || cl->state == cs_spawned) 
+			&& cl->lastmessage < droppoint)
+		{
+			SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
+			SV_DropClient (cl); 
+			cl->state = cs_free;	// don't bother with zombie state
+		}
+	}
+}
+
+/*
+================
+SV_PrepWorldFrame
+
+This has to be done before the world logic, because
+player processing happens outside RunWorldFrame
+================
+*/
+void SV_PrepWorldFrame (void)
+{
+	edict_t	*ent;
+	int		i;
+
+	for (i=0 ; i<ge->num_edicts ; i++, ent++)
+	{
+		ent = EDICT_NUM(i);
+		// events only last for a single message
+		ent->s.event = 0;
+	}
+
+}
+
+
+/*
+=================
+SV_RunGameFrame
+=================
+*/
+void SV_RunGameFrame (void)
+{
+	if (host_speeds->value)
+		time_before_game = Sys_Milliseconds ();
+
+	// we always need to bump framenum, even if we
+	// don't run the world, otherwise the delta
+	// compression can get confused when a client
+	// has the "current" frame
+	sv.framenum++;
+	sv.time = sv.framenum*100;
+
+	// don't run if paused
+	if (!sv_paused->value || maxclients->value > 1)
+	{
+		ge->RunFrame ();
+
+		// never get more than one tic behind
+		if (sv.time < svs.realtime)
+		{
+			if (sv_showclamp->value)
+				Com_Printf ("sv highclamp\n");
+			svs.realtime = sv.time;
+		}
+	}
+
+	if (host_speeds->value)
+		time_after_game = Sys_Milliseconds ();
+
+}
+
+/*
+==================
+SV_Frame
+
+==================
+*/
+void SV_Frame (int msec)
+{
+	time_before_game = time_after_game = 0;
+
+	// if server is not active, do nothing
+	if (!svs.initialized)
+		return;
+
+    svs.realtime += msec;
+
+	// keep the random time dependent
+	rand ();
+
+	// check timeouts
+	SV_CheckTimeouts ();
+
+	// get packets from clients
+	SV_ReadPackets ();
+
+	// move autonomous things around if enough time has passed
+	if (!sv_timedemo->value && svs.realtime < sv.time)
+	{
+		// never let the time get too far off
+		if (sv.time - svs.realtime > 100)
+		{
+			if (sv_showclamp->value)
+				Com_Printf ("sv lowclamp\n");
+			svs.realtime = sv.time - 100;
+		}
+		NET_Sleep(sv.time - svs.realtime);
+		return;
+	}
+
+	// update ping based on the last known frame from all clients
+	SV_CalcPings ();
+
+	// give the clients some timeslices
+	SV_GiveMsec ();
+
+	// let everything in the world think and move
+	SV_RunGameFrame ();
+
+	// send messages back to the clients that had packets read this frame
+	SV_SendClientMessages ();
+
+	// save the entire world state if recording a serverdemo
+	SV_RecordDemoMessage ();
+
+	// send a heartbeat to the master if needed
+	Master_Heartbeat ();
+
+	// clear teleport flags, etc for next frame
+	SV_PrepWorldFrame ();
+
+}
+
+//============================================================================
+
+/*
+================
+Master_Heartbeat
+
+Send a message to the master every few minutes to
+let it know we are alive, and log information
+================
+*/
+#define	HEARTBEAT_SECONDS	300
+void Master_Heartbeat (void)
+{
+	char		*string;
+	int			i;
+
+	
+	if (!dedicated->value)
+		return;		// only dedicated servers send heartbeats
+
+	if (!public_server->value)
+		return;		// a private dedicated game
+
+	// check for time wraparound
+	if (svs.last_heartbeat > svs.realtime)
+		svs.last_heartbeat = svs.realtime;
+
+	if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
+		return;		// not time to send yet
+
+	svs.last_heartbeat = svs.realtime;
+
+	// send the same string that we would give for a status OOB command
+	string = SV_StatusString();
+
+	// send to group master
+	for (i=0 ; i<MAX_MASTERS ; i++)
+		if (master_adr[i].port)
+		{
+			Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
+			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
+		}
+}
+
+/*
+=================
+Master_Shutdown
+
+Informs all masters that this server is going down
+=================
+*/
+void Master_Shutdown (void)
+{
+	int			i;
+
+	if (!dedicated->value)
+		return;		// only dedicated servers send heartbeats
+
+	if (!public_server->value)
+		return;		// a private dedicated game
+
+	// send to group master
+	for (i=0 ; i<MAX_MASTERS ; i++)
+		if (master_adr[i].port)
+		{
+			if (i > 0)
+				Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
+			Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
+		}
+}
+
+//============================================================================
+
+
+/*
+=================
+SV_UserinfoChanged
+
+Pull specific info from a newly changed userinfo string
+into a more C freindly form.
+=================
+*/
+void SV_UserinfoChanged (client_t *cl)
+{
+	char	*val;
+	int		i;
+
+	// call prog code to allow overrides
+	ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
+	
+	// name for C code
+	strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
+	// mask off high bit
+	for (i=0 ; i<sizeof(cl->name) ; i++)
+		cl->name[i] &= 127;
+
+	// rate command
+	val = Info_ValueForKey (cl->userinfo, "rate");
+	if (strlen(val))
+	{
+		i = atoi(val);
+		cl->rate = i;
+		if (cl->rate < 100)
+			cl->rate = 100;
+		if (cl->rate > 15000)
+			cl->rate = 15000;
+	}
+	else
+		cl->rate = 5000;
+
+	// msg command
+	val = Info_ValueForKey (cl->userinfo, "msg");
+	if (strlen(val))
+	{
+		cl->messagelevel = atoi(val);
+	}
+
+}
+
+
+//============================================================================
+
+/*
+===============
+SV_Init
+
+Only called at quake2.exe startup, not for each game
+===============
+*/
+void SV_Init (void)
+{
+	SV_InitOperatorCommands	();
+
+	rcon_password = Cvar_Get ("rcon_password", "", 0);
+	Cvar_Get ("skill", "1", 0);
+	Cvar_Get ("deathmatch", "0", CVAR_LATCH);
+	Cvar_Get ("coop", "0", CVAR_LATCH);
+	Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
+	Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
+	Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
+	Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
+	Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
+	maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
+	hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
+	timeout = Cvar_Get ("timeout", "125", 0);
+	zombietime = Cvar_Get ("zombietime", "2", 0);
+	sv_showclamp = Cvar_Get ("showclamp", "0", 0);
+	sv_paused = Cvar_Get ("paused", "0", 0);
+	sv_timedemo = Cvar_Get ("timedemo", "0", 0);
+	sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
+	allow_download = Cvar_Get ("allow_download", "0", CVAR_ARCHIVE);
+	allow_download_players  = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
+	allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
+	allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
+	allow_download_maps	  = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
+
+	sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
+
+	sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
+
+	public_server = Cvar_Get ("public", "0", 0);
+
+	sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
+
+	SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
+}
+
+/*
+==================
+SV_FinalMessage
+
+Used by SV_Shutdown to send a final message to all
+connected clients before the server goes down.  The messages are sent immediately,
+not just stuck on the outgoing message list, because the server is going
+to totally exit after returning from this function.
+==================
+*/
+void SV_FinalMessage (char *message, qboolean reconnect)
+{
+	int			i;
+	client_t	*cl;
+	
+	SZ_Clear (&net_message);
+	MSG_WriteByte (&net_message, svc_print);
+	MSG_WriteByte (&net_message, PRINT_HIGH);
+	MSG_WriteString (&net_message, message);
+
+	if (reconnect)
+		MSG_WriteByte (&net_message, svc_reconnect);
+	else
+		MSG_WriteByte (&net_message, svc_disconnect);
+
+	// send it twice
+	// stagger the packets to crutch operating system limited buffers
+
+	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
+		if (cl->state >= cs_connected)
+			Netchan_Transmit (&cl->netchan, net_message.cursize
+			, net_message.data);
+
+	for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
+		if (cl->state >= cs_connected)
+			Netchan_Transmit (&cl->netchan, net_message.cursize
+			, net_message.data);
+}
+
+
+
+/*
+================
+SV_Shutdown
+
+Called when each game quits,
+before Sys_Quit or Sys_Error
+================
+*/
+void SV_Shutdown (char *finalmsg, qboolean reconnect)
+{
+	if (svs.clients)
+		SV_FinalMessage (finalmsg, reconnect);
+
+	Master_Shutdown ();
+	SV_ShutdownGameProgs ();
+
+	// free current level
+	if (sv.demofile)
+		fclose (sv.demofile);
+	memset (&sv, 0, sizeof(sv));
+	Com_SetServerState (sv.state);
+
+	// free server static data
+	if (svs.clients)
+		Z_Free (svs.clients);
+	if (svs.client_entities)
+		Z_Free (svs.client_entities);
+	if (svs.demofile)
+		fclose (svs.demofile);
+	memset (&svs, 0, sizeof(svs));
+}
+
--- /dev/null
+++ b/server/sv_null.c
@@ -1,0 +1,15 @@
+// sv_null.c -- this file can stub out the entire server system
+// for pure net-only clients
+
+void SV_Init (void)
+{
+}
+
+void SV_Shutdown (char *finalmsg, qboolean reconnect)
+{
+}
+
+void SV_Frame (float time)
+{
+}
+
--- /dev/null
+++ b/server/sv_send.c
@@ -1,0 +1,567 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+/*
+=============================================================================
+
+Com_Printf redirection
+
+=============================================================================
+*/
+
+char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+
+void SV_FlushRedirect (int sv_redirected, char *outputbuf)
+{
+	if (sv_redirected == RD_PACKET)
+	{
+		Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf);
+	}
+	else if (sv_redirected == RD_CLIENT)
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_print);
+		MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH);
+		MSG_WriteString (&sv_client->netchan.message, outputbuf);
+	}
+}
+
+
+/*
+=============================================================================
+
+EVENT MESSAGES
+
+=============================================================================
+*/
+
+
+/*
+=================
+SV_ClientPrintf
+
+Sends text across to be displayed if the level passes
+=================
+*/
+void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		string[1024];
+	
+	if (level < cl->messagelevel)
+		return;
+	
+	va_start (argptr,fmt);
+	vsprintf (string, fmt,argptr);
+	va_end (argptr);
+	
+	MSG_WriteByte (&cl->netchan.message, svc_print);
+	MSG_WriteByte (&cl->netchan.message, level);
+	MSG_WriteString (&cl->netchan.message, string);
+}
+
+/*
+=================
+SV_BroadcastPrintf
+
+Sends text to all active clients
+=================
+*/
+void SV_BroadcastPrintf (int level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		string[2048];
+	client_t	*cl;
+	int			i;
+
+	va_start (argptr,fmt);
+	vsprintf (string, fmt,argptr);
+	va_end (argptr);
+	
+	// echo to console
+	if (dedicated->value)
+	{
+		char	copy[1024];
+		int		i;
+		
+		// mask off high bits
+		for (i=0 ; i<1023 && string[i] ; i++)
+			copy[i] = string[i]&127;
+		copy[i] = 0;
+		Com_Printf ("%s", copy);
+	}
+
+	for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++)
+	{
+		if (level < cl->messagelevel)
+			continue;
+		if (cl->state != cs_spawned)
+			continue;
+		MSG_WriteByte (&cl->netchan.message, svc_print);
+		MSG_WriteByte (&cl->netchan.message, level);
+		MSG_WriteString (&cl->netchan.message, string);
+	}
+}
+
+/*
+=================
+SV_BroadcastCommand
+
+Sends text to all active clients
+=================
+*/
+void SV_BroadcastCommand (char *fmt, ...)
+{
+	va_list		argptr;
+	char		string[1024];
+	
+	if (!sv.state)
+		return;
+	va_start (argptr,fmt);
+	vsprintf (string, fmt,argptr);
+	va_end (argptr);
+
+	MSG_WriteByte (&sv.multicast, svc_stufftext);
+	MSG_WriteString (&sv.multicast, string);
+	SV_Multicast (NULL, MULTICAST_ALL_R);
+}
+
+
+/*
+=================
+SV_Multicast
+
+Sends the contents of sv.multicast to a subset of the clients,
+then clears sv.multicast.
+
+MULTICAST_ALL	same as broadcast (origin can be NULL)
+MULTICAST_PVS	send to clients potentially visible from org
+MULTICAST_PHS	send to clients potentially hearable from org
+=================
+*/
+void SV_Multicast (vec3_t origin, multicast_t to)
+{
+	client_t	*client;
+	byte		*mask;
+	int			leafnum, cluster;
+	int			j;
+	qboolean	reliable;
+	int			area1, area2;
+
+	reliable = false;
+
+	if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
+	{
+		leafnum = CM_PointLeafnum (origin);
+		area1 = CM_LeafArea (leafnum);
+	}
+	else
+	{
+		leafnum = 0;	// just to avoid compiler warnings
+		area1 = 0;
+	}
+
+	// if doing a serverrecord, store everything
+	if (svs.demofile)
+		SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize);
+	
+	switch (to)
+	{
+	case MULTICAST_ALL_R:
+		reliable = true;	// intentional fallthrough
+	case MULTICAST_ALL:
+		leafnum = 0;
+		mask = NULL;
+		break;
+
+	case MULTICAST_PHS_R:
+		reliable = true;	// intentional fallthrough
+	case MULTICAST_PHS:
+		leafnum = CM_PointLeafnum (origin);
+		cluster = CM_LeafCluster (leafnum);
+		mask = CM_ClusterPHS (cluster);
+		break;
+
+	case MULTICAST_PVS_R:
+		reliable = true;	// intentional fallthrough
+	case MULTICAST_PVS:
+		leafnum = CM_PointLeafnum (origin);
+		cluster = CM_LeafCluster (leafnum);
+		mask = CM_ClusterPVS (cluster);
+		break;
+
+	default:
+		mask = NULL;
+		Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to);
+	}
+
+	// send the data to all relevent clients
+	for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
+	{
+		if (client->state == cs_free || client->state == cs_zombie)
+			continue;
+		if (client->state != cs_spawned && !reliable)
+			continue;
+
+		if (mask)
+		{
+			leafnum = CM_PointLeafnum (client->edict->s.origin);
+			cluster = CM_LeafCluster (leafnum);
+			area2 = CM_LeafArea (leafnum);
+			if (!CM_AreasConnected (area1, area2))
+				continue;
+			if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+				continue;
+		}
+
+		if (reliable)
+			SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
+		else
+			SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
+	}
+
+	SZ_Clear (&sv.multicast);
+}
+
+
+/*  
+==================
+SV_StartSound
+
+Each entity can have eight independant sound sources, like voice,
+weapon, feet, etc.
+
+If cahnnel & 8, the sound will be sent to everyone, not just
+things in the PHS.
+
+FIXME: if entity isn't in PHS, they must be forced to be sent or
+have the origin explicitly sent.
+
+Channel 0 is an auto-allocate channel, the others override anything
+already 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)
+
+Timeofs can range from 0.0 to 0.1 to cause sounds to be started
+later in the frame than they normally would.
+
+If origin is NULL, the origin is determined from the entity origin
+or the midpoint of the entity box for bmodels.
+==================
+*/  
+void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
+					int soundindex, float volume,
+					float attenuation, float timeofs)
+{       
+	int			sendchan;
+    int			flags;
+    int			i;
+	int			ent;
+	vec3_t		origin_v;
+	qboolean	use_phs;
+
+	if (volume < 0 || volume > 1.0)
+		Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume);
+
+	if (attenuation < 0 || attenuation > 4)
+		Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation);
+
+//	if (channel < 0 || channel > 15)
+//		Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel);
+
+	if (timeofs < 0 || timeofs > 0.255)
+		Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs);
+
+	ent = NUM_FOR_EDICT(entity);
+
+	if (channel & 8)	// no PHS flag
+	{
+		use_phs = false;
+		channel &= 7;
+	}
+	else
+		use_phs = true;
+
+	sendchan = (ent<<3) | (channel&7);
+
+	flags = 0;
+	if (volume != DEFAULT_SOUND_PACKET_VOLUME)
+		flags |= SND_VOLUME;
+	if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
+		flags |= SND_ATTENUATION;
+
+	// the client doesn't know that bmodels have weird origins
+	// the origin can also be explicitly set
+	if ( (entity->svflags & SVF_NOCLIENT)
+		|| (entity->solid == SOLID_BSP) 
+		|| origin )
+		flags |= SND_POS;
+
+	// always send the entity number for channel overrides
+	flags |= SND_ENT;
+
+	if (timeofs)
+		flags |= SND_OFFSET;
+
+	// use the entity origin unless it is a bmodel or explicitly specified
+	if (!origin)
+	{
+		origin = origin_v;
+		if (entity->solid == SOLID_BSP)
+		{
+			for (i=0 ; i<3 ; i++)
+				origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]);
+		}
+		else
+		{
+			VectorCopy (entity->s.origin, origin_v);
+		}
+	}
+
+	MSG_WriteByte (&sv.multicast, svc_sound);
+	MSG_WriteByte (&sv.multicast, flags);
+	MSG_WriteByte (&sv.multicast, soundindex);
+
+	if (flags & SND_VOLUME)
+		MSG_WriteByte (&sv.multicast, volume*255);
+	if (flags & SND_ATTENUATION)
+		MSG_WriteByte (&sv.multicast, attenuation*64);
+	if (flags & SND_OFFSET)
+		MSG_WriteByte (&sv.multicast, timeofs*1000);
+
+	if (flags & SND_ENT)
+		MSG_WriteShort (&sv.multicast, sendchan);
+
+	if (flags & SND_POS)
+		MSG_WritePos (&sv.multicast, origin);
+
+	// if the sound doesn't attenuate,send it to everyone
+	// (global radio chatter, voiceovers, etc)
+	if (attenuation == ATTN_NONE)
+		use_phs = false;
+
+	if (channel & CHAN_RELIABLE)
+	{
+		if (use_phs)
+			SV_Multicast (origin, MULTICAST_PHS_R);
+		else
+			SV_Multicast (origin, MULTICAST_ALL_R);
+	}
+	else
+	{
+		if (use_phs)
+			SV_Multicast (origin, MULTICAST_PHS);
+		else
+			SV_Multicast (origin, MULTICAST_ALL);
+	}
+}           
+
+
+/*
+===============================================================================
+
+FRAME UPDATES
+
+===============================================================================
+*/
+
+
+
+/*
+=======================
+SV_SendClientDatagram
+=======================
+*/
+qboolean SV_SendClientDatagram (client_t *client)
+{
+	byte		msg_buf[MAX_MSGLEN];
+	sizebuf_t	msg;
+
+	SV_BuildClientFrame (client);
+
+	SZ_Init (&msg, msg_buf, sizeof(msg_buf));
+	msg.allowoverflow = true;
+
+	// send over all the relevant entity_state_t
+	// and the player_state_t
+	SV_WriteFrameToClient (client, &msg);
+
+	// copy the accumulated multicast datagram
+	// for this client out to the message
+	// it is necessary for this to be after the WriteEntities
+	// so that entity references will be current
+	if (client->datagram.overflowed)
+		Com_Printf ("WARNING: datagram overflowed for %s\n", client->name);
+	else
+		SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
+	SZ_Clear (&client->datagram);
+
+	if (msg.overflowed)
+	{	// must have room left for the packet header
+		Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
+		SZ_Clear (&msg);
+	}
+
+	// send the datagram
+	Netchan_Transmit (&client->netchan, msg.cursize, msg.data);
+
+	// record the size for rate estimation
+	client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
+
+	return true;
+}
+
+
+/*
+==================
+SV_DemoCompleted
+==================
+*/
+void SV_DemoCompleted (void)
+{
+	if (sv.demofile)
+	{
+		fclose (sv.demofile);
+		sv.demofile = NULL;
+	}
+	SV_Nextserver ();
+}
+
+
+/*
+=======================
+SV_RateDrop
+
+Returns true if the client is over its current
+bandwidth estimation and should not be sent another packet
+=======================
+*/
+qboolean SV_RateDrop (client_t *c)
+{
+	int		total;
+	int		i;
+
+	// never drop over the loopback
+	if (c->netchan.remote_address.type == NA_LOOPBACK)
+		return false;
+
+	total = 0;
+
+	for (i = 0 ; i < RATE_MESSAGES ; i++)
+	{
+		total += c->message_size[i];
+	}
+
+	if (total > c->rate)
+	{
+		c->surpressCount++;
+		c->message_size[sv.framenum % RATE_MESSAGES] = 0;
+		return true;
+	}
+
+	return false;
+}
+
+/*
+=======================
+SV_SendClientMessages
+=======================
+*/
+void SV_SendClientMessages (void)
+{
+	int			i;
+	client_t	*c;
+	int			msglen;
+	byte		msgbuf[MAX_MSGLEN];
+	int			r;
+
+	msglen = 0;
+
+	// read the next demo message if needed
+	if (sv.state == ss_demo && sv.demofile)
+	{
+		if (sv_paused->value)
+			msglen = 0;
+		else
+		{
+			// get the next message
+			r = fread (&msglen, 4, 1, sv.demofile);
+			if (r != 1)
+			{
+				SV_DemoCompleted ();
+				return;
+			}
+			msglen = LittleLong (msglen);
+			if (msglen == -1)
+			{
+				SV_DemoCompleted ();
+				return;
+			}
+			if (msglen > MAX_MSGLEN)
+				Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN");
+			r = fread (msgbuf, msglen, 1, sv.demofile);
+			if (r != 1)
+			{
+				SV_DemoCompleted ();
+				return;
+			}
+		}
+	}
+
+	// send a message to each connected client
+	for (i=0, c = svs.clients ; i<maxclients->value; i++, c++)
+	{
+		if (!c->state)
+			continue;
+		// if the reliable message overflowed,
+		// drop the client
+		if (c->netchan.message.overflowed)
+		{
+			SZ_Clear (&c->netchan.message);
+			SZ_Clear (&c->datagram);
+			SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
+			SV_DropClient (c);
+		}
+
+		if (sv.state == ss_cinematic 
+			|| sv.state == ss_demo 
+			|| sv.state == ss_pic
+			)
+			Netchan_Transmit (&c->netchan, msglen, msgbuf);
+		else if (c->state == cs_spawned)
+		{
+			// don't overrun bandwidth
+			if (SV_RateDrop (c))
+				continue;
+
+			SV_SendClientDatagram (c);
+		}
+		else
+		{
+	// just update reliable	if needed
+			if (c->netchan.message.cursize	|| curtime - c->netchan.last_sent > 1000 )
+				Netchan_Transmit (&c->netchan, 0, NULL);
+		}
+	}
+}
+
--- /dev/null
+++ b/server/sv_user.c
@@ -1,0 +1,664 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+edict_t	*sv_player;
+
+/*
+============================================================
+
+USER STRINGCMD EXECUTION
+
+sv_client and sv_player will be valid.
+============================================================
+*/
+
+/*
+==================
+SV_BeginDemoServer
+==================
+*/
+void SV_BeginDemoserver (void)
+{
+	char		name[MAX_OSPATH];
+
+	Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
+	FS_FOpenFile (name, &sv.demofile);
+	if (!sv.demofile)
+		Com_Error (ERR_DROP, "Couldn't open %s\n", name);
+}
+
+/*
+================
+SV_New_f
+
+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_New_f (void)
+{
+	char		*gamedir;
+	int			playernum;
+	edict_t		*ent;
+
+	Com_DPrintf ("New() from %s\n", sv_client->name);
+
+	if (sv_client->state != cs_connected)
+	{
+		Com_Printf ("New not valid -- already spawned\n");
+		return;
+	}
+
+	// demo servers just dump the file message
+	if (sv.state == ss_demo)
+	{
+		SV_BeginDemoserver ();
+		return;
+	}
+
+	//
+	// serverdata needs to go over for all types of servers
+	// to make sure the protocol is right, and to set the gamedir
+	//
+	gamedir = Cvar_VariableString ("gamedir");
+
+	// send the serverdata
+	MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
+	MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
+	MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
+	MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
+	MSG_WriteString (&sv_client->netchan.message, gamedir);
+
+	if (sv.state == ss_cinematic || sv.state == ss_pic)
+		playernum = -1;
+	else
+		playernum = sv_client - svs.clients;
+	MSG_WriteShort (&sv_client->netchan.message, playernum);
+
+	// send full levelname
+	MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
+
+	//
+	// game server
+	// 
+	if (sv.state == ss_game)
+	{
+		// set up the entity for the client
+		ent = EDICT_NUM(playernum+1);
+		ent->s.number = playernum+1;
+		sv_client->edict = ent;
+		memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
+
+		// begin fetching configstrings
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
+	}
+
+}
+
+/*
+==================
+SV_Configstrings_f
+==================
+*/
+void SV_Configstrings_f (void)
+{
+	int			start;
+
+	Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
+
+	if (sv_client->state != cs_connected)
+	{
+		Com_Printf ("configstrings not valid -- already spawned\n");
+		return;
+	}
+
+	// handle the case of a level changing while a client was connecting
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+	{
+		Com_Printf ("SV_Configstrings_f from different level\n");
+		SV_New_f ();
+		return;
+	}
+	
+	start = atoi(Cmd_Argv(2));
+
+	// write a packet full of data
+
+	while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 
+		&& start < MAX_CONFIGSTRINGS)
+	{
+		if (sv.configstrings[start][0])
+		{
+			MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
+			MSG_WriteShort (&sv_client->netchan.message, start);
+			MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
+		}
+		start++;
+	}
+
+	// send next command
+
+	if (start == MAX_CONFIGSTRINGS)
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
+	}
+	else
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
+	}
+}
+
+/*
+==================
+SV_Baselines_f
+==================
+*/
+void SV_Baselines_f (void)
+{
+	int		start;
+	entity_state_t	nullstate;
+	entity_state_t	*base;
+
+	Com_DPrintf ("Baselines() from %s\n", sv_client->name);
+
+	if (sv_client->state != cs_connected)
+	{
+		Com_Printf ("baselines not valid -- already spawned\n");
+		return;
+	}
+	
+	// handle the case of a level changing while a client was connecting
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+	{
+		Com_Printf ("SV_Baselines_f from different level\n");
+		SV_New_f ();
+		return;
+	}
+	
+	start = atoi(Cmd_Argv(2));
+
+	memset (&nullstate, 0, sizeof(nullstate));
+
+	// write a packet full of data
+
+	while ( sv_client->netchan.message.cursize <  MAX_MSGLEN/2
+		&& start < MAX_EDICTS)
+	{
+		base = &sv.baselines[start];
+		if (base->modelindex || base->sound || base->effects)
+		{
+			MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
+			MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
+		}
+		start++;
+	}
+
+	// send next command
+
+	if (start == MAX_EDICTS)
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
+	}
+	else
+	{
+		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
+	}
+}
+
+/*
+==================
+SV_Begin_f
+==================
+*/
+void SV_Begin_f (void)
+{
+	Com_DPrintf ("Begin() from %s\n", sv_client->name);
+
+	// handle the case of a level changing while a client was connecting
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+	{
+		Com_Printf ("SV_Begin_f from different level\n");
+		SV_New_f ();
+		return;
+	}
+
+	sv_client->state = cs_spawned;
+
+	// call the game begin function
+	ge->ClientBegin (sv_player);
+
+	Cbuf_InsertFromDefer ();
+}
+
+//=============================================================================
+
+/*
+==================
+SV_NextDownload_f
+==================
+*/
+void SV_NextDownload_f (void)
+{
+	int		r;
+	int		percent;
+	int		size;
+
+	if (!sv_client->download)
+		return;
+
+	r = sv_client->downloadsize - sv_client->downloadcount;
+	if (r > 1024)
+		r = 1024;
+
+	MSG_WriteByte (&sv_client->netchan.message, svc_download);
+	MSG_WriteShort (&sv_client->netchan.message, r);
+
+	sv_client->downloadcount += r;
+	size = sv_client->downloadsize;
+	if (!size)
+		size = 1;
+	percent = sv_client->downloadcount*100/size;
+	MSG_WriteByte (&sv_client->netchan.message, percent);
+	SZ_Write (&sv_client->netchan.message,
+		sv_client->download + sv_client->downloadcount - r, r);
+
+	if (sv_client->downloadcount != sv_client->downloadsize)
+		return;
+
+	FS_FreeFile (sv_client->download);
+	sv_client->download = NULL;
+}
+
+/*
+==================
+SV_BeginDownload_f
+==================
+*/
+void SV_BeginDownload_f(void)
+{
+	char	*name;
+	extern	cvar_t *allow_download;
+	extern	cvar_t *allow_download_players;
+	extern	cvar_t *allow_download_models;
+	extern	cvar_t *allow_download_sounds;
+	extern	cvar_t *allow_download_maps;
+	extern	int		file_from_pak; // ZOID did file come from pak?
+	int offset = 0;
+
+	name = Cmd_Argv(1);
+
+	if (Cmd_Argc() > 2)
+		offset = atoi(Cmd_Argv(2)); // downloaded offset
+
+	// hacked by zoid to allow more conrol over download
+	// first off, no .. or global allow check
+	if (strstr (name, "..") || !allow_download->value
+		// leading dot is no good
+		|| *name == '.' 
+		// leading slash bad as well, must be in subdir
+		|| *name == '/'
+		// next up, skin check
+		|| (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
+		// now models
+		|| (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
+		// now sounds
+		|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
+		// now maps (note special case for maps, must not be in pak)
+		|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
+		// MUST be in a subdirectory	
+		|| !strstr (name, "/") )	
+	{	// don't allow anything with .. path
+		MSG_WriteByte (&sv_client->netchan.message, svc_download);
+		MSG_WriteShort (&sv_client->netchan.message, -1);
+		MSG_WriteByte (&sv_client->netchan.message, 0);
+		return;
+	}
+
+
+	if (sv_client->download)
+		FS_FreeFile (sv_client->download);
+
+	sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download);
+	sv_client->downloadcount = offset;
+
+	if (offset > sv_client->downloadsize)
+		sv_client->downloadcount = sv_client->downloadsize;
+
+	if (!sv_client->download
+		// special check for maps, if it came from a pak file, don't allow
+		// download  ZOID
+		|| (strncmp(name, "maps/", 5) == 0 && file_from_pak))
+	{
+		Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name);
+		if (sv_client->download) {
+			FS_FreeFile (sv_client->download);
+			sv_client->download = NULL;
+		}
+
+		MSG_WriteByte (&sv_client->netchan.message, svc_download);
+		MSG_WriteShort (&sv_client->netchan.message, -1);
+		MSG_WriteByte (&sv_client->netchan.message, 0);
+		return;
+	}
+
+	SV_NextDownload_f ();
+	Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name);
+}
+
+
+
+//============================================================================
+
+
+/*
+=================
+SV_Disconnect_f
+
+The client is going to disconnect, so remove the connection immediately
+=================
+*/
+void SV_Disconnect_f (void)
+{
+//	SV_EndRedirect ();
+	SV_DropClient (sv_client);	
+}
+
+
+/*
+==================
+SV_ShowServerinfo_f
+
+Dumps the serverinfo info string
+==================
+*/
+void SV_ShowServerinfo_f (void)
+{
+	Info_Print (Cvar_Serverinfo());
+}
+
+
+void SV_Nextserver (void)
+{
+	char	*v;
+
+	//ZOID, ss_pic can be nextserver'd in coop mode
+	if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop")))
+		return;		// can't nextserver while playing a normal game
+
+	svs.spawncount++;	// make sure another doesn't sneak in
+	v = Cvar_VariableString ("nextserver");
+	if (!v[0])
+		Cbuf_AddText ("killserver\n");
+	else
+	{
+		Cbuf_AddText (v);
+		Cbuf_AddText ("\n");
+	}
+	Cvar_Set ("nextserver","");
+}
+
+/*
+==================
+SV_Nextserver_f
+
+A cinematic has completed or been aborted by a client, so move
+to the next server,
+==================
+*/
+void SV_Nextserver_f (void)
+{
+	if ( atoi(Cmd_Argv(1)) != svs.spawncount ) {
+		Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name);
+		return;		// leftover from last server
+	}
+
+	Com_DPrintf ("Nextserver() from %s\n", sv_client->name);
+
+	SV_Nextserver ();
+}
+
+typedef struct
+{
+	char	*name;
+	void	(*func) (void);
+} ucmd_t;
+
+ucmd_t ucmds[] =
+{
+	// auto issued
+	{"new", SV_New_f},
+	{"configstrings", SV_Configstrings_f},
+	{"baselines", SV_Baselines_f},
+	{"begin", SV_Begin_f},
+
+	{"nextserver", SV_Nextserver_f},
+
+	{"disconnect", SV_Disconnect_f},
+
+	// issued by hand at client consoles	
+	{"info", SV_ShowServerinfo_f},
+
+	{"download", SV_BeginDownload_f},
+	{"nextdl", SV_NextDownload_f},
+
+	{NULL, NULL}
+};
+
+/*
+==================
+SV_ExecuteUserCommand
+==================
+*/
+void SV_ExecuteUserCommand (char *s)
+{
+	ucmd_t	*u;
+	
+	Cmd_TokenizeString (s, true);
+	sv_player = sv_client->edict;
+
+//	SV_BeginRedirect (RD_CLIENT);
+
+	for (u=ucmds ; u->name ; u++)
+		if (!strcmp (Cmd_Argv(0), u->name) )
+		{
+			u->func ();
+			break;
+		}
+
+	if (!u->name && sv.state == ss_game)
+		ge->ClientCommand (sv_player);
+
+//	SV_EndRedirect ();
+}
+
+/*
+===========================================================================
+
+USER CMD EXECUTION
+
+===========================================================================
+*/
+
+
+
+void SV_ClientThink (client_t *cl, usercmd_t *cmd)
+
+{
+	cl->commandMsec -= cmd->msec;
+
+	if (cl->commandMsec < 0 && sv_enforcetime->value )
+	{
+		Com_DPrintf ("commandMsec underflow from %s\n", cl->name);
+		return;
+	}
+
+	ge->ClientThink (cl->edict, cmd);
+}
+
+
+
+#define	MAX_STRINGCMDS	8
+/*
+===================
+SV_ExecuteClientMessage
+
+The current net_message is parsed for the given client
+===================
+*/
+void SV_ExecuteClientMessage (client_t *cl)
+{
+	int		c;
+	char	*s;
+
+	usercmd_t	nullcmd;
+	usercmd_t	oldest, oldcmd, newcmd;
+	int		net_drop;
+	int		stringCmdCount;
+	int		checksum, calculatedChecksum;
+	int		checksumIndex;
+	qboolean	move_issued;
+	int		lastframe;
+
+	sv_client = cl;
+	sv_player = sv_client->edict;
+
+	// only allow one move command
+	move_issued = false;
+	stringCmdCount = 0;
+
+	while (1)
+	{
+		if (net_message.readcount > net_message.cursize)
+		{
+			Com_Printf ("SV_ReadClientMessage: badread\n");
+			SV_DropClient (cl);
+			return;
+		}	
+
+		c = MSG_ReadByte (&net_message);
+		if (c == -1)
+			break;
+				
+		switch (c)
+		{
+		default:
+			Com_Printf ("SV_ReadClientMessage: unknown command char\n");
+			SV_DropClient (cl);
+			return;
+						
+		case clc_nop:
+			break;
+
+		case clc_userinfo:
+			strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1);
+			SV_UserinfoChanged (cl);
+			break;
+
+		case clc_move:
+			if (move_issued)
+				return;		// someone is trying to cheat...
+
+			move_issued = true;
+			checksumIndex = net_message.readcount;
+			checksum = MSG_ReadByte (&net_message);
+			lastframe = MSG_ReadLong (&net_message);
+			if (lastframe != cl->lastframe) {
+				cl->lastframe = lastframe;
+				if (cl->lastframe > 0) {
+					cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] = 
+						svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime;
+				}
+			}
+
+			memset (&nullcmd, 0, sizeof(nullcmd));
+			MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest);
+			MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd);
+			MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd);
+
+			if ( cl->state != cs_spawned )
+			{
+				cl->lastframe = -1;
+				break;
+			}
+
+			// if the checksum fails, ignore the rest of the packet
+			calculatedChecksum = COM_BlockSequenceCRCByte (
+				net_message.data + checksumIndex + 1,
+				net_message.readcount - checksumIndex - 1,
+				cl->netchan.incoming_sequence);
+
+			if (calculatedChecksum != checksum)
+			{
+				Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n", 
+					cl->name, calculatedChecksum, checksum, 
+					cl->netchan.incoming_sequence);
+				return;
+			}
+
+			if (!sv_paused->value)
+			{
+				net_drop = cl->netchan.dropped;
+				if (net_drop < 20)
+				{
+
+//if (net_drop > 2)
+
+//	Com_Printf ("drop %i\n", net_drop);
+					while (net_drop > 2)
+					{
+						SV_ClientThink (cl, &cl->lastcmd);
+
+						net_drop--;
+					}
+					if (net_drop > 1)
+						SV_ClientThink (cl, &oldest);
+
+					if (net_drop > 0)
+						SV_ClientThink (cl, &oldcmd);
+
+				}
+				SV_ClientThink (cl, &newcmd);
+			}
+
+			cl->lastcmd = newcmd;
+			break;
+
+		case clc_stringcmd:	
+			s = MSG_ReadString (&net_message);
+
+			// malicious users may try using too many string commands
+			if (++stringCmdCount < MAX_STRINGCMDS)
+				SV_ExecuteUserCommand (s);
+
+			if (cl->state == cs_zombie)
+				return;	// disconnect command
+			break;
+		}
+	}
+}
+
--- /dev/null
+++ b/server/sv_world.c
@@ -1,0 +1,659 @@
+/*
+Copyright (C) 1997-2001 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 "server.h"
+
+/*
+===============================================================================
+
+ENTITY AREA CHECKING
+
+FIXME: this use of "area" is different from the bsp file use
+===============================================================================
+*/
+
+// (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)))
+
+#define	EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
+
+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
+
+areanode_t	sv_areanodes[AREA_NODES];
+int			sv_numareanodes;
+
+float	*area_mins, *area_maxs;
+edict_t	**area_list;
+int		area_count, area_maxcount;
+int		area_type;
+
+int SV_HullForEntity (edict_t *ent);
+
+
+// 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;
+}
+
+/*
+===============
+SV_CreateAreaNode
+
+Builds a uniformly subdivided tree for the given world size
+===============
+*/
+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)
+{
+	memset (sv_areanodes, 0, sizeof(sv_areanodes));
+	sv_numareanodes = 0;
+	SV_CreateAreaNode (0, sv.models[1]->mins, sv.models[1]->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_LinkEdict
+
+===============
+*/
+#define MAX_TOTAL_ENT_LEAFS		128
+void SV_LinkEdict (edict_t *ent)
+{
+	areanode_t	*node;
+	int			leafs[MAX_TOTAL_ENT_LEAFS];
+	int			clusters[MAX_TOTAL_ENT_LEAFS];
+	int			num_leafs;
+	int			i, j, k;
+	int			area;
+	int			topnode;
+
+	if (ent->area.prev)
+		SV_UnlinkEdict (ent);	// unlink from old position
+		
+	if (ent == ge->edicts)
+		return;		// don't add the world
+
+	if (!ent->inuse)
+		return;
+
+	// set the size
+	VectorSubtract (ent->maxs, ent->mins, ent->size);
+	
+	// encode the size into the entity_state for client prediction
+	if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
+	{	// assume that x/y are equal and symetric
+		i = ent->maxs[0]/8;
+		if (i<1)
+			i = 1;
+		if (i>31)
+			i = 31;
+
+		// z is not symetric
+		j = (-ent->mins[2])/8;
+		if (j<1)
+			j = 1;
+		if (j>31)
+			j = 31;
+
+		// and z maxs can be negative...
+		k = (ent->maxs[2]+32)/8;
+		if (k<1)
+			k = 1;
+		if (k>63)
+			k = 63;
+
+		ent->s.solid = (k<<10) | (j<<5) | i;
+	}
+	else if (ent->solid == SOLID_BSP)
+	{
+		ent->s.solid = 31;		// a solid_bbox will never create this value
+	}
+	else
+		ent->s.solid = 0;
+
+	// set the abs box
+	if (ent->solid == SOLID_BSP && 
+	(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
+	{	// expand for rotation
+		float		max, v;
+		int			i;
+
+		max = 0;
+		for (i=0 ; i<3 ; i++)
+		{
+			v =fabs( ent->mins[i]);
+			if (v > max)
+				max = v;
+			v =fabs( ent->maxs[i]);
+			if (v > max)
+				max = v;
+		}
+		for (i=0 ; i<3 ; i++)
+		{
+			ent->absmin[i] = ent->s.origin[i] - max;
+			ent->absmax[i] = ent->s.origin[i] + max;
+		}
+	}
+	else
+	{	// normal
+		VectorAdd (ent->s.origin, ent->mins, ent->absmin);	
+		VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
+	}
+
+	// because movement is clipped an epsilon away from an actual edge,
+	// we must fully check even when bounding boxes don't quite touch
+	ent->absmin[0] -= 1;
+	ent->absmin[1] -= 1;
+	ent->absmin[2] -= 1;
+	ent->absmax[0] += 1;
+	ent->absmax[1] += 1;
+	ent->absmax[2] += 1;
+
+// link to PVS leafs
+	ent->num_clusters = 0;
+	ent->areanum = 0;
+	ent->areanum2 = 0;
+
+	//get all leafs, including solids
+	num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
+		leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
+
+	// set areas
+	for (i=0 ; i<num_leafs ; i++)
+	{
+		clusters[i] = CM_LeafCluster (leafs[i]);
+		area = CM_LeafArea (leafs[i]);
+		if (area)
+		{	// doors may legally straggle two areas,
+			// but nothing should evern need more than that
+			if (ent->areanum && ent->areanum != area)
+			{
+				if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
+					Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
+					ent->absmin[0], ent->absmin[1], ent->absmin[2]);
+				ent->areanum2 = area;
+			}
+			else
+				ent->areanum = area;
+		}
+	}
+
+	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
+	{	// assume we missed some leafs, and mark by headnode
+		ent->num_clusters = -1;
+		ent->headnode = topnode;
+	}
+	else
+	{
+		ent->num_clusters = 0;
+		for (i=0 ; i<num_leafs ; i++)
+		{
+			if (clusters[i] == -1)
+				continue;		// not a visible leaf
+			for (j=0 ; j<i ; j++)
+				if (clusters[j] == clusters[i])
+					break;
+			if (j == i)
+			{
+				if (ent->num_clusters == MAX_ENT_CLUSTERS)
+				{	// assume we missed some leafs, and mark by headnode
+					ent->num_clusters = -1;
+					ent->headnode = topnode;
+					break;
+				}
+
+				ent->clusternums[ent->num_clusters++] = clusters[i];
+			}
+		}
+	}
+
+	// if first time, make sure old_origin is valid
+	if (!ent->linkcount)
+	{
+		VectorCopy (ent->s.origin, ent->s.old_origin);
+	}
+	ent->linkcount++;
+
+	if (ent->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->absmin[node->axis] > node->dist)
+			node = node->children[0];
+		else if (ent->absmax[node->axis] < node->dist)
+			node = node->children[1];
+		else
+			break;		// crosses the node
+	}
+	
+	// link it in	
+	if (ent->solid == SOLID_TRIGGER)
+		InsertLinkBefore (&ent->area, &node->trigger_edicts);
+	else
+		InsertLinkBefore (&ent->area, &node->solid_edicts);
+
+}
+
+
+/*
+====================
+SV_AreaEdicts_r
+
+====================
+*/
+void SV_AreaEdicts_r (areanode_t *node)
+{
+	link_t		*l, *next, *start;
+	edict_t		*check;
+	int			count;
+
+	count = 0;
+
+	// touch linked edicts
+	if (area_type == AREA_SOLID)
+		start = &node->solid_edicts;
+	else
+		start = &node->trigger_edicts;
+
+	for (l=start->next  ; l != start ; l = next)
+	{
+		next = l->next;
+		check = EDICT_FROM_AREA(l);
+
+		if (check->solid == SOLID_NOT)
+			continue;		// deactivated
+		if (check->absmin[0] > area_maxs[0]
+		|| check->absmin[1] > area_maxs[1]
+		|| check->absmin[2] > area_maxs[2]
+		|| check->absmax[0] < area_mins[0]
+		|| check->absmax[1] < area_mins[1]
+		|| check->absmax[2] < area_mins[2])
+			continue;		// not touching
+
+		if (area_count == area_maxcount)
+		{
+			Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
+			return;
+		}
+
+		area_list[area_count] = check;
+		area_count++;
+	}
+	
+	if (node->axis == -1)
+		return;		// terminal node
+
+	// recurse down both sides
+	if ( area_maxs[node->axis] > node->dist )
+		SV_AreaEdicts_r ( node->children[0] );
+	if ( area_mins[node->axis] < node->dist )
+		SV_AreaEdicts_r ( node->children[1] );
+}
+
+/*
+================
+SV_AreaEdicts
+================
+*/
+int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list,
+	int maxcount, int areatype)
+{
+	area_mins = mins;
+	area_maxs = maxs;
+	area_list = list;
+	area_count = 0;
+	area_maxcount = maxcount;
+	area_type = areatype;
+
+	SV_AreaEdicts_r (sv_areanodes);
+
+	return area_count;
+}
+
+
+//===========================================================================
+
+/*
+=============
+SV_PointContents
+=============
+*/
+int SV_PointContents (vec3_t p)
+{
+	edict_t		*touch[MAX_EDICTS], *hit;
+	int			i, num;
+	int			contents, c2;
+	int			headnode;
+	float		*angles;
+
+	// get base contents from world
+	contents = CM_PointContents (p, sv.models[1]->headnode);
+
+	// or in contents from all the other entities
+	num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID);
+
+	for (i=0 ; i<num ; i++)
+	{
+		hit = touch[i];
+
+		// might intersect, so do an exact clip
+		headnode = SV_HullForEntity (hit);
+		angles = hit->s.angles;
+		if (hit->solid != SOLID_BSP)
+			angles = vec3_origin;	// boxes don't rotate
+
+		c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles);
+
+		contents |= c2;
+	}
+
+	return contents;
+}
+
+
+
+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;
+	edict_t		*passedict;
+	int			contentmask;
+} moveclip_t;
+
+
+
+/*
+================
+SV_HullForEntity
+
+Returns a headnode 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.
+================
+*/
+int SV_HullForEntity (edict_t *ent)
+{
+	cmodel_t	*model;
+
+// decide which clipping hull to use, based on the size
+	if (ent->solid == SOLID_BSP)
+	{	// explicit hulls in the BSP model
+		model = sv.models[ ent->s.modelindex ];
+
+		if (!model)
+			Com_Error (ERR_FATAL, "MOVETYPE_PUSH with a non bsp model");
+
+		return model->headnode;
+	}
+
+	// create a temp hull from bounding box sizes
+
+	return CM_HeadnodeForBox (ent->mins, ent->maxs);
+}
+
+
+//===========================================================================
+
+/*
+====================
+SV_ClipMoveToEntities
+
+====================
+*/
+void SV_ClipMoveToEntities ( moveclip_t *clip )
+{
+	int			i, num;
+	edict_t		*touchlist[MAX_EDICTS], *touch;
+	trace_t		trace;
+	int			headnode;
+	float		*angles;
+
+	num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist
+		, MAX_EDICTS, AREA_SOLID);
+
+	// be careful, it is possible to have an entity in this
+	// list removed before we get to it (killtriggered)
+	for (i=0 ; i<num ; i++)
+	{
+		touch = touchlist[i];
+		if (touch->solid == SOLID_NOT)
+			continue;
+		if (touch == clip->passedict)
+			continue;
+		if (clip->trace.allsolid)
+			return;
+		if (clip->passedict)
+		{
+		 	if (touch->owner == clip->passedict)
+				continue;	// don't clip against own missiles
+			if (clip->passedict->owner == touch)
+				continue;	// don't clip against owner
+		}
+
+		if ( !(clip->contentmask & CONTENTS_DEADMONSTER)
+		&& (touch->svflags & SVF_DEADMONSTER) )
+				continue;
+
+		// might intersect, so do an exact clip
+		headnode = SV_HullForEntity (touch);
+		angles = touch->s.angles;
+		if (touch->solid != SOLID_BSP)
+			angles = vec3_origin;	// boxes don't rotate
+
+		if (touch->svflags & SVF_MONSTER)
+			trace = CM_TransformedBoxTrace (clip->start, clip->end,
+				clip->mins2, clip->maxs2, headnode, clip->contentmask,
+				touch->s.origin, angles);
+		else
+			trace = CM_TransformedBoxTrace (clip->start, clip->end,
+				clip->mins, clip->maxs, headnode,  clip->contentmask,
+				touch->s.origin, angles);
+
+		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;
+	}
+}
+
+
+/*
+==================
+SV_TraceBounds
+==================
+*/
+void SV_TraceBounds (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_Trace
+
+Moves the given mins/maxs volume through the world from start to end.
+
+Passedict and edicts owned by passedict are explicitly not checked.
+
+==================
+*/
+trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
+{
+	moveclip_t	clip;
+
+	if (!mins)
+		mins = vec3_origin;
+	if (!maxs)
+		maxs = vec3_origin;
+
+	memset ( &clip, 0, sizeof ( moveclip_t ) );
+
+	// clip to world
+	clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
+	clip.trace.ent = ge->edicts;
+	if (clip.trace.fraction == 0)
+		return clip.trace;		// blocked by the world
+
+	clip.contentmask = contentmask;
+	clip.start = start;
+	clip.end = end;
+	clip.mins = mins;
+	clip.maxs = maxs;
+	clip.passedict = passedict;
+
+	VectorCopy (mins, clip.mins2);
+	VectorCopy (maxs, clip.maxs2);
+	
+	// create the bounding box of the entire move
+	SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
+
+	// clip to other solid entities
+	SV_ClipMoveToEntities ( &clip );
+
+	return clip.trace;
+}
+
--- /dev/null
+++ b/solaris/Makefile.OLD
@@ -1,0 +1,478 @@
+#
+# Quake2 Makefile for Solaris
+#
+# Jan '98 by Zoid <[email protected]>
+#
+
+ifneq (,$(findstring i86pc,$(shell uname -m)))
+ARCH=i386
+else
+ARCH=sparc
+endif
+
+MOUNT_DIR=/chest/Quake2/code
+
+BUILD_DEBUG_DIR=debug$(ARCH)
+BUILD_RELEASE_DIR=release$(ARCH)
+CLIENT_DIR=$(MOUNT_DIR)/client
+SERVER_DIR=$(MOUNT_DIR)/server
+COMMON_DIR=$(MOUNT_DIR)/qcommon
+SOLARIS_DIR=$(MOUNT_DIR)/solaris
+GAME_DIR=$(MOUNT_DIR)/game
+XATRIX_DIR=$(MOUNT_DIR)/xatrix
+CTF_DIR=$(MOUNT_DIR)/game
+NULL_DIR=$(MOUNT_DIR)/null
+
+ARCH=i386
+
+CC=gcc
+BASE_CFLAGS=-Dstricmp=strcasecmp
+RELEASE_CFLAGS=$(BASE_CFLAGS) -O6 -fomit-frame-pointer -fno-strength-reduce -funroll-loops -fexpensive-optimizations
+DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+LDFLAGS=-ldl -lm -lnsl -lsocket
+
+SHLIBEXT=so
+
+SHLIBCFLAGS=-fPIC
+SHLIBLDFLAGS=-G
+
+DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
+DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+
+#############################################################################
+# SETUP AND BUILD
+#############################################################################
+
+TARGETS=$(BUILDDIR)/quake2 $(BUILDDIR)/game$(ARCH).$(SHLIBEXT) 
+
+build_debug:
+	@-mkdir $(BUILD_DEBUG_DIR) \
+		$(BUILD_DEBUG_DIR)/client \
+		$(BUILD_DEBUG_DIR)/game
+	$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+build_release:
+	@-mkdir $(BUILD_RELEASE_DIR) \
+		$(BUILD_RELEASE_DIR)/client \
+		$(BUILD_RELEASE_DIR)/game
+	$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
+
+all: build_debug build_release
+
+targets: $(TARGETS)
+
+#############################################################################
+# CLIENT/SERVER
+#############################################################################
+
+QUAKE2_OBJS = \
+	$(BUILDDIR)/client/cl_cin.o \
+	$(BUILDDIR)/client/cl_ents.o \
+	$(BUILDDIR)/client/cl_fx.o \
+	$(BUILDDIR)/client/cl_input.o \
+	$(BUILDDIR)/client/cl_inv.o \
+	$(BUILDDIR)/client/cl_main.o \
+	$(BUILDDIR)/client/cl_parse.o \
+	$(BUILDDIR)/client/cl_pred.o \
+	$(BUILDDIR)/client/cl_tent.o \
+	$(BUILDDIR)/client/cl_scrn.o \
+	$(BUILDDIR)/client/cl_view.o \
+	$(BUILDDIR)/client/console.o \
+	$(BUILDDIR)/client/keys.o \
+	$(BUILDDIR)/client/menu.o \
+	$(BUILDDIR)/client/qmenu.o \
+	$(BUILDDIR)/client/m_flash.o \
+	\
+	$(BUILDDIR)/client/cmd.o \
+	$(BUILDDIR)/client/cmodel.o \
+	$(BUILDDIR)/client/common.o \
+	$(BUILDDIR)/client/cvar.o \
+	$(BUILDDIR)/client/files.o \
+	$(BUILDDIR)/client/md4.o \
+	$(BUILDDIR)/client/net_chan.o \
+	\
+	$(BUILDDIR)/client/sv_ccmds.o \
+	$(BUILDDIR)/client/sv_ents.o \
+	$(BUILDDIR)/client/sv_game.o \
+	$(BUILDDIR)/client/sv_init.o \
+	$(BUILDDIR)/client/sv_main.o \
+	$(BUILDDIR)/client/sv_send.o \
+	$(BUILDDIR)/client/sv_user.o \
+	$(BUILDDIR)/client/sv_world.o \
+	\
+	$(BUILDDIR)/client/snd_dma.o \
+	$(BUILDDIR)/client/snd_mem.o \
+	$(BUILDDIR)/client/snd_mix.o \
+	\
+	$(BUILDDIR)/client/cd_null.o \
+	$(BUILDDIR)/client/q_shsolaris.o \
+	$(BUILDDIR)/client/vid_null.o \
+	$(BUILDDIR)/client/ref_null.o \
+	$(BUILDDIR)/client/in_null.o \
+	$(BUILDDIR)/client/snddma_null.o \
+	$(BUILDDIR)/client/sys_solaris.o \
+	$(BUILDDIR)/client/glob.o \
+	$(BUILDDIR)/client/net_udp.o \
+	\
+	$(BUILDDIR)/client/q_shared.o \
+	$(BUILDDIR)/client/pmove.o
+
+$(BUILDDIR)/quake2 : $(QUAKE2_OBJS)
+	$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(LDFLAGS)
+
+$(BUILDDIR)/client/cl_cin.o :     $(CLIENT_DIR)/cl_cin.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_ents.o :    $(CLIENT_DIR)/cl_ents.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_fx.o :      $(CLIENT_DIR)/cl_fx.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_input.o :   $(CLIENT_DIR)/cl_input.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_inv.o :     $(CLIENT_DIR)/cl_inv.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_main.o :    $(CLIENT_DIR)/cl_main.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_parse.o :   $(CLIENT_DIR)/cl_parse.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_pred.o :    $(CLIENT_DIR)/cl_pred.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_tent.o :    $(CLIENT_DIR)/cl_tent.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_scrn.o :    $(CLIENT_DIR)/cl_scrn.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_view.o :    $(CLIENT_DIR)/cl_view.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/console.o :    $(CLIENT_DIR)/console.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/keys.o :       $(CLIENT_DIR)/keys.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/menu.o :       $(CLIENT_DIR)/menu.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/qmenu.o :      $(CLIENT_DIR)/qmenu.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/m_flash.o :    $(GAME_DIR)/m_flash.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cmd.o :        $(COMMON_DIR)/cmd.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cmodel.o :     $(COMMON_DIR)/cmodel.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/common.o :     $(COMMON_DIR)/common.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cvar.o :       $(COMMON_DIR)/cvar.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/files.o :      $(COMMON_DIR)/files.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/md4.o :        $(COMMON_DIR)/md4.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_chan.o :   $(COMMON_DIR)/net_chan.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shared.o :   $(GAME_DIR)/q_shared.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/pmove.o :      $(COMMON_DIR)/pmove.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ccmds.o :   $(SERVER_DIR)/sv_ccmds.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ents.o :    $(SERVER_DIR)/sv_ents.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_game.o :    $(SERVER_DIR)/sv_game.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_init.o :    $(SERVER_DIR)/sv_init.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_main.o :    $(SERVER_DIR)/sv_main.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_send.o :    $(SERVER_DIR)/sv_send.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_user.o :    $(SERVER_DIR)/sv_user.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_world.o :   $(SERVER_DIR)/sv_world.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cd_null.o :   $(NULL_DIR)/cd_null.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shsolaris.o :  $(SOLARIS_DIR)/q_shsolaris.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/vid_null.o :   $(NULL_DIR)/vid_null.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/ref_null.o :   $(NULL_DIR)/ref_null.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snddma_null.o :  $(NULL_DIR)/snddma_null.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_dma.o :  $(CLIENT_DIR)/snd_dma.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_mem.o :  $(CLIENT_DIR)/snd_mem.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/snd_mix.o :  $(CLIENT_DIR)/snd_mix.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/in_null.o :  $(NULL_DIR)/in_null.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sys_solaris.o :  $(SOLARIS_DIR)/sys_solaris.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/glob.o :       $(SOLARIS_DIR)/glob.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_udp.o :    $(SOLARIS_DIR)/net_udp.c
+	$(DO_CC)
+
+#############################################################################
+# GAME
+#############################################################################
+
+GAME_OBJS = \
+	$(BUILDDIR)/game/g_ai.o \
+	$(BUILDDIR)/game/p_client.o \
+	$(BUILDDIR)/game/g_cmds.o \
+	$(BUILDDIR)/game/g_svcmds.o \
+	$(BUILDDIR)/game/g_combat.o \
+	$(BUILDDIR)/game/g_func.o \
+	$(BUILDDIR)/game/g_items.o \
+	$(BUILDDIR)/game/g_main.o \
+	$(BUILDDIR)/game/g_misc.o \
+	$(BUILDDIR)/game/g_monster.o \
+	$(BUILDDIR)/game/g_phys.o \
+	$(BUILDDIR)/game/g_save.o \
+	$(BUILDDIR)/game/g_spawn.o \
+	$(BUILDDIR)/game/g_target.o \
+	$(BUILDDIR)/game/g_trigger.o \
+	$(BUILDDIR)/game/g_turret.o \
+	$(BUILDDIR)/game/g_utils.o \
+	$(BUILDDIR)/game/g_weapon.o \
+	$(BUILDDIR)/game/m_actor.o \
+	$(BUILDDIR)/game/m_berserk.o \
+	$(BUILDDIR)/game/m_boss2.o \
+	$(BUILDDIR)/game/m_boss3.o \
+	$(BUILDDIR)/game/m_boss31.o \
+	$(BUILDDIR)/game/m_boss32.o \
+	$(BUILDDIR)/game/m_brain.o \
+	$(BUILDDIR)/game/m_chick.o \
+	$(BUILDDIR)/game/m_flipper.o \
+	$(BUILDDIR)/game/m_float.o \
+	$(BUILDDIR)/game/m_flyer.o \
+	$(BUILDDIR)/game/m_gladiator.o \
+	$(BUILDDIR)/game/m_gunner.o \
+	$(BUILDDIR)/game/m_hover.o \
+	$(BUILDDIR)/game/m_infantry.o \
+	$(BUILDDIR)/game/m_insane.o \
+	$(BUILDDIR)/game/m_medic.o \
+	$(BUILDDIR)/game/m_move.o \
+	$(BUILDDIR)/game/m_mutant.o \
+	$(BUILDDIR)/game/m_parasite.o \
+	$(BUILDDIR)/game/m_soldier.o \
+	$(BUILDDIR)/game/m_supertank.o \
+	$(BUILDDIR)/game/m_tank.o \
+	$(BUILDDIR)/game/p_hud.o \
+	$(BUILDDIR)/game/p_trail.o \
+	$(BUILDDIR)/game/p_view.o \
+	$(BUILDDIR)/game/p_weapon.o \
+	$(BUILDDIR)/game/q_shared.o \
+	$(BUILDDIR)/game/m_flash.o \
+	$(BUILDDIR)/game/g_so.o
+
+$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
+
+$(BUILDDIR)/game/g_ai.o :        $(GAME_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_client.o :    $(GAME_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_cmds.o :      $(GAME_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_svcmds.o :      $(GAME_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_combat.o :    $(GAME_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_func.o :      $(GAME_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_items.o :     $(GAME_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_main.o :      $(GAME_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_misc.o :      $(GAME_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_monster.o :   $(GAME_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_phys.o :      $(GAME_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_save.o :      $(GAME_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_spawn.o :     $(GAME_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_target.o :    $(GAME_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_trigger.o :   $(GAME_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_turret.o :    $(GAME_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_utils.o :     $(GAME_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_weapon.o :    $(GAME_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_actor.o :     $(GAME_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_berserk.o :   $(GAME_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss2.o :     $(GAME_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss3.o :     $(GAME_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss31.o :     $(GAME_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss32.o :     $(GAME_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_brain.o :     $(GAME_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_chick.o :     $(GAME_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flipper.o :   $(GAME_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_float.o :     $(GAME_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flyer.o :     $(GAME_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gladiator.o : $(GAME_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gunner.o :    $(GAME_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_hover.o :     $(GAME_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_infantry.o :  $(GAME_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_insane.o :    $(GAME_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_medic.o :     $(GAME_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_move.o :      $(GAME_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_mutant.o :    $(GAME_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_parasite.o :  $(GAME_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_soldier.o :   $(GAME_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_supertank.o : $(GAME_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_tank.o :      $(GAME_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_hud.o :       $(GAME_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_trail.o :     $(GAME_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_view.o :      $(GAME_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_weapon.o :    $(GAME_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/q_shared.o :    $(GAME_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flash.o :     $(GAME_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_so.o :     $(SOLARIS_DIR)/g_so.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean: clean-debug clean-release
+
+clean-debug:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean-release:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean2:
+	-rm -f $(QUAKE2_OBJS) \
+		$(GAME_OBJS) \
+		$(REF_SOFT_OBJS) \
+		$(REF_SOFT_SVGA_OBJS) \
+		$(REF_SOFT_X11_OBJS) \
+		$(REF_GL_OBJS)
+
--- /dev/null
+++ b/solaris/Makefile.Solaris
@@ -1,0 +1,719 @@
+#
+# Quake2 Makefile for Solaris
+#
+# Nov '97 by Zoid <[email protected]>
+#
+# ELF only
+#
+
+ifneq (,$(findstring i86pc,$(shell uname -m)))
+ARCH=i386
+else
+ARCH=sparc
+endif
+
+MOUNT_DIR=/chest/Quake2/code
+
+BUILD_DEBUG_DIR=debug$(ARCH)
+BUILD_RELEASE_DIR=release$(ARCH)
+CLIENT_DIR=$(MOUNT_DIR)/client
+SERVER_DIR=$(MOUNT_DIR)/server
+COMMON_DIR=$(MOUNT_DIR)/qcommon
+SOLARIS_DIR=$(MOUNT_DIR)/solaris
+GAME_DIR=$(MOUNT_DIR)/game
+CTF_DIR=$(MOUNT_DIR)/ctf
+XATRIX_DIR=$(MOUNT_DIR)/xatrix
+NULL_DIR=$(MOUNT_DIR)/null
+
+CC=gcc
+BASE_CFLAGS=-Dstricmp=strcasecmp -DC_ONLY -DDEDICATED_ONLY
+RELEASE_CFLAGS=$(BASE_CFLAGS) -ffast-math -funroll-loops \
+	-fomit-frame-pointer -fexpensive-optimizations
+
+DEBUG_CFLAGS=$(BASE_CFLAGS) -g
+LDFLAGS=-ldl -lm -lsocket -lnsl
+
+SHLIBEXT=so
+
+SHLIBCFLAGS=-fPIC
+SHLIBLDFLAGS=-shared
+
+DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
+DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+
+#############################################################################
+# SETUP AND BUILD
+#############################################################################
+
+TARGETS=$(BUILDDIR)/q2ded \
+	$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) \
+	$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT)
+
+build_debug:
+	@-mkdir $(BUILD_DEBUG_DIR) \
+		$(BUILD_DEBUG_DIR)/client \
+		$(BUILD_DEBUG_DIR)/game \
+		$(BUILD_DEBUG_DIR)/ctf \
+		$(BUILD_DEBUG_DIR)/xatrix
+	$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+build_release:
+	@-mkdir $(BUILD_RELEASE_DIR) \
+		$(BUILD_RELEASE_DIR)/client \
+		$(BUILD_RELEASE_DIR)/game \
+		$(BUILD_RELEASE_DIR)/ctf \
+		$(BUILD_RELEASE_DIR)/xatrix
+	$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
+
+all: build_debug build_release
+
+targets: $(TARGETS)
+
+#############################################################################
+# CLIENT/SERVER
+#############################################################################
+
+QUAKE2_OBJS = \
+	\
+	$(BUILDDIR)/client/cmd.o \
+	$(BUILDDIR)/client/cmodel.o \
+	$(BUILDDIR)/client/common.o \
+	$(BUILDDIR)/client/crc.o \
+	$(BUILDDIR)/client/cvar.o \
+	$(BUILDDIR)/client/files.o \
+	$(BUILDDIR)/client/md4.o \
+	$(BUILDDIR)/client/net_chan.o \
+	\
+	$(BUILDDIR)/client/sv_ccmds.o \
+	$(BUILDDIR)/client/sv_ents.o \
+	$(BUILDDIR)/client/sv_game.o \
+	$(BUILDDIR)/client/sv_init.o \
+	$(BUILDDIR)/client/sv_main.o \
+	$(BUILDDIR)/client/sv_send.o \
+	$(BUILDDIR)/client/sv_user.o \
+	$(BUILDDIR)/client/sv_world.o \
+	\
+	$(BUILDDIR)/client/q_shsolaris.o \
+	$(BUILDDIR)/client/sys_solaris.o \
+	$(BUILDDIR)/client/glob.o \
+	$(BUILDDIR)/client/net_udp.o \
+	\
+	$(BUILDDIR)/client/q_shared.o \
+	$(BUILDDIR)/client/pmove.o \
+	\
+	$(BUILDDIR)/client/cl_null.o \
+	$(BUILDDIR)/client/cd_null.o
+
+$(BUILDDIR)/q2ded : $(QUAKE2_OBJS)
+	$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(LDFLAGS)
+
+$(BUILDDIR)/client/cmd.o :        $(COMMON_DIR)/cmd.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cmodel.o :     $(COMMON_DIR)/cmodel.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/common.o :     $(COMMON_DIR)/common.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/crc.o :        $(COMMON_DIR)/crc.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cvar.o :       $(COMMON_DIR)/cvar.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/files.o :      $(COMMON_DIR)/files.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/md4.o :        $(COMMON_DIR)/md4.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_chan.o :   $(COMMON_DIR)/net_chan.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shared.o :   $(GAME_DIR)/q_shared.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/pmove.o :      $(COMMON_DIR)/pmove.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ccmds.o :   $(SERVER_DIR)/sv_ccmds.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_ents.o :    $(SERVER_DIR)/sv_ents.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_game.o :    $(SERVER_DIR)/sv_game.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_init.o :    $(SERVER_DIR)/sv_init.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_main.o :    $(SERVER_DIR)/sv_main.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_send.o :    $(SERVER_DIR)/sv_send.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_user.o :    $(SERVER_DIR)/sv_user.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sv_world.o :   $(SERVER_DIR)/sv_world.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/q_shsolaris.o :  $(SOLARIS_DIR)/q_shsolaris.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/sys_solaris.o :  $(SOLARIS_DIR)/sys_solaris.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/glob.o :       $(SOLARIS_DIR)/glob.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/net_udp.o :    $(SOLARIS_DIR)/net_udp.c
+	$(DO_CC)
+
+$(BUILDDIR)/client/cd_null.o     : $(NULL_DIR)/cd_null.c    
+	$(DO_CC)
+
+$(BUILDDIR)/client/cl_null.o     : $(NULL_DIR)/cl_null.c    
+	$(DO_CC)
+
+#############################################################################
+# GAME
+#############################################################################
+
+GAME_OBJS = \
+	$(BUILDDIR)/game/g_ai.o \
+	$(BUILDDIR)/game/p_client.o \
+	$(BUILDDIR)/game/g_cmds.o \
+	$(BUILDDIR)/game/g_svcmds.o \
+	$(BUILDDIR)/game/g_combat.o \
+	$(BUILDDIR)/game/g_func.o \
+	$(BUILDDIR)/game/g_items.o \
+	$(BUILDDIR)/game/g_main.o \
+	$(BUILDDIR)/game/g_misc.o \
+	$(BUILDDIR)/game/g_monster.o \
+	$(BUILDDIR)/game/g_phys.o \
+	$(BUILDDIR)/game/g_save.o \
+	$(BUILDDIR)/game/g_spawn.o \
+	$(BUILDDIR)/game/g_target.o \
+	$(BUILDDIR)/game/g_trigger.o \
+	$(BUILDDIR)/game/g_turret.o \
+	$(BUILDDIR)/game/g_utils.o \
+	$(BUILDDIR)/game/g_weapon.o \
+	$(BUILDDIR)/game/m_actor.o \
+	$(BUILDDIR)/game/m_berserk.o \
+	$(BUILDDIR)/game/m_boss2.o \
+	$(BUILDDIR)/game/m_boss3.o \
+	$(BUILDDIR)/game/m_boss31.o \
+	$(BUILDDIR)/game/m_boss32.o \
+	$(BUILDDIR)/game/m_brain.o \
+	$(BUILDDIR)/game/m_chick.o \
+	$(BUILDDIR)/game/m_flipper.o \
+	$(BUILDDIR)/game/m_float.o \
+	$(BUILDDIR)/game/m_flyer.o \
+	$(BUILDDIR)/game/m_gladiator.o \
+	$(BUILDDIR)/game/m_gunner.o \
+	$(BUILDDIR)/game/m_hover.o \
+	$(BUILDDIR)/game/m_infantry.o \
+	$(BUILDDIR)/game/m_insane.o \
+	$(BUILDDIR)/game/m_medic.o \
+	$(BUILDDIR)/game/m_move.o \
+	$(BUILDDIR)/game/m_mutant.o \
+	$(BUILDDIR)/game/m_parasite.o \
+	$(BUILDDIR)/game/m_soldier.o \
+	$(BUILDDIR)/game/m_supertank.o \
+	$(BUILDDIR)/game/m_tank.o \
+	$(BUILDDIR)/game/p_hud.o \
+	$(BUILDDIR)/game/p_trail.o \
+	$(BUILDDIR)/game/p_view.o \
+	$(BUILDDIR)/game/p_weapon.o \
+	$(BUILDDIR)/game/q_shared.o \
+	$(BUILDDIR)/game/m_flash.o
+
+$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
+
+$(BUILDDIR)/game/g_ai.o :        $(GAME_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_client.o :    $(GAME_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_cmds.o :      $(GAME_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_svcmds.o :    $(GAME_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_combat.o :    $(GAME_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_func.o :      $(GAME_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_items.o :     $(GAME_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_main.o :      $(GAME_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_misc.o :      $(GAME_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_monster.o :   $(GAME_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_phys.o :      $(GAME_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_save.o :      $(GAME_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_spawn.o :     $(GAME_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_target.o :    $(GAME_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_trigger.o :   $(GAME_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_turret.o :    $(GAME_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_utils.o :     $(GAME_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/g_weapon.o :    $(GAME_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_actor.o :     $(GAME_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_berserk.o :   $(GAME_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss2.o :     $(GAME_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss3.o :     $(GAME_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss31.o :     $(GAME_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_boss32.o :     $(GAME_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_brain.o :     $(GAME_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_chick.o :     $(GAME_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flipper.o :   $(GAME_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_float.o :     $(GAME_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flyer.o :     $(GAME_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gladiator.o : $(GAME_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_gunner.o :    $(GAME_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_hover.o :     $(GAME_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_infantry.o :  $(GAME_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_insane.o :    $(GAME_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_medic.o :     $(GAME_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_move.o :      $(GAME_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_mutant.o :    $(GAME_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_parasite.o :  $(GAME_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_soldier.o :   $(GAME_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_supertank.o : $(GAME_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_tank.o :      $(GAME_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_hud.o :       $(GAME_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_trail.o :     $(GAME_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_view.o :      $(GAME_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/p_weapon.o :    $(GAME_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/q_shared.o :    $(GAME_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/game/m_flash.o :     $(GAME_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# CTF
+#############################################################################
+
+CTF_OBJS = \
+	$(BUILDDIR)/ctf/g_ai.o \
+	$(BUILDDIR)/ctf/g_chase.o \
+	$(BUILDDIR)/ctf/g_cmds.o \
+	$(BUILDDIR)/ctf/g_combat.o \
+	$(BUILDDIR)/ctf/g_ctf.o \
+	$(BUILDDIR)/ctf/g_func.o \
+	$(BUILDDIR)/ctf/g_items.o \
+	$(BUILDDIR)/ctf/g_main.o \
+	$(BUILDDIR)/ctf/g_misc.o \
+	$(BUILDDIR)/ctf/g_monster.o \
+	$(BUILDDIR)/ctf/g_phys.o \
+	$(BUILDDIR)/ctf/g_save.o \
+	$(BUILDDIR)/ctf/g_spawn.o \
+	$(BUILDDIR)/ctf/g_svcmds.o \
+	$(BUILDDIR)/ctf/g_target.o \
+	$(BUILDDIR)/ctf/g_trigger.o \
+	$(BUILDDIR)/ctf/g_utils.o \
+	$(BUILDDIR)/ctf/g_weapon.o \
+	$(BUILDDIR)/ctf/m_move.o \
+	$(BUILDDIR)/ctf/p_client.o \
+	$(BUILDDIR)/ctf/p_hud.o \
+	$(BUILDDIR)/ctf/p_menu.o \
+	$(BUILDDIR)/ctf/p_trail.o \
+	$(BUILDDIR)/ctf/p_view.o \
+	$(BUILDDIR)/ctf/p_weapon.o \
+	$(BUILDDIR)/ctf/q_shared.o
+
+$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) : $(CTF_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CTF_OBJS)
+
+$(BUILDDIR)/ctf/g_ai.o :       $(CTF_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_chase.o :    $(CTF_DIR)/g_chase.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_cmds.o :     $(CTF_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_combat.o :   $(CTF_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_ctf.o :      $(CTF_DIR)/g_ctf.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_func.o :     $(CTF_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_items.o :    $(CTF_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_main.o :     $(CTF_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_misc.o :     $(CTF_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_monster.o :  $(CTF_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_phys.o :     $(CTF_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_save.o :     $(CTF_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_spawn.o :    $(CTF_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_svcmds.o :   $(CTF_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_target.o :   $(CTF_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_trigger.o :  $(CTF_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_utils.o :    $(CTF_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/g_weapon.o :   $(CTF_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/m_move.o :     $(CTF_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_client.o :   $(CTF_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_hud.o :      $(CTF_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_menu.o :     $(CTF_DIR)/p_menu.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_trail.o :    $(CTF_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_view.o :     $(CTF_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/p_weapon.o :   $(CTF_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/ctf/q_shared.o :   $(CTF_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# XATRIX
+#############################################################################
+
+XATRIX_OBJS = \
+	$(BUILDDIR)/xatrix/g_ai.o \
+	$(BUILDDIR)/xatrix/g_cmds.o \
+	$(BUILDDIR)/xatrix/g_combat.o \
+	$(BUILDDIR)/xatrix/g_func.o \
+	$(BUILDDIR)/xatrix/g_items.o \
+	$(BUILDDIR)/xatrix/g_main.o \
+	$(BUILDDIR)/xatrix/g_misc.o \
+	$(BUILDDIR)/xatrix/g_monster.o \
+	$(BUILDDIR)/xatrix/g_phys.o \
+	$(BUILDDIR)/xatrix/g_save.o \
+	$(BUILDDIR)/xatrix/g_spawn.o \
+	$(BUILDDIR)/xatrix/g_svcmds.o \
+	$(BUILDDIR)/xatrix/g_target.o \
+	$(BUILDDIR)/xatrix/g_trigger.o \
+	$(BUILDDIR)/xatrix/g_turret.o \
+	$(BUILDDIR)/xatrix/g_utils.o \
+	$(BUILDDIR)/xatrix/g_weapon.o \
+	$(BUILDDIR)/xatrix/m_actor.o \
+	$(BUILDDIR)/xatrix/m_berserk.o \
+	$(BUILDDIR)/xatrix/m_boss2.o \
+	$(BUILDDIR)/xatrix/m_boss3.o \
+	$(BUILDDIR)/xatrix/m_boss31.o \
+	$(BUILDDIR)/xatrix/m_boss32.o \
+	$(BUILDDIR)/xatrix/m_boss5.o \
+	$(BUILDDIR)/xatrix/m_brain.o \
+	$(BUILDDIR)/xatrix/m_chick.o \
+	$(BUILDDIR)/xatrix/m_fixbot.o \
+	$(BUILDDIR)/xatrix/m_flash.o \
+	$(BUILDDIR)/xatrix/m_flipper.o \
+	$(BUILDDIR)/xatrix/m_float.o \
+	$(BUILDDIR)/xatrix/m_flyer.o \
+	$(BUILDDIR)/xatrix/m_gekk.o \
+	$(BUILDDIR)/xatrix/m_gladb.o \
+	$(BUILDDIR)/xatrix/m_gladiator.o \
+	$(BUILDDIR)/xatrix/m_gunner.o \
+	$(BUILDDIR)/xatrix/m_hover.o \
+	$(BUILDDIR)/xatrix/m_infantry.o \
+	$(BUILDDIR)/xatrix/m_insane.o \
+	$(BUILDDIR)/xatrix/m_medic.o \
+	$(BUILDDIR)/xatrix/m_move.o \
+	$(BUILDDIR)/xatrix/m_mutant.o \
+	$(BUILDDIR)/xatrix/m_parasite.o \
+	$(BUILDDIR)/xatrix/m_soldier.o \
+	$(BUILDDIR)/xatrix/m_supertank.o \
+	$(BUILDDIR)/xatrix/m_tank.o \
+	$(BUILDDIR)/xatrix/p_client.o \
+	$(BUILDDIR)/xatrix/p_hud.o \
+	$(BUILDDIR)/xatrix/p_trail.o \
+	$(BUILDDIR)/xatrix/p_view.o \
+	$(BUILDDIR)/xatrix/p_weapon.o \
+	$(BUILDDIR)/xatrix/q_shared.o
+
+$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT) : $(XATRIX_OBJS)
+	$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(XATRIX_OBJS)
+
+$(BUILDDIR)/xatrix/g_ai.o :        $(XATRIX_DIR)/g_ai.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_cmds.o :      $(XATRIX_DIR)/g_cmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_combat.o :    $(XATRIX_DIR)/g_combat.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_func.o :      $(XATRIX_DIR)/g_func.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_items.o :     $(XATRIX_DIR)/g_items.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_main.o :      $(XATRIX_DIR)/g_main.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_misc.o :      $(XATRIX_DIR)/g_misc.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_monster.o :   $(XATRIX_DIR)/g_monster.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_phys.o :      $(XATRIX_DIR)/g_phys.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_save.o :      $(XATRIX_DIR)/g_save.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_spawn.o :     $(XATRIX_DIR)/g_spawn.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_svcmds.o :    $(XATRIX_DIR)/g_svcmds.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_target.o :    $(XATRIX_DIR)/g_target.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_trigger.o :   $(XATRIX_DIR)/g_trigger.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_turret.o :    $(XATRIX_DIR)/g_turret.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_utils.o :     $(XATRIX_DIR)/g_utils.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/g_weapon.o :    $(XATRIX_DIR)/g_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_actor.o :     $(XATRIX_DIR)/m_actor.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_berserk.o :   $(XATRIX_DIR)/m_berserk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss2.o :     $(XATRIX_DIR)/m_boss2.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss3.o :     $(XATRIX_DIR)/m_boss3.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss31.o :    $(XATRIX_DIR)/m_boss31.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss32.o :    $(XATRIX_DIR)/m_boss32.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_boss5.o :     $(XATRIX_DIR)/m_boss5.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_brain.o :     $(XATRIX_DIR)/m_brain.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_chick.o :     $(XATRIX_DIR)/m_chick.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_fixbot.o :    $(XATRIX_DIR)/m_fixbot.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flash.o :     $(XATRIX_DIR)/m_flash.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flipper.o :   $(XATRIX_DIR)/m_flipper.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_float.o :     $(XATRIX_DIR)/m_float.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_flyer.o :     $(XATRIX_DIR)/m_flyer.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gekk.o :      $(XATRIX_DIR)/m_gekk.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gladb.o :     $(XATRIX_DIR)/m_gladb.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gladiator.o : $(XATRIX_DIR)/m_gladiator.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_gunner.o :    $(XATRIX_DIR)/m_gunner.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_hover.o :     $(XATRIX_DIR)/m_hover.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_infantry.o :  $(XATRIX_DIR)/m_infantry.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_insane.o :    $(XATRIX_DIR)/m_insane.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_medic.o :     $(XATRIX_DIR)/m_medic.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_move.o :      $(XATRIX_DIR)/m_move.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_mutant.o :    $(XATRIX_DIR)/m_mutant.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_parasite.o :  $(XATRIX_DIR)/m_parasite.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_soldier.o :   $(XATRIX_DIR)/m_soldier.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_supertank.o : $(XATRIX_DIR)/m_supertank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/m_tank.o :      $(XATRIX_DIR)/m_tank.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_client.o :    $(XATRIX_DIR)/p_client.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_hud.o :       $(XATRIX_DIR)/p_hud.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_trail.o :     $(XATRIX_DIR)/p_trail.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_view.o :      $(XATRIX_DIR)/p_view.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/p_weapon.o :    $(XATRIX_DIR)/p_weapon.c
+	$(DO_SHLIB_CC)
+
+$(BUILDDIR)/xatrix/q_shared.o :    $(XATRIX_DIR)/q_shared.c
+	$(DO_SHLIB_CC)
+
+#############################################################################
+# MISC
+#############################################################################
+
+clean: clean-debug clean-release
+
+clean-debug:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean-release:
+	$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
+
+clean2:
+	-rm -f $(QUAKE2_OBJS) $(GAME_OBJS) $(CTF_OBJS) $(XATRIX_OBJS)
--- /dev/null
+++ b/solaris/g_so.c
@@ -1,0 +1,3 @@
+int main(int argc, char *argv)
+{
+}
--- /dev/null
+++ b/solaris/glob.c
@@ -1,0 +1,164 @@
+
+#include <stdio.h>
+#include "../linux/glob.h"
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
+static int glob_match_after_star(char *pattern, char *text)
+{
+	register char *p = pattern, *t = text;
+	register char c, c1;
+
+	while ((c = *p++) == '?' || c == '*')
+		if (c == '?' && *t++ == '\0')
+			return 0;
+
+	if (c == '\0')
+		return 1;
+
+	if (c == '\\')
+		c1 = *p;
+	else
+		c1 = c;
+
+	while (1) {
+		if ((c == '[' || *t == c1) && glob_match(p - 1, t))
+			return 1;
+		if (*t++ == '\0')
+			return 0;
+	}
+}
+
+/* Return nonzero if PATTERN has any special globbing chars in it.  */
+static int glob_pattern_p(char *pattern)
+{
+	register char *p = pattern;
+	register char c;
+	int open = 0;
+
+	while ((c = *p++) != '\0')
+		switch (c) {
+		case '?':
+		case '*':
+			return 1;
+
+		case '[':		/* Only accept an open brace if there is a close */
+			open++;		/* brace to match it.  Bracket expressions must be */
+			continue;	/* complete, according to Posix.2 */
+		case ']':
+			if (open)
+				return 1;
+			continue;
+
+		case '\\':
+			if (*p++ == '\0')
+				return 0;
+		}
+
+	return 0;
+}
+
+/* Match the pattern PATTERN against the string TEXT;
+   return 1 if it matches, 0 otherwise.
+
+   A match means the entire string TEXT is used up in matching.
+
+   In the pattern string, `*' matches any sequence of characters,
+   `?' matches any character, [SET] matches any character in the specified set,
+   [!SET] matches any character not in the specified set.
+
+   A set is composed of characters or ranges; a range looks like
+   character hyphen character (as in 0-9 or A-Z).
+   [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
+   Any other character in the pattern must be matched exactly.
+
+   To suppress the special syntactic significance of any of `[]*?!-\',
+   and match the character exactly, precede it with a `\'.
+*/
+
+int glob_match(char *pattern, char *text)
+{
+	register char *p = pattern, *t = text;
+	register char c;
+
+	while ((c = *p++) != '\0')
+		switch (c) {
+		case '?':
+			if (*t == '\0')
+				return 0;
+			else
+				++t;
+			break;
+
+		case '\\':
+			if (*p++ != *t++)
+				return 0;
+			break;
+
+		case '*':
+			return glob_match_after_star(p, t);
+
+		case '[':
+			{
+				register char c1 = *t++;
+				int invert;
+
+				if (!c1)
+					return (0);
+
+				invert = ((*p == '!') || (*p == '^'));
+				if (invert)
+					p++;
+
+				c = *p++;
+				while (1) {
+					register char cstart = c, cend = c;
+
+					if (c == '\\') {
+						cstart = *p++;
+						cend = cstart;
+					}
+					if (c == '\0')
+						return 0;
+
+					c = *p++;
+					if (c == '-' && *p != ']') {
+						cend = *p++;
+						if (cend == '\\')
+							cend = *p++;
+						if (cend == '\0')
+							return 0;
+						c = *p++;
+					}
+					if (c1 >= cstart && c1 <= cend)
+						goto match;
+					if (c == ']')
+						break;
+				}
+				if (!invert)
+					return 0;
+				break;
+
+			  match:
+				/* Skip the rest of the [...] construct that already matched.  */
+				while (c != ']') {
+					if (c == '\0')
+						return 0;
+					c = *p++;
+					if (c == '\0')
+						return 0;
+					else if (c == '\\')
+						++p;
+				}
+				if (invert)
+					return 0;
+				break;
+			}
+
+		default:
+			if (c != *t++)
+				return 0;
+		}
+
+	return *t == '\0';
+}
+
--- /dev/null
+++ b/solaris/glob.h
@@ -1,0 +1,1 @@
+int glob_match(char *pattern, char *text);
--- /dev/null
+++ b/solaris/net_udp.c
@@ -1,0 +1,537 @@
+// net_wins.c
+
+#include "../qcommon/qcommon.h"
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <sys/filio.h>
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+
+netadr_t	net_local_adr;
+
+#define	LOOPBACK	0x7f000001
+
+#define	MAX_LOOPBACK	4
+
+typedef struct
+{
+	byte	data[MAX_MSGLEN];
+	int		datalen;
+} loopmsg_t;
+
+typedef struct
+{
+	loopmsg_t	msgs[MAX_LOOPBACK];
+	int			get, send;
+} loopback_t;
+
+loopback_t	loopbacks[2];
+int			ip_sockets[2];
+int			ipx_sockets[2];
+
+int NET_Socket (char *net_interface, int port);
+char *NET_ErrorString (void);
+
+//=============================================================================
+
+void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
+{
+	memset (s, 0, sizeof(*s));
+
+	if (a->type == NA_BROADCAST)
+	{
+		s->sin_family = AF_INET;
+
+		s->sin_port = a->port;
+		*(int *)&s->sin_addr = -1;
+	}
+	else if (a->type == NA_IP)
+	{
+		s->sin_family = AF_INET;
+
+		*(int *)&s->sin_addr = *(int *)&a->ip;
+		s->sin_port = a->port;
+	}
+}
+
+void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
+{
+	*(int *)&a->ip = *(int *)&s->sin_addr;
+	a->port = s->sin_port;
+	a->type = NA_IP;
+}
+
+
+qboolean	NET_CompareAdr (netadr_t a, netadr_t b)
+{
+	if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
+		return true;
+	return false;
+}
+
+/*
+===================
+NET_CompareBaseAdr
+
+Compares without the port
+===================
+*/
+qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b)
+{
+	if (a.type != b.type)
+		return false;
+
+	if (a.type == NA_LOOPBACK)
+		return true;
+
+	if (a.type == NA_IP)
+	{
+		if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
+			return true;
+		return false;
+	}
+
+	if (a.type == NA_IPX)
+	{
+		if ((memcmp(a.ipx, b.ipx, 10) == 0))
+			return true;
+		return false;
+	}
+}
+
+char	*NET_AdrToString (netadr_t a)
+{
+	static	char	s[64];
+	
+	Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
+
+	return s;
+}
+
+char	*NET_BaseAdrToString (netadr_t a)
+{
+	static	char	s[64];
+	
+	Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
+
+	return s;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean	NET_StringToSockaddr (char *s, struct sockaddr *sadr)
+{
+	struct hostent	*h;
+	char	*colon;
+	char	copy[128];
+	
+	memset (sadr, 0, sizeof(*sadr));
+	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
+	
+	((struct sockaddr_in *)sadr)->sin_port = 0;
+
+	strcpy (copy, s);
+	// strip off a trailing :port if present
+	for (colon = copy ; *colon ; colon++)
+		if (*colon == ':')
+		{
+			*colon = 0;
+			((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));	
+		}
+	
+	if (copy[0] >= '0' && copy[0] <= '9')
+	{
+		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
+	}
+	else
+	{
+		if (! (h = gethostbyname(copy)) )
+			return 0;
+		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
+	}
+	
+	return true;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean	NET_StringToAdr (char *s, netadr_t *a)
+{
+	struct sockaddr_in sadr;
+	
+	if (!strcmp (s, "localhost"))
+	{
+		memset (a, 0, sizeof(*a));
+		a->type = NA_LOOPBACK;
+		return true;
+	}
+
+	if (!NET_StringToSockaddr (s, (struct sockaddr *)&sadr))
+		return false;
+	
+	SockadrToNetadr (&sadr, a);
+
+	return true;
+}
+
+
+qboolean	NET_IsLocalAddress (netadr_t adr)
+{
+	return NET_CompareAdr (adr, net_local_adr);
+}
+
+/*
+=============================================================================
+
+LOOPBACK BUFFERS FOR LOCAL PLAYER
+
+=============================================================================
+*/
+
+qboolean	NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+	int		i;
+	loopback_t	*loop;
+
+	loop = &loopbacks[sock];
+
+	if (loop->send - loop->get > MAX_LOOPBACK)
+		loop->get = loop->send - MAX_LOOPBACK;
+
+	if (loop->get >= loop->send)
+		return false;
+
+	i = loop->get & (MAX_LOOPBACK-1);
+	loop->get++;
+
+	memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
+	net_message->cursize = loop->msgs[i].datalen;
+	*net_from = net_local_adr;
+	return true;
+
+}
+
+
+void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+	int		i;
+	loopback_t	*loop;
+
+	loop = &loopbacks[sock^1];
+
+	i = loop->send & (MAX_LOOPBACK-1);
+	loop->send++;
+
+	memcpy (loop->msgs[i].data, data, length);
+	loop->msgs[i].datalen = length;
+}
+
+//=============================================================================
+
+qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+	int 	ret;
+	struct sockaddr_in	from;
+	int		fromlen;
+	int		net_socket;
+	int		protocol;
+	int		err;
+
+	if (NET_GetLoopPacket (sock, net_from, net_message))
+		return true;
+
+	for (protocol = 0 ; protocol < 2 ; protocol++)
+	{
+		if (protocol == 0)
+			net_socket = ip_sockets[sock];
+		else
+			net_socket = ipx_sockets[sock];
+
+		if (!net_socket)
+			continue;
+
+		fromlen = sizeof(from);
+		ret = recvfrom (net_socket, net_message->data, net_message->maxsize
+			, 0, (struct sockaddr *)&from, &fromlen);
+		if (ret == -1)
+		{
+			err = errno;
+
+			if (err == EWOULDBLOCK || err == ECONNREFUSED)
+				continue;
+			Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
+			continue;
+		}
+
+		if (ret == net_message->maxsize)
+		{
+			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
+			continue;
+		}
+
+		net_message->cursize = ret;
+		SockadrToNetadr (&from, net_from);
+		return true;
+	}
+
+	return false;
+}
+
+//=============================================================================
+
+void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+	int		ret;
+	struct sockaddr_in	addr;
+	int		net_socket;
+
+	if ( to.type == NA_LOOPBACK )
+	{
+		NET_SendLoopPacket (sock, length, data, to);
+		return;
+	}
+
+	if (to.type == NA_BROADCAST)
+	{
+		net_socket = ip_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_IP)
+	{
+		net_socket = ip_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_IPX)
+	{
+		net_socket = ipx_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_BROADCAST_IPX)
+	{
+		net_socket = ipx_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else
+		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
+
+	NetadrToSockadr (&to, &addr);
+
+	ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
+	if (ret == -1)
+	{
+		Com_Printf ("NET_SendPacket ERROR: %i\n", NET_ErrorString());
+	}
+}
+
+
+//=============================================================================
+
+
+
+
+/*
+====================
+NET_OpenIP
+====================
+*/
+void NET_OpenIP (void)
+{
+	cvar_t	*port, *ip;
+
+	port = Cvar_Get ("port", va("%i", PORT_SERVER), CVAR_NOSET);
+	ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
+
+	if (!ip_sockets[NS_SERVER])
+		ip_sockets[NS_SERVER] = NET_Socket (ip->string, port->value);
+	if (!ip_sockets[NS_CLIENT])
+		ip_sockets[NS_CLIENT] = NET_Socket (ip->string, PORT_ANY);
+}
+
+/*
+====================
+NET_OpenIPX
+====================
+*/
+void NET_OpenIPX (void)
+{
+}
+
+
+/*
+====================
+NET_Config
+
+A single player game will only use the loopback code
+====================
+*/
+void	NET_Config (qboolean multiplayer)
+{
+	int		i;
+
+	if (!multiplayer)
+	{	// shut down any existing sockets
+		for (i=0 ; i<2 ; i++)
+		{
+			if (ip_sockets[i])
+			{
+				close (ip_sockets[i]);
+				ip_sockets[i] = 0;
+			}
+			if (ipx_sockets[i])
+			{
+				close (ipx_sockets[i]);
+				ipx_sockets[i] = 0;
+			}
+		}
+	}
+	else
+	{	// open sockets
+		NET_OpenIP ();
+		NET_OpenIPX ();
+	}
+}
+
+
+//===================================================================
+
+
+/*
+====================
+NET_Init
+====================
+*/
+void NET_Init (void)
+{
+}
+
+
+/*
+====================
+NET_Socket
+====================
+*/
+int NET_Socket (char *net_interface, int port)
+{
+	int newsocket;
+	struct sockaddr_in address;
+	qboolean _true = true;
+	int	i = 1;
+
+	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
+		return 0;
+	}
+
+	// make it non-blocking
+	if (ioctl (newsocket, FIONBIO, &_true) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
+		return 0;
+	}
+
+	// make it broadcast capable
+	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
+		return 0;
+	}
+
+	if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
+		address.sin_addr.s_addr = INADDR_ANY;
+	else
+		NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
+
+	if (port == PORT_ANY)
+		address.sin_port = 0;
+	else
+		address.sin_port = htons((short)port);
+
+	address.sin_family = AF_INET;
+
+	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+	{
+		Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
+		close (newsocket);
+		return 0;
+	}
+
+	return newsocket;
+}
+
+
+/*
+====================
+NET_Shutdown
+====================
+*/
+void	NET_Shutdown (void)
+{
+	NET_Config (false);	// close sockets
+}
+
+
+/*
+====================
+NET_ErrorString
+====================
+*/
+char *NET_ErrorString (void)
+{
+	int		code;
+
+	code = errno;
+	return strerror (code);
+}
+
+// sleeps msec or until net socket is ready
+void NET_Sleep(int msec)
+{
+    struct timeval timeout;
+	fd_set	fdset;
+	extern cvar_t *dedicated;
+	extern qboolean stdin_active;
+
+	if (!ip_sockets[NS_SERVER] || (dedicated && !dedicated->value))
+		return; // we're not a server, just run full speed
+
+	FD_ZERO(&fdset);
+	if (stdin_active)
+		FD_SET(0, &fdset); // stdin is processed too
+	FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
+	timeout.tv_sec = msec/1000;
+	timeout.tv_usec = (msec%1000)*1000;
+	select(ip_sockets[NS_SERVER]+1, &fdset, NULL, NULL, &timeout);
+}
+
--- /dev/null
+++ b/solaris/q_shsolaris.c
@@ -1,0 +1,196 @@
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "../linux/glob.h"
+
+#include "../qcommon/qcommon.h"
+
+//===============================================================================
+
+byte *membase;
+int maxhunksize;
+int curhunksize;
+
+void *Hunk_Begin (int maxsize)
+{
+	// reserve a huge chunk of memory, but don't commit any yet
+	maxhunksize = maxsize;
+	curhunksize = 0;
+	membase = malloc(maxhunksize);
+	if (membase == NULL)
+		Sys_Error(ERR_FATAL, "unable to allocate %d bytes", maxsize);
+
+	return membase;
+}
+
+void *Hunk_Alloc (int size)
+{
+	byte *buf;
+
+	// round to cacheline
+	size = (size+31)&~31;
+	if (curhunksize + size > maxhunksize)
+		Sys_Error(ERR_FATAL, "Hunk_Alloc overflow");
+	buf = membase + curhunksize;
+	curhunksize += size;
+	return buf;
+}
+
+int Hunk_End (void)
+{
+	byte *n;
+
+	n = realloc(membase, curhunksize);
+	if (n != membase)
+		Sys_Error(ERR_FATAL, "Hunk_End:  Could not remap virtual block (%d)", errno);
+	
+	return curhunksize;
+}
+
+void Hunk_Free (void *base)
+{
+	if (base) 
+		free(base);
+}
+
+//===============================================================================
+
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int curtime;
+int Sys_Milliseconds (void)
+{
+	struct timeval tp;
+	struct timezone tzp;
+	static int		secbase;
+
+	gettimeofday(&tp, &tzp);
+	
+	if (!secbase)
+	{
+		secbase = tp.tv_sec;
+		return tp.tv_usec/1000;
+	}
+
+	curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
+	
+	return curtime;
+}
+
+void Sys_Mkdir (char *path)
+{
+    mkdir (path, 0777);
+}
+
+char *strlwr (char *s)
+{
+	while (*s) {
+		*s = tolower(*s);
+		s++;
+	}
+}
+
+//============================================
+
+static	char	findbase[MAX_OSPATH];
+static	char	findpath[MAX_OSPATH];
+static	char	findpattern[MAX_OSPATH];
+static	DIR		*fdir;
+
+static qboolean CompareAttributes(char *path, char *name,
+	unsigned musthave, unsigned canthave )
+{
+	struct stat st;
+	char fn[MAX_OSPATH];
+
+// . and .. never match
+	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+		return false;
+
+	sprintf(fn, "%s/%s", path, name);
+	if (stat(fn, &st) == -1)
+		return false; // shouldn't happen
+
+	if ( ( st.st_mode & S_IFDIR ) && ( canthave & SFF_SUBDIR ) )
+		return false;
+
+	if ( ( musthave & SFF_SUBDIR ) && !( st.st_mode & S_IFDIR ) )
+		return false;
+
+	return true;
+}
+
+char *Sys_FindFirst (char *path, unsigned musthave, unsigned canhave)
+{
+	struct dirent *d;
+	char *p;
+
+	if (fdir)
+		Sys_Error ("Sys_BeginFind without close");
+
+//	COM_FilePath (path, findbase);
+	strcpy(findbase, path);
+	
+	if ((p = strrchr(findbase, '/')) != NULL) {
+		*p = 0;
+		strcpy(findpattern, p + 1);
+	} else
+		strcpy(findpattern, "*");
+
+	if (strcmp(findpattern, "*.*") == 0)
+		strcpy(findpattern, "*");
+	
+	if ((fdir = opendir(path)) == NULL)
+		return NULL;
+	while ((d = readdir(fdir)) != NULL) {
+		if (!*findpattern || glob_match(findpattern, d->d_name)) {
+//			if (*findpattern)
+//				printf("%s matched %s\n", findpattern, d->d_name);
+			if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+				sprintf (findpath, "%s/%s", findbase, d->d_name);
+				return findpath;
+			}
+		}
+	}
+	return NULL;
+}
+
+char *Sys_FindNext (unsigned musthave, unsigned canhave)
+{
+	struct dirent *d;
+
+	if (fdir == NULL)
+		return NULL;
+	while ((d = readdir(fdir)) != NULL) {
+		if (!*findpattern || glob_match(findpattern, d->d_name)) {
+//			if (*findpattern)
+//				printf("%s matched %s\n", findpattern, d->d_name);
+			if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
+				sprintf (findpath, "%s/%s", findbase, d->d_name);
+				return findpath;
+			}
+		}
+	}
+	return NULL;
+}
+
+void Sys_FindClose (void)
+{
+	if (fdir != NULL)
+		closedir(fdir);
+	fdir = NULL;
+}
+
+
+//============================================
+
--- /dev/null
+++ b/solaris/sys_solaris.c
@@ -1,0 +1,337 @@
+#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 <sys/file.h>
+
+#include <dlfcn.h>
+
+#include "../qcommon/qcommon.h"
+
+cvar_t *nostdout;
+
+unsigned	sys_frame_time;
+
+qboolean stdin_active = true;
+
+// =======================================================================
+// General routines
+// =======================================================================
+
+void Sys_ConsoleOutput (char *string)
+{
+	if (nostdout && nostdout->value)
+		return;
+
+	fputs(string, stdout);
+}
+
+void Sys_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+	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 && nostdout->value)
+        return;
+
+	for (p = (unsigned char *)text; *p; p++) {
+		*p &= 0x7f;
+		if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
+			printf("[%02x]", *p);
+		else
+			putc(*p, stdout);
+	}
+}
+
+void Sys_Quit (void)
+{
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+    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);
+
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+	_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 floating_point_exception_handler(int whatever)
+{
+//	Sys_Warn("floating point exception\n");
+	signal(SIGFPE, floating_point_exception_handler);
+}
+
+char *Sys_ConsoleInput(void)
+{
+    static char text[256];
+    int     len;
+	fd_set	fdset;
+    struct timeval timeout;
+
+	if (!dedicated || !dedicated->value)
+		return NULL;
+
+	if (!stdin_active)
+		return NULL;
+
+	FD_ZERO(&fdset);
+	FD_SET(0, &fdset); // stdin
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+	if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
+		return NULL;
+
+	len = read (0, text, sizeof(text));
+	if (len == 0) { // eof!
+		stdin_active = false;
+		return NULL;
+	}
+	if (len < 1)
+		return NULL;
+	text[len-1] = 0;    // rip off the /n and terminate
+
+	return text;
+}
+
+/*****************************************************************************/
+
+static void *game_library;
+
+/*
+=================
+Sys_UnloadGame
+=================
+*/
+void Sys_UnloadGame (void)
+{
+	if (game_library) 
+		dlclose (game_library);
+	game_library = NULL;
+}
+
+/*
+=================
+Sys_GetGameAPI
+
+Loads the game dll
+=================
+*/
+void *Sys_GetGameAPI (void *parms)
+{
+	void	*(*GetGameAPI) (void *);
+
+	char	name[MAX_OSPATH];
+	char	curpath[MAX_OSPATH];
+	char	*path;
+#ifdef __i386__
+	const char *gamename = "gamei386.so";
+#elif defined __sun__
+	const char *gamename = "gamesparc.so";
+#else
+#error Unknown arch
+#endif
+
+	if (game_library)
+		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
+
+	getcwd(curpath, sizeof(curpath));
+
+	Com_Printf("------- Loading %s -------", gamename);
+
+	// now run through the search paths
+	path = NULL;
+	while (1)
+	{
+		path = FS_NextPath (path);
+		if (!path)
+			return NULL;		// couldn't find one anywhere
+		sprintf (name, "%s/%s/%s", curpath, path, gamename);
+		game_library = dlopen (name, RTLD_NOW );
+		if (game_library)
+		{
+			Com_DPrintf ("LoadLibrary (%s)\n",name);
+			break;
+		} else
+			Com_Printf("error: %s\n", dlerror());
+	}
+
+	GetGameAPI = (void *)dlsym (game_library, "GetGameAPI");
+	if (!GetGameAPI)
+	{
+		Sys_UnloadGame ();		
+		return NULL;
+	}
+
+	return GetGameAPI (parms);
+}
+
+/*****************************************************************************/
+
+void Sys_AppActivate (void)
+{
+}
+
+void Sys_SendKeyEvents (void)
+{
+	// grab frame time 
+	sys_frame_time = Sys_Milliseconds();
+}
+
+/*****************************************************************************/
+
+char *Sys_GetClipboardData(void)
+{
+	return NULL;
+}
+
+int main (int argc, char **argv)
+{
+	int 	time, oldtime, newtime;
+
+#if 0
+	int newargc;
+	char **newargv;
+	int i;
+
+	// force dedicated
+	newargc = argc;
+	newargv = malloc((argc + 3) * sizeof(char *));
+	newargv[0] = argv[0];
+	newargv[1] = "+set";
+	newargv[2] = "dedicated";
+	newargv[3] = "1";
+	for (i = 1; i < argc; i++)
+		newargv[i + 3] = argv[i];
+	newargc += 3;
+
+	Qcommon_Init(newargc, newargv);
+#else
+	Qcommon_Init(argc, argv);
+#endif
+
+	fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+
+	nostdout = Cvar_Get("nostdout", "0", 0);
+
+	if (!nostdout->value) {
+		fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+//		printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
+	}
+
+    oldtime = Sys_Milliseconds ();
+    while (1)
+    {
+// find time spent rendering last frame
+		do {
+			newtime = Sys_Milliseconds ();
+			time = newtime - oldtime;
+		} while (time < 1);
+        Qcommon_Frame (time);
+		oldtime = newtime;
+    }
+
+}
+
+void Sys_CopyProtect(void)
+{
+	return;
+}
+
+#if 0
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+	int r;
+	unsigned long addr;
+	int psize = getpagesize();
+
+	addr = (startaddr & ~(psize-1)) - psize;
+
+//	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+//			addr, startaddr+length, length);
+
+	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+	if (r < 0)
+    		Sys_Error("Protection change failed\n");
+
+}
+
+#endif
--- /dev/null
+++ b/unix/makefile
@@ -1,0 +1,308 @@
+
+CFLAGS = -c
+LDFLAGS =
+ODIR = baddir
+
+EXEBASE = quake2
+EXE = $(ODIR)/quake2
+all: $(EXE)
+
+#----------------------------------------------------------------------
+
+SERVERFILES = $(ODIR)/sv_ccmds.o $(ODIR)/sv_ents.o $(ODIR)/sv_game.o $(ODIR)/sv_init.o $(ODIR)/sv_main.o $(ODIR)/sv_send.o $(ODIR)/sv_user.o $(ODIR)/sv_world.o
+
+CLIENTFILES = $(ODIR)/cl_demo.o $(ODIR)/cl_ents.o $(ODIR)/cl_fx.o $(ODIR)/cl_input.o $(ODIR)/cl_inv.o $(ODIR)/cl_main.o $(ODIR)/cl_parse.o $(ODIR)/cl_tent.o $(ODIR)/console.o $(ODIR)/keys.o $(ODIR)/menu.o $(ODIR)/qmenu.o $(ODIR)/screen.o $(ODIR)/scr_cin.o $(ODIR)/snd_dma.o $(ODIR)/snd_mem.o $(ODIR)/snd_mix.o $(ODIR)/view.o
+
+# commonfiles are used by both client and server
+COMMONFILES = $(ODIR)/cmd.o $(ODIR)/cmodel.o $(ODIR)/cvar.o $(ODIR)/files.o $(ODIR)/md4.o $(ODIR)/net_chan.o $(ODIR)/net_udp.o
+
+REFGLFILES = $(ODIR)/gl_draw.o $(ODIR)/gl_inter.o $(ODIR)/gl_light.o $(ODIR)/gl_math.o $(ODIR)/gl_mesh.o $(ODIR)/gl_model.o $(ODIR)/gl_rmain.o $(ODIR)/gl_rmisc.o $(ODIR)/gl_rsurf.o $(ODIR)/gl_textr.o $(ODIR)/gl_warp.
+
+REFSOFTFILES = $(ODIR)/r_aclip.o $(ODIR)/r_alias.o $(ODIR)/r_bsp.o $(ODIR)/r_draw.o $(ODIR)/r_edge.o $(ODIR)/r_image.o $(ODIR)/r_light.o $(ODIR)/r_main.o $(ODIR)/r_misc.o $(ODIR)/r_model.o $(ODIR)/r_part.o $(ODIR)/r_polyse.o $(ODIR)/r_poly.o $(ODIR)/r_rast.o $(ODIR)/r_scan.o $(ODIR)/r_sprite.o $(ODIR)/r_surf.o
+
+# sharedfiles are included in EVERY dll
+SHAREDFILES = $(ODIR)/q_shared
+
+#----------------------------------------------------------------------
+
+_next:
+	make "CFLAGS = -c -Wall -g -O" "ODIR = next"
+	
+_irix:
+	make "CFLAGS = -c -O2 -Xcpluscomm -woff 513 -woff 594 -woff 596" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
+	
+_irixdebug:
+	make "CFLAGS = -c -O2 -g -Xcpluscomm" "LDFLAGS = -g" "ODIR = irix"
+		
+clean:
+	rm -f next/*.o next/$(EXEBASE)
+	rm -f irix/*.o irix/$(EXEBASE)
+
+#----------------------------------------------------------------------
+
+FILES = $(SERVERFILES) $(COMMONFILES) $(CLIENTFILES) $(REFSOFTFILES) $(SHAREDFILES)
+
+$(EXE) : $(FILES)
+	cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
+
+#----------------------------------------------------------------------
+
+$(ODIR)/q_shared.o : ../qcommon/q_shared.c
+	cc $(CFLAGS) -o $@ $?
+
+#----------------------------------------------------------------------
+
+$(ODIR)/sv_ccmds.o : ../server/sv_ccmds.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_ents.o : ../server/sv_ents.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_game.o : ../server/sv_game.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_init.o : ../server/sv_init.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_main.o : ../server/sv_main.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_send.o : ../server/sv_send.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_user.o : ../server/sv_user.c
+	cc $(CFLAGS) -o $@ $?
+
+$(ODIR)/sv_world.o : ../server/sv_world.c
+	cc $(CFLAGS) -o $@ $?
+
+#----------------------------------------------------------------------
+
+$(ODIR)/cl_demo.o : ../client/cl_demo.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_ents.o : ../client/cl_ents.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_fx.o : ../client/cl_fx.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_input.o : ../client/cl_input.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_inv.o : ../client/cl_inv.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_main.o : ../client/cl_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_parse.o : ../client/cl_parse.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_tent.o : ../client/cl_tent.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/console.o : ../client/console.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/keys.o : ../client/keys.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/menu.o : ../client/menu.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/qmenu.o : ../client/qmenu.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sbar2.o : ../client/sbar2.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/screen.o : ../client/screen.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/scr_cin.o : ../client/scr_cin.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_dma.o : ../client/snd_dma.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_mem.o : ../client/snd_mem.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_mix.o : ../client/snd_mix.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/view.o : ../client/view.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+	
+#----------------------------------------------------------------------
+
+$(ODIR)/cmd.o : ../qcommon/cmd.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cmodel.o : ../qcommon/cmodel.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cvar.o : ../qcommon/cvar.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/files.o : ../qcommon/files.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/md4.o : ../qcommon/md4.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/net_chan.o : ../qcommon/net_chan.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/net_udp.o : ../qcommon/net_udp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sys_null.o : ../qcommon/sys_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#----------------------------------------------------------------------
+
+$(ODIR)/gl_draw.o : ../ref_gl/gl_draw.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_inter.o : ../ref_gl/gl_inter.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_light.o : ../ref_gl/gl_light.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_math.o : ../ref_gl/gl_math.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_mesh.o : ../ref_gl/gl_mesh.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_model.o : ../ref_gl/gl_model.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_rmain.o : ../ref_gl/gl_rmain.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_rmisc.o : ../ref_gl/gl_rmisc.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_rsurf.o : ../ref_gl/gl_rsurf.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_textr.o : ../ref_gl/gl_textr.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_warp.o : ../ref_gl/gl_warp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#----------------------------------------------------------------------
+
+$(ODIR)/r_aclip.o : ../ref_soft/r_aclip.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_alias.o : ../ref_soft/r_alias.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_bsp.o : ../ref_soft/r_bsp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_draw.o : ../ref_soft/r_draw.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_edge.o : ../ref_soft/r_edge.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_image.o : ../ref_soft/r_image.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_light.o : ../ref_soft/r_light.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_main.o : ../ref_soft/r_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_misc.o : ../ref_soft/r_misc.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_model.o : ../ref_soft/r_model.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_part.o : ../ref_soft/r_part.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_polyse.o : ../ref_soft/r_polyse.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_poly.o : ../ref_soft/r_poly.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_rast.o : ../ref_soft/r_rast.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_scan.o : ../ref_soft/r_scan.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_sprite.o : ../ref_soft/r_sprite.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_surf.o : ../ref_soft/r_surf.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+	
+#----------------------------------------------------------------------
+
--- /dev/null
+++ b/unix/makefile_old
@@ -1,0 +1,317 @@
+
+CFLAGS = -c
+LDFLAGS =
+ODIR = baddir
+
+EXEBASE = quake2
+EXE = $(ODIR)/quake2
+all: $(EXE)
+
+#----------------------------------------------------------------------
+
+SERVERFILES = $(ODIR)/sv_ccmds.o $(ODIR)/sv_ents.o $(ODIR)/sv_game.o $(ODIR)/sv_init.o $(ODIR)/sv_main.o $(ODIR)/sv_send.o $(ODIR)/sv_user.o $(ODIR)/sv_world.o
+
+CLIENTFILES = $(ODIR)/cl_demo.o $(ODIR)/cl_ents.o $(ODIR)/cl_fx.o $(ODIR)/cl_input.o $(ODIR)/cl_inv.o $(ODIR)/cl_main.o $(ODIR)/cl_parse.o $(ODIR)/cl_tent.o $(ODIR)/console.o $(ODIR)/keys.o $(ODIR)/menu.o $(ODIR)/qmenu.o $(ODIR)/screen.o $(ODIR)/scr_cin.o $(ODIR)/snd_dma.o $(ODIR)/snd_mem.o $(ODIR)/snd_mix.o $(ODIR)/view.o
+
+# commonfiles are used by both client and server
+COMMONFILES = $(ODIR)/cmd.o $(ODIR)/cmodel.o $(ODIR)/cvar.o $(ODIR)/files.o $(ODIR)/md4.o $(ODIR)/net_chan.o $(ODIR)/net_udp.o
+
+REFGLFILES = $(ODIR)/gl_draw.o $(ODIR)/gl_inter.o $(ODIR)/gl_light.o $(ODIR)/gl_math.o $(ODIR)/gl_mesh.o $(ODIR)/gl_model.o $(ODIR)/gl_rmain.o $(ODIR)/gl_rmisc.o $(ODIR)/gl_rsurf.o $(ODIR)/gl_textr.o $(ODIR)/gl_warp.
+
+REFSOFTFILES = $(ODIR)/r_aclip.o $(ODIR)/r_alias.o $(ODIR)/r_bsp.o $(ODIR)/r_draw.o $(ODIR)/r_edge.o $(ODIR)/r_image.o $(ODIR)/r_light.o $(ODIR)/r_main.o $(ODIR)/r_misc.o $(ODIR)/r_model.o $(ODIR)/r_part.o $(ODIR)/r_polyse.o $(ODIR)/r_poly.o $(ODIR)/r_rast.o $(ODIR)/r_scan.o $(ODIR)/r_sprite.o $(ODIR)/r_surf.o
+
+# sharedfiles are included in EVERY dll
+SHAREDFILES = $(ODIR)/q_shared
+
+#----------------------------------------------------------------------
+
+_next:
+	make "CFLAGS = -c -Wall -g -O" "ODIR = next"
+	
+_irix:
+	make "CFLAGS = -c -woff 513 -Ofast=ip32_10k -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
+	
+_irixdebug:
+	make "CFLAGS = -c -O2 -g -Xcpluscomm" "LDFLAGS = -g" "ODIR = irix"
+		
+clean:
+	rm -f next/*.o next/$(EXEBASE)
+	rm -f irix/*.o irix/$(EXEBASE)
+
+#----------------------------------------------------------------------
+
+FILES = $(SERVERFILES) $(COMMONFILES) $(CLIENTFILES) $(REFSOFTFILES) $(SHAREDFILES)
+
+$(EXE) : $(FILES)
+	cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
+
+#----------------------------------------------------------------------
+
+$(ODIR)/q_shared.o : ../qcommon/q_shared.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#----------------------------------------------------------------------
+
+$(ODIR)/sv_ccmds.o : ../server/sv_ccmds.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_ents.o : ../server/sv_ents.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_game.o : ../server/sv_game.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_init.o : ../server/sv_init.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_main.o : ../server/sv_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_send.o : ../server/sv_send.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_user.o : ../server/sv_user.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sv_world.o : ../server/sv_world.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#----------------------------------------------------------------------
+
+$(ODIR)/cl_demo.o : ../client/cl_demo.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_ents.o : ../client/cl_ents.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_fx.o : ../client/cl_fx.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_input.o : ../client/cl_input.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_inv.o : ../client/cl_inv.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_main.o : ../client/cl_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_parse.o : ../client/cl_parse.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cl_tent.o : ../client/cl_tent.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/console.o : ../client/console.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/keys.o : ../client/keys.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/menu.o : ../client/menu.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/qmenu.o : ../client/qmenu.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sbar2.o : ../client/sbar2.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/screen.o : ../client/screen.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/scr_cin.o : ../client/scr_cin.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_dma.o : ../client/snd_dma.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_mem.o : ../client/snd_mem.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/snd_mix.o : ../client/snd_mix.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/view.o : ../client/view.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+	
+#----------------------------------------------------------------------
+
+$(ODIR)/cmd.o : ../qcommon/cmd.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cmodel.o : ../qcommon/cmodel.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cvar.o : ../qcommon/cvar.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/files.o : ../qcommon/files.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/md4.o : ../qcommon/md4.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/net_chan.o : ../qcommon/net_chan.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/net_udp.o : ../qcommon/net_udp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/sys_null.o : ../qcommon/sys_null.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#----------------------------------------------------------------------
+
+$(ODIR)/gl_draw.o : ../ref_gl/gl_draw.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_inter.o : ../ref_gl/gl_inter.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_light.o : ../ref_gl/gl_light.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_math.o : ../ref_gl/gl_math.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_mesh.o : ../ref_gl/gl_mesh.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_model.o : ../ref_gl/gl_model.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_rmain.o : ../ref_gl/gl_rmain.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_rmisc.o : ../ref_gl/gl_rmisc.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_rsurf.o : ../ref_gl/gl_rsurf.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_textr.o : ../ref_gl/gl_textr.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/gl_warp.o : ../ref_gl/gl_warp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+#----------------------------------------------------------------------
+
+$(ODIR)/r_aclip.o : ../ref_soft/r_aclip.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_alias.o : ../ref_soft/r_alias.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_bsp.o : ../ref_soft/r_bsp.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_draw.o : ../ref_soft/r_draw.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_edge.o : ../ref_soft/r_edge.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_image.o : ../ref_soft/r_image.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_light.o : ../ref_soft/r_light.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_main.o : ../ref_soft/r_main.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_misc.o : ../ref_soft/r_misc.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_model.o : ../ref_soft/r_model.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_part.o : ../ref_soft/r_part.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_polyse.o : ../ref_soft/r_polyse.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_poly.o : ../ref_soft/r_poly.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_rast.o : ../ref_soft/r_rast.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_scan.o : ../ref_soft/r_scan.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_sprite.o : ../ref_soft/r_sprite.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/r_surf.o : ../ref_soft/r_surf.c
+	cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+	cc $(CFLAGS) -o $@ /tmp/temp.i
+	
+#----------------------------------------------------------------------
+
binary files /dev/null b/unix/next/sv_ccmds.o differ
--- /dev/null
+++ b/win32/cd_win.c
@@ -1,0 +1,510 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
+// rights reserved.
+
+#include <windows.h>
+#include "../client/client.h"
+
+extern	HWND	cl_hwnd;
+
+static qboolean cdValid = false;
+static qboolean	playing = false;
+static qboolean	wasPlaying = false;
+static qboolean	initialized = false;
+static qboolean	enabled = false;
+static qboolean playLooping = false;
+static byte 	remap[100];
+static byte		cdrom;
+static byte		playTrack;
+static byte		maxTrack;
+
+cvar_t *cd_nocd;
+cvar_t *cd_loopcount;
+cvar_t *cd_looptrack;
+
+UINT	wDeviceID;
+int		loopcounter;
+
+
+void CDAudio_Pause(void);
+
+static void CDAudio_Eject(void)
+{
+	DWORD	dwReturn;
+
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL))
+		Com_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn);
+}
+
+
+static void CDAudio_CloseDoor(void)
+{
+	DWORD	dwReturn;
+
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL))
+		Com_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn);
+}
+
+
+static int CDAudio_GetAudioDiskInfo(void)
+{
+	DWORD				dwReturn;
+	MCI_STATUS_PARMS	mciStatusParms;
+
+
+	cdValid = false;
+
+	mciStatusParms.dwItem = MCI_STATUS_READY;
+    dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
+	if (dwReturn)
+	{
+		Com_DPrintf("CDAudio: drive ready test - get status failed\n");
+		return -1;
+	}
+	if (!mciStatusParms.dwReturn)
+	{
+		Com_DPrintf("CDAudio: drive not ready\n");
+		return -1;
+	}
+
+	mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
+    dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
+	if (dwReturn)
+	{
+		Com_DPrintf("CDAudio: get tracks - status failed\n");
+		return -1;
+	}
+	if (mciStatusParms.dwReturn < 1)
+	{
+		Com_DPrintf("CDAudio: no music tracks\n");
+		return -1;
+	}
+
+	cdValid = true;
+	maxTrack = mciStatusParms.dwReturn;
+
+	return 0;
+}
+
+
+
+void CDAudio_Play2(int track, qboolean looping)
+{
+	DWORD				dwReturn;
+    MCI_PLAY_PARMS		mciPlayParms;
+	MCI_STATUS_PARMS	mciStatusParms;
+
+	if (!enabled)
+		return;
+	
+	if (!cdValid)
+	{
+		CDAudio_GetAudioDiskInfo();
+		if (!cdValid)
+			return;
+	}
+
+	track = remap[track];
+
+	if (track < 1 || track > maxTrack)
+	{
+		CDAudio_Stop();
+		return;
+	}
+
+	// don't try to play a non-audio track
+	mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
+	mciStatusParms.dwTrack = track;
+    dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
+	if (dwReturn)
+	{
+		Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
+		return;
+	}
+	if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
+	{
+		Com_Printf("CDAudio: track %i is not audio\n", track);
+		return;
+	}
+
+	// get the length of the track to be played
+	mciStatusParms.dwItem = MCI_STATUS_LENGTH;
+	mciStatusParms.dwTrack = track;
+    dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
+	if (dwReturn)
+	{
+		Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
+		return;
+	}
+
+	if (playing)
+	{
+		if (playTrack == track)
+			return;
+		CDAudio_Stop();
+	}
+
+    mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
+	mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
+    mciPlayParms.dwCallback = (DWORD)cl_hwnd;
+    dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
+	if (dwReturn)
+	{
+		Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
+		return;
+	}
+
+	playLooping = looping;
+	playTrack = track;
+	playing = true;
+
+	if ( Cvar_VariableValue( "cd_nocd" ) )
+		CDAudio_Pause ();
+}
+
+
+void CDAudio_Play(int track, qboolean looping)
+{
+	// set a loop counter so that this track will change to the
+	// looptrack later
+	loopcounter = 0;
+	CDAudio_Play2(track, looping);
+}
+
+void CDAudio_Stop(void)
+{
+	DWORD	dwReturn;
+
+	if (!enabled)
+		return;
+	
+	if (!playing)
+		return;
+
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL))
+		Com_DPrintf("MCI_STOP failed (%i)", dwReturn);
+
+	wasPlaying = false;
+	playing = false;
+}
+
+
+void CDAudio_Pause(void)
+{
+	DWORD				dwReturn;
+	MCI_GENERIC_PARMS	mciGenericParms;
+
+	if (!enabled)
+		return;
+
+	if (!playing)
+		return;
+
+	mciGenericParms.dwCallback = (DWORD)cl_hwnd;
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms))
+		Com_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
+
+	wasPlaying = playing;
+	playing = false;
+}
+
+
+void CDAudio_Resume(void)
+{
+	DWORD			dwReturn;
+    MCI_PLAY_PARMS	mciPlayParms;
+
+	if (!enabled)
+		return;
+	
+	if (!cdValid)
+		return;
+
+	if (!wasPlaying)
+		return;
+	
+    mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
+    mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
+    mciPlayParms.dwCallback = (DWORD)cl_hwnd;
+    dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
+	if (dwReturn)
+	{
+		Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
+		return;
+	}
+	playing = true;
+}
+
+
+static void CD_f (void)
+{
+	char	*command;
+	int		ret;
+	int		n;
+
+	if (Cmd_Argc() < 2)
+		return;
+
+	command = Cmd_Argv (1);
+
+	if (Q_strcasecmp(command, "on") == 0)
+	{
+		enabled = true;
+		return;
+	}
+
+	if (Q_strcasecmp(command, "off") == 0)
+	{
+		if (playing)
+			CDAudio_Stop();
+		enabled = false;
+		return;
+	}
+
+	if (Q_strcasecmp(command, "reset") == 0)
+	{
+		enabled = true;
+		if (playing)
+			CDAudio_Stop();
+		for (n = 0; n < 100; n++)
+			remap[n] = n;
+		CDAudio_GetAudioDiskInfo();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "remap") == 0)
+	{
+		ret = Cmd_Argc() - 2;
+		if (ret <= 0)
+		{
+			for (n = 1; n < 100; n++)
+				if (remap[n] != n)
+					Com_Printf("  %u -> %u\n", n, remap[n]);
+			return;
+		}
+		for (n = 1; n <= ret; n++)
+			remap[n] = atoi(Cmd_Argv (n+1));
+		return;
+	}
+
+	if (Q_strcasecmp(command, "close") == 0)
+	{
+		CDAudio_CloseDoor();
+		return;
+	}
+
+	if (!cdValid)
+	{
+		CDAudio_GetAudioDiskInfo();
+		if (!cdValid)
+		{
+			Com_Printf("No CD in player.\n");
+			return;
+		}
+	}
+
+	if (Q_strcasecmp(command, "play") == 0)
+	{
+		CDAudio_Play(atoi(Cmd_Argv (2)), false);
+		return;
+	}
+
+	if (Q_strcasecmp(command, "loop") == 0)
+	{
+		CDAudio_Play(atoi(Cmd_Argv (2)), true);
+		return;
+	}
+
+	if (Q_strcasecmp(command, "stop") == 0)
+	{
+		CDAudio_Stop();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "pause") == 0)
+	{
+		CDAudio_Pause();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "resume") == 0)
+	{
+		CDAudio_Resume();
+		return;
+	}
+
+	if (Q_strcasecmp(command, "eject") == 0)
+	{
+		if (playing)
+			CDAudio_Stop();
+		CDAudio_Eject();
+		cdValid = false;
+		return;
+	}
+
+	if (Q_strcasecmp(command, "info") == 0)
+	{
+		Com_Printf("%u tracks\n", maxTrack);
+		if (playing)
+			Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+		else if (wasPlaying)
+			Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+		return;
+	}
+}
+
+
+LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+	if (lParam != wDeviceID)
+		return 1;
+
+	switch (wParam)
+	{
+		case MCI_NOTIFY_SUCCESSFUL:
+			if (playing)
+			{
+				playing = false;
+				if (playLooping)
+				{
+					// if the track has played the given number of times,
+					// go to the ambient track
+					if (++loopcounter >= cd_loopcount->value)
+						CDAudio_Play2(cd_looptrack->value, true);
+					else
+						CDAudio_Play2(playTrack, true);
+				}
+			}
+			break;
+
+		case MCI_NOTIFY_ABORTED:
+		case MCI_NOTIFY_SUPERSEDED:
+			break;
+
+		case MCI_NOTIFY_FAILURE:
+			Com_DPrintf("MCI_NOTIFY_FAILURE\n");
+			CDAudio_Stop ();
+			cdValid = false;
+			break;
+
+		default:
+			Com_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
+			return 1;
+	}
+
+	return 0;
+}
+
+
+void CDAudio_Update(void)
+{
+	if ( cd_nocd->value != !enabled )
+	{
+		if ( cd_nocd->value )
+		{
+			CDAudio_Stop();
+			enabled = false;
+		}
+		else
+		{
+			enabled = true;
+			CDAudio_Resume ();
+		}
+	}
+}
+
+
+int CDAudio_Init(void)
+{
+	DWORD	dwReturn;
+	MCI_OPEN_PARMS	mciOpenParms;
+    MCI_SET_PARMS	mciSetParms;
+	int				n;
+
+	cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
+	cd_loopcount = Cvar_Get ("cd_loopcount", "4", 0);
+	cd_looptrack = Cvar_Get ("cd_looptrack", "11", 0);
+	if ( cd_nocd->value)
+		return -1;
+
+	mciOpenParms.lpstrDeviceType = "cdaudio";
+	if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms))
+	{
+		Com_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
+		return -1;
+	}
+	wDeviceID = mciOpenParms.wDeviceID;
+
+    // Set the time format to track/minute/second/frame (TMSF).
+    mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
+    {
+		Com_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
+        mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
+		return -1;
+    }
+
+	for (n = 0; n < 100; n++)
+		remap[n] = n;
+	initialized = true;
+	enabled = true;
+
+	if (CDAudio_GetAudioDiskInfo())
+	{
+//		Com_Printf("CDAudio_Init: No CD in player.\n");
+		cdValid = false;
+		enabled = false;
+	}
+
+	Cmd_AddCommand ("cd", CD_f);
+
+	Com_Printf("CD Audio Initialized\n");
+
+	return 0;
+}
+
+
+void CDAudio_Shutdown(void)
+{
+	if (!initialized)
+		return;
+	CDAudio_Stop();
+	if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
+		Com_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
+}
+
+
+/*
+===========
+CDAudio_Activate
+
+Called when the main window gains or loses focus.
+The window have been destroyed and recreated
+between a deactivate and an activate.
+===========
+*/
+void CDAudio_Activate (qboolean active)
+{
+	if (active)
+		CDAudio_Resume ();
+	else
+		CDAudio_Pause ();
+}
--- /dev/null
+++ b/win32/conproc.c
@@ -1,0 +1,431 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// conproc.c -- support for qhost
+#include <stdio.h>
+#include <process.h>
+#include <windows.h>
+#include "conproc.h"
+
+#define CCOM_WRITE_TEXT		0x2
+// Param1 : Text
+
+#define CCOM_GET_TEXT		0x3
+// Param1 : Begin line
+// Param2 : End line
+
+#define CCOM_GET_SCR_LINES	0x4
+// No params
+
+#define CCOM_SET_SCR_LINES	0x5
+// Param1 : Number of lines
+
+
+HANDLE	heventDone;
+HANDLE	hfileBuffer;
+HANDLE	heventChildSend;
+HANDLE	heventParentSend;
+HANDLE	hStdout;
+HANDLE	hStdin;
+
+unsigned _stdcall RequestProc (void *arg);
+LPVOID GetMappedBuffer (HANDLE hfileBuffer);
+void ReleaseMappedBuffer (LPVOID pBuffer);
+BOOL GetScreenBufferLines (int *piLines);
+BOOL SetScreenBufferLines (int iLines);
+BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine);
+BOOL WriteText (LPCTSTR szText);
+int CharToCode (char c);
+BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy);
+
+int		ccom_argc;
+char	**ccom_argv;
+
+/*
+================
+CCheckParm
+
+Returns the position (1 to argc-1) in the program's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+int CCheckParm (char *parm)
+{
+	int             i;
+	
+	for (i=1 ; i<ccom_argc ; i++)
+	{
+		if (!ccom_argv[i])
+			continue;
+		if (!strcmp (parm,ccom_argv[i]))
+			return i;
+	}
+		
+	return 0;
+}
+
+
+void InitConProc (int argc, char **argv)
+{
+	unsigned	threadAddr;
+	HANDLE		hFile;
+	HANDLE		heventParent;
+	HANDLE		heventChild;
+	int			t;
+
+	ccom_argc = argc;
+	ccom_argv = argv;
+
+// give QHOST a chance to hook into the console
+	if ((t = CCheckParm ("-HFILE")) > 0)
+	{
+		if (t < argc)
+			hFile = (HANDLE)atoi (ccom_argv[t+1]);
+	}
+		
+	if ((t = CCheckParm ("-HPARENT")) > 0)
+	{
+		if (t < argc)
+			heventParent = (HANDLE)atoi (ccom_argv[t+1]);
+	}
+		
+	if ((t = CCheckParm ("-HCHILD")) > 0)
+	{
+		if (t < argc)
+			heventChild = (HANDLE)atoi (ccom_argv[t+1]);
+	}
+
+
+// ignore if we don't have all the events.
+	if (!hFile || !heventParent || !heventChild)
+	{
+		printf ("Qhost not present.\n");
+		return;
+	}
+
+	printf ("Initializing for qhost.\n");
+
+	hfileBuffer = hFile;
+	heventParentSend = heventParent;
+	heventChildSend = heventChild;
+
+// so we'll know when to go away.
+	heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+	if (!heventDone)
+	{
+		printf ("Couldn't create heventDone\n");
+		return;
+	}
+
+	if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr))
+	{
+		CloseHandle (heventDone);
+		printf ("Couldn't create QHOST thread\n");
+		return;
+	}
+
+// save off the input/output handles.
+	hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
+	hStdin = GetStdHandle (STD_INPUT_HANDLE);
+
+// force 80 character width, at least 25 character height
+	SetConsoleCXCY (hStdout, 80, 25);
+}
+
+
+void DeinitConProc (void)
+{
+	if (heventDone)
+		SetEvent (heventDone);
+}
+
+
+unsigned _stdcall RequestProc (void *arg)
+{
+	int		*pBuffer;
+	DWORD	dwRet;
+	HANDLE	heventWait[2];
+	int		iBeginLine, iEndLine;
+	
+	heventWait[0] = heventParentSend;
+	heventWait[1] = heventDone;
+
+	while (1)
+	{
+		dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE);
+
+	// heventDone fired, so we're exiting.
+		if (dwRet == WAIT_OBJECT_0 + 1)	
+			break;
+
+		pBuffer = (int *) GetMappedBuffer (hfileBuffer);
+		
+	// hfileBuffer is invalid.  Just leave.
+		if (!pBuffer)
+		{
+			printf ("Invalid hfileBuffer\n");
+			break;
+		}
+
+		switch (pBuffer[0])
+		{
+			case CCOM_WRITE_TEXT:
+			// Param1 : Text
+				pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
+				break;
+
+			case CCOM_GET_TEXT:
+			// Param1 : Begin line
+			// Param2 : End line
+				iBeginLine = pBuffer[1];
+				iEndLine = pBuffer[2];
+				pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine, 
+									   iEndLine);
+				break;
+
+			case CCOM_GET_SCR_LINES:
+			// No params
+				pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
+				break;
+
+			case CCOM_SET_SCR_LINES:
+			// Param1 : Number of lines
+				pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
+				break;
+		}
+
+		ReleaseMappedBuffer (pBuffer);
+		SetEvent (heventChildSend);
+	}
+
+	_endthreadex (0);
+	return 0;
+}
+
+
+LPVOID GetMappedBuffer (HANDLE hfileBuffer)
+{
+	LPVOID pBuffer;
+
+	pBuffer = MapViewOfFile (hfileBuffer,
+							FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
+
+	return pBuffer;
+}
+
+
+void ReleaseMappedBuffer (LPVOID pBuffer)
+{
+	UnmapViewOfFile (pBuffer);
+}
+
+
+BOOL GetScreenBufferLines (int *piLines)
+{
+	CONSOLE_SCREEN_BUFFER_INFO	info;							  
+	BOOL						bRet;
+
+	bRet = GetConsoleScreenBufferInfo (hStdout, &info);
+		
+	if (bRet)
+		*piLines = info.dwSize.Y;
+
+	return bRet;
+}
+
+
+BOOL SetScreenBufferLines (int iLines)
+{
+
+	return SetConsoleCXCY (hStdout, 80, iLines);
+}
+
+
+BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
+{
+	COORD	coord;
+	DWORD	dwRead;
+	BOOL	bRet;
+
+	coord.X = 0;
+	coord.Y = iBeginLine;
+
+	bRet = ReadConsoleOutputCharacter(
+		hStdout,
+		pszText,
+		80 * (iEndLine - iBeginLine + 1),
+		coord,
+		&dwRead);
+
+	// Make sure it's null terminated.
+	if (bRet)
+		pszText[dwRead] = '\0';
+
+	return bRet;
+}
+
+
+BOOL WriteText (LPCTSTR szText)
+{
+	DWORD			dwWritten;
+	INPUT_RECORD	rec;
+	char			upper, *sz;
+
+	sz = (LPTSTR) szText;
+
+	while (*sz)
+	{
+	// 13 is the code for a carriage return (\n) instead of 10.
+		if (*sz == 10)
+			*sz = 13;
+
+		upper = toupper(*sz);
+
+		rec.EventType = KEY_EVENT;
+		rec.Event.KeyEvent.bKeyDown = TRUE;
+		rec.Event.KeyEvent.wRepeatCount = 1;
+		rec.Event.KeyEvent.wVirtualKeyCode = upper;
+		rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
+		rec.Event.KeyEvent.uChar.AsciiChar = *sz;
+		rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
+		rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; 
+
+		WriteConsoleInput(
+			hStdin,
+			&rec,
+			1,
+			&dwWritten);
+
+		rec.Event.KeyEvent.bKeyDown = FALSE;
+
+		WriteConsoleInput(
+			hStdin,
+			&rec,
+			1,
+			&dwWritten);
+
+		sz++;
+	}
+
+	return TRUE;
+}
+
+
+int CharToCode (char c)
+{
+	char upper;
+		
+	upper = toupper(c);
+
+	switch (c)
+	{
+		case 13:
+			return 28;
+
+		default:
+			break;
+	}
+
+	if (isalpha(c))
+		return (30 + upper - 65); 
+
+	if (isdigit(c))
+		return (1 + upper - 47);
+
+	return c;
+}
+
+
+BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
+{
+	CONSOLE_SCREEN_BUFFER_INFO	info;
+	COORD						coordMax;
+ 
+	coordMax = GetLargestConsoleWindowSize(hStdout);
+
+	if (cy > coordMax.Y)
+		cy = coordMax.Y;
+
+	if (cx > coordMax.X)
+		cx = coordMax.X;
+ 
+	if (!GetConsoleScreenBufferInfo(hStdout, &info))
+		return FALSE;
+ 
+// height
+    info.srWindow.Left = 0;         
+    info.srWindow.Right = info.dwSize.X - 1;                
+    info.srWindow.Top = 0;
+    info.srWindow.Bottom = cy - 1;          
+ 
+	if (cy < info.dwSize.Y)
+	{
+		if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+			return FALSE;
+ 
+		info.dwSize.Y = cy;
+ 
+		if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+			return FALSE;
+    }
+    else if (cy > info.dwSize.Y)
+    {
+		info.dwSize.Y = cy;
+ 
+		if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+			return FALSE;
+ 
+		if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+			return FALSE;
+    }
+ 
+	if (!GetConsoleScreenBufferInfo(hStdout, &info))
+		return FALSE;
+ 
+// width
+	info.srWindow.Left = 0;         
+	info.srWindow.Right = cx - 1;
+	info.srWindow.Top = 0;
+	info.srWindow.Bottom = info.dwSize.Y - 1;               
+ 
+	if (cx < info.dwSize.X)
+	{
+		if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+			return FALSE;
+ 
+		info.dwSize.X = cx;
+    
+		if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+			return FALSE;
+	}
+	else if (cx > info.dwSize.X)
+	{
+		info.dwSize.X = cx;
+ 
+		if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+			return FALSE;
+ 
+		if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+			return FALSE;
+	}
+ 
+	return TRUE;
+}
+     
--- /dev/null
+++ b/win32/conproc.h
@@ -1,0 +1,24 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// conproc.h -- support for qhost
+
+void InitConProc (int argc, char **argv);
+void DeinitConProc (void);
+
--- /dev/null
+++ b/win32/glw_imp.c
@@ -1,0 +1,616 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+** GLW_IMP.C
+**
+** This file contains ALL Win32 specific stuff having to do with the
+** OpenGL refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** GLimp_EndFrame
+** GLimp_Init
+** GLimp_Shutdown
+** GLimp_SwitchFullscreen
+**
+*/
+#include <assert.h>
+#include <windows.h>
+#include "../ref_gl/gl_local.h"
+#include "glw_win.h"
+#include "winquake.h"
+
+static qboolean GLimp_SwitchFullscreen( int width, int height );
+qboolean GLimp_InitGL (void);
+
+glwstate_t glw_state;
+
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_ref;
+
+static qboolean VerifyDriver( void )
+{
+	char buffer[1024];
+
+	strcpy( buffer, qglGetString( GL_RENDERER ) );
+	strlwr( buffer );
+	if ( strcmp( buffer, "gdi generic" ) == 0 )
+		if ( !glw_state.mcd_accelerated )
+			return false;
+	return true;
+}
+
+/*
+** VID_CreateWindow
+*/
+#define	WINDOW_CLASS_NAME	"Quake 2"
+
+qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
+{
+	WNDCLASS		wc;
+	RECT			r;
+	cvar_t			*vid_xpos, *vid_ypos;
+	int				stylebits;
+	int				x, y, w, h;
+	int				exstyle;
+
+	/* Register the frame class */
+    wc.style         = 0;
+    wc.lpfnWndProc   = (WNDPROC)glw_state.wndproc;
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = glw_state.hInstance;
+    wc.hIcon         = 0;
+    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
+	wc.hbrBackground = (void *)COLOR_GRAYTEXT;
+    wc.lpszMenuName  = 0;
+    wc.lpszClassName = WINDOW_CLASS_NAME;
+
+    if (!RegisterClass (&wc) )
+		ri.Sys_Error (ERR_FATAL, "Couldn't register window class");
+
+	if (fullscreen)
+	{
+		exstyle = WS_EX_TOPMOST;
+		stylebits = WS_POPUP|WS_VISIBLE;
+	}
+	else
+	{
+		exstyle = 0;
+		stylebits = WINDOW_STYLE;
+	}
+
+	r.left = 0;
+	r.top = 0;
+	r.right  = width;
+	r.bottom = height;
+
+	AdjustWindowRect (&r, stylebits, FALSE);
+
+	w = r.right - r.left;
+	h = r.bottom - r.top;
+
+	if (fullscreen)
+	{
+		x = 0;
+		y = 0;
+	}
+	else
+	{
+		vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
+		vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
+		x = vid_xpos->value;
+		y = vid_ypos->value;
+	}
+
+	glw_state.hWnd = CreateWindowEx (
+		 exstyle, 
+		 WINDOW_CLASS_NAME,
+		 "Quake 2",
+		 stylebits,
+		 x, y, w, h,
+		 NULL,
+		 NULL,
+		 glw_state.hInstance,
+		 NULL);
+
+	if (!glw_state.hWnd)
+		ri.Sys_Error (ERR_FATAL, "Couldn't create window");
+	
+	ShowWindow( glw_state.hWnd, SW_SHOW );
+	UpdateWindow( glw_state.hWnd );
+
+	// init all the gl stuff for the window
+	if (!GLimp_InitGL ())
+	{
+		ri.Con_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n");
+		return false;
+	}
+
+	SetForegroundWindow( glw_state.hWnd );
+	SetFocus( glw_state.hWnd );
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (width, height);
+
+	return true;
+}
+
+
+/*
+** GLimp_SetMode
+*/
+rserr_t GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+	int width, height;
+	const char *win_fs[] = { "W", "FS" };
+
+	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
+
+	ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
+
+	if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
+	{
+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+		return rserr_invalid_mode;
+	}
+
+	ri.Con_Printf( PRINT_ALL, " %d %d %s\n", width, height, win_fs[fullscreen] );
+
+	// destroy the existing window
+	if (glw_state.hWnd)
+	{
+		GLimp_Shutdown ();
+	}
+
+	// do a CDS if needed
+	if ( fullscreen )
+	{
+		DEVMODE dm;
+
+		ri.Con_Printf( PRINT_ALL, "...attempting fullscreen\n" );
+
+		memset( &dm, 0, sizeof( dm ) );
+
+		dm.dmSize = sizeof( dm );
+
+		dm.dmPelsWidth  = width;
+		dm.dmPelsHeight = height;
+		dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;
+
+		if ( gl_bitdepth->value != 0 )
+		{
+			dm.dmBitsPerPel = gl_bitdepth->value;
+			dm.dmFields |= DM_BITSPERPEL;
+			ri.Con_Printf( PRINT_ALL, "...using gl_bitdepth of %d\n", ( int ) gl_bitdepth->value );
+		}
+		else
+		{
+			HDC hdc = GetDC( NULL );
+			int bitspixel = GetDeviceCaps( hdc, BITSPIXEL );
+
+			ri.Con_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel );
+
+			ReleaseDC( 0, hdc );
+		}
+
+		ri.Con_Printf( PRINT_ALL, "...calling CDS: " );
+		if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
+		{
+			*pwidth = width;
+			*pheight = height;
+
+			gl_state.fullscreen = true;
+
+			ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+			if ( !VID_CreateWindow (width, height, true) )
+				return rserr_invalid_mode;
+
+			return rserr_ok;
+		}
+		else
+		{
+			*pwidth = width;
+			*pheight = height;
+
+			ri.Con_Printf( PRINT_ALL, "failed\n" );
+
+			ri.Con_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" );
+
+			dm.dmPelsWidth = width * 2;
+			dm.dmPelsHeight = height;
+			dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+
+			if ( gl_bitdepth->value != 0 )
+			{
+				dm.dmBitsPerPel = gl_bitdepth->value;
+				dm.dmFields |= DM_BITSPERPEL;
+			}
+
+			/*
+			** our first CDS failed, so maybe we're running on some weird dual monitor
+			** system 
+			*/
+			if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
+			{
+				ri.Con_Printf( PRINT_ALL, " failed\n" );
+
+				ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
+
+				ChangeDisplaySettings( 0, 0 );
+
+				*pwidth = width;
+				*pheight = height;
+				gl_state.fullscreen = false;
+				if ( !VID_CreateWindow (width, height, false) )
+					return rserr_invalid_mode;
+				return rserr_invalid_fullscreen;
+			}
+			else
+			{
+				ri.Con_Printf( PRINT_ALL, " ok\n" );
+				if ( !VID_CreateWindow (width, height, true) )
+					return rserr_invalid_mode;
+
+				gl_state.fullscreen = true;
+				return rserr_ok;
+			}
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
+
+		ChangeDisplaySettings( 0, 0 );
+
+		*pwidth = width;
+		*pheight = height;
+		gl_state.fullscreen = false;
+		if ( !VID_CreateWindow (width, height, false) )
+			return rserr_invalid_mode;
+	}
+
+	return rserr_ok;
+}
+
+/*
+** GLimp_Shutdown
+**
+** This routine does all OS specific shutdown procedures for the OpenGL
+** subsystem.  Under OpenGL this means NULLing out the current DC and
+** HGLRC, deleting the rendering context, and releasing the DC acquired
+** for the window.  The state structure is also nulled out.
+**
+*/
+void GLimp_Shutdown( void )
+{
+	if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) )
+		ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n");
+	if ( glw_state.hGLRC )
+	{
+		if (  qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) )
+			ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n");
+		glw_state.hGLRC = NULL;
+	}
+	if (glw_state.hDC)
+	{
+		if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) )
+			ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" );
+		glw_state.hDC   = NULL;
+	}
+	if (glw_state.hWnd)
+	{
+		DestroyWindow (	glw_state.hWnd );
+		glw_state.hWnd = NULL;
+	}
+
+	if ( glw_state.log_fp )
+	{
+		fclose( glw_state.log_fp );
+		glw_state.log_fp = 0;
+	}
+
+	UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance);
+
+	if ( gl_state.fullscreen )
+	{
+		ChangeDisplaySettings( 0, 0 );
+		gl_state.fullscreen = false;
+	}
+}
+
+
+/*
+** GLimp_Init
+**
+** This routine is responsible for initializing the OS specific portions
+** of OpenGL.  Under Win32 this means dealing with the pixelformats and
+** doing the wgl interface stuff.
+*/
+qboolean GLimp_Init( void *hinstance, void *wndproc )
+{
+#define OSR2_BUILD_NUMBER 1111
+
+	OSVERSIONINFO	vinfo;
+
+	vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+
+	glw_state.allowdisplaydepthchange = false;
+
+	if ( GetVersionEx( &vinfo) )
+	{
+		if ( vinfo.dwMajorVersion > 4 )
+		{
+			glw_state.allowdisplaydepthchange = true;
+		}
+		else if ( vinfo.dwMajorVersion == 4 )
+		{
+			if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+			{
+				glw_state.allowdisplaydepthchange = true;
+			}
+			else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+			{
+				if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
+				{
+					glw_state.allowdisplaydepthchange = true;
+				}
+			}
+		}
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" );
+		return false;
+	}
+
+	glw_state.hInstance = ( HINSTANCE ) hinstance;
+	glw_state.wndproc = wndproc;
+
+	return true;
+}
+
+qboolean GLimp_InitGL (void)
+{
+    PIXELFORMATDESCRIPTOR pfd = 
+	{
+		sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
+		1,								// version number
+		PFD_DRAW_TO_WINDOW |			// support window
+		PFD_SUPPORT_OPENGL |			// support OpenGL
+		PFD_DOUBLEBUFFER,				// double buffered
+		PFD_TYPE_RGBA,					// RGBA type
+		24,								// 24-bit color depth
+		0, 0, 0, 0, 0, 0,				// color bits ignored
+		0,								// no alpha buffer
+		0,								// shift bit ignored
+		0,								// no accumulation buffer
+		0, 0, 0, 0, 					// accum bits ignored
+		32,								// 32-bit z-buffer	
+		0,								// no stencil buffer
+		0,								// no auxiliary buffer
+		PFD_MAIN_PLANE,					// main layer
+		0,								// reserved
+		0, 0, 0							// layer masks ignored
+    };
+    int  pixelformat;
+	cvar_t *stereo;
+	
+	stereo = ri.Cvar_Get( "cl_stereo", "0", 0 );
+
+	/*
+	** set PFD_STEREO if necessary
+	*/
+	if ( stereo->value != 0 )
+	{
+		ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" );
+		pfd.dwFlags |= PFD_STEREO;
+		gl_state.stereo_enabled = true;
+	}
+	else
+	{
+		gl_state.stereo_enabled = false;
+	}
+
+	/*
+	** figure out if we're running on a minidriver or not
+	*/
+	if ( strstr( gl_driver->string, "opengl32" ) != 0 )
+		glw_state.minidriver = false;
+	else
+		glw_state.minidriver = true;
+
+	/*
+	** Get a DC for the specified window
+	*/
+	if ( glw_state.hDC != NULL )
+		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" );
+
+    if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
+	{
+		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" );
+		return false;
+	}
+
+	if ( glw_state.minidriver )
+	{
+		if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
+		{
+			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n");
+			return false;
+		}
+		if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
+		{
+			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n");
+			return false;
+		}
+		qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
+	}
+	else
+	{
+		if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
+		{
+			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n");
+			return false;
+		}
+		if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
+		{
+			ri.Con_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n");
+			return false;
+		}
+		DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
+
+		if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
+		{
+			extern cvar_t *gl_allow_software;
+
+			if ( gl_allow_software->value )
+				glw_state.mcd_accelerated = true;
+			else
+				glw_state.mcd_accelerated = false;
+		}
+		else
+		{
+			glw_state.mcd_accelerated = true;
+		}
+	}
+
+	/*
+	** report if stereo is desired but unavailable
+	*/
+	if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) ) 
+	{
+		ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
+		ri.Cvar_SetValue( "cl_stereo", 0 );
+		gl_state.stereo_enabled = false;
+	}
+
+	/*
+	** startup the OpenGL subsystem by creating a context and making
+	** it current
+	*/
+	if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
+	{
+		ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n");
+
+		goto fail;
+	}
+
+    if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
+	{
+		ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n");
+
+		goto fail;
+	}
+
+	if ( !VerifyDriver() )
+	{
+		ri.Con_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected\n" );
+		goto fail;
+	}
+
+	/*
+	** print out PFD specifics 
+	*/
+	ri.Con_Printf( PRINT_ALL, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );
+
+	return true;
+
+fail:
+	if ( glw_state.hGLRC )
+	{
+		qwglDeleteContext( glw_state.hGLRC );
+		glw_state.hGLRC = NULL;
+	}
+
+	if ( glw_state.hDC )
+	{
+		ReleaseDC( glw_state.hWnd, glw_state.hDC );
+		glw_state.hDC = NULL;
+	}
+	return false;
+}
+
+/*
+** GLimp_BeginFrame
+*/
+void GLimp_BeginFrame( float camera_separation )
+{
+	if ( gl_bitdepth->modified )
+	{
+		if ( gl_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange )
+		{
+			ri.Cvar_SetValue( "gl_bitdepth", 0 );
+			ri.Con_Printf( PRINT_ALL, "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
+		}
+		gl_bitdepth->modified = false;
+	}
+
+	if ( camera_separation < 0 && gl_state.stereo_enabled )
+	{
+		qglDrawBuffer( GL_BACK_LEFT );
+	}
+	else if ( camera_separation > 0 && gl_state.stereo_enabled )
+	{
+		qglDrawBuffer( GL_BACK_RIGHT );
+	}
+	else
+	{
+		qglDrawBuffer( GL_BACK );
+	}
+}
+
+/*
+** GLimp_EndFrame
+** 
+** Responsible for doing a swapbuffers and possibly for other stuff
+** as yet to be determined.  Probably better not to make this a GLimp
+** function and instead do a call to GLimp_SwapBuffers.
+*/
+void GLimp_EndFrame (void)
+{
+	int		err;
+
+	err = qglGetError();
+	assert( err == GL_NO_ERROR );
+
+	if ( stricmp( gl_drawbuffer->string, "GL_BACK" ) == 0 )
+	{
+		if ( !qwglSwapBuffers( glw_state.hDC ) )
+			ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" );
+	}
+}
+
+/*
+** GLimp_AppActivate
+*/
+void GLimp_AppActivate( qboolean active )
+{
+	if ( active )
+	{
+		SetForegroundWindow( glw_state.hWnd );
+		ShowWindow( glw_state.hWnd, SW_RESTORE );
+	}
+	else
+	{
+		if ( vid_fullscreen->value )
+			ShowWindow( glw_state.hWnd, SW_MINIMIZE );
+	}
+}
--- /dev/null
+++ b/win32/glw_win.h
@@ -1,0 +1,47 @@
+/*
+Copyright (C) 1997-2001 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 _WIN32
+#  error You should not be including this file on this platform
+#endif
+
+#ifndef __GLW_WIN_H__
+#define __GLW_WIN_H__
+
+typedef struct
+{
+	HINSTANCE	hInstance;
+	void	*wndproc;
+
+	HDC     hDC;			// handle to device context
+	HWND    hWnd;			// handle to window
+	HGLRC   hGLRC;			// handle to GL rendering context
+
+	HINSTANCE hinstOpenGL;	// HINSTANCE for the OpenGL library
+
+	qboolean minidriver;
+	qboolean allowdisplaydepthchange;
+	qboolean mcd_accelerated;
+
+	FILE *log_fp;
+} glwstate_t;
+
+extern glwstate_t glw_state;
+
+#endif
--- /dev/null
+++ b/win32/in_win.c
@@ -1,0 +1,889 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// in_win.c -- windows 95 mouse and joystick code
+// 02/21/97 JCB Added extended DirectInput code to support external controllers.
+
+#include "../client/client.h"
+#include "winquake.h"
+
+extern	unsigned	sys_msg_time;
+
+// joystick defines and variables
+// where should defines be moved?
+#define JOY_ABSOLUTE_AXIS	0x00000000		// control like a joystick
+#define JOY_RELATIVE_AXIS	0x00000010		// control like a mouse, spinner, trackball
+#define	JOY_MAX_AXES		6				// X, Y, Z, R, U, V
+#define JOY_AXIS_X			0
+#define JOY_AXIS_Y			1
+#define JOY_AXIS_Z			2
+#define JOY_AXIS_R			3
+#define JOY_AXIS_U			4
+#define JOY_AXIS_V			5
+
+enum _ControlList
+{
+	AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn, AxisUp
+};
+
+DWORD	dwAxisFlags[JOY_MAX_AXES] =
+{
+	JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
+};
+
+DWORD	dwAxisMap[JOY_MAX_AXES];
+DWORD	dwControlMap[JOY_MAX_AXES];
+PDWORD	pdwRawValue[JOY_MAX_AXES];
+
+cvar_t	*in_mouse;
+cvar_t	*in_joystick;
+
+
+// none of these cvars are saved over a session
+// this means that advanced controller configuration needs to be executed
+// each time.  this avoids any problems with getting back to a default usage
+// or when changing from one controller to another.  this way at least something
+// works.
+cvar_t	*joy_name;
+cvar_t	*joy_advanced;
+cvar_t	*joy_advaxisx;
+cvar_t	*joy_advaxisy;
+cvar_t	*joy_advaxisz;
+cvar_t	*joy_advaxisr;
+cvar_t	*joy_advaxisu;
+cvar_t	*joy_advaxisv;
+cvar_t	*joy_forwardthreshold;
+cvar_t	*joy_sidethreshold;
+cvar_t	*joy_pitchthreshold;
+cvar_t	*joy_yawthreshold;
+cvar_t	*joy_forwardsensitivity;
+cvar_t	*joy_sidesensitivity;
+cvar_t	*joy_pitchsensitivity;
+cvar_t	*joy_yawsensitivity;
+cvar_t	*joy_upthreshold;
+cvar_t	*joy_upsensitivity;
+
+qboolean	joy_avail, joy_advancedinit, joy_haspov;
+DWORD		joy_oldbuttonstate, joy_oldpovstate;
+
+int			joy_id;
+DWORD		joy_flags;
+DWORD		joy_numbuttons;
+
+static JOYINFOEX	ji;
+
+qboolean	in_appactive;
+
+// forward-referenced functions
+void IN_StartupJoystick (void);
+void Joy_AdvancedUpdate_f (void);
+void IN_JoyMove (usercmd_t *cmd);
+
+/*
+============================================================
+
+  MOUSE CONTROL
+
+============================================================
+*/
+
+// mouse variables
+cvar_t	*m_filter;
+
+qboolean	mlooking;
+
+void IN_MLookDown (void) { mlooking = true; }
+void IN_MLookUp (void) {
+mlooking = false;
+if (!freelook->value && lookspring->value)
+		IN_CenterView ();
+}
+
+int			mouse_buttons;
+int			mouse_oldbuttonstate;
+POINT		current_pos;
+int			mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
+
+int			old_x, old_y;
+
+qboolean	mouseactive;	// false when not focus app
+
+qboolean	restore_spi;
+qboolean	mouseinitialized;
+int		originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
+qboolean	mouseparmsvalid;
+
+int			window_center_x, window_center_y;
+RECT		window_rect;
+
+
+/*
+===========
+IN_ActivateMouse
+
+Called when the window gains focus or changes in some way
+===========
+*/
+void IN_ActivateMouse (void)
+{
+	int		width, height;
+
+	if (!mouseinitialized)
+		return;
+	if (!in_mouse->value)
+	{
+		mouseactive = false;
+		return;
+	}
+	if (mouseactive)
+		return;
+
+	mouseactive = true;
+
+	if (mouseparmsvalid)
+		restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
+
+	width = GetSystemMetrics (SM_CXSCREEN);
+	height = GetSystemMetrics (SM_CYSCREEN);
+
+	GetWindowRect ( cl_hwnd, &window_rect);
+	if (window_rect.left < 0)
+		window_rect.left = 0;
+	if (window_rect.top < 0)
+		window_rect.top = 0;
+	if (window_rect.right >= width)
+		window_rect.right = width-1;
+	if (window_rect.bottom >= height-1)
+		window_rect.bottom = height-1;
+
+	window_center_x = (window_rect.right + window_rect.left)/2;
+	window_center_y = (window_rect.top + window_rect.bottom)/2;
+
+	SetCursorPos (window_center_x, window_center_y);
+
+	old_x = window_center_x;
+	old_y = window_center_y;
+
+	SetCapture ( cl_hwnd );
+	ClipCursor (&window_rect);
+	while (ShowCursor (FALSE) >= 0)
+		;
+}
+
+
+/*
+===========
+IN_DeactivateMouse
+
+Called when the window loses focus
+===========
+*/
+void IN_DeactivateMouse (void)
+{
+	if (!mouseinitialized)
+		return;
+	if (!mouseactive)
+		return;
+
+	if (restore_spi)
+		SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
+
+	mouseactive = false;
+
+	ClipCursor (NULL);
+	ReleaseCapture ();
+	while (ShowCursor (TRUE) < 0)
+		;
+}
+
+
+
+/*
+===========
+IN_StartupMouse
+===========
+*/
+void IN_StartupMouse (void)
+{
+	cvar_t		*cv;
+
+	cv = Cvar_Get ("in_initmouse", "1", CVAR_NOSET);
+	if ( !cv->value ) 
+		return; 
+
+	mouseinitialized = true;
+	mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
+	mouse_buttons = 3;
+}
+
+/*
+===========
+IN_MouseEvent
+===========
+*/
+void IN_MouseEvent (int mstate)
+{
+	int		i;
+
+	if (!mouseinitialized)
+		return;
+
+// perform button actions
+	for (i=0 ; i<mouse_buttons ; i++)
+	{
+		if ( (mstate & (1<<i)) &&
+			!(mouse_oldbuttonstate & (1<<i)) )
+		{
+			Key_Event (K_MOUSE1 + i, true, sys_msg_time);
+		}
+
+		if ( !(mstate & (1<<i)) &&
+			(mouse_oldbuttonstate & (1<<i)) )
+		{
+				Key_Event (K_MOUSE1 + i, false, sys_msg_time);
+		}
+	}	
+		
+	mouse_oldbuttonstate = mstate;
+}
+
+
+/*
+===========
+IN_MouseMove
+===========
+*/
+void IN_MouseMove (usercmd_t *cmd)
+{
+	int		mx, my;
+
+	if (!mouseactive)
+		return;
+
+	// find mouse movement
+	if (!GetCursorPos (&current_pos))
+		return;
+
+	mx = current_pos.x - window_center_x;
+	my = current_pos.y - window_center_y;
+
+#if 0
+	if (!mx && !my)
+		return;
+#endif
+
+	if (m_filter->value)
+	{
+		mouse_x = (mx + old_mouse_x) * 0.5;
+		mouse_y = (my + old_mouse_y) * 0.5;
+	}
+	else
+	{
+		mouse_x = mx;
+		mouse_y = my;
+	}
+
+	old_mouse_x = mx;
+	old_mouse_y = my;
+
+	mouse_x *= sensitivity->value;
+	mouse_y *= sensitivity->value;
+
+// add mouse X/Y movement to cmd
+	if ( (in_strafe.state & 1) || (lookstrafe->value && mlooking ))
+		cmd->sidemove += m_side->value * mouse_x;
+	else
+		cl.viewangles[YAW] -= m_yaw->value * mouse_x;
+
+	if ( (mlooking || freelook->value) && !(in_strafe.state & 1))
+	{
+		cl.viewangles[PITCH] += m_pitch->value * mouse_y;
+	}
+	else
+	{
+		cmd->forwardmove -= m_forward->value * mouse_y;
+	}
+
+	// force the mouse to the center, so there's room to move
+	if (mx || my)
+		SetCursorPos (window_center_x, window_center_y);
+}
+
+
+/*
+=========================================================================
+
+VIEW CENTERING
+
+=========================================================================
+*/
+
+cvar_t	*v_centermove;
+cvar_t	*v_centerspeed;
+
+
+/*
+===========
+IN_Init
+===========
+*/
+void IN_Init (void)
+{
+	// mouse variables
+	m_filter				= Cvar_Get ("m_filter",					"0",		0);
+    in_mouse				= Cvar_Get ("in_mouse",					"1",		CVAR_ARCHIVE);
+
+	// joystick variables
+	in_joystick				= Cvar_Get ("in_joystick",				"0",		CVAR_ARCHIVE);
+	joy_name				= Cvar_Get ("joy_name",					"joystick",	0);
+	joy_advanced			= Cvar_Get ("joy_advanced",				"0",		0);
+	joy_advaxisx			= Cvar_Get ("joy_advaxisx",				"0",		0);
+	joy_advaxisy			= Cvar_Get ("joy_advaxisy",				"0",		0);
+	joy_advaxisz			= Cvar_Get ("joy_advaxisz",				"0",		0);
+	joy_advaxisr			= Cvar_Get ("joy_advaxisr",				"0",		0);
+	joy_advaxisu			= Cvar_Get ("joy_advaxisu",				"0",		0);
+	joy_advaxisv			= Cvar_Get ("joy_advaxisv",				"0",		0);
+	joy_forwardthreshold	= Cvar_Get ("joy_forwardthreshold",		"0.15",		0);
+	joy_sidethreshold		= Cvar_Get ("joy_sidethreshold",		"0.15",		0);
+	joy_upthreshold  		= Cvar_Get ("joy_upthreshold",			"0.15",		0);
+	joy_pitchthreshold		= Cvar_Get ("joy_pitchthreshold",		"0.15",		0);
+	joy_yawthreshold		= Cvar_Get ("joy_yawthreshold",			"0.15",		0);
+	joy_forwardsensitivity	= Cvar_Get ("joy_forwardsensitivity",	"-1",		0);
+	joy_sidesensitivity		= Cvar_Get ("joy_sidesensitivity",		"-1",		0);
+	joy_upsensitivity		= Cvar_Get ("joy_upsensitivity",		"-1",		0);
+	joy_pitchsensitivity	= Cvar_Get ("joy_pitchsensitivity",		"1",		0);
+	joy_yawsensitivity		= Cvar_Get ("joy_yawsensitivity",		"-1",		0);
+
+	// centering
+	v_centermove			= Cvar_Get ("v_centermove",				"0.15",		0);
+	v_centerspeed			= Cvar_Get ("v_centerspeed",			"500",		0);
+
+	Cmd_AddCommand ("+mlook", IN_MLookDown);
+	Cmd_AddCommand ("-mlook", IN_MLookUp);
+
+	Cmd_AddCommand ("joy_advancedupdate", Joy_AdvancedUpdate_f);
+
+	IN_StartupMouse ();
+	IN_StartupJoystick ();
+}
+
+/*
+===========
+IN_Shutdown
+===========
+*/
+void IN_Shutdown (void)
+{
+	IN_DeactivateMouse ();
+}
+
+
+/*
+===========
+IN_Activate
+
+Called when the main window gains or loses focus.
+The window may have been destroyed and recreated
+between a deactivate and an activate.
+===========
+*/
+void IN_Activate (qboolean active)
+{
+	in_appactive = active;
+	mouseactive = !active;		// force a new window check or turn off
+}
+
+
+/*
+==================
+IN_Frame
+
+Called every frame, even if not generating commands
+==================
+*/
+void IN_Frame (void)
+{
+	if (!mouseinitialized)
+		return;
+
+	if (!in_mouse || !in_appactive)
+	{
+		IN_DeactivateMouse ();
+		return;
+	}
+
+	if ( !cl.refresh_prepped
+		|| cls.key_dest == key_console
+		|| cls.key_dest == key_menu)
+	{
+		// temporarily deactivate if in fullscreen
+		if (Cvar_VariableValue ("vid_fullscreen") == 0)
+		{
+			IN_DeactivateMouse ();
+			return;
+		}
+	}
+
+	IN_ActivateMouse ();
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void IN_Move (usercmd_t *cmd)
+{
+	IN_MouseMove (cmd);
+
+	if (ActiveApp)
+		IN_JoyMove (cmd);
+}
+
+
+/*
+===================
+IN_ClearStates
+===================
+*/
+void IN_ClearStates (void)
+{
+	mx_accum = 0;
+	my_accum = 0;
+	mouse_oldbuttonstate = 0;
+}
+
+
+/*
+=========================================================================
+
+JOYSTICK
+
+=========================================================================
+*/
+
+/* 
+=============== 
+IN_StartupJoystick 
+=============== 
+*/  
+void IN_StartupJoystick (void) 
+{ 
+	int			numdevs;
+	JOYCAPS		jc;
+	MMRESULT	mmr;
+	cvar_t		*cv;
+
+ 	// assume no joystick
+	joy_avail = false; 
+
+	// abort startup if user requests no joystick
+	cv = Cvar_Get ("in_initjoy", "1", CVAR_NOSET);
+	if ( !cv->value ) 
+		return; 
+ 
+	// verify joystick driver is present
+	if ((numdevs = joyGetNumDevs ()) == 0)
+	{
+//		Com_Printf ("\njoystick not found -- driver not present\n\n");
+		return;
+	}
+
+	// cycle through the joystick ids for the first valid one
+	for (joy_id=0 ; joy_id<numdevs ; joy_id++)
+	{
+		memset (&ji, 0, sizeof(ji));
+		ji.dwSize = sizeof(ji);
+		ji.dwFlags = JOY_RETURNCENTERED;
+
+		if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
+			break;
+	} 
+
+	// abort startup if we didn't find a valid joystick
+	if (mmr != JOYERR_NOERROR)
+	{
+		Com_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
+		return;
+	}
+
+	// get the capabilities of the selected joystick
+	// abort startup if command fails
+	memset (&jc, 0, sizeof(jc));
+	if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
+	{
+		Com_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr); 
+		return;
+	}
+
+	// save the joystick's number of buttons and POV status
+	joy_numbuttons = jc.wNumButtons;
+	joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
+
+	// old button and POV states default to no buttons pressed
+	joy_oldbuttonstate = joy_oldpovstate = 0;
+
+	// mark the joystick as available and advanced initialization not completed
+	// this is needed as cvars are not available during initialization
+
+	joy_avail = true; 
+	joy_advancedinit = false;
+
+	Com_Printf ("\njoystick detected\n\n"); 
+}
+
+
+/*
+===========
+RawValuePointer
+===========
+*/
+PDWORD RawValuePointer (int axis)
+{
+	switch (axis)
+	{
+	case JOY_AXIS_X:
+		return &ji.dwXpos;
+	case JOY_AXIS_Y:
+		return &ji.dwYpos;
+	case JOY_AXIS_Z:
+		return &ji.dwZpos;
+	case JOY_AXIS_R:
+		return &ji.dwRpos;
+	case JOY_AXIS_U:
+		return &ji.dwUpos;
+	case JOY_AXIS_V:
+		return &ji.dwVpos;
+	}
+}
+
+
+/*
+===========
+Joy_AdvancedUpdate_f
+===========
+*/
+void Joy_AdvancedUpdate_f (void)
+{
+
+	// called once by IN_ReadJoystick and by user whenever an update is needed
+	// cvars are now available
+	int	i;
+	DWORD dwTemp;
+
+	// initialize all the maps
+	for (i = 0; i < JOY_MAX_AXES; i++)
+	{
+		dwAxisMap[i] = AxisNada;
+		dwControlMap[i] = JOY_ABSOLUTE_AXIS;
+		pdwRawValue[i] = RawValuePointer(i);
+	}
+
+	if( joy_advanced->value == 0.0)
+	{
+		// default joystick initialization
+		// 2 axes only with joystick control
+		dwAxisMap[JOY_AXIS_X] = AxisTurn;
+		// dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
+		dwAxisMap[JOY_AXIS_Y] = AxisForward;
+		// dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
+	}
+	else
+	{
+		if (strcmp (joy_name->string, "joystick") != 0)
+		{
+			// notify user of advanced controller
+			Com_Printf ("\n%s configured\n\n", joy_name->string);
+		}
+
+		// advanced initialization here
+		// data supplied by user via joy_axisn cvars
+		dwTemp = (DWORD) joy_advaxisx->value;
+		dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
+		dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
+		dwTemp = (DWORD) joy_advaxisy->value;
+		dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
+		dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
+		dwTemp = (DWORD) joy_advaxisz->value;
+		dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
+		dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
+		dwTemp = (DWORD) joy_advaxisr->value;
+		dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
+		dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
+		dwTemp = (DWORD) joy_advaxisu->value;
+		dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
+		dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
+		dwTemp = (DWORD) joy_advaxisv->value;
+		dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
+		dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
+	}
+
+	// compute the axes to collect from DirectInput
+	joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
+	for (i = 0; i < JOY_MAX_AXES; i++)
+	{
+		if (dwAxisMap[i] != AxisNada)
+		{
+			joy_flags |= dwAxisFlags[i];
+		}
+	}
+}
+
+
+/*
+===========
+IN_Commands
+===========
+*/
+void IN_Commands (void)
+{
+	int		i, key_index;
+	DWORD	buttonstate, povstate;
+
+	if (!joy_avail)
+	{
+		return;
+	}
+
+	
+	// loop through the joystick buttons
+	// key a joystick event or auxillary event for higher number buttons for each state change
+	buttonstate = ji.dwButtons;
+	for (i=0 ; i < joy_numbuttons ; i++)
+	{
+		if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
+		{
+			key_index = (i < 4) ? K_JOY1 : K_AUX1;
+			Key_Event (key_index + i, true, 0);
+		}
+
+		if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
+		{
+			key_index = (i < 4) ? K_JOY1 : K_AUX1;
+			Key_Event (key_index + i, false, 0);
+		}
+	}
+	joy_oldbuttonstate = buttonstate;
+
+	if (joy_haspov)
+	{
+		// convert POV information into 4 bits of state information
+		// this avoids any potential problems related to moving from one
+		// direction to another without going through the center position
+		povstate = 0;
+		if(ji.dwPOV != JOY_POVCENTERED)
+		{
+			if (ji.dwPOV == JOY_POVFORWARD)
+				povstate |= 0x01;
+			if (ji.dwPOV == JOY_POVRIGHT)
+				povstate |= 0x02;
+			if (ji.dwPOV == JOY_POVBACKWARD)
+				povstate |= 0x04;
+			if (ji.dwPOV == JOY_POVLEFT)
+				povstate |= 0x08;
+		}
+		// determine which bits have changed and key an auxillary event for each change
+		for (i=0 ; i < 4 ; i++)
+		{
+			if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
+			{
+				Key_Event (K_AUX29 + i, true, 0);
+			}
+
+			if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
+			{
+				Key_Event (K_AUX29 + i, false, 0);
+			}
+		}
+		joy_oldpovstate = povstate;
+	}
+}
+
+
+/* 
+=============== 
+IN_ReadJoystick
+=============== 
+*/  
+qboolean IN_ReadJoystick (void)
+{
+
+	memset (&ji, 0, sizeof(ji));
+	ji.dwSize = sizeof(ji);
+	ji.dwFlags = joy_flags;
+
+	if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
+	{
+		return true;
+	}
+	else
+	{
+		// read error occurred
+		// turning off the joystick seems too harsh for 1 read error,\
+		// but what should be done?
+		// Com_Printf ("IN_ReadJoystick: no response\n");
+		// joy_avail = false;
+		return false;
+	}
+}
+
+
+/*
+===========
+IN_JoyMove
+===========
+*/
+void IN_JoyMove (usercmd_t *cmd)
+{
+	float	speed, aspeed;
+	float	fAxisValue;
+	int		i;
+
+	// complete initialization if first time in
+	// this is needed as cvars are not available at initialization time
+	if( joy_advancedinit != true )
+	{
+		Joy_AdvancedUpdate_f();
+		joy_advancedinit = true;
+	}
+
+	// verify joystick is available and that the user wants to use it
+	if (!joy_avail || !in_joystick->value)
+	{
+		return; 
+	}
+ 
+	// collect the joystick data, if possible
+	if (IN_ReadJoystick () != true)
+	{
+		return;
+	}
+
+	if ( (in_speed.state & 1) ^ (int)cl_run->value)
+		speed = 2;
+	else
+		speed = 1;
+	aspeed = speed * cls.frametime;
+
+	// loop through the axes
+	for (i = 0; i < JOY_MAX_AXES; i++)
+	{
+		// get the floating point zero-centered, potentially-inverted data for the current axis
+		fAxisValue = (float) *pdwRawValue[i];
+		// move centerpoint to zero
+		fAxisValue -= 32768.0;
+
+		// convert range from -32768..32767 to -1..1 
+		fAxisValue /= 32768.0;
+
+		switch (dwAxisMap[i])
+		{
+		case AxisForward:
+			if ((joy_advanced->value == 0.0) && mlooking)
+			{
+				// user wants forward control to become look control
+				if (fabs(fAxisValue) > joy_pitchthreshold->value)
+				{		
+					// if mouse invert is on, invert the joystick pitch value
+					// only absolute control support here (joy_advanced is false)
+					if (m_pitch->value < 0.0)
+					{
+						cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
+					}
+					else
+					{
+						cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
+					}
+				}
+			}
+			else
+			{
+				// user wants forward control to be forward control
+				if (fabs(fAxisValue) > joy_forwardthreshold->value)
+				{
+					cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value;
+				}
+			}
+			break;
+
+		case AxisSide:
+			if (fabs(fAxisValue) > joy_sidethreshold->value)
+			{
+				cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
+			}
+			break;
+
+		case AxisUp:
+			if (fabs(fAxisValue) > joy_upthreshold->value)
+			{
+				cmd->upmove += (fAxisValue * joy_upsensitivity->value) * speed * cl_upspeed->value;
+			}
+			break;
+
+		case AxisTurn:
+			if ((in_strafe.state & 1) || (lookstrafe->value && mlooking))
+			{
+				// user wants turn control to become side control
+				if (fabs(fAxisValue) > joy_sidethreshold->value)
+				{
+					cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
+				}
+			}
+			else
+			{
+				// user wants turn control to be turn control
+				if (fabs(fAxisValue) > joy_yawthreshold->value)
+				{
+					if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
+					{
+						cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value;
+					}
+					else
+					{
+						cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0;
+					}
+
+				}
+			}
+			break;
+
+		case AxisLook:
+			if (mlooking)
+			{
+				if (fabs(fAxisValue) > joy_pitchthreshold->value)
+				{
+					// pitch movement detected and pitch movement desired by user
+					if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
+					{
+						cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
+					}
+					else
+					{
+						cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0;
+					}
+				}
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
--- /dev/null
+++ b/win32/net_wins.c
@@ -1,0 +1,842 @@
+/*
+Copyright (C) 1997-2001 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_wins.c
+
+#include "winsock.h"
+#include "wsipx.h"
+#include "../qcommon/qcommon.h"
+
+#define	MAX_LOOPBACK	4
+
+typedef struct
+{
+	byte	data[MAX_MSGLEN];
+	int		datalen;
+} loopmsg_t;
+
+typedef struct
+{
+	loopmsg_t	msgs[MAX_LOOPBACK];
+	int			get, send;
+} loopback_t;
+
+
+cvar_t		*net_shownet;
+static cvar_t	*noudp;
+static cvar_t	*noipx;
+
+loopback_t	loopbacks[2];
+int			ip_sockets[2];
+int			ipx_sockets[2];
+
+char *NET_ErrorString (void);
+
+//=============================================================================
+
+void NetadrToSockadr (netadr_t *a, struct sockaddr *s)
+{
+	memset (s, 0, sizeof(*s));
+
+	if (a->type == NA_BROADCAST)
+	{
+		((struct sockaddr_in *)s)->sin_family = AF_INET;
+		((struct sockaddr_in *)s)->sin_port = a->port;
+		((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
+	}
+	else if (a->type == NA_IP)
+	{
+		((struct sockaddr_in *)s)->sin_family = AF_INET;
+		((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
+		((struct sockaddr_in *)s)->sin_port = a->port;
+	}
+	else if (a->type == NA_IPX)
+	{
+		((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
+		memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
+		memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
+		((struct sockaddr_ipx *)s)->sa_socket = a->port;
+	}
+	else if (a->type == NA_BROADCAST_IPX)
+	{
+		((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
+		memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4);
+		memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6);
+		((struct sockaddr_ipx *)s)->sa_socket = a->port;
+	}
+}
+
+void SockadrToNetadr (struct sockaddr *s, netadr_t *a)
+{
+	if (s->sa_family == AF_INET)
+	{
+		a->type = NA_IP;
+		*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
+		a->port = ((struct sockaddr_in *)s)->sin_port;
+	}
+	else if (s->sa_family == AF_IPX)
+	{
+		a->type = NA_IPX;
+		memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
+		memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
+		a->port = ((struct sockaddr_ipx *)s)->sa_socket;
+	}
+}
+
+
+qboolean	NET_CompareAdr (netadr_t a, netadr_t b)
+{
+	if (a.type != b.type)
+		return false;
+
+	if (a.type == NA_LOOPBACK)
+		return TRUE;
+
+	if (a.type == NA_IP)
+	{
+		if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
+			return true;
+		return false;
+	}
+
+	if (a.type == NA_IPX)
+	{
+		if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
+			return true;
+		return false;
+	}
+}
+
+/*
+===================
+NET_CompareBaseAdr
+
+Compares without the port
+===================
+*/
+qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b)
+{
+	if (a.type != b.type)
+		return false;
+
+	if (a.type == NA_LOOPBACK)
+		return TRUE;
+
+	if (a.type == NA_IP)
+	{
+		if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
+			return true;
+		return false;
+	}
+
+	if (a.type == NA_IPX)
+	{
+		if ((memcmp(a.ipx, b.ipx, 10) == 0))
+			return true;
+		return false;
+	}
+}
+
+char	*NET_AdrToString (netadr_t a)
+{
+	static	char	s[64];
+
+	if (a.type == NA_LOOPBACK)
+		Com_sprintf (s, sizeof(s), "loopback");
+	else if (a.type == NA_IP)
+		Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
+	else
+		Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
+
+	return s;
+}
+
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+#define DO(src,dest)	\
+	copy[0] = s[src];	\
+	copy[1] = s[src + 1];	\
+	sscanf (copy, "%x", &val);	\
+	((struct sockaddr_ipx *)sadr)->dest = val
+
+qboolean	NET_StringToSockaddr (char *s, struct sockaddr *sadr)
+{
+	struct hostent	*h;
+	char	*colon;
+	int		val;
+	char	copy[128];
+	
+	memset (sadr, 0, sizeof(*sadr));
+
+	if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':'))	// check for an IPX address
+	{
+		((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
+		copy[2] = 0;
+		DO(0, sa_netnum[0]);
+		DO(2, sa_netnum[1]);
+		DO(4, sa_netnum[2]);
+		DO(6, sa_netnum[3]);
+		DO(9, sa_nodenum[0]);
+		DO(11, sa_nodenum[1]);
+		DO(13, sa_nodenum[2]);
+		DO(15, sa_nodenum[3]);
+		DO(17, sa_nodenum[4]);
+		DO(19, sa_nodenum[5]);
+		sscanf (&s[22], "%u", &val);
+		((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val);
+	}
+	else
+	{
+		((struct sockaddr_in *)sadr)->sin_family = AF_INET;
+		
+		((struct sockaddr_in *)sadr)->sin_port = 0;
+
+		strcpy (copy, s);
+		// strip off a trailing :port if present
+		for (colon = copy ; *colon ; colon++)
+			if (*colon == ':')
+			{
+				*colon = 0;
+				((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));	
+			}
+		
+		if (copy[0] >= '0' && copy[0] <= '9')
+		{
+			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
+		}
+		else
+		{
+			if (! (h = gethostbyname(copy)) )
+				return 0;
+			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
+		}
+	}
+	
+	return true;
+}
+
+#undef DO
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean	NET_StringToAdr (char *s, netadr_t *a)
+{
+	struct sockaddr sadr;
+	
+	if (!strcmp (s, "localhost"))
+	{
+		memset (a, 0, sizeof(*a));
+		a->type = NA_LOOPBACK;
+		return true;
+	}
+
+	if (!NET_StringToSockaddr (s, &sadr))
+		return false;
+	
+	SockadrToNetadr (&sadr, a);
+
+	return true;
+}
+
+
+qboolean	NET_IsLocalAddress (netadr_t adr)
+{
+	return adr.type == NA_LOOPBACK;
+}
+
+/*
+=============================================================================
+
+LOOPBACK BUFFERS FOR LOCAL PLAYER
+
+=============================================================================
+*/
+
+qboolean	NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+	int		i;
+	loopback_t	*loop;
+
+	loop = &loopbacks[sock];
+
+	if (loop->send - loop->get > MAX_LOOPBACK)
+		loop->get = loop->send - MAX_LOOPBACK;
+
+	if (loop->get >= loop->send)
+		return false;
+
+	i = loop->get & (MAX_LOOPBACK-1);
+	loop->get++;
+
+	memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
+	net_message->cursize = loop->msgs[i].datalen;
+	memset (net_from, 0, sizeof(*net_from));
+	net_from->type = NA_LOOPBACK;
+	return true;
+
+}
+
+
+void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+	int		i;
+	loopback_t	*loop;
+
+	loop = &loopbacks[sock^1];
+
+	i = loop->send & (MAX_LOOPBACK-1);
+	loop->send++;
+
+	memcpy (loop->msgs[i].data, data, length);
+	loop->msgs[i].datalen = length;
+}
+
+//=============================================================================
+
+qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+{
+	int 	ret;
+	struct sockaddr from;
+	int		fromlen;
+	int		net_socket;
+	int		protocol;
+	int		err;
+
+	if (NET_GetLoopPacket (sock, net_from, net_message))
+		return true;
+
+	for (protocol = 0 ; protocol < 2 ; protocol++)
+	{
+		if (protocol == 0)
+			net_socket = ip_sockets[sock];
+		else
+			net_socket = ipx_sockets[sock];
+
+		if (!net_socket)
+			continue;
+
+		fromlen = sizeof(from);
+		ret = recvfrom (net_socket, net_message->data, net_message->maxsize
+			, 0, (struct sockaddr *)&from, &fromlen);
+		if (ret == -1)
+		{
+			err = WSAGetLastError();
+
+			if (err == WSAEWOULDBLOCK)
+				continue;
+			if (dedicated->value)	// let dedicated servers continue after errors
+				Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
+			else
+				Com_Error (ERR_DROP, "NET_GetPacket: %s", NET_ErrorString());
+			continue;
+		}
+
+		SockadrToNetadr (&from, net_from);
+
+		if (ret == net_message->maxsize)
+		{
+			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
+			continue;
+		}
+
+		net_message->cursize = ret;
+		return true;
+	}
+
+	return false;
+}
+
+//=============================================================================
+
+void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
+{
+	int		ret;
+	struct sockaddr	addr;
+	int		net_socket;
+
+	if ( to.type == NA_LOOPBACK )
+	{
+		NET_SendLoopPacket (sock, length, data, to);
+		return;
+	}
+
+	if (to.type == NA_BROADCAST)
+	{
+		net_socket = ip_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_IP)
+	{
+		net_socket = ip_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_IPX)
+	{
+		net_socket = ipx_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else if (to.type == NA_BROADCAST_IPX)
+	{
+		net_socket = ipx_sockets[sock];
+		if (!net_socket)
+			return;
+	}
+	else
+		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
+
+	NetadrToSockadr (&to, &addr);
+
+	ret = sendto (net_socket, data, length, 0, &addr, sizeof(addr) );
+	if (ret == -1)
+	{
+		int err = WSAGetLastError();
+
+		// wouldblock is silent
+		if (err == WSAEWOULDBLOCK)
+			return;
+
+		// some PPP links dont allow broadcasts
+		if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
+			return;
+
+		if (dedicated->value)	// let dedicated servers continue after errors
+		{
+			Com_Printf ("NET_SendPacket ERROR: %s\n", NET_ErrorString());
+		}
+		else
+		{
+			if (err == WSAEADDRNOTAVAIL)
+			{
+				Com_DPrintf ("NET_SendPacket Warning: %s : %s\n", NET_ErrorString(), NET_AdrToString (to));
+			}
+			else
+			{
+				Com_Error (ERR_DROP, "NET_SendPacket ERROR: %s\n", NET_ErrorString());
+			}
+		}
+	}
+}
+
+
+//=============================================================================
+
+
+/*
+====================
+NET_Socket
+====================
+*/
+int NET_IPSocket (char *net_interface, int port)
+{
+	int					newsocket;
+	struct sockaddr_in	address;
+	qboolean			_true = true;
+	int					i = 1;
+	int					err;
+
+	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+	{
+		err = WSAGetLastError();
+		if (err != WSAEAFNOSUPPORT)
+			Com_Printf ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
+		return 0;
+	}
+
+	// make it non-blocking
+	if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
+	{
+		Com_Printf ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
+		return 0;
+	}
+
+	// make it broadcast capable
+	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
+	{
+		Com_Printf ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
+		return 0;
+	}
+
+	if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
+		address.sin_addr.s_addr = INADDR_ANY;
+	else
+		NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
+
+	if (port == PORT_ANY)
+		address.sin_port = 0;
+	else
+		address.sin_port = htons((short)port);
+
+	address.sin_family = AF_INET;
+
+	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+	{
+		Com_Printf ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
+		closesocket (newsocket);
+		return 0;
+	}
+
+	return newsocket;
+}
+
+
+/*
+====================
+NET_OpenIP
+====================
+*/
+void NET_OpenIP (void)
+{
+	cvar_t	*ip;
+	int		port;
+	int		dedicated;
+
+	ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
+
+	dedicated = Cvar_VariableValue ("dedicated");
+
+	if (!ip_sockets[NS_SERVER])
+	{
+		port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value;
+		if (!port)
+		{
+			port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
+			if (!port)
+			{
+				port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
+			}
+		}
+		ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
+		if (!ip_sockets[NS_SERVER] && dedicated)
+			Com_Error (ERR_FATAL, "Couldn't allocate dedicated server IP port");
+	}
+
+
+	// dedicated servers don't need client ports
+	if (dedicated)
+		return;
+
+	if (!ip_sockets[NS_CLIENT])
+	{
+		port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value;
+		if (!port)
+		{
+			port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
+			if (!port)
+				port = PORT_ANY;
+		}
+		ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
+		if (!ip_sockets[NS_CLIENT])
+			ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
+	}
+}
+
+
+/*
+====================
+IPX_Socket
+====================
+*/
+int NET_IPXSocket (int port)
+{
+	int					newsocket;
+	struct sockaddr_ipx	address;
+	int					_true = 1;
+	int					err;
+
+	if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
+	{
+		err = WSAGetLastError();
+		if (err != WSAEAFNOSUPPORT)
+			Com_Printf ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
+		return 0;
+	}
+
+	// make it non-blocking
+	if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
+	{
+		Com_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
+		return 0;
+	}
+
+	// make it broadcast capable
+	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
+	{
+		Com_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
+		return 0;
+	}
+
+	address.sa_family = AF_IPX;
+	memset (address.sa_netnum, 0, 4);
+	memset (address.sa_nodenum, 0, 6);
+	if (port == PORT_ANY)
+		address.sa_socket = 0;
+	else
+		address.sa_socket = htons((short)port);
+
+	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+	{
+		Com_Printf ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
+		closesocket (newsocket);
+		return 0;
+	}
+
+	return newsocket;
+}
+
+
+/*
+====================
+NET_OpenIPX
+====================
+*/
+void NET_OpenIPX (void)
+{
+	int		port;
+	int		dedicated;
+
+	dedicated = Cvar_VariableValue ("dedicated");
+
+	if (!ipx_sockets[NS_SERVER])
+	{
+		port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value;
+		if (!port)
+		{
+			port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
+			if (!port)
+			{
+				port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
+			}
+		}
+		ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
+	}
+
+	// dedicated servers don't need client ports
+	if (dedicated)
+		return;
+
+	if (!ipx_sockets[NS_CLIENT])
+	{
+		port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value;
+		if (!port)
+		{
+			port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
+			if (!port)
+				port = PORT_ANY;
+		}
+		ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
+		if (!ipx_sockets[NS_CLIENT])
+			ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
+	}
+}
+
+
+/*
+====================
+NET_Config
+
+A single player game will only use the loopback code
+====================
+*/
+void	NET_Config (qboolean multiplayer)
+{
+	int		i;
+	static	qboolean	old_config;
+
+	if (old_config == multiplayer)
+		return;
+
+	old_config = multiplayer;
+
+	if (!multiplayer)
+	{	// shut down any existing sockets
+		for (i=0 ; i<2 ; i++)
+		{
+			if (ip_sockets[i])
+			{
+				closesocket (ip_sockets[i]);
+				ip_sockets[i] = 0;
+			}
+			if (ipx_sockets[i])
+			{
+				closesocket (ipx_sockets[i]);
+				ipx_sockets[i] = 0;
+			}
+		}
+	}
+	else
+	{	// open sockets
+		if (! noudp->value)
+			NET_OpenIP ();
+		if (! noipx->value)
+			NET_OpenIPX ();
+	}
+}
+
+// sleeps msec or until net socket is ready
+void NET_Sleep(int msec)
+{
+    struct timeval timeout;
+	fd_set	fdset;
+	extern cvar_t *dedicated;
+	int i;
+
+	if (!dedicated || !dedicated->value)
+		return; // we're not a server, just run full speed
+
+	FD_ZERO(&fdset);
+	i = 0;
+	if (ip_sockets[NS_SERVER]) {
+		FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
+		i = ip_sockets[NS_SERVER];
+	}
+	if (ipx_sockets[NS_SERVER]) {
+		FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
+		if (ipx_sockets[NS_SERVER] > i)
+			i = ipx_sockets[NS_SERVER];
+	}
+	timeout.tv_sec = msec/1000;
+	timeout.tv_usec = (msec%1000)*1000;
+	select(i+1, &fdset, NULL, NULL, &timeout);
+}
+
+//===================================================================
+
+
+static WSADATA		winsockdata;
+
+/*
+====================
+NET_Init
+====================
+*/
+void NET_Init (void)
+{
+	WORD	wVersionRequested; 
+	int		r;
+
+	wVersionRequested = MAKEWORD(1, 1); 
+
+	r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
+
+	if (r)
+		Com_Error (ERR_FATAL,"Winsock initialization failed.");
+
+	Com_Printf("Winsock Initialized\n");
+
+	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
+	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
+
+	net_shownet = Cvar_Get ("net_shownet", "0", 0);
+}
+
+
+/*
+====================
+NET_Shutdown
+====================
+*/
+void	NET_Shutdown (void)
+{
+	NET_Config (false);	// close sockets
+
+	WSACleanup ();
+}
+
+
+/*
+====================
+NET_ErrorString
+====================
+*/
+char *NET_ErrorString (void)
+{
+	int		code;
+
+	code = WSAGetLastError ();
+	switch (code)
+	{
+	case WSAEINTR: return "WSAEINTR";
+	case WSAEBADF: return "WSAEBADF";
+	case WSAEACCES: return "WSAEACCES";
+	case WSAEDISCON: return "WSAEDISCON";
+	case WSAEFAULT: return "WSAEFAULT";
+	case WSAEINVAL: return "WSAEINVAL";
+	case WSAEMFILE: return "WSAEMFILE";
+	case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
+	case WSAEINPROGRESS: return "WSAEINPROGRESS";
+	case WSAEALREADY: return "WSAEALREADY";
+	case WSAENOTSOCK: return "WSAENOTSOCK";
+	case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
+	case WSAEMSGSIZE: return "WSAEMSGSIZE";
+	case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
+	case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
+	case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
+	case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
+	case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
+	case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
+	case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
+	case WSAEADDRINUSE: return "WSAEADDRINUSE";
+	case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
+	case WSAENETDOWN: return "WSAENETDOWN";
+	case WSAENETUNREACH: return "WSAENETUNREACH";
+	case WSAENETRESET: return "WSAENETRESET";
+	case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
+	case WSAECONNRESET: return "WSAECONNRESET";
+	case WSAENOBUFS: return "WSAENOBUFS";
+	case WSAEISCONN: return "WSAEISCONN";
+	case WSAENOTCONN: return "WSAENOTCONN";
+	case WSAESHUTDOWN: return "WSAESHUTDOWN";
+	case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
+	case WSAETIMEDOUT: return "WSAETIMEDOUT";
+	case WSAECONNREFUSED: return "WSAECONNREFUSED";
+	case WSAELOOP: return "WSAELOOP";
+	case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
+	case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
+	case WSASYSNOTREADY: return "WSASYSNOTREADY";
+	case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
+	case WSANOTINITIALISED: return "WSANOTINITIALISED";
+	case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
+	case WSATRY_AGAIN: return "WSATRY_AGAIN";
+	case WSANO_RECOVERY: return "WSANO_RECOVERY";
+	case WSANO_DATA: return "WSANO_DATA";
+	default: return "NO ERROR";
+	}
+}
binary files /dev/null b/win32/q2.aps differ
binary files /dev/null b/win32/q2.ico differ
--- /dev/null
+++ b/win32/q2.rc
@@ -1,0 +1,72 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1               ICON    DISCARDABLE     "q2.ico"
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
--- /dev/null
+++ b/win32/q_shwin.c
@@ -1,0 +1,215 @@
+/*
+Copyright (C) 1997-2001 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 "../qcommon/qcommon.h"
+#include "winquake.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <direct.h>
+#include <io.h>
+#include <conio.h>
+
+//===============================================================================
+
+int		hunkcount;
+
+
+byte	*membase;
+int		hunkmaxsize;
+int		cursize;
+
+#define	VIRTUAL_ALLOC
+
+void *Hunk_Begin (int maxsize)
+{
+	// reserve a huge chunk of memory, but don't commit any yet
+	cursize = 0;
+	hunkmaxsize = maxsize;
+#ifdef VIRTUAL_ALLOC
+	membase = VirtualAlloc (NULL, maxsize, MEM_RESERVE, PAGE_NOACCESS);
+#else
+	membase = malloc (maxsize);
+	memset (membase, 0, maxsize);
+#endif
+	if (!membase)
+		Sys_Error ("VirtualAlloc reserve failed");
+	return (void *)membase;
+}
+
+void *Hunk_Alloc (int size)
+{
+	void	*buf;
+
+	// round to cacheline
+	size = (size+31)&~31;
+
+#ifdef VIRTUAL_ALLOC
+	// commit pages as needed
+//	buf = VirtualAlloc (membase+cursize, size, MEM_COMMIT, PAGE_READWRITE);
+	buf = VirtualAlloc (membase, cursize+size, MEM_COMMIT, PAGE_READWRITE);
+	if (!buf)
+	{
+		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
+		Sys_Error ("VirtualAlloc commit failed.\n%s", buf);
+	}
+#endif
+	cursize += size;
+	if (cursize > hunkmaxsize)
+		Sys_Error ("Hunk_Alloc overflow");
+
+	return (void *)(membase+cursize-size);
+}
+
+int Hunk_End (void)
+{
+
+	// free the remaining unused virtual memory
+#if 0
+	void	*buf;
+
+	// write protect it
+	buf = VirtualAlloc (membase, cursize, MEM_COMMIT, PAGE_READONLY);
+	if (!buf)
+		Sys_Error ("VirtualAlloc commit failed");
+#endif
+
+	hunkcount++;
+//Com_Printf ("hunkcount: %i\n", hunkcount);
+	return cursize;
+}
+
+void Hunk_Free (void *base)
+{
+	if ( base )
+#ifdef VIRTUAL_ALLOC
+		VirtualFree (base, 0, MEM_RELEASE);
+#else
+		free (base);
+#endif
+
+	hunkcount--;
+}
+
+//===============================================================================
+
+
+/*
+================
+Sys_Milliseconds
+================
+*/
+int	curtime;
+int Sys_Milliseconds (void)
+{
+	static int		base;
+	static qboolean	initialized = false;
+
+	if (!initialized)
+	{	// let base retain 16 bits of effectively random data
+		base = timeGetTime() & 0xffff0000;
+		initialized = true;
+	}
+	curtime = timeGetTime() - base;
+
+	return curtime;
+}
+
+void Sys_Mkdir (char *path)
+{
+	_mkdir (path);
+}
+
+//============================================
+
+char	findbase[MAX_OSPATH];
+char	findpath[MAX_OSPATH];
+int		findhandle;
+
+static qboolean CompareAttributes( unsigned found, unsigned musthave, unsigned canthave )
+{
+	if ( ( found & _A_RDONLY ) && ( canthave & SFF_RDONLY ) )
+		return false;
+	if ( ( found & _A_HIDDEN ) && ( canthave & SFF_HIDDEN ) )
+		return false;
+	if ( ( found & _A_SYSTEM ) && ( canthave & SFF_SYSTEM ) )
+		return false;
+	if ( ( found & _A_SUBDIR ) && ( canthave & SFF_SUBDIR ) )
+		return false;
+	if ( ( found & _A_ARCH ) && ( canthave & SFF_ARCH ) )
+		return false;
+
+	if ( ( musthave & SFF_RDONLY ) && !( found & _A_RDONLY ) )
+		return false;
+	if ( ( musthave & SFF_HIDDEN ) && !( found & _A_HIDDEN ) )
+		return false;
+	if ( ( musthave & SFF_SYSTEM ) && !( found & _A_SYSTEM ) )
+		return false;
+	if ( ( musthave & SFF_SUBDIR ) && !( found & _A_SUBDIR ) )
+		return false;
+	if ( ( musthave & SFF_ARCH ) && !( found & _A_ARCH ) )
+		return false;
+
+	return true;
+}
+
+char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave )
+{
+	struct _finddata_t findinfo;
+
+	if (findhandle)
+		Sys_Error ("Sys_BeginFind without close");
+	findhandle = 0;
+
+	COM_FilePath (path, findbase);
+	findhandle = _findfirst (path, &findinfo);
+	if (findhandle == -1)
+		return NULL;
+	if ( !CompareAttributes( findinfo.attrib, musthave, canthave ) )
+		return NULL;
+	Com_sprintf (findpath, sizeof(findpath), "%s/%s", findbase, findinfo.name);
+	return findpath;
+}
+
+char *Sys_FindNext ( unsigned musthave, unsigned canthave )
+{
+	struct _finddata_t findinfo;
+
+	if (findhandle == -1)
+		return NULL;
+	if (_findnext (findhandle, &findinfo) == -1)
+		return NULL;
+	if ( !CompareAttributes( findinfo.attrib, musthave, canthave ) )
+		return NULL;
+
+	Com_sprintf (findpath, sizeof(findpath), "%s/%s", findbase, findinfo.name);
+	return findpath;
+}
+
+void Sys_FindClose (void)
+{
+	if (findhandle != -1)
+		_findclose (findhandle);
+	findhandle = 0;
+}
+
+
+//============================================
+
binary files /dev/null b/win32/qe3.ico differ
--- /dev/null
+++ b/win32/qgl_win.c
@@ -1,0 +1,4133 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+** QGL_WIN.C
+**
+** This file implements the operating system binding of GL to QGL function
+** pointers.  When doing a port of Quake2 you must implement the following
+** two functions:
+**
+** QGL_Init() - loads libraries, assigns function pointers, etc.
+** QGL_Shutdown() - unloads libraries, NULLs function pointers
+*/
+#include <float.h>
+#include "../ref_gl/gl_local.h"
+#include "glw_win.h"
+
+int   ( WINAPI * qwglChoosePixelFormat )(HDC, CONST PIXELFORMATDESCRIPTOR *);
+int   ( WINAPI * qwglDescribePixelFormat) (HDC, int, UINT, LPPIXELFORMATDESCRIPTOR);
+int   ( WINAPI * qwglGetPixelFormat)(HDC);
+BOOL  ( WINAPI * qwglSetPixelFormat)(HDC, int, CONST PIXELFORMATDESCRIPTOR *);
+BOOL  ( WINAPI * qwglSwapBuffers)(HDC);
+
+BOOL  ( WINAPI * qwglCopyContext)(HGLRC, HGLRC, UINT);
+HGLRC ( WINAPI * qwglCreateContext)(HDC);
+HGLRC ( WINAPI * qwglCreateLayerContext)(HDC, int);
+BOOL  ( WINAPI * qwglDeleteContext)(HGLRC);
+HGLRC ( WINAPI * qwglGetCurrentContext)(VOID);
+HDC   ( WINAPI * qwglGetCurrentDC)(VOID);
+PROC  ( WINAPI * qwglGetProcAddress)(LPCSTR);
+BOOL  ( WINAPI * qwglMakeCurrent)(HDC, HGLRC);
+BOOL  ( WINAPI * qwglShareLists)(HGLRC, HGLRC);
+BOOL  ( WINAPI * qwglUseFontBitmaps)(HDC, DWORD, DWORD, DWORD);
+
+BOOL  ( WINAPI * qwglUseFontOutlines)(HDC, DWORD, DWORD, DWORD, FLOAT,
+                                           FLOAT, int, LPGLYPHMETRICSFLOAT);
+
+BOOL ( WINAPI * qwglDescribeLayerPlane)(HDC, int, int, UINT,
+                                            LPLAYERPLANEDESCRIPTOR);
+int  ( WINAPI * qwglSetLayerPaletteEntries)(HDC, int, int, int,
+                                                CONST COLORREF *);
+int  ( WINAPI * qwglGetLayerPaletteEntries)(HDC, int, int, int,
+                                                COLORREF *);
+BOOL ( WINAPI * qwglRealizeLayerPalette)(HDC, int, BOOL);
+BOOL ( WINAPI * qwglSwapLayerBuffers)(HDC, UINT);
+
+void ( APIENTRY * qglAccum )(GLenum op, GLfloat value);
+void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref);
+GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+void ( APIENTRY * qglArrayElement )(GLint i);
+void ( APIENTRY * qglBegin )(GLenum mode);
+void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture);
+void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor);
+void ( APIENTRY * qglCallList )(GLuint list);
+void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+void ( APIENTRY * qglClear )(GLbitfield mask);
+void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void ( APIENTRY * qglClearDepth )(GLclampd depth);
+void ( APIENTRY * qglClearIndex )(GLfloat c);
+void ( APIENTRY * qglClearStencil )(GLint s);
+void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation);
+void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+void ( APIENTRY * qglColor3bv )(const GLbyte *v);
+void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+void ( APIENTRY * qglColor3dv )(const GLdouble *v);
+void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+void ( APIENTRY * qglColor3fv )(const GLfloat *v);
+void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue);
+void ( APIENTRY * qglColor3iv )(const GLint *v);
+void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue);
+void ( APIENTRY * qglColor3sv )(const GLshort *v);
+void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+void ( APIENTRY * qglColor3ubv )(const GLubyte *v);
+void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue);
+void ( APIENTRY * qglColor3uiv )(const GLuint *v);
+void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue);
+void ( APIENTRY * qglColor3usv )(const GLushort *v);
+void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+void ( APIENTRY * qglColor4bv )(const GLbyte *v);
+void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+void ( APIENTRY * qglColor4dv )(const GLdouble *v);
+void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void ( APIENTRY * qglColor4fv )(const GLfloat *v);
+void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+void ( APIENTRY * qglColor4iv )(const GLint *v);
+void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+void ( APIENTRY * qglColor4sv )(const GLshort *v);
+void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+void ( APIENTRY * qglColor4ubv )(const GLubyte *v);
+void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+void ( APIENTRY * qglColor4uiv )(const GLuint *v);
+void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+void ( APIENTRY * qglColor4usv )(const GLushort *v);
+void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode);
+void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+void ( APIENTRY * qglCullFace )(GLenum mode);
+void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range);
+void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures);
+void ( APIENTRY * qglDepthFunc )(GLenum func);
+void ( APIENTRY * qglDepthMask )(GLboolean flag);
+void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar);
+void ( APIENTRY * qglDisable )(GLenum cap);
+void ( APIENTRY * qglDisableClientState )(GLenum array);
+void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count);
+void ( APIENTRY * qglDrawBuffer )(GLenum mode);
+void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglEdgeFlag )(GLboolean flag);
+void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag);
+void ( APIENTRY * qglEnable )(GLenum cap);
+void ( APIENTRY * qglEnableClientState )(GLenum array);
+void ( APIENTRY * qglEnd )(void);
+void ( APIENTRY * qglEndList )(void);
+void ( APIENTRY * qglEvalCoord1d )(GLdouble u);
+void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u);
+void ( APIENTRY * qglEvalCoord1f )(GLfloat u);
+void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u);
+void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v);
+void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u);
+void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v);
+void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u);
+void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+void ( APIENTRY * qglEvalPoint1 )(GLint i);
+void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j);
+void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+void ( APIENTRY * qglFinish )(void);
+void ( APIENTRY * qglFlush )(void);
+void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglFogi )(GLenum pname, GLint param);
+void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params);
+void ( APIENTRY * qglFrontFace )(GLenum mode);
+void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLuint ( APIENTRY * qglGenLists )(GLsizei range);
+void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures);
+void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params);
+void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation);
+void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params);
+GLenum ( APIENTRY * qglGetError )(void);
+void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params);
+void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v);
+void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values);
+void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values);
+void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values);
+void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params);
+void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask);
+const GLubyte * ( APIENTRY * qglGetString )(GLenum name);
+void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+void ( APIENTRY * qglHint )(GLenum target, GLenum mode);
+void ( APIENTRY * qglIndexMask )(GLuint mask);
+void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglIndexd )(GLdouble c);
+void ( APIENTRY * qglIndexdv )(const GLdouble *c);
+void ( APIENTRY * qglIndexf )(GLfloat c);
+void ( APIENTRY * qglIndexfv )(const GLfloat *c);
+void ( APIENTRY * qglIndexi )(GLint c);
+void ( APIENTRY * qglIndexiv )(const GLint *c);
+void ( APIENTRY * qglIndexs )(GLshort c);
+void ( APIENTRY * qglIndexsv )(const GLshort *c);
+void ( APIENTRY * qglIndexub )(GLubyte c);
+void ( APIENTRY * qglIndexubv )(const GLubyte *c);
+void ( APIENTRY * qglInitNames )(void);
+void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap);
+GLboolean ( APIENTRY * qglIsList )(GLuint list);
+GLboolean ( APIENTRY * qglIsTexture )(GLuint texture);
+void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param);
+void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params);
+void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param);
+void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param);
+void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params);
+void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern);
+void ( APIENTRY * qglLineWidth )(GLfloat width);
+void ( APIENTRY * qglListBase )(GLuint base);
+void ( APIENTRY * qglLoadIdentity )(void);
+void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m);
+void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m);
+void ( APIENTRY * qglLoadName )(GLuint name);
+void ( APIENTRY * qglLogicOp )(GLenum opcode);
+void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param);
+void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param);
+void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+void ( APIENTRY * qglMatrixMode )(GLenum mode);
+void ( APIENTRY * qglMultMatrixd )(const GLdouble *m);
+void ( APIENTRY * qglMultMatrixf )(const GLfloat *m);
+void ( APIENTRY * qglNewList )(GLuint list, GLenum mode);
+void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+void ( APIENTRY * qglNormal3bv )(const GLbyte *v);
+void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+void ( APIENTRY * qglNormal3dv )(const GLdouble *v);
+void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+void ( APIENTRY * qglNormal3fv )(const GLfloat *v);
+void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz);
+void ( APIENTRY * qglNormal3iv )(const GLint *v);
+void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+void ( APIENTRY * qglNormal3sv )(const GLshort *v);
+void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+void ( APIENTRY * qglPassThrough )(GLfloat token);
+void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param);
+void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param);
+void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param);
+void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+void ( APIENTRY * qglPointSize )(GLfloat size);
+void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode);
+void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units);
+void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask);
+void ( APIENTRY * qglPopAttrib )(void);
+void ( APIENTRY * qglPopClientAttrib )(void);
+void ( APIENTRY * qglPopMatrix )(void);
+void ( APIENTRY * qglPopName )(void);
+void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+void ( APIENTRY * qglPushAttrib )(GLbitfield mask);
+void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask);
+void ( APIENTRY * qglPushMatrix )(void);
+void ( APIENTRY * qglPushName )(GLuint name);
+void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y);
+void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y);
+void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y);
+void ( APIENTRY * qglRasterPos2iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y);
+void ( APIENTRY * qglRasterPos2sv )(const GLshort *v);
+void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z);
+void ( APIENTRY * qglRasterPos3iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z);
+void ( APIENTRY * qglRasterPos3sv )(const GLshort *v);
+void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v);
+void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v);
+void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+void ( APIENTRY * qglRasterPos4iv )(const GLint *v);
+void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+void ( APIENTRY * qglRasterPos4sv )(const GLshort *v);
+void ( APIENTRY * qglReadBuffer )(GLenum mode);
+void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2);
+void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2);
+void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2);
+void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2);
+GLint ( APIENTRY * qglRenderMode )(GLenum mode);
+void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer);
+void ( APIENTRY * qglShadeModel )(GLenum mode);
+void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask);
+void ( APIENTRY * qglStencilMask )(GLuint mask);
+void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+void ( APIENTRY * qglTexCoord1d )(GLdouble s);
+void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord1f )(GLfloat s);
+void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord1i )(GLint s);
+void ( APIENTRY * qglTexCoord1iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord1s )(GLshort s);
+void ( APIENTRY * qglTexCoord1sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t);
+void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t);
+void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t);
+void ( APIENTRY * qglTexCoord2iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t);
+void ( APIENTRY * qglTexCoord2sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r);
+void ( APIENTRY * qglTexCoord3iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r);
+void ( APIENTRY * qglTexCoord3sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v);
+void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v);
+void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+void ( APIENTRY * qglTexCoord4iv )(const GLint *v);
+void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+void ( APIENTRY * qglTexCoord4sv )(const GLshort *v);
+void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param);
+void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param);
+void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param);
+void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param);
+void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y);
+void ( APIENTRY * qglVertex2dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y);
+void ( APIENTRY * qglVertex2fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex2i )(GLint x, GLint y);
+void ( APIENTRY * qglVertex2iv )(const GLint *v);
+void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y);
+void ( APIENTRY * qglVertex2sv )(const GLshort *v);
+void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+void ( APIENTRY * qglVertex3dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+void ( APIENTRY * qglVertex3fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z);
+void ( APIENTRY * qglVertex3iv )(const GLint *v);
+void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z);
+void ( APIENTRY * qglVertex3sv )(const GLshort *v);
+void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+void ( APIENTRY * qglVertex4dv )(const GLdouble *v);
+void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void ( APIENTRY * qglVertex4fv )(const GLfloat *v);
+void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w);
+void ( APIENTRY * qglVertex4iv )(const GLint *v);
+void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+void ( APIENTRY * qglVertex4sv )(const GLshort *v);
+void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+void ( APIENTRY * qglLockArraysEXT)( int, int);
+void ( APIENTRY * qglUnlockArraysEXT) ( void );
+
+BOOL ( WINAPI * qwglSwapIntervalEXT)( int interval );
+BOOL ( WINAPI * qwglGetDeviceGammaRampEXT)( unsigned char *, unsigned char *, unsigned char * );
+BOOL ( WINAPI * qwglSetDeviceGammaRampEXT)( const unsigned char *, const unsigned char *, const unsigned char * );
+void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value );
+void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value );
+void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * );
+void ( APIENTRY * qglSelectTextureSGIS)( GLenum );
+void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat );
+
+static void ( APIENTRY * dllAccum )(GLenum op, GLfloat value);
+static void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref);
+GLboolean ( APIENTRY * dllAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences);
+static void ( APIENTRY * dllArrayElement )(GLint i);
+static void ( APIENTRY * dllBegin )(GLenum mode);
+static void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture);
+static void ( APIENTRY * dllBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
+static void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor);
+static void ( APIENTRY * dllCallList )(GLuint list);
+static void ( APIENTRY * dllCallLists )(GLsizei n, GLenum type, const GLvoid *lists);
+static void ( APIENTRY * dllClear )(GLbitfield mask);
+static void ( APIENTRY * dllClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+static void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+static void ( APIENTRY * dllClearDepth )(GLclampd depth);
+static void ( APIENTRY * dllClearIndex )(GLfloat c);
+static void ( APIENTRY * dllClearStencil )(GLint s);
+static void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation);
+static void ( APIENTRY * dllColor3b )(GLbyte red, GLbyte green, GLbyte blue);
+static void ( APIENTRY * dllColor3bv )(const GLbyte *v);
+static void ( APIENTRY * dllColor3d )(GLdouble red, GLdouble green, GLdouble blue);
+static void ( APIENTRY * dllColor3dv )(const GLdouble *v);
+static void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue);
+static void ( APIENTRY * dllColor3fv )(const GLfloat *v);
+static void ( APIENTRY * dllColor3i )(GLint red, GLint green, GLint blue);
+static void ( APIENTRY * dllColor3iv )(const GLint *v);
+static void ( APIENTRY * dllColor3s )(GLshort red, GLshort green, GLshort blue);
+static void ( APIENTRY * dllColor3sv )(const GLshort *v);
+static void ( APIENTRY * dllColor3ub )(GLubyte red, GLubyte green, GLubyte blue);
+static void ( APIENTRY * dllColor3ubv )(const GLubyte *v);
+static void ( APIENTRY * dllColor3ui )(GLuint red, GLuint green, GLuint blue);
+static void ( APIENTRY * dllColor3uiv )(const GLuint *v);
+static void ( APIENTRY * dllColor3us )(GLushort red, GLushort green, GLushort blue);
+static void ( APIENTRY * dllColor3usv )(const GLushort *v);
+static void ( APIENTRY * dllColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
+static void ( APIENTRY * dllColor4bv )(const GLbyte *v);
+static void ( APIENTRY * dllColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
+static void ( APIENTRY * dllColor4dv )(const GLdouble *v);
+static void ( APIENTRY * dllColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+static void ( APIENTRY * dllColor4fv )(const GLfloat *v);
+static void ( APIENTRY * dllColor4i )(GLint red, GLint green, GLint blue, GLint alpha);
+static void ( APIENTRY * dllColor4iv )(const GLint *v);
+static void ( APIENTRY * dllColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha);
+static void ( APIENTRY * dllColor4sv )(const GLshort *v);
+static void ( APIENTRY * dllColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+static void ( APIENTRY * dllColor4ubv )(const GLubyte *v);
+static void ( APIENTRY * dllColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha);
+static void ( APIENTRY * dllColor4uiv )(const GLuint *v);
+static void ( APIENTRY * dllColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha);
+static void ( APIENTRY * dllColor4usv )(const GLushort *v);
+static void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+static void ( APIENTRY * dllColorMaterial )(GLenum face, GLenum mode);
+static void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
+static void ( APIENTRY * dllCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
+static void ( APIENTRY * dllCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+static void ( APIENTRY * dllCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+static void ( APIENTRY * dllCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+static void ( APIENTRY * dllCullFace )(GLenum mode);
+static void ( APIENTRY * dllDeleteLists )(GLuint list, GLsizei range);
+static void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures);
+static void ( APIENTRY * dllDepthFunc )(GLenum func);
+static void ( APIENTRY * dllDepthMask )(GLboolean flag);
+static void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar);
+static void ( APIENTRY * dllDisable )(GLenum cap);
+static void ( APIENTRY * dllDisableClientState )(GLenum array);
+static void ( APIENTRY * dllDrawArrays )(GLenum mode, GLint first, GLsizei count);
+static void ( APIENTRY * dllDrawBuffer )(GLenum mode);
+static void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+static void ( APIENTRY * dllDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllEdgeFlag )(GLboolean flag);
+static void ( APIENTRY * dllEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllEdgeFlagv )(const GLboolean *flag);
+static void ( APIENTRY * dllEnable )(GLenum cap);
+static void ( APIENTRY * dllEnableClientState )(GLenum array);
+static void ( APIENTRY * dllEnd )(void);
+static void ( APIENTRY * dllEndList )(void);
+static void ( APIENTRY * dllEvalCoord1d )(GLdouble u);
+static void ( APIENTRY * dllEvalCoord1dv )(const GLdouble *u);
+static void ( APIENTRY * dllEvalCoord1f )(GLfloat u);
+static void ( APIENTRY * dllEvalCoord1fv )(const GLfloat *u);
+static void ( APIENTRY * dllEvalCoord2d )(GLdouble u, GLdouble v);
+static void ( APIENTRY * dllEvalCoord2dv )(const GLdouble *u);
+static void ( APIENTRY * dllEvalCoord2f )(GLfloat u, GLfloat v);
+static void ( APIENTRY * dllEvalCoord2fv )(const GLfloat *u);
+static void ( APIENTRY * dllEvalMesh1 )(GLenum mode, GLint i1, GLint i2);
+static void ( APIENTRY * dllEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
+static void ( APIENTRY * dllEvalPoint1 )(GLint i);
+static void ( APIENTRY * dllEvalPoint2 )(GLint i, GLint j);
+static void ( APIENTRY * dllFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer);
+static void ( APIENTRY * dllFinish )(void);
+static void ( APIENTRY * dllFlush )(void);
+static void ( APIENTRY * dllFogf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllFogfv )(GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllFogi )(GLenum pname, GLint param);
+static void ( APIENTRY * dllFogiv )(GLenum pname, const GLint *params);
+static void ( APIENTRY * dllFrontFace )(GLenum mode);
+static void ( APIENTRY * dllFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLuint ( APIENTRY * dllGenLists )(GLsizei range);
+static void ( APIENTRY * dllGenTextures )(GLsizei n, GLuint *textures);
+static void ( APIENTRY * dllGetBooleanv )(GLenum pname, GLboolean *params);
+static void ( APIENTRY * dllGetClipPlane )(GLenum plane, GLdouble *equation);
+static void ( APIENTRY * dllGetDoublev )(GLenum pname, GLdouble *params);
+GLenum ( APIENTRY * dllGetError )(void);
+static void ( APIENTRY * dllGetFloatv )(GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetLightfv )(GLenum light, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetLightiv )(GLenum light, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetMapdv )(GLenum target, GLenum query, GLdouble *v);
+static void ( APIENTRY * dllGetMapfv )(GLenum target, GLenum query, GLfloat *v);
+static void ( APIENTRY * dllGetMapiv )(GLenum target, GLenum query, GLint *v);
+static void ( APIENTRY * dllGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetMaterialiv )(GLenum face, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetPixelMapfv )(GLenum map, GLfloat *values);
+static void ( APIENTRY * dllGetPixelMapuiv )(GLenum map, GLuint *values);
+static void ( APIENTRY * dllGetPixelMapusv )(GLenum map, GLushort *values);
+static void ( APIENTRY * dllGetPointerv )(GLenum pname, GLvoid* *params);
+static void ( APIENTRY * dllGetPolygonStipple )(GLubyte *mask);
+const GLubyte * ( APIENTRY * dllGetString )(GLenum name);
+static void ( APIENTRY * dllGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexEnviv )(GLenum target, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params);
+static void ( APIENTRY * dllGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexGeniv )(GLenum coord, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+static void ( APIENTRY * dllGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params);
+static void ( APIENTRY * dllGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params);
+static void ( APIENTRY * dllGetTexParameteriv )(GLenum target, GLenum pname, GLint *params);
+static void ( APIENTRY * dllHint )(GLenum target, GLenum mode);
+static void ( APIENTRY * dllIndexMask )(GLuint mask);
+static void ( APIENTRY * dllIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllIndexd )(GLdouble c);
+static void ( APIENTRY * dllIndexdv )(const GLdouble *c);
+static void ( APIENTRY * dllIndexf )(GLfloat c);
+static void ( APIENTRY * dllIndexfv )(const GLfloat *c);
+static void ( APIENTRY * dllIndexi )(GLint c);
+static void ( APIENTRY * dllIndexiv )(const GLint *c);
+static void ( APIENTRY * dllIndexs )(GLshort c);
+static void ( APIENTRY * dllIndexsv )(const GLshort *c);
+static void ( APIENTRY * dllIndexub )(GLubyte c);
+static void ( APIENTRY * dllIndexubv )(const GLubyte *c);
+static void ( APIENTRY * dllInitNames )(void);
+static void ( APIENTRY * dllInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer);
+GLboolean ( APIENTRY * dllIsEnabled )(GLenum cap);
+GLboolean ( APIENTRY * dllIsList )(GLuint list);
+GLboolean ( APIENTRY * dllIsTexture )(GLuint texture);
+static void ( APIENTRY * dllLightModelf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllLightModelfv )(GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllLightModeli )(GLenum pname, GLint param);
+static void ( APIENTRY * dllLightModeliv )(GLenum pname, const GLint *params);
+static void ( APIENTRY * dllLightf )(GLenum light, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllLightfv )(GLenum light, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllLighti )(GLenum light, GLenum pname, GLint param);
+static void ( APIENTRY * dllLightiv )(GLenum light, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllLineStipple )(GLint factor, GLushort pattern);
+static void ( APIENTRY * dllLineWidth )(GLfloat width);
+static void ( APIENTRY * dllListBase )(GLuint base);
+static void ( APIENTRY * dllLoadIdentity )(void);
+static void ( APIENTRY * dllLoadMatrixd )(const GLdouble *m);
+static void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m);
+static void ( APIENTRY * dllLoadName )(GLuint name);
+static void ( APIENTRY * dllLogicOp )(GLenum opcode);
+static void ( APIENTRY * dllMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+static void ( APIENTRY * dllMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+static void ( APIENTRY * dllMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+static void ( APIENTRY * dllMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+static void ( APIENTRY * dllMapGrid1d )(GLint un, GLdouble u1, GLdouble u2);
+static void ( APIENTRY * dllMapGrid1f )(GLint un, GLfloat u1, GLfloat u2);
+static void ( APIENTRY * dllMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
+static void ( APIENTRY * dllMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
+static void ( APIENTRY * dllMaterialf )(GLenum face, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllMaterialfv )(GLenum face, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllMateriali )(GLenum face, GLenum pname, GLint param);
+static void ( APIENTRY * dllMaterialiv )(GLenum face, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllMatrixMode )(GLenum mode);
+static void ( APIENTRY * dllMultMatrixd )(const GLdouble *m);
+static void ( APIENTRY * dllMultMatrixf )(const GLfloat *m);
+static void ( APIENTRY * dllNewList )(GLuint list, GLenum mode);
+static void ( APIENTRY * dllNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz);
+static void ( APIENTRY * dllNormal3bv )(const GLbyte *v);
+static void ( APIENTRY * dllNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz);
+static void ( APIENTRY * dllNormal3dv )(const GLdouble *v);
+static void ( APIENTRY * dllNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz);
+static void ( APIENTRY * dllNormal3fv )(const GLfloat *v);
+static void ( APIENTRY * dllNormal3i )(GLint nx, GLint ny, GLint nz);
+static void ( APIENTRY * dllNormal3iv )(const GLint *v);
+static void ( APIENTRY * dllNormal3s )(GLshort nx, GLshort ny, GLshort nz);
+static void ( APIENTRY * dllNormal3sv )(const GLshort *v);
+static void ( APIENTRY * dllNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+static void ( APIENTRY * dllPassThrough )(GLfloat token);
+static void ( APIENTRY * dllPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values);
+static void ( APIENTRY * dllPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values);
+static void ( APIENTRY * dllPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values);
+static void ( APIENTRY * dllPixelStoref )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllPixelStorei )(GLenum pname, GLint param);
+static void ( APIENTRY * dllPixelTransferf )(GLenum pname, GLfloat param);
+static void ( APIENTRY * dllPixelTransferi )(GLenum pname, GLint param);
+static void ( APIENTRY * dllPixelZoom )(GLfloat xfactor, GLfloat yfactor);
+static void ( APIENTRY * dllPointSize )(GLfloat size);
+static void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode);
+static void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units);
+static void ( APIENTRY * dllPolygonStipple )(const GLubyte *mask);
+static void ( APIENTRY * dllPopAttrib )(void);
+static void ( APIENTRY * dllPopClientAttrib )(void);
+static void ( APIENTRY * dllPopMatrix )(void);
+static void ( APIENTRY * dllPopName )(void);
+static void ( APIENTRY * dllPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities);
+static void ( APIENTRY * dllPushAttrib )(GLbitfield mask);
+static void ( APIENTRY * dllPushClientAttrib )(GLbitfield mask);
+static void ( APIENTRY * dllPushMatrix )(void);
+static void ( APIENTRY * dllPushName )(GLuint name);
+static void ( APIENTRY * dllRasterPos2d )(GLdouble x, GLdouble y);
+static void ( APIENTRY * dllRasterPos2dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos2f )(GLfloat x, GLfloat y);
+static void ( APIENTRY * dllRasterPos2fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos2i )(GLint x, GLint y);
+static void ( APIENTRY * dllRasterPos2iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos2s )(GLshort x, GLshort y);
+static void ( APIENTRY * dllRasterPos2sv )(const GLshort *v);
+static void ( APIENTRY * dllRasterPos3d )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllRasterPos3dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos3f )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllRasterPos3fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos3i )(GLint x, GLint y, GLint z);
+static void ( APIENTRY * dllRasterPos3iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos3s )(GLshort x, GLshort y, GLshort z);
+static void ( APIENTRY * dllRasterPos3sv )(const GLshort *v);
+static void ( APIENTRY * dllRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+static void ( APIENTRY * dllRasterPos4dv )(const GLdouble *v);
+static void ( APIENTRY * dllRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+static void ( APIENTRY * dllRasterPos4fv )(const GLfloat *v);
+static void ( APIENTRY * dllRasterPos4i )(GLint x, GLint y, GLint z, GLint w);
+static void ( APIENTRY * dllRasterPos4iv )(const GLint *v);
+static void ( APIENTRY * dllRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+static void ( APIENTRY * dllRasterPos4sv )(const GLshort *v);
+static void ( APIENTRY * dllReadBuffer )(GLenum mode);
+static void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+static void ( APIENTRY * dllRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
+static void ( APIENTRY * dllRectdv )(const GLdouble *v1, const GLdouble *v2);
+static void ( APIENTRY * dllRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+static void ( APIENTRY * dllRectfv )(const GLfloat *v1, const GLfloat *v2);
+static void ( APIENTRY * dllRecti )(GLint x1, GLint y1, GLint x2, GLint y2);
+static void ( APIENTRY * dllRectiv )(const GLint *v1, const GLint *v2);
+static void ( APIENTRY * dllRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
+static void ( APIENTRY * dllRectsv )(const GLshort *v1, const GLshort *v2);
+GLint ( APIENTRY * dllRenderMode )(GLenum mode);
+static void ( APIENTRY * dllRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllScaled )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllScalef )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height);
+static void ( APIENTRY * dllSelectBuffer )(GLsizei size, GLuint *buffer);
+static void ( APIENTRY * dllShadeModel )(GLenum mode);
+static void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask);
+static void ( APIENTRY * dllStencilMask )(GLuint mask);
+static void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass);
+static void ( APIENTRY * dllTexCoord1d )(GLdouble s);
+static void ( APIENTRY * dllTexCoord1dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord1f )(GLfloat s);
+static void ( APIENTRY * dllTexCoord1fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord1i )(GLint s);
+static void ( APIENTRY * dllTexCoord1iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord1s )(GLshort s);
+static void ( APIENTRY * dllTexCoord1sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord2d )(GLdouble s, GLdouble t);
+static void ( APIENTRY * dllTexCoord2dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t);
+static void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord2i )(GLint s, GLint t);
+static void ( APIENTRY * dllTexCoord2iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord2s )(GLshort s, GLshort t);
+static void ( APIENTRY * dllTexCoord2sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord3d )(GLdouble s, GLdouble t, GLdouble r);
+static void ( APIENTRY * dllTexCoord3dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord3f )(GLfloat s, GLfloat t, GLfloat r);
+static void ( APIENTRY * dllTexCoord3fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord3i )(GLint s, GLint t, GLint r);
+static void ( APIENTRY * dllTexCoord3iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord3s )(GLshort s, GLshort t, GLshort r);
+static void ( APIENTRY * dllTexCoord3sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+static void ( APIENTRY * dllTexCoord4dv )(const GLdouble *v);
+static void ( APIENTRY * dllTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+static void ( APIENTRY * dllTexCoord4fv )(const GLfloat *v);
+static void ( APIENTRY * dllTexCoord4i )(GLint s, GLint t, GLint r, GLint q);
+static void ( APIENTRY * dllTexCoord4iv )(const GLint *v);
+static void ( APIENTRY * dllTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q);
+static void ( APIENTRY * dllTexCoord4sv )(const GLshort *v);
+static void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexEnvi )(GLenum target, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexEnviv )(GLenum target, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexGend )(GLenum coord, GLenum pname, GLdouble param);
+static void ( APIENTRY * dllTexGendv )(GLenum coord, GLenum pname, const GLdouble *params);
+static void ( APIENTRY * dllTexGenf )(GLenum coord, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexGeni )(GLenum coord, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexGeniv )(GLenum coord, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param);
+static void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params);
+static void ( APIENTRY * dllTexParameteri )(GLenum target, GLenum pname, GLint param);
+static void ( APIENTRY * dllTexParameteriv )(GLenum target, GLenum pname, const GLint *params);
+static void ( APIENTRY * dllTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+static void ( APIENTRY * dllTranslated )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllTranslatef )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllVertex2d )(GLdouble x, GLdouble y);
+static void ( APIENTRY * dllVertex2dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y);
+static void ( APIENTRY * dllVertex2fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex2i )(GLint x, GLint y);
+static void ( APIENTRY * dllVertex2iv )(const GLint *v);
+static void ( APIENTRY * dllVertex2s )(GLshort x, GLshort y);
+static void ( APIENTRY * dllVertex2sv )(const GLshort *v);
+static void ( APIENTRY * dllVertex3d )(GLdouble x, GLdouble y, GLdouble z);
+static void ( APIENTRY * dllVertex3dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z);
+static void ( APIENTRY * dllVertex3fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex3i )(GLint x, GLint y, GLint z);
+static void ( APIENTRY * dllVertex3iv )(const GLint *v);
+static void ( APIENTRY * dllVertex3s )(GLshort x, GLshort y, GLshort z);
+static void ( APIENTRY * dllVertex3sv )(const GLshort *v);
+static void ( APIENTRY * dllVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+static void ( APIENTRY * dllVertex4dv )(const GLdouble *v);
+static void ( APIENTRY * dllVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+static void ( APIENTRY * dllVertex4fv )(const GLfloat *v);
+static void ( APIENTRY * dllVertex4i )(GLint x, GLint y, GLint z, GLint w);
+static void ( APIENTRY * dllVertex4iv )(const GLint *v);
+static void ( APIENTRY * dllVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w);
+static void ( APIENTRY * dllVertex4sv )(const GLshort *v);
+static void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height);
+
+static void APIENTRY logAccum(GLenum op, GLfloat value)
+{
+	fprintf( glw_state.log_fp, "glAccum\n" );
+	dllAccum( op, value );
+}
+
+static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref)
+{
+	fprintf( glw_state.log_fp, "glAlphaFunc( 0x%x, %f )\n", func, ref );
+	dllAlphaFunc( func, ref );
+}
+
+static GLboolean APIENTRY logAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences)
+{
+	fprintf( glw_state.log_fp, "glAreTexturesResident\n" );
+	return dllAreTexturesResident( n, textures, residences );
+}
+
+static void APIENTRY logArrayElement(GLint i)
+{
+	fprintf( glw_state.log_fp, "glArrayElement\n" );
+	dllArrayElement( i );
+}
+
+static void APIENTRY logBegin(GLenum mode)
+{
+	fprintf( glw_state.log_fp, "glBegin( 0x%x )\n", mode );
+	dllBegin( mode );
+}
+
+static void APIENTRY logBindTexture(GLenum target, GLuint texture)
+{
+	fprintf( glw_state.log_fp, "glBindTexture( 0x%x, %u )\n", target, texture );
+	dllBindTexture( target, texture );
+}
+
+static void APIENTRY logBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
+{
+	fprintf( glw_state.log_fp, "glBitmap\n" );
+	dllBitmap( width, height, xorig, yorig, xmove, ymove, bitmap );
+}
+
+static void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+	fprintf( glw_state.log_fp, "glBlendFunc( 0x%x, 0x%x )\n", sfactor, dfactor );
+	dllBlendFunc( sfactor, dfactor );
+}
+
+static void APIENTRY logCallList(GLuint list)
+{
+	fprintf( glw_state.log_fp, "glCallList( %u )\n", list );
+	dllCallList( list );
+}
+
+static void APIENTRY logCallLists(GLsizei n, GLenum type, const void *lists)
+{
+	fprintf( glw_state.log_fp, "glCallLists\n" );
+	dllCallLists( n, type, lists );
+}
+
+static void APIENTRY logClear(GLbitfield mask)
+{
+	fprintf( glw_state.log_fp, "glClear\n" );
+	dllClear( mask );
+}
+
+static void APIENTRY logClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+	fprintf( glw_state.log_fp, "glClearAccum\n" );
+	dllClearAccum( red, green, blue, alpha );
+}
+
+static void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+	fprintf( glw_state.log_fp, "glClearColor\n" );
+	dllClearColor( red, green, blue, alpha );
+}
+
+static void APIENTRY logClearDepth(GLclampd depth)
+{
+	fprintf( glw_state.log_fp, "glClearDepth\n" );
+	dllClearDepth( depth );
+}
+
+static void APIENTRY logClearIndex(GLfloat c)
+{
+	fprintf( glw_state.log_fp, "glClearIndex\n" );
+	dllClearIndex( c );
+}
+
+static void APIENTRY logClearStencil(GLint s)
+{
+	fprintf( glw_state.log_fp, "glClearStencil\n" );
+	dllClearStencil( s );
+}
+
+static void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation)
+{
+	fprintf( glw_state.log_fp, "glClipPlane\n" );
+	dllClipPlane( plane, equation );
+}
+
+static void APIENTRY logColor3b(GLbyte red, GLbyte green, GLbyte blue)
+{
+	fprintf( glw_state.log_fp, "glColor3b\n" );
+	dllColor3b( red, green, blue );
+}
+
+static void APIENTRY logColor3bv(const GLbyte *v)
+{
+	fprintf( glw_state.log_fp, "glColor3bv\n" );
+	dllColor3bv( v );
+}
+
+static void APIENTRY logColor3d(GLdouble red, GLdouble green, GLdouble blue)
+{
+	fprintf( glw_state.log_fp, "glColor3d\n" );
+	dllColor3d( red, green, blue );
+}
+
+static void APIENTRY logColor3dv(const GLdouble *v)
+{
+	fprintf( glw_state.log_fp, "glColor3dv\n" );
+	dllColor3dv( v );
+}
+
+static void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue)
+{
+	fprintf( glw_state.log_fp, "glColor3f\n" );
+	dllColor3f( red, green, blue );
+}
+
+static void APIENTRY logColor3fv(const GLfloat *v)
+{
+	fprintf( glw_state.log_fp, "glColor3fv\n" );
+	dllColor3fv( v );
+}
+
+static void APIENTRY logColor3i(GLint red, GLint green, GLint blue)
+{
+	fprintf( glw_state.log_fp, "glColor3i\n" );
+	dllColor3i( red, green, blue );
+}
+
+static void APIENTRY logColor3iv(const GLint *v)
+{
+	fprintf( glw_state.log_fp, "glColor3iv\n" );
+	dllColor3iv( v );
+}
+
+static void APIENTRY logColor3s(GLshort red, GLshort green, GLshort blue)
+{
+	fprintf( glw_state.log_fp, "glColor3s\n" );
+	dllColor3s( red, green, blue );
+}
+
+static void APIENTRY logColor3sv(const GLshort *v)
+{
+	fprintf( glw_state.log_fp, "glColor3sv\n" );
+	dllColor3sv( v );
+}
+
+static void APIENTRY logColor3ub(GLubyte red, GLubyte green, GLubyte blue)
+{
+	fprintf( glw_state.log_fp, "glColor3ub\n" );
+	dllColor3ub( red, green, blue );
+}
+
+static void APIENTRY logColor3ubv(const GLubyte *v)
+{
+	fprintf( glw_state.log_fp, "glColor3ubv\n" );
+	dllColor3ubv( v );
+}
+
+#define SIG( x ) fprintf( glw_state.log_fp, x "\n" )
+
+static void APIENTRY logColor3ui(GLuint red, GLuint green, GLuint blue)
+{
+	SIG( "glColor3ui" );
+	dllColor3ui( red, green, blue );
+}
+
+static void APIENTRY logColor3uiv(const GLuint *v)
+{
+	SIG( "glColor3uiv" );
+	dllColor3uiv( v );
+}
+
+static void APIENTRY logColor3us(GLushort red, GLushort green, GLushort blue)
+{
+	SIG( "glColor3us" );
+	dllColor3us( red, green, blue );
+}
+
+static void APIENTRY logColor3usv(const GLushort *v)
+{
+	SIG( "glColor3usv" );
+	dllColor3usv( v );
+}
+
+static void APIENTRY logColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha)
+{
+	SIG( "glColor4b" );
+	dllColor4b( red, green, blue, alpha );
+}
+
+static void APIENTRY logColor4bv(const GLbyte *v)
+{
+	SIG( "glColor4bv" );
+	dllColor4bv( v );
+}
+
+static void APIENTRY logColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
+{
+	SIG( "glColor4d" );
+	dllColor4d( red, green, blue, alpha );
+}
+static void APIENTRY logColor4dv(const GLdouble *v)
+{
+	SIG( "glColor4dv" );
+	dllColor4dv( v );
+}
+static void APIENTRY logColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+	fprintf( glw_state.log_fp, "glColor4f( %f,%f,%f,%f )\n", red, green, blue, alpha );
+	dllColor4f( red, green, blue, alpha );
+}
+static void APIENTRY logColor4fv(const GLfloat *v)
+{
+	fprintf( glw_state.log_fp, "glColor4fv( %f,%f,%f,%f )\n", v[0], v[1], v[2], v[3] );
+	dllColor4fv( v );
+}
+static void APIENTRY logColor4i(GLint red, GLint green, GLint blue, GLint alpha)
+{
+	SIG( "glColor4i" );
+	dllColor4i( red, green, blue, alpha );
+}
+static void APIENTRY logColor4iv(const GLint *v)
+{
+	SIG( "glColor4iv" );
+	dllColor4iv( v );
+}
+static void APIENTRY logColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha)
+{
+	SIG( "glColor4s" );
+	dllColor4s( red, green, blue, alpha );
+}
+static void APIENTRY logColor4sv(const GLshort *v)
+{
+	SIG( "glColor4sv" );
+	dllColor4sv( v );
+}
+static void APIENTRY logColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+{
+	SIG( "glColor4b" );
+	dllColor4b( red, green, blue, alpha );
+}
+static void APIENTRY logColor4ubv(const GLubyte *v)
+{
+	SIG( "glColor4ubv" );
+	dllColor4ubv( v );
+}
+static void APIENTRY logColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha)
+{
+	SIG( "glColor4ui" );
+	dllColor4ui( red, green, blue, alpha );
+}
+static void APIENTRY logColor4uiv(const GLuint *v)
+{
+	SIG( "glColor4uiv" );
+	dllColor4uiv( v );
+}
+static void APIENTRY logColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha)
+{
+	SIG( "glColor4us" );
+	dllColor4us( red, green, blue, alpha );
+}
+static void APIENTRY logColor4usv(const GLushort *v)
+{
+	SIG( "glColor4usv" );
+	dllColor4usv( v );
+}
+static void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+	SIG( "glColorMask" );
+	dllColorMask( red, green, blue, alpha );
+}
+static void APIENTRY logColorMaterial(GLenum face, GLenum mode)
+{
+	SIG( "glColorMaterial" );
+	dllColorMaterial( face, mode );
+}
+
+static void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glColorPointer" );
+	dllColorPointer( size, type, stride, pointer );
+}
+
+static void APIENTRY logCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)
+{
+	SIG( "glCopyPixels" );
+	dllCopyPixels( x, y, width, height, type );
+}
+
+static void APIENTRY logCopyTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border)
+{
+	SIG( "glCopyTexImage1D" );
+	dllCopyTexImage1D( target, level, internalFormat, x, y, width, border );
+}
+
+static void APIENTRY logCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+	SIG( "glCopyTexImage2D" );
+	dllCopyTexImage2D( target, level, internalFormat, x, y, width, height, border );
+}
+
+static void APIENTRY logCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+	SIG( "glCopyTexSubImage1D" );
+	dllCopyTexSubImage1D( target, level, xoffset, x, y, width );
+}
+
+static void APIENTRY logCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glCopyTexSubImage2D" );
+	dllCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height );
+}
+
+static void APIENTRY logCullFace(GLenum mode)
+{
+	SIG( "glCullFace" );
+	dllCullFace( mode );
+}
+
+static void APIENTRY logDeleteLists(GLuint list, GLsizei range)
+{
+	SIG( "glDeleteLists" );
+	dllDeleteLists( list, range );
+}
+
+static void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures)
+{
+	SIG( "glDeleteTextures" );
+	dllDeleteTextures( n, textures );
+}
+
+static void APIENTRY logDepthFunc(GLenum func)
+{
+	SIG( "glDepthFunc" );
+	dllDepthFunc( func );
+}
+
+static void APIENTRY logDepthMask(GLboolean flag)
+{
+	SIG( "glDepthMask" );
+	dllDepthMask( flag );
+}
+
+static void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar)
+{
+	SIG( "glDepthRange" );
+	dllDepthRange( zNear, zFar );
+}
+
+static void APIENTRY logDisable(GLenum cap)
+{
+	fprintf( glw_state.log_fp, "glDisable( 0x%x )\n", cap );
+	dllDisable( cap );
+}
+
+static void APIENTRY logDisableClientState(GLenum array)
+{
+	SIG( "glDisableClientState" );
+	dllDisableClientState( array );
+}
+
+static void APIENTRY logDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+	SIG( "glDrawArrays" );
+	dllDrawArrays( mode, first, count );
+}
+
+static void APIENTRY logDrawBuffer(GLenum mode)
+{
+	SIG( "glDrawBuffer" );
+	dllDrawBuffer( mode );
+}
+
+static void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+	SIG( "glDrawElements" );
+	dllDrawElements( mode, count, type, indices );
+}
+
+static void APIENTRY logDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glDrawPixels" );
+	dllDrawPixels( width, height, format, type, pixels );
+}
+
+static void APIENTRY logEdgeFlag(GLboolean flag)
+{
+	SIG( "glEdgeFlag" );
+	dllEdgeFlag( flag );
+}
+
+static void APIENTRY logEdgeFlagPointer(GLsizei stride, const void *pointer)
+{
+	SIG( "glEdgeFlagPointer" );
+	dllEdgeFlagPointer( stride, pointer );
+}
+
+static void APIENTRY logEdgeFlagv(const GLboolean *flag)
+{
+	SIG( "glEdgeFlagv" );
+	dllEdgeFlagv( flag );
+}
+
+static void APIENTRY logEnable(GLenum cap)
+{
+	fprintf( glw_state.log_fp, "glEnable( 0x%x )\n", cap );
+	dllEnable( cap );
+}
+
+static void APIENTRY logEnableClientState(GLenum array)
+{
+	SIG( "glEnableClientState" );
+	dllEnableClientState( array );
+}
+
+static void APIENTRY logEnd(void)
+{
+	SIG( "glEnd" );
+	dllEnd();
+}
+
+static void APIENTRY logEndList(void)
+{
+	SIG( "glEndList" );
+	dllEndList();
+}
+
+static void APIENTRY logEvalCoord1d(GLdouble u)
+{
+	SIG( "glEvalCoord1d" );
+	dllEvalCoord1d( u );
+}
+
+static void APIENTRY logEvalCoord1dv(const GLdouble *u)
+{
+	SIG( "glEvalCoord1dv" );
+	dllEvalCoord1dv( u );
+}
+
+static void APIENTRY logEvalCoord1f(GLfloat u)
+{
+	SIG( "glEvalCoord1f" );
+	dllEvalCoord1f( u );
+}
+
+static void APIENTRY logEvalCoord1fv(const GLfloat *u)
+{
+	SIG( "glEvalCoord1fv" );
+	dllEvalCoord1fv( u );
+}
+static void APIENTRY logEvalCoord2d(GLdouble u, GLdouble v)
+{
+	SIG( "glEvalCoord2d" );
+	dllEvalCoord2d( u, v );
+}
+static void APIENTRY logEvalCoord2dv(const GLdouble *u)
+{
+	SIG( "glEvalCoord2dv" );
+	dllEvalCoord2dv( u );
+}
+static void APIENTRY logEvalCoord2f(GLfloat u, GLfloat v)
+{
+	SIG( "glEvalCoord2f" );
+	dllEvalCoord2f( u, v );
+}
+static void APIENTRY logEvalCoord2fv(const GLfloat *u)
+{
+	SIG( "glEvalCoord2fv" );
+	dllEvalCoord2fv( u );
+}
+
+static void APIENTRY logEvalMesh1(GLenum mode, GLint i1, GLint i2)
+{
+	SIG( "glEvalMesh1" );
+	dllEvalMesh1( mode, i1, i2 );
+}
+static void APIENTRY logEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
+{
+	SIG( "glEvalMesh2" );
+	dllEvalMesh2( mode, i1, i2, j1, j2 );
+}
+static void APIENTRY logEvalPoint1(GLint i)
+{
+	SIG( "glEvalPoint1" );
+	dllEvalPoint1( i );
+}
+static void APIENTRY logEvalPoint2(GLint i, GLint j)
+{
+	SIG( "glEvalPoint2" );
+	dllEvalPoint2( i, j );
+}
+
+static void APIENTRY logFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer)
+{
+	SIG( "glFeedbackBuffer" );
+	dllFeedbackBuffer( size, type, buffer );
+}
+
+static void APIENTRY logFinish(void)
+{
+	SIG( "glFinish" );
+	dllFinish();
+}
+
+static void APIENTRY logFlush(void)
+{
+	SIG( "glFlush" );
+	dllFlush();
+}
+
+static void APIENTRY logFogf(GLenum pname, GLfloat param)
+{
+	SIG( "glFogf" );
+	dllFogf( pname, param );
+}
+
+static void APIENTRY logFogfv(GLenum pname, const GLfloat *params)
+{
+	SIG( "glFogfv" );
+	dllFogfv( pname, params );
+}
+
+static void APIENTRY logFogi(GLenum pname, GLint param)
+{
+	SIG( "glFogi" );
+	dllFogi( pname, param );
+}
+
+static void APIENTRY logFogiv(GLenum pname, const GLint *params)
+{
+	SIG( "glFogiv" );
+	dllFogiv( pname, params );
+}
+
+static void APIENTRY logFrontFace(GLenum mode)
+{
+	SIG( "glFrontFace" );
+	dllFrontFace( mode );
+}
+
+static void APIENTRY logFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+{
+	SIG( "glFrustum" );
+	dllFrustum( left, right, bottom, top, zNear, zFar );
+}
+
+static GLuint APIENTRY logGenLists(GLsizei range)
+{
+	SIG( "glGenLists" );
+	return dllGenLists( range );
+}
+
+static void APIENTRY logGenTextures(GLsizei n, GLuint *textures)
+{
+	SIG( "glGenTextures" );
+	dllGenTextures( n, textures );
+}
+
+static void APIENTRY logGetBooleanv(GLenum pname, GLboolean *params)
+{
+	SIG( "glGetBooleanv" );
+	dllGetBooleanv( pname, params );
+}
+
+static void APIENTRY logGetClipPlane(GLenum plane, GLdouble *equation)
+{
+	SIG( "glGetClipPlane" );
+	dllGetClipPlane( plane, equation );
+}
+
+static void APIENTRY logGetDoublev(GLenum pname, GLdouble *params)
+{
+	SIG( "glGetDoublev" );
+	dllGetDoublev( pname, params );
+}
+
+static GLenum APIENTRY logGetError(void)
+{
+	SIG( "glGetError" );
+	return dllGetError();
+}
+
+static void APIENTRY logGetFloatv(GLenum pname, GLfloat *params)
+{
+	SIG( "glGetFloatv" );
+	dllGetFloatv( pname, params );
+}
+
+static void APIENTRY logGetIntegerv(GLenum pname, GLint *params)
+{
+	SIG( "glGetIntegerv" );
+	dllGetIntegerv( pname, params );
+}
+
+static void APIENTRY logGetLightfv(GLenum light, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetLightfv" );
+	dllGetLightfv( light, pname, params );
+}
+
+static void APIENTRY logGetLightiv(GLenum light, GLenum pname, GLint *params)
+{
+	SIG( "glGetLightiv" );
+	dllGetLightiv( light, pname, params );
+}
+
+static void APIENTRY logGetMapdv(GLenum target, GLenum query, GLdouble *v)
+{
+	SIG( "glGetMapdv" );
+	dllGetMapdv( target, query, v );
+}
+
+static void APIENTRY logGetMapfv(GLenum target, GLenum query, GLfloat *v)
+{
+	SIG( "glGetMapfv" );
+	dllGetMapfv( target, query, v );
+}
+
+static void APIENTRY logGetMapiv(GLenum target, GLenum query, GLint *v)
+{
+	SIG( "glGetMapiv" );
+	dllGetMapiv( target, query, v );
+}
+
+static void APIENTRY logGetMaterialfv(GLenum face, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetMaterialfv" );
+	dllGetMaterialfv( face, pname, params );
+}
+
+static void APIENTRY logGetMaterialiv(GLenum face, GLenum pname, GLint *params)
+{
+	SIG( "glGetMaterialiv" );
+	dllGetMaterialiv( face, pname, params );
+}
+
+static void APIENTRY logGetPixelMapfv(GLenum map, GLfloat *values)
+{
+	SIG( "glGetPixelMapfv" );
+	dllGetPixelMapfv( map, values );
+}
+
+static void APIENTRY logGetPixelMapuiv(GLenum map, GLuint *values)
+{
+	SIG( "glGetPixelMapuiv" );
+	dllGetPixelMapuiv( map, values );
+}
+
+static void APIENTRY logGetPixelMapusv(GLenum map, GLushort *values)
+{
+	SIG( "glGetPixelMapusv" );
+	dllGetPixelMapusv( map, values );
+}
+
+static void APIENTRY logGetPointerv(GLenum pname, GLvoid* *params)
+{
+	SIG( "glGetPointerv" );
+	dllGetPointerv( pname, params );
+}
+
+static void APIENTRY logGetPolygonStipple(GLubyte *mask)
+{
+	SIG( "glGetPolygonStipple" );
+	dllGetPolygonStipple( mask );
+}
+
+static const GLubyte * APIENTRY logGetString(GLenum name)
+{
+	SIG( "glGetString" );
+	return dllGetString( name );
+}
+
+static void APIENTRY logGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexEnvfv" );
+	dllGetTexEnvfv( target, pname, params );
+}
+
+static void APIENTRY logGetTexEnviv(GLenum target, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexEnviv" );
+	dllGetTexEnviv( target, pname, params );
+}
+
+static void APIENTRY logGetTexGendv(GLenum coord, GLenum pname, GLdouble *params)
+{
+	SIG( "glGetTexGendv" );
+	dllGetTexGendv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexGenfv" );
+	dllGetTexGenfv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexGeniv(GLenum coord, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexGeniv" );
+	dllGetTexGeniv( coord, pname, params );
+}
+
+static void APIENTRY logGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels)
+{
+	SIG( "glGetTexImage" );
+	dllGetTexImage( target, level, format, type, pixels );
+}
+static void APIENTRY logGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params )
+{
+	SIG( "glGetTexLevelParameterfv" );
+	dllGetTexLevelParameterfv( target, level, pname, params );
+}
+
+static void APIENTRY logGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexLevelParameteriv" );
+	dllGetTexLevelParameteriv( target, level, pname, params );
+}
+
+static void APIENTRY logGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params)
+{
+	SIG( "glGetTexParameterfv" );
+	dllGetTexParameterfv( target, pname, params );
+}
+
+static void APIENTRY logGetTexParameteriv(GLenum target, GLenum pname, GLint *params)
+{
+	SIG( "glGetTexParameteriv" );
+	dllGetTexParameteriv( target, pname, params );
+}
+
+static void APIENTRY logHint(GLenum target, GLenum mode)
+{
+	fprintf( glw_state.log_fp, "glHint( 0x%x, 0x%x )\n", target, mode );
+	dllHint( target, mode );
+}
+
+static void APIENTRY logIndexMask(GLuint mask)
+{
+	SIG( "glIndexMask" );
+	dllIndexMask( mask );
+}
+
+static void APIENTRY logIndexPointer(GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glIndexPointer" );
+	dllIndexPointer( type, stride, pointer );
+}
+
+static void APIENTRY logIndexd(GLdouble c)
+{
+	SIG( "glIndexd" );
+	dllIndexd( c );
+}
+
+static void APIENTRY logIndexdv(const GLdouble *c)
+{
+	SIG( "glIndexdv" );
+	dllIndexdv( c );
+}
+
+static void APIENTRY logIndexf(GLfloat c)
+{
+	SIG( "glIndexf" );
+	dllIndexf( c );
+}
+
+static void APIENTRY logIndexfv(const GLfloat *c)
+{
+	SIG( "glIndexfv" );
+	dllIndexfv( c );
+}
+
+static void APIENTRY logIndexi(GLint c)
+{
+	SIG( "glIndexi" );
+	dllIndexi( c );
+}
+
+static void APIENTRY logIndexiv(const GLint *c)
+{
+	SIG( "glIndexiv" );
+	dllIndexiv( c );
+}
+
+static void APIENTRY logIndexs(GLshort c)
+{
+	SIG( "glIndexs" );
+	dllIndexs( c );
+}
+
+static void APIENTRY logIndexsv(const GLshort *c)
+{
+	SIG( "glIndexsv" );
+	dllIndexsv( c );
+}
+
+static void APIENTRY logIndexub(GLubyte c)
+{
+	SIG( "glIndexub" );
+	dllIndexub( c );
+}
+
+static void APIENTRY logIndexubv(const GLubyte *c)
+{
+	SIG( "glIndexubv" );
+	dllIndexubv( c );
+}
+
+static void APIENTRY logInitNames(void)
+{
+	SIG( "glInitNames" );
+	dllInitNames();
+}
+
+static void APIENTRY logInterleavedArrays(GLenum format, GLsizei stride, const void *pointer)
+{
+	SIG( "glInterleavedArrays" );
+	dllInterleavedArrays( format, stride, pointer );
+}
+
+static GLboolean APIENTRY logIsEnabled(GLenum cap)
+{
+	SIG( "glIsEnabled" );
+	return dllIsEnabled( cap );
+}
+static GLboolean APIENTRY logIsList(GLuint list)
+{
+	SIG( "glIsList" );
+	return dllIsList( list );
+}
+static GLboolean APIENTRY logIsTexture(GLuint texture)
+{
+	SIG( "glIsTexture" );
+	return dllIsTexture( texture );
+}
+
+static void APIENTRY logLightModelf(GLenum pname, GLfloat param)
+{
+	SIG( "glLightModelf" );
+	dllLightModelf( pname, param );
+}
+
+static void APIENTRY logLightModelfv(GLenum pname, const GLfloat *params)
+{
+	SIG( "glLightModelfv" );
+	dllLightModelfv( pname, params );
+}
+
+static void APIENTRY logLightModeli(GLenum pname, GLint param)
+{
+	SIG( "glLightModeli" );
+	dllLightModeli( pname, param );
+
+}
+
+static void APIENTRY logLightModeliv(GLenum pname, const GLint *params)
+{
+	SIG( "glLightModeliv" );
+	dllLightModeliv( pname, params );
+}
+
+static void APIENTRY logLightf(GLenum light, GLenum pname, GLfloat param)
+{
+	SIG( "glLightf" );
+	dllLightf( light, pname, param );
+}
+
+static void APIENTRY logLightfv(GLenum light, GLenum pname, const GLfloat *params)
+{
+	SIG( "glLightfv" );
+	dllLightfv( light, pname, params );
+}
+
+static void APIENTRY logLighti(GLenum light, GLenum pname, GLint param)
+{
+	SIG( "glLighti" );
+	dllLighti( light, pname, param );
+}
+
+static void APIENTRY logLightiv(GLenum light, GLenum pname, const GLint *params)
+{
+	SIG( "glLightiv" );
+	dllLightiv( light, pname, params );
+}
+
+static void APIENTRY logLineStipple(GLint factor, GLushort pattern)
+{
+	SIG( "glLineStipple" );
+	dllLineStipple( factor, pattern );
+}
+
+static void APIENTRY logLineWidth(GLfloat width)
+{
+	SIG( "glLineWidth" );
+	dllLineWidth( width );
+}
+
+static void APIENTRY logListBase(GLuint base)
+{
+	SIG( "glListBase" );
+	dllListBase( base );
+}
+
+static void APIENTRY logLoadIdentity(void)
+{
+	SIG( "glLoadIdentity" );
+	dllLoadIdentity();
+}
+
+static void APIENTRY logLoadMatrixd(const GLdouble *m)
+{
+	SIG( "glLoadMatrixd" );
+	dllLoadMatrixd( m );
+}
+
+static void APIENTRY logLoadMatrixf(const GLfloat *m)
+{
+	SIG( "glLoadMatrixf" );
+	dllLoadMatrixf( m );
+}
+
+static void APIENTRY logLoadName(GLuint name)
+{
+	SIG( "glLoadName" );
+	dllLoadName( name );
+}
+
+static void APIENTRY logLogicOp(GLenum opcode)
+{
+	SIG( "glLogicOp" );
+	dllLogicOp( opcode );
+}
+
+static void APIENTRY logMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points)
+{
+	SIG( "glMap1d" );
+	dllMap1d( target, u1, u2, stride, order, points );
+}
+
+static void APIENTRY logMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points)
+{
+	SIG( "glMap1f" );
+	dllMap1f( target, u1, u2, stride, order, points );
+}
+
+static void APIENTRY logMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points)
+{
+	SIG( "glMap2d" );
+	dllMap2d( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points );
+}
+
+static void APIENTRY logMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points)
+{
+	SIG( "glMap2f" );
+	dllMap2f( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points );
+}
+
+static void APIENTRY logMapGrid1d(GLint un, GLdouble u1, GLdouble u2)
+{
+	SIG( "glMapGrid1d" );
+	dllMapGrid1d( un, u1, u2 );
+}
+
+static void APIENTRY logMapGrid1f(GLint un, GLfloat u1, GLfloat u2)
+{
+	SIG( "glMapGrid1f" );
+	dllMapGrid1f( un, u1, u2 );
+}
+
+static void APIENTRY logMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2)
+{
+	SIG( "glMapGrid2d" );
+	dllMapGrid2d( un, u1, u2, vn, v1, v2 );
+}
+static void APIENTRY logMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2)
+{
+	SIG( "glMapGrid2f" );
+	dllMapGrid2f( un, u1, u2, vn, v1, v2 );
+}
+static void APIENTRY logMaterialf(GLenum face, GLenum pname, GLfloat param)
+{
+	SIG( "glMaterialf" );
+	dllMaterialf( face, pname, param );
+}
+static void APIENTRY logMaterialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+	SIG( "glMaterialfv" );
+	dllMaterialfv( face, pname, params );
+}
+
+static void APIENTRY logMateriali(GLenum face, GLenum pname, GLint param)
+{
+	SIG( "glMateriali" );
+	dllMateriali( face, pname, param );
+}
+
+static void APIENTRY logMaterialiv(GLenum face, GLenum pname, const GLint *params)
+{
+	SIG( "glMaterialiv" );
+	dllMaterialiv( face, pname, params );
+}
+
+static void APIENTRY logMatrixMode(GLenum mode)
+{
+	SIG( "glMatrixMode" );
+	dllMatrixMode( mode );
+}
+
+static void APIENTRY logMultMatrixd(const GLdouble *m)
+{
+	SIG( "glMultMatrixd" );
+	dllMultMatrixd( m );
+}
+
+static void APIENTRY logMultMatrixf(const GLfloat *m)
+{
+	SIG( "glMultMatrixf" );
+	dllMultMatrixf( m );
+}
+
+static void APIENTRY logNewList(GLuint list, GLenum mode)
+{
+	SIG( "glNewList" );
+	dllNewList( list, mode );
+}
+
+static void APIENTRY logNormal3b(GLbyte nx, GLbyte ny, GLbyte nz)
+{
+	SIG ("glNormal3b" );
+	dllNormal3b( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3bv(const GLbyte *v)
+{
+	SIG( "glNormal3bv" );
+	dllNormal3bv( v );
+}
+
+static void APIENTRY logNormal3d(GLdouble nx, GLdouble ny, GLdouble nz)
+{
+	SIG( "glNormal3d" );
+	dllNormal3d( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3dv(const GLdouble *v)
+{
+	SIG( "glNormal3dv" );
+	dllNormal3dv( v );
+}
+
+static void APIENTRY logNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
+{
+	SIG( "glNormal3f" );
+	dllNormal3f( nx, ny, nz );
+}
+
+static void APIENTRY logNormal3fv(const GLfloat *v)
+{
+	SIG( "glNormal3fv" );
+	dllNormal3fv( v );
+}
+static void APIENTRY logNormal3i(GLint nx, GLint ny, GLint nz)
+{
+	SIG( "glNormal3i" );
+	dllNormal3i( nx, ny, nz );
+}
+static void APIENTRY logNormal3iv(const GLint *v)
+{
+	SIG( "glNormal3iv" );
+	dllNormal3iv( v );
+}
+static void APIENTRY logNormal3s(GLshort nx, GLshort ny, GLshort nz)
+{
+	SIG( "glNormal3s" );
+	dllNormal3s( nx, ny, nz );
+}
+static void APIENTRY logNormal3sv(const GLshort *v)
+{
+	SIG( "glNormal3sv" );
+	dllNormal3sv( v );
+}
+static void APIENTRY logNormalPointer(GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glNormalPointer" );
+	dllNormalPointer( type, stride, pointer );
+}
+static void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+{
+	SIG( "glOrtho" );
+	dllOrtho( left, right, bottom, top, zNear, zFar );
+}
+
+static void APIENTRY logPassThrough(GLfloat token)
+{
+	SIG( "glPassThrough" );
+	dllPassThrough( token );
+}
+
+static void APIENTRY logPixelMapfv(GLenum map, GLsizei mapsize, const GLfloat *values)
+{
+	SIG( "glPixelMapfv" );
+	dllPixelMapfv( map, mapsize, values );
+}
+
+static void APIENTRY logPixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values)
+{
+	SIG( "glPixelMapuiv" );
+	dllPixelMapuiv( map, mapsize, values );
+}
+
+static void APIENTRY logPixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values)
+{
+	SIG( "glPixelMapusv" );
+	dllPixelMapusv( map, mapsize, values );
+}
+static void APIENTRY logPixelStoref(GLenum pname, GLfloat param)
+{
+	SIG( "glPixelStoref" );
+	dllPixelStoref( pname, param );
+}
+static void APIENTRY logPixelStorei(GLenum pname, GLint param)
+{
+	SIG( "glPixelStorei" );
+	dllPixelStorei( pname, param );
+}
+static void APIENTRY logPixelTransferf(GLenum pname, GLfloat param)
+{
+	SIG( "glPixelTransferf" );
+	dllPixelTransferf( pname, param );
+}
+
+static void APIENTRY logPixelTransferi(GLenum pname, GLint param)
+{
+	SIG( "glPixelTransferi" );
+	dllPixelTransferi( pname, param );
+}
+
+static void APIENTRY logPixelZoom(GLfloat xfactor, GLfloat yfactor)
+{
+	SIG( "glPixelZoom" );
+	dllPixelZoom( xfactor, yfactor );
+}
+
+static void APIENTRY logPointSize(GLfloat size)
+{
+	SIG( "glPointSize" );
+	dllPointSize( size );
+}
+
+static void APIENTRY logPolygonMode(GLenum face, GLenum mode)
+{
+	fprintf( glw_state.log_fp, "glPolygonMode( 0x%x, 0x%x )\n", face, mode );
+	dllPolygonMode( face, mode );
+}
+
+static void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units)
+{
+	SIG( "glPolygonOffset" );
+	dllPolygonOffset( factor, units );
+}
+static void APIENTRY logPolygonStipple(const GLubyte *mask )
+{
+	SIG( "glPolygonStipple" );
+	dllPolygonStipple( mask );
+}
+static void APIENTRY logPopAttrib(void)
+{
+	SIG( "glPopAttrib" );
+	dllPopAttrib();
+}
+
+static void APIENTRY logPopClientAttrib(void)
+{
+	SIG( "glPopClientAttrib" );
+	dllPopClientAttrib();
+}
+
+static void APIENTRY logPopMatrix(void)
+{
+	SIG( "glPopMatrix" );
+	dllPopMatrix();
+}
+
+static void APIENTRY logPopName(void)
+{
+	SIG( "glPopName" );
+	dllPopName();
+}
+
+static void APIENTRY logPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities)
+{
+	SIG( "glPrioritizeTextures" );
+	dllPrioritizeTextures( n, textures, priorities );
+}
+
+static void APIENTRY logPushAttrib(GLbitfield mask)
+{
+	SIG( "glPushAttrib" );
+	dllPushAttrib( mask );
+}
+
+static void APIENTRY logPushClientAttrib(GLbitfield mask)
+{
+	SIG( "glPushClientAttrib" );
+	dllPushClientAttrib( mask );
+}
+
+static void APIENTRY logPushMatrix(void)
+{
+	SIG( "glPushMatrix" );
+	dllPushMatrix();
+}
+
+static void APIENTRY logPushName(GLuint name)
+{
+	SIG( "glPushName" );
+	dllPushName( name );
+}
+
+static void APIENTRY logRasterPos2d(GLdouble x, GLdouble y)
+{
+	SIG ("glRasterPot2d" );
+	dllRasterPos2d( x, y );
+}
+
+static void APIENTRY logRasterPos2dv(const GLdouble *v)
+{
+	SIG( "glRasterPos2dv" );
+	dllRasterPos2dv( v );
+}
+
+static void APIENTRY logRasterPos2f(GLfloat x, GLfloat y)
+{
+	SIG( "glRasterPos2f" );
+	dllRasterPos2f( x, y );
+}
+static void APIENTRY logRasterPos2fv(const GLfloat *v)
+{
+	SIG( "glRasterPos2dv" );
+	dllRasterPos2fv( v );
+}
+static void APIENTRY logRasterPos2i(GLint x, GLint y)
+{
+	SIG( "glRasterPos2if" );
+	dllRasterPos2i( x, y );
+}
+static void APIENTRY logRasterPos2iv(const GLint *v)
+{
+	SIG( "glRasterPos2iv" );
+	dllRasterPos2iv( v );
+}
+static void APIENTRY logRasterPos2s(GLshort x, GLshort y)
+{
+	SIG( "glRasterPos2s" );
+	dllRasterPos2s( x, y );
+}
+static void APIENTRY logRasterPos2sv(const GLshort *v)
+{
+	SIG( "glRasterPos2sv" );
+	dllRasterPos2sv( v );
+}
+static void APIENTRY logRasterPos3d(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glRasterPos3d" );
+	dllRasterPos3d( x, y, z );
+}
+static void APIENTRY logRasterPos3dv(const GLdouble *v)
+{
+	SIG( "glRasterPos3dv" );
+	dllRasterPos3dv( v );
+}
+static void APIENTRY logRasterPos3f(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glRasterPos3f" );
+	dllRasterPos3f( x, y, z );
+}
+static void APIENTRY logRasterPos3fv(const GLfloat *v)
+{
+	SIG( "glRasterPos3fv" );
+	dllRasterPos3fv( v );
+}
+static void APIENTRY logRasterPos3i(GLint x, GLint y, GLint z)
+{
+	SIG( "glRasterPos3i" );
+	dllRasterPos3i( x, y, z );
+}
+static void APIENTRY logRasterPos3iv(const GLint *v)
+{
+	SIG( "glRasterPos3iv" );
+	dllRasterPos3iv( v );
+}
+static void APIENTRY logRasterPos3s(GLshort x, GLshort y, GLshort z)
+{
+	SIG( "glRasterPos3s" );
+	dllRasterPos3s( x, y, z );
+}
+static void APIENTRY logRasterPos3sv(const GLshort *v)
+{
+	SIG( "glRasterPos3sv" );
+	dllRasterPos3sv( v );
+}
+static void APIENTRY logRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+	SIG( "glRasterPos4d" );
+	dllRasterPos4d( x, y, z, w );
+}
+static void APIENTRY logRasterPos4dv(const GLdouble *v)
+{
+	SIG( "glRasterPos4dv" );
+	dllRasterPos4dv( v );
+}
+static void APIENTRY logRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	SIG( "glRasterPos4f" );
+	dllRasterPos4f( x, y, z, w );
+}
+static void APIENTRY logRasterPos4fv(const GLfloat *v)
+{
+	SIG( "glRasterPos4fv" );
+	dllRasterPos4fv( v );
+}
+static void APIENTRY logRasterPos4i(GLint x, GLint y, GLint z, GLint w)
+{
+	SIG( "glRasterPos4i" );
+	dllRasterPos4i( x, y, z, w );
+}
+static void APIENTRY logRasterPos4iv(const GLint *v)
+{
+	SIG( "glRasterPos4iv" );
+	dllRasterPos4iv( v );
+}
+static void APIENTRY logRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w)
+{
+	SIG( "glRasterPos4s" );
+	dllRasterPos4s( x, y, z, w );
+}
+static void APIENTRY logRasterPos4sv(const GLshort *v)
+{
+	SIG( "glRasterPos4sv" );
+	dllRasterPos4sv( v );
+}
+static void APIENTRY logReadBuffer(GLenum mode)
+{
+	SIG( "glReadBuffer" );
+	dllReadBuffer( mode );
+}
+static void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)
+{
+	SIG( "glReadPixels" );
+	dllReadPixels( x, y, width, height, format, type, pixels );
+}
+
+static void APIENTRY logRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
+{
+	SIG( "glRectd" );
+	dllRectd( x1, y1, x2, y2 );
+}
+
+static void APIENTRY logRectdv(const GLdouble *v1, const GLdouble *v2)
+{
+	SIG( "glRectdv" );
+	dllRectdv( v1, v2 );
+}
+
+static void APIENTRY logRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+	SIG( "glRectf" );
+	dllRectf( x1, y1, x2, y2 );
+}
+
+static void APIENTRY logRectfv(const GLfloat *v1, const GLfloat *v2)
+{
+	SIG( "glRectfv" );
+	dllRectfv( v1, v2 );
+}
+static void APIENTRY logRecti(GLint x1, GLint y1, GLint x2, GLint y2)
+{
+	SIG( "glRecti" );
+	dllRecti( x1, y1, x2, y2 );
+}
+static void APIENTRY logRectiv(const GLint *v1, const GLint *v2)
+{
+	SIG( "glRectiv" );
+	dllRectiv( v1, v2 );
+}
+static void APIENTRY logRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
+{
+	SIG( "glRects" );
+	dllRects( x1, y1, x2, y2 );
+}
+static void APIENTRY logRectsv(const GLshort *v1, const GLshort *v2)
+{
+	SIG( "glRectsv" );
+	dllRectsv( v1, v2 );
+}
+static GLint APIENTRY logRenderMode(GLenum mode)
+{
+	SIG( "glRenderMode" );
+	return dllRenderMode( mode );
+}
+static void APIENTRY logRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glRotated" );
+	dllRotated( angle, x, y, z );
+}
+
+static void APIENTRY logRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glRotatef" );
+	dllRotatef( angle, x, y, z );
+}
+
+static void APIENTRY logScaled(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glScaled" );
+	dllScaled( x, y, z );
+}
+
+static void APIENTRY logScalef(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glScalef" );
+	dllScalef( x, y, z );
+}
+
+static void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glScissor" );
+	dllScissor( x, y, width, height );
+}
+
+static void APIENTRY logSelectBuffer(GLsizei size, GLuint *buffer)
+{
+	SIG( "glSelectBuffer" );
+	dllSelectBuffer( size, buffer );
+}
+
+static void APIENTRY logShadeModel(GLenum mode)
+{
+	SIG( "glShadeModel" );
+	dllShadeModel( mode );
+}
+
+static void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+	SIG( "glStencilFunc" );
+	dllStencilFunc( func, ref, mask );
+}
+
+static void APIENTRY logStencilMask(GLuint mask)
+{
+	SIG( "glStencilMask" );
+	dllStencilMask( mask );
+}
+
+static void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+	SIG( "glStencilOp" );
+	dllStencilOp( fail, zfail, zpass );
+}
+
+static void APIENTRY logTexCoord1d(GLdouble s)
+{
+	SIG( "glTexCoord1d" );
+	dllTexCoord1d( s );
+}
+
+static void APIENTRY logTexCoord1dv(const GLdouble *v)
+{
+	SIG( "glTexCoord1dv" );
+	dllTexCoord1dv( v );
+}
+
+static void APIENTRY logTexCoord1f(GLfloat s)
+{
+	SIG( "glTexCoord1f" );
+	dllTexCoord1f( s );
+}
+static void APIENTRY logTexCoord1fv(const GLfloat *v)
+{
+	SIG( "glTexCoord1fv" );
+	dllTexCoord1fv( v );
+}
+static void APIENTRY logTexCoord1i(GLint s)
+{
+	SIG( "glTexCoord1i" );
+	dllTexCoord1i( s );
+}
+static void APIENTRY logTexCoord1iv(const GLint *v)
+{
+	SIG( "glTexCoord1iv" );
+	dllTexCoord1iv( v );
+}
+static void APIENTRY logTexCoord1s(GLshort s)
+{
+	SIG( "glTexCoord1s" );
+	dllTexCoord1s( s );
+}
+static void APIENTRY logTexCoord1sv(const GLshort *v)
+{
+	SIG( "glTexCoord1sv" );
+	dllTexCoord1sv( v );
+}
+static void APIENTRY logTexCoord2d(GLdouble s, GLdouble t)
+{
+	SIG( "glTexCoord2d" );
+	dllTexCoord2d( s, t );
+}
+
+static void APIENTRY logTexCoord2dv(const GLdouble *v)
+{
+	SIG( "glTexCoord2dv" );
+	dllTexCoord2dv( v );
+}
+static void APIENTRY logTexCoord2f(GLfloat s, GLfloat t)
+{
+	SIG( "glTexCoord2f" );
+	dllTexCoord2f( s, t );
+}
+static void APIENTRY logTexCoord2fv(const GLfloat *v)
+{
+	SIG( "glTexCoord2fv" );
+	dllTexCoord2fv( v );
+}
+static void APIENTRY logTexCoord2i(GLint s, GLint t)
+{
+	SIG( "glTexCoord2i" );
+	dllTexCoord2i( s, t );
+}
+static void APIENTRY logTexCoord2iv(const GLint *v)
+{
+	SIG( "glTexCoord2iv" );
+	dllTexCoord2iv( v );
+}
+static void APIENTRY logTexCoord2s(GLshort s, GLshort t)
+{
+	SIG( "glTexCoord2s" );
+	dllTexCoord2s( s, t );
+}
+static void APIENTRY logTexCoord2sv(const GLshort *v)
+{
+	SIG( "glTexCoord2sv" );
+	dllTexCoord2sv( v );
+}
+static void APIENTRY logTexCoord3d(GLdouble s, GLdouble t, GLdouble r)
+{
+	SIG( "glTexCoord3d" );
+	dllTexCoord3d( s, t, r );
+}
+static void APIENTRY logTexCoord3dv(const GLdouble *v)
+{
+	SIG( "glTexCoord3dv" );
+	dllTexCoord3dv( v );
+}
+static void APIENTRY logTexCoord3f(GLfloat s, GLfloat t, GLfloat r)
+{
+	SIG( "glTexCoord3f" );
+	dllTexCoord3f( s, t, r );
+}
+static void APIENTRY logTexCoord3fv(const GLfloat *v)
+{
+	SIG( "glTexCoord3fv" );
+	dllTexCoord3fv( v );
+}
+static void APIENTRY logTexCoord3i(GLint s, GLint t, GLint r)
+{
+	SIG( "glTexCoord3i" );
+	dllTexCoord3i( s, t, r );
+}
+static void APIENTRY logTexCoord3iv(const GLint *v)
+{
+	SIG( "glTexCoord3iv" );
+	dllTexCoord3iv( v );
+}
+static void APIENTRY logTexCoord3s(GLshort s, GLshort t, GLshort r)
+{
+	SIG( "glTexCoord3s" );
+	dllTexCoord3s( s, t, r );
+}
+static void APIENTRY logTexCoord3sv(const GLshort *v)
+{
+	SIG( "glTexCoord3sv" );
+	dllTexCoord3sv( v );
+}
+static void APIENTRY logTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q)
+{
+	SIG( "glTexCoord4d" );
+	dllTexCoord4d( s, t, r, q );
+}
+static void APIENTRY logTexCoord4dv(const GLdouble *v)
+{
+	SIG( "glTexCoord4dv" );
+	dllTexCoord4dv( v );
+}
+static void APIENTRY logTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+	SIG( "glTexCoord4f" );
+	dllTexCoord4f( s, t, r, q );
+}
+static void APIENTRY logTexCoord4fv(const GLfloat *v)
+{
+	SIG( "glTexCoord4fv" );
+	dllTexCoord4fv( v );
+}
+static void APIENTRY logTexCoord4i(GLint s, GLint t, GLint r, GLint q)
+{
+	SIG( "glTexCoord4i" );
+	dllTexCoord4i( s, t, r, q );
+}
+static void APIENTRY logTexCoord4iv(const GLint *v)
+{
+	SIG( "glTexCoord4iv" );
+	dllTexCoord4iv( v );
+}
+static void APIENTRY logTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q)
+{
+	SIG( "glTexCoord4s" );
+	dllTexCoord4s( s, t, r, q );
+}
+static void APIENTRY logTexCoord4sv(const GLshort *v)
+{
+	SIG( "glTexCoord4sv" );
+	dllTexCoord4sv( v );
+}
+static void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glTexCoordPointer" );
+	dllTexCoordPointer( size, type, stride, pointer );
+}
+
+static void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param)
+{
+	fprintf( glw_state.log_fp, "glTexEnvf( 0x%x, 0x%x, %f )\n", target, pname, param );
+	dllTexEnvf( target, pname, param );
+}
+
+static void APIENTRY logTexEnvfv(GLenum target, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexEnvfv" );
+	dllTexEnvfv( target, pname, params );
+}
+
+static void APIENTRY logTexEnvi(GLenum target, GLenum pname, GLint param)
+{
+	fprintf( glw_state.log_fp, "glTexEnvi( 0x%x, 0x%x, 0x%x )\n", target, pname, param );
+	dllTexEnvi( target, pname, param );
+}
+static void APIENTRY logTexEnviv(GLenum target, GLenum pname, const GLint *params)
+{
+	SIG( "glTexEnviv" );
+	dllTexEnviv( target, pname, params );
+}
+
+static void APIENTRY logTexGend(GLenum coord, GLenum pname, GLdouble param)
+{
+	SIG( "glTexGend" );
+	dllTexGend( coord, pname, param );
+}
+
+static void APIENTRY logTexGendv(GLenum coord, GLenum pname, const GLdouble *params)
+{
+	SIG( "glTexGendv" );
+	dllTexGendv( coord, pname, params );
+}
+
+static void APIENTRY logTexGenf(GLenum coord, GLenum pname, GLfloat param)
+{
+	SIG( "glTexGenf" );
+	dllTexGenf( coord, pname, param );
+}
+static void APIENTRY logTexGenfv(GLenum coord, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexGenfv" );
+	dllTexGenfv( coord, pname, params );
+}
+static void APIENTRY logTexGeni(GLenum coord, GLenum pname, GLint param)
+{
+	SIG( "glTexGeni" );
+	dllTexGeni( coord, pname, param );
+}
+static void APIENTRY logTexGeniv(GLenum coord, GLenum pname, const GLint *params)
+{
+	SIG( "glTexGeniv" );
+	dllTexGeniv( coord, pname, params );
+}
+static void APIENTRY logTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexImage1D" );
+	dllTexImage1D( target, level, internalformat, width, border, format, type, pixels );
+}
+static void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexImage2D" );
+	dllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels );
+}
+
+static void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+	fprintf( glw_state.log_fp, "glTexParameterf( 0x%x, 0x%x, %f )\n", target, pname, param );
+	dllTexParameterf( target, pname, param );
+}
+
+static void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
+{
+	SIG( "glTexParameterfv" );
+	dllTexParameterfv( target, pname, params );
+}
+static void APIENTRY logTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+	fprintf( glw_state.log_fp, "glTexParameteri( 0x%x, 0x%x, 0x%x )\n", target, pname, param );
+	dllTexParameteri( target, pname, param );
+}
+static void APIENTRY logTexParameteriv(GLenum target, GLenum pname, const GLint *params)
+{
+	SIG( "glTexParameteriv" );
+	dllTexParameteriv( target, pname, params );
+}
+static void APIENTRY logTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexSubImage1D" );
+	dllTexSubImage1D( target, level, xoffset, width, format, type, pixels );
+}
+static void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+	SIG( "glTexSubImage2D" );
+	dllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels );
+}
+static void APIENTRY logTranslated(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glTranslated" );
+	dllTranslated( x, y, z );
+}
+
+static void APIENTRY logTranslatef(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glTranslatef" );
+	dllTranslatef( x, y, z );
+}
+
+static void APIENTRY logVertex2d(GLdouble x, GLdouble y)
+{
+	SIG( "glVertex2d" );
+	dllVertex2d( x, y );
+}
+
+static void APIENTRY logVertex2dv(const GLdouble *v)
+{
+	SIG( "glVertex2dv" );
+	dllVertex2dv( v );
+}
+static void APIENTRY logVertex2f(GLfloat x, GLfloat y)
+{
+	SIG( "glVertex2f" );
+	dllVertex2f( x, y );
+}
+static void APIENTRY logVertex2fv(const GLfloat *v)
+{
+	SIG( "glVertex2fv" );
+	dllVertex2fv( v );
+}
+static void APIENTRY logVertex2i(GLint x, GLint y)
+{
+	SIG( "glVertex2i" );
+	dllVertex2i( x, y );
+}
+static void APIENTRY logVertex2iv(const GLint *v)
+{
+	SIG( "glVertex2iv" );
+	dllVertex2iv( v );
+}
+static void APIENTRY logVertex2s(GLshort x, GLshort y)
+{
+	SIG( "glVertex2s" );
+	dllVertex2s( x, y );
+}
+static void APIENTRY logVertex2sv(const GLshort *v)
+{
+	SIG( "glVertex2sv" );
+	dllVertex2sv( v );
+}
+static void APIENTRY logVertex3d(GLdouble x, GLdouble y, GLdouble z)
+{
+	SIG( "glVertex3d" );
+	dllVertex3d( x, y, z );
+}
+static void APIENTRY logVertex3dv(const GLdouble *v)
+{
+	SIG( "glVertex3dv" );
+	dllVertex3dv( v );
+}
+static void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z)
+{
+	SIG( "glVertex3f" );
+	dllVertex3f( x, y, z );
+}
+static void APIENTRY logVertex3fv(const GLfloat *v)
+{
+	SIG( "glVertex3fv" );
+	dllVertex3fv( v );
+}
+static void APIENTRY logVertex3i(GLint x, GLint y, GLint z)
+{
+	SIG( "glVertex3i" );
+	dllVertex3i( x, y, z );
+}
+static void APIENTRY logVertex3iv(const GLint *v)
+{
+	SIG( "glVertex3iv" );
+	dllVertex3iv( v );
+}
+static void APIENTRY logVertex3s(GLshort x, GLshort y, GLshort z)
+{
+	SIG( "glVertex3s" );
+	dllVertex3s( x, y, z );
+}
+static void APIENTRY logVertex3sv(const GLshort *v)
+{
+	SIG( "glVertex3sv" );
+	dllVertex3sv( v );
+}
+static void APIENTRY logVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+	SIG( "glVertex4d" );
+	dllVertex4d( x, y, z, w );
+}
+static void APIENTRY logVertex4dv(const GLdouble *v)
+{
+	SIG( "glVertex4dv" );
+	dllVertex4dv( v );
+}
+static void APIENTRY logVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	SIG( "glVertex4f" );
+	dllVertex4f( x, y, z, w );
+}
+static void APIENTRY logVertex4fv(const GLfloat *v)
+{
+	SIG( "glVertex4fv" );
+	dllVertex4fv( v );
+}
+static void APIENTRY logVertex4i(GLint x, GLint y, GLint z, GLint w)
+{
+	SIG( "glVertex4i" );
+	dllVertex4i( x, y, z, w );
+}
+static void APIENTRY logVertex4iv(const GLint *v)
+{
+	SIG( "glVertex4iv" );
+	dllVertex4iv( v );
+}
+static void APIENTRY logVertex4s(GLshort x, GLshort y, GLshort z, GLshort w)
+{
+	SIG( "glVertex4s" );
+	dllVertex4s( x, y, z, w );
+}
+static void APIENTRY logVertex4sv(const GLshort *v)
+{
+	SIG( "glVertex4sv" );
+	dllVertex4sv( v );
+}
+static void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer)
+{
+	SIG( "glVertexPointer" );
+	dllVertexPointer( size, type, stride, pointer );
+}
+static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+	SIG( "glViewport" );
+	dllViewport( x, y, width, height );
+}
+
+/*
+** QGL_Shutdown
+**
+** Unloads the specified DLL then nulls out all the proc pointers.
+*/
+void QGL_Shutdown( void )
+{
+	if ( glw_state.hinstOpenGL )
+	{
+		FreeLibrary( glw_state.hinstOpenGL );
+		glw_state.hinstOpenGL = NULL;
+	}
+
+	glw_state.hinstOpenGL = NULL;
+
+	qglAccum                     = NULL;
+	qglAlphaFunc                 = NULL;
+	qglAreTexturesResident       = NULL;
+	qglArrayElement              = NULL;
+	qglBegin                     = NULL;
+	qglBindTexture               = NULL;
+	qglBitmap                    = NULL;
+	qglBlendFunc                 = NULL;
+	qglCallList                  = NULL;
+	qglCallLists                 = NULL;
+	qglClear                     = NULL;
+	qglClearAccum                = NULL;
+	qglClearColor                = NULL;
+	qglClearDepth                = NULL;
+	qglClearIndex                = NULL;
+	qglClearStencil              = NULL;
+	qglClipPlane                 = NULL;
+	qglColor3b                   = NULL;
+	qglColor3bv                  = NULL;
+	qglColor3d                   = NULL;
+	qglColor3dv                  = NULL;
+	qglColor3f                   = NULL;
+	qglColor3fv                  = NULL;
+	qglColor3i                   = NULL;
+	qglColor3iv                  = NULL;
+	qglColor3s                   = NULL;
+	qglColor3sv                  = NULL;
+	qglColor3ub                  = NULL;
+	qglColor3ubv                 = NULL;
+	qglColor3ui                  = NULL;
+	qglColor3uiv                 = NULL;
+	qglColor3us                  = NULL;
+	qglColor3usv                 = NULL;
+	qglColor4b                   = NULL;
+	qglColor4bv                  = NULL;
+	qglColor4d                   = NULL;
+	qglColor4dv                  = NULL;
+	qglColor4f                   = NULL;
+	qglColor4fv                  = NULL;
+	qglColor4i                   = NULL;
+	qglColor4iv                  = NULL;
+	qglColor4s                   = NULL;
+	qglColor4sv                  = NULL;
+	qglColor4ub                  = NULL;
+	qglColor4ubv                 = NULL;
+	qglColor4ui                  = NULL;
+	qglColor4uiv                 = NULL;
+	qglColor4us                  = NULL;
+	qglColor4usv                 = NULL;
+	qglColorMask                 = NULL;
+	qglColorMaterial             = NULL;
+	qglColorPointer              = NULL;
+	qglCopyPixels                = NULL;
+	qglCopyTexImage1D            = NULL;
+	qglCopyTexImage2D            = NULL;
+	qglCopyTexSubImage1D         = NULL;
+	qglCopyTexSubImage2D         = NULL;
+	qglCullFace                  = NULL;
+	qglDeleteLists               = NULL;
+	qglDeleteTextures            = NULL;
+	qglDepthFunc                 = NULL;
+	qglDepthMask                 = NULL;
+	qglDepthRange                = NULL;
+	qglDisable                   = NULL;
+	qglDisableClientState        = NULL;
+	qglDrawArrays                = NULL;
+	qglDrawBuffer                = NULL;
+	qglDrawElements              = NULL;
+	qglDrawPixels                = NULL;
+	qglEdgeFlag                  = NULL;
+	qglEdgeFlagPointer           = NULL;
+	qglEdgeFlagv                 = NULL;
+	qglEnable                    = NULL;
+	qglEnableClientState         = NULL;
+	qglEnd                       = NULL;
+	qglEndList                   = NULL;
+	qglEvalCoord1d               = NULL;
+	qglEvalCoord1dv              = NULL;
+	qglEvalCoord1f               = NULL;
+	qglEvalCoord1fv              = NULL;
+	qglEvalCoord2d               = NULL;
+	qglEvalCoord2dv              = NULL;
+	qglEvalCoord2f               = NULL;
+	qglEvalCoord2fv              = NULL;
+	qglEvalMesh1                 = NULL;
+	qglEvalMesh2                 = NULL;
+	qglEvalPoint1                = NULL;
+	qglEvalPoint2                = NULL;
+	qglFeedbackBuffer            = NULL;
+	qglFinish                    = NULL;
+	qglFlush                     = NULL;
+	qglFogf                      = NULL;
+	qglFogfv                     = NULL;
+	qglFogi                      = NULL;
+	qglFogiv                     = NULL;
+	qglFrontFace                 = NULL;
+	qglFrustum                   = NULL;
+	qglGenLists                  = NULL;
+	qglGenTextures               = NULL;
+	qglGetBooleanv               = NULL;
+	qglGetClipPlane              = NULL;
+	qglGetDoublev                = NULL;
+	qglGetError                  = NULL;
+	qglGetFloatv                 = NULL;
+	qglGetIntegerv               = NULL;
+	qglGetLightfv                = NULL;
+	qglGetLightiv                = NULL;
+	qglGetMapdv                  = NULL;
+	qglGetMapfv                  = NULL;
+	qglGetMapiv                  = NULL;
+	qglGetMaterialfv             = NULL;
+	qglGetMaterialiv             = NULL;
+	qglGetPixelMapfv             = NULL;
+	qglGetPixelMapuiv            = NULL;
+	qglGetPixelMapusv            = NULL;
+	qglGetPointerv               = NULL;
+	qglGetPolygonStipple         = NULL;
+	qglGetString                 = NULL;
+	qglGetTexEnvfv               = NULL;
+	qglGetTexEnviv               = NULL;
+	qglGetTexGendv               = NULL;
+	qglGetTexGenfv               = NULL;
+	qglGetTexGeniv               = NULL;
+	qglGetTexImage               = NULL;
+	qglGetTexLevelParameterfv    = NULL;
+	qglGetTexLevelParameteriv    = NULL;
+	qglGetTexParameterfv         = NULL;
+	qglGetTexParameteriv         = NULL;
+	qglHint                      = NULL;
+	qglIndexMask                 = NULL;
+	qglIndexPointer              = NULL;
+	qglIndexd                    = NULL;
+	qglIndexdv                   = NULL;
+	qglIndexf                    = NULL;
+	qglIndexfv                   = NULL;
+	qglIndexi                    = NULL;
+	qglIndexiv                   = NULL;
+	qglIndexs                    = NULL;
+	qglIndexsv                   = NULL;
+	qglIndexub                   = NULL;
+	qglIndexubv                  = NULL;
+	qglInitNames                 = NULL;
+	qglInterleavedArrays         = NULL;
+	qglIsEnabled                 = NULL;
+	qglIsList                    = NULL;
+	qglIsTexture                 = NULL;
+	qglLightModelf               = NULL;
+	qglLightModelfv              = NULL;
+	qglLightModeli               = NULL;
+	qglLightModeliv              = NULL;
+	qglLightf                    = NULL;
+	qglLightfv                   = NULL;
+	qglLighti                    = NULL;
+	qglLightiv                   = NULL;
+	qglLineStipple               = NULL;
+	qglLineWidth                 = NULL;
+	qglListBase                  = NULL;
+	qglLoadIdentity              = NULL;
+	qglLoadMatrixd               = NULL;
+	qglLoadMatrixf               = NULL;
+	qglLoadName                  = NULL;
+	qglLogicOp                   = NULL;
+	qglMap1d                     = NULL;
+	qglMap1f                     = NULL;
+	qglMap2d                     = NULL;
+	qglMap2f                     = NULL;
+	qglMapGrid1d                 = NULL;
+	qglMapGrid1f                 = NULL;
+	qglMapGrid2d                 = NULL;
+	qglMapGrid2f                 = NULL;
+	qglMaterialf                 = NULL;
+	qglMaterialfv                = NULL;
+	qglMateriali                 = NULL;
+	qglMaterialiv                = NULL;
+	qglMatrixMode                = NULL;
+	qglMultMatrixd               = NULL;
+	qglMultMatrixf               = NULL;
+	qglNewList                   = NULL;
+	qglNormal3b                  = NULL;
+	qglNormal3bv                 = NULL;
+	qglNormal3d                  = NULL;
+	qglNormal3dv                 = NULL;
+	qglNormal3f                  = NULL;
+	qglNormal3fv                 = NULL;
+	qglNormal3i                  = NULL;
+	qglNormal3iv                 = NULL;
+	qglNormal3s                  = NULL;
+	qglNormal3sv                 = NULL;
+	qglNormalPointer             = NULL;
+	qglOrtho                     = NULL;
+	qglPassThrough               = NULL;
+	qglPixelMapfv                = NULL;
+	qglPixelMapuiv               = NULL;
+	qglPixelMapusv               = NULL;
+	qglPixelStoref               = NULL;
+	qglPixelStorei               = NULL;
+	qglPixelTransferf            = NULL;
+	qglPixelTransferi            = NULL;
+	qglPixelZoom                 = NULL;
+	qglPointSize                 = NULL;
+	qglPolygonMode               = NULL;
+	qglPolygonOffset             = NULL;
+	qglPolygonStipple            = NULL;
+	qglPopAttrib                 = NULL;
+	qglPopClientAttrib           = NULL;
+	qglPopMatrix                 = NULL;
+	qglPopName                   = NULL;
+	qglPrioritizeTextures        = NULL;
+	qglPushAttrib                = NULL;
+	qglPushClientAttrib          = NULL;
+	qglPushMatrix                = NULL;
+	qglPushName                  = NULL;
+	qglRasterPos2d               = NULL;
+	qglRasterPos2dv              = NULL;
+	qglRasterPos2f               = NULL;
+	qglRasterPos2fv              = NULL;
+	qglRasterPos2i               = NULL;
+	qglRasterPos2iv              = NULL;
+	qglRasterPos2s               = NULL;
+	qglRasterPos2sv              = NULL;
+	qglRasterPos3d               = NULL;
+	qglRasterPos3dv              = NULL;
+	qglRasterPos3f               = NULL;
+	qglRasterPos3fv              = NULL;
+	qglRasterPos3i               = NULL;
+	qglRasterPos3iv              = NULL;
+	qglRasterPos3s               = NULL;
+	qglRasterPos3sv              = NULL;
+	qglRasterPos4d               = NULL;
+	qglRasterPos4dv              = NULL;
+	qglRasterPos4f               = NULL;
+	qglRasterPos4fv              = NULL;
+	qglRasterPos4i               = NULL;
+	qglRasterPos4iv              = NULL;
+	qglRasterPos4s               = NULL;
+	qglRasterPos4sv              = NULL;
+	qglReadBuffer                = NULL;
+	qglReadPixels                = NULL;
+	qglRectd                     = NULL;
+	qglRectdv                    = NULL;
+	qglRectf                     = NULL;
+	qglRectfv                    = NULL;
+	qglRecti                     = NULL;
+	qglRectiv                    = NULL;
+	qglRects                     = NULL;
+	qglRectsv                    = NULL;
+	qglRenderMode                = NULL;
+	qglRotated                   = NULL;
+	qglRotatef                   = NULL;
+	qglScaled                    = NULL;
+	qglScalef                    = NULL;
+	qglScissor                   = NULL;
+	qglSelectBuffer              = NULL;
+	qglShadeModel                = NULL;
+	qglStencilFunc               = NULL;
+	qglStencilMask               = NULL;
+	qglStencilOp                 = NULL;
+	qglTexCoord1d                = NULL;
+	qglTexCoord1dv               = NULL;
+	qglTexCoord1f                = NULL;
+	qglTexCoord1fv               = NULL;
+	qglTexCoord1i                = NULL;
+	qglTexCoord1iv               = NULL;
+	qglTexCoord1s                = NULL;
+	qglTexCoord1sv               = NULL;
+	qglTexCoord2d                = NULL;
+	qglTexCoord2dv               = NULL;
+	qglTexCoord2f                = NULL;
+	qglTexCoord2fv               = NULL;
+	qglTexCoord2i                = NULL;
+	qglTexCoord2iv               = NULL;
+	qglTexCoord2s                = NULL;
+	qglTexCoord2sv               = NULL;
+	qglTexCoord3d                = NULL;
+	qglTexCoord3dv               = NULL;
+	qglTexCoord3f                = NULL;
+	qglTexCoord3fv               = NULL;
+	qglTexCoord3i                = NULL;
+	qglTexCoord3iv               = NULL;
+	qglTexCoord3s                = NULL;
+	qglTexCoord3sv               = NULL;
+	qglTexCoord4d                = NULL;
+	qglTexCoord4dv               = NULL;
+	qglTexCoord4f                = NULL;
+	qglTexCoord4fv               = NULL;
+	qglTexCoord4i                = NULL;
+	qglTexCoord4iv               = NULL;
+	qglTexCoord4s                = NULL;
+	qglTexCoord4sv               = NULL;
+	qglTexCoordPointer           = NULL;
+	qglTexEnvf                   = NULL;
+	qglTexEnvfv                  = NULL;
+	qglTexEnvi                   = NULL;
+	qglTexEnviv                  = NULL;
+	qglTexGend                   = NULL;
+	qglTexGendv                  = NULL;
+	qglTexGenf                   = NULL;
+	qglTexGenfv                  = NULL;
+	qglTexGeni                   = NULL;
+	qglTexGeniv                  = NULL;
+	qglTexImage1D                = NULL;
+	qglTexImage2D                = NULL;
+	qglTexParameterf             = NULL;
+	qglTexParameterfv            = NULL;
+	qglTexParameteri             = NULL;
+	qglTexParameteriv            = NULL;
+	qglTexSubImage1D             = NULL;
+	qglTexSubImage2D             = NULL;
+	qglTranslated                = NULL;
+	qglTranslatef                = NULL;
+	qglVertex2d                  = NULL;
+	qglVertex2dv                 = NULL;
+	qglVertex2f                  = NULL;
+	qglVertex2fv                 = NULL;
+	qglVertex2i                  = NULL;
+	qglVertex2iv                 = NULL;
+	qglVertex2s                  = NULL;
+	qglVertex2sv                 = NULL;
+	qglVertex3d                  = NULL;
+	qglVertex3dv                 = NULL;
+	qglVertex3f                  = NULL;
+	qglVertex3fv                 = NULL;
+	qglVertex3i                  = NULL;
+	qglVertex3iv                 = NULL;
+	qglVertex3s                  = NULL;
+	qglVertex3sv                 = NULL;
+	qglVertex4d                  = NULL;
+	qglVertex4dv                 = NULL;
+	qglVertex4f                  = NULL;
+	qglVertex4fv                 = NULL;
+	qglVertex4i                  = NULL;
+	qglVertex4iv                 = NULL;
+	qglVertex4s                  = NULL;
+	qglVertex4sv                 = NULL;
+	qglVertexPointer             = NULL;
+	qglViewport                  = NULL;
+
+	qwglCopyContext              = NULL;
+	qwglCreateContext            = NULL;
+	qwglCreateLayerContext       = NULL;
+	qwglDeleteContext            = NULL;
+	qwglDescribeLayerPlane       = NULL;
+	qwglGetCurrentContext        = NULL;
+	qwglGetCurrentDC             = NULL;
+	qwglGetLayerPaletteEntries   = NULL;
+	qwglGetProcAddress           = NULL;
+	qwglMakeCurrent              = NULL;
+	qwglRealizeLayerPalette      = NULL;
+	qwglSetLayerPaletteEntries   = NULL;
+	qwglShareLists               = NULL;
+	qwglSwapLayerBuffers         = NULL;
+	qwglUseFontBitmaps           = NULL;
+	qwglUseFontOutlines          = NULL;
+
+	qwglChoosePixelFormat        = NULL;
+	qwglDescribePixelFormat      = NULL;
+	qwglGetPixelFormat           = NULL;
+	qwglSetPixelFormat           = NULL;
+	qwglSwapBuffers              = NULL;
+
+	qwglSwapIntervalEXT	= NULL;
+
+	qwglGetDeviceGammaRampEXT = NULL;
+	qwglSetDeviceGammaRampEXT = NULL;
+}
+
+#	pragma warning (disable : 4113 4133 4047 )
+#	define GPA( a ) GetProcAddress( glw_state.hinstOpenGL, a )
+
+/*
+** QGL_Init
+**
+** This is responsible for binding our qgl function pointers to 
+** the appropriate GL stuff.  In Windows this means doing a 
+** LoadLibrary and a bunch of calls to GetProcAddress.  On other
+** operating systems we need to do the right thing, whatever that
+** might be.
+** 
+*/
+qboolean QGL_Init( const char *dllname )
+{
+	// update 3Dfx gamma irrespective of underlying DLL
+	{
+		char envbuffer[1024];
+		float g;
+
+		g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
+		Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g );
+		putenv( envbuffer );
+		Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
+		putenv( envbuffer );
+	}
+
+	if ( ( glw_state.hinstOpenGL = LoadLibrary( dllname ) ) == 0 )
+	{
+		char *buf = NULL;
+
+		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
+		ri.Con_Printf( PRINT_ALL, "%s\n", buf );
+		return false;
+	}
+
+	gl_config.allow_cds = true;
+
+	qglAccum                     = dllAccum = GPA( "glAccum" );
+	qglAlphaFunc                 = dllAlphaFunc = GPA( "glAlphaFunc" );
+	qglAreTexturesResident       = dllAreTexturesResident = GPA( "glAreTexturesResident" );
+	qglArrayElement              = dllArrayElement = GPA( "glArrayElement" );
+	qglBegin                     = dllBegin = GPA( "glBegin" );
+	qglBindTexture               = dllBindTexture = GPA( "glBindTexture" );
+	qglBitmap                    = dllBitmap = GPA( "glBitmap" );
+	qglBlendFunc                 = dllBlendFunc = GPA( "glBlendFunc" );
+	qglCallList                  = dllCallList = GPA( "glCallList" );
+	qglCallLists                 = dllCallLists = GPA( "glCallLists" );
+	qglClear                     = dllClear = GPA( "glClear" );
+	qglClearAccum                = dllClearAccum = GPA( "glClearAccum" );
+	qglClearColor                = dllClearColor = GPA( "glClearColor" );
+	qglClearDepth                = dllClearDepth = GPA( "glClearDepth" );
+	qglClearIndex                = dllClearIndex = GPA( "glClearIndex" );
+	qglClearStencil              = dllClearStencil = GPA( "glClearStencil" );
+	qglClipPlane                 = dllClipPlane = GPA( "glClipPlane" );
+	qglColor3b                   = dllColor3b = GPA( "glColor3b" );
+	qglColor3bv                  = dllColor3bv = GPA( "glColor3bv" );
+	qglColor3d                   = dllColor3d = GPA( "glColor3d" );
+	qglColor3dv                  = dllColor3dv = GPA( "glColor3dv" );
+	qglColor3f                   = dllColor3f = GPA( "glColor3f" );
+	qglColor3fv                  = dllColor3fv = GPA( "glColor3fv" );
+	qglColor3i                   = dllColor3i = GPA( "glColor3i" );
+	qglColor3iv                  = dllColor3iv = GPA( "glColor3iv" );
+	qglColor3s                   = dllColor3s = GPA( "glColor3s" );
+	qglColor3sv                  = dllColor3sv = GPA( "glColor3sv" );
+	qglColor3ub                  = dllColor3ub = GPA( "glColor3ub" );
+	qglColor3ubv                 = dllColor3ubv = GPA( "glColor3ubv" );
+	qglColor3ui                  = dllColor3ui = GPA( "glColor3ui" );
+	qglColor3uiv                 = dllColor3uiv = GPA( "glColor3uiv" );
+	qglColor3us                  = dllColor3us = GPA( "glColor3us" );
+	qglColor3usv                 = dllColor3usv = GPA( "glColor3usv" );
+	qglColor4b                   = dllColor4b = GPA( "glColor4b" );
+	qglColor4bv                  = dllColor4bv = GPA( "glColor4bv" );
+	qglColor4d                   = dllColor4d = GPA( "glColor4d" );
+	qglColor4dv                  = dllColor4dv = GPA( "glColor4dv" );
+	qglColor4f                   = dllColor4f = GPA( "glColor4f" );
+	qglColor4fv                  = dllColor4fv = GPA( "glColor4fv" );
+	qglColor4i                   = dllColor4i = GPA( "glColor4i" );
+	qglColor4iv                  = dllColor4iv = GPA( "glColor4iv" );
+	qglColor4s                   = dllColor4s = GPA( "glColor4s" );
+	qglColor4sv                  = dllColor4sv = GPA( "glColor4sv" );
+	qglColor4ub                  = dllColor4ub = GPA( "glColor4ub" );
+	qglColor4ubv                 = dllColor4ubv = GPA( "glColor4ubv" );
+	qglColor4ui                  = dllColor4ui = GPA( "glColor4ui" );
+	qglColor4uiv                 = dllColor4uiv = GPA( "glColor4uiv" );
+	qglColor4us                  = dllColor4us = GPA( "glColor4us" );
+	qglColor4usv                 = dllColor4usv = GPA( "glColor4usv" );
+	qglColorMask                 = dllColorMask = GPA( "glColorMask" );
+	qglColorMaterial             = dllColorMaterial = GPA( "glColorMaterial" );
+	qglColorPointer              = dllColorPointer = GPA( "glColorPointer" );
+	qglCopyPixels                = dllCopyPixels = GPA( "glCopyPixels" );
+	qglCopyTexImage1D            = dllCopyTexImage1D = GPA( "glCopyTexImage1D" );
+	qglCopyTexImage2D            = dllCopyTexImage2D = GPA( "glCopyTexImage2D" );
+	qglCopyTexSubImage1D         = dllCopyTexSubImage1D = GPA( "glCopyTexSubImage1D" );
+	qglCopyTexSubImage2D         = dllCopyTexSubImage2D = GPA( "glCopyTexSubImage2D" );
+	qglCullFace                  = dllCullFace = GPA( "glCullFace" );
+	qglDeleteLists               = dllDeleteLists = GPA( "glDeleteLists" );
+	qglDeleteTextures            = dllDeleteTextures = GPA( "glDeleteTextures" );
+	qglDepthFunc                 = dllDepthFunc = GPA( "glDepthFunc" );
+	qglDepthMask                 = dllDepthMask = GPA( "glDepthMask" );
+	qglDepthRange                = dllDepthRange = GPA( "glDepthRange" );
+	qglDisable                   = dllDisable = GPA( "glDisable" );
+	qglDisableClientState        = dllDisableClientState = GPA( "glDisableClientState" );
+	qglDrawArrays                = dllDrawArrays = GPA( "glDrawArrays" );
+	qglDrawBuffer                = dllDrawBuffer = GPA( "glDrawBuffer" );
+	qglDrawElements              = dllDrawElements = GPA( "glDrawElements" );
+	qglDrawPixels                = dllDrawPixels = GPA( "glDrawPixels" );
+	qglEdgeFlag                  = dllEdgeFlag = GPA( "glEdgeFlag" );
+	qglEdgeFlagPointer           = dllEdgeFlagPointer = GPA( "glEdgeFlagPointer" );
+	qglEdgeFlagv                 = dllEdgeFlagv = GPA( "glEdgeFlagv" );
+	qglEnable                    = 	dllEnable                    = GPA( "glEnable" );
+	qglEnableClientState         = 	dllEnableClientState         = GPA( "glEnableClientState" );
+	qglEnd                       = 	dllEnd                       = GPA( "glEnd" );
+	qglEndList                   = 	dllEndList                   = GPA( "glEndList" );
+	qglEvalCoord1d				 = 	dllEvalCoord1d				 = GPA( "glEvalCoord1d" );
+	qglEvalCoord1dv              = 	dllEvalCoord1dv              = GPA( "glEvalCoord1dv" );
+	qglEvalCoord1f               = 	dllEvalCoord1f               = GPA( "glEvalCoord1f" );
+	qglEvalCoord1fv              = 	dllEvalCoord1fv              = GPA( "glEvalCoord1fv" );
+	qglEvalCoord2d               = 	dllEvalCoord2d               = GPA( "glEvalCoord2d" );
+	qglEvalCoord2dv              = 	dllEvalCoord2dv              = GPA( "glEvalCoord2dv" );
+	qglEvalCoord2f               = 	dllEvalCoord2f               = GPA( "glEvalCoord2f" );
+	qglEvalCoord2fv              = 	dllEvalCoord2fv              = GPA( "glEvalCoord2fv" );
+	qglEvalMesh1                 = 	dllEvalMesh1                 = GPA( "glEvalMesh1" );
+	qglEvalMesh2                 = 	dllEvalMesh2                 = GPA( "glEvalMesh2" );
+	qglEvalPoint1                = 	dllEvalPoint1                = GPA( "glEvalPoint1" );
+	qglEvalPoint2                = 	dllEvalPoint2                = GPA( "glEvalPoint2" );
+	qglFeedbackBuffer            = 	dllFeedbackBuffer            = GPA( "glFeedbackBuffer" );
+	qglFinish                    = 	dllFinish                    = GPA( "glFinish" );
+	qglFlush                     = 	dllFlush                     = GPA( "glFlush" );
+	qglFogf                      = 	dllFogf                      = GPA( "glFogf" );
+	qglFogfv                     = 	dllFogfv                     = GPA( "glFogfv" );
+	qglFogi                      = 	dllFogi                      = GPA( "glFogi" );
+	qglFogiv                     = 	dllFogiv                     = GPA( "glFogiv" );
+	qglFrontFace                 = 	dllFrontFace                 = GPA( "glFrontFace" );
+	qglFrustum                   = 	dllFrustum                   = GPA( "glFrustum" );
+	qglGenLists                  = 	dllGenLists                  = GPA( "glGenLists" );
+	qglGenTextures               = 	dllGenTextures               = GPA( "glGenTextures" );
+	qglGetBooleanv               = 	dllGetBooleanv               = GPA( "glGetBooleanv" );
+	qglGetClipPlane              = 	dllGetClipPlane              = GPA( "glGetClipPlane" );
+	qglGetDoublev                = 	dllGetDoublev                = GPA( "glGetDoublev" );
+	qglGetError                  = 	dllGetError                  = GPA( "glGetError" );
+	qglGetFloatv                 = 	dllGetFloatv                 = GPA( "glGetFloatv" );
+	qglGetIntegerv               = 	dllGetIntegerv               = GPA( "glGetIntegerv" );
+	qglGetLightfv                = 	dllGetLightfv                = GPA( "glGetLightfv" );
+	qglGetLightiv                = 	dllGetLightiv                = GPA( "glGetLightiv" );
+	qglGetMapdv                  = 	dllGetMapdv                  = GPA( "glGetMapdv" );
+	qglGetMapfv                  = 	dllGetMapfv                  = GPA( "glGetMapfv" );
+	qglGetMapiv                  = 	dllGetMapiv                  = GPA( "glGetMapiv" );
+	qglGetMaterialfv             = 	dllGetMaterialfv             = GPA( "glGetMaterialfv" );
+	qglGetMaterialiv             = 	dllGetMaterialiv             = GPA( "glGetMaterialiv" );
+	qglGetPixelMapfv             = 	dllGetPixelMapfv             = GPA( "glGetPixelMapfv" );
+	qglGetPixelMapuiv            = 	dllGetPixelMapuiv            = GPA( "glGetPixelMapuiv" );
+	qglGetPixelMapusv            = 	dllGetPixelMapusv            = GPA( "glGetPixelMapusv" );
+	qglGetPointerv               = 	dllGetPointerv               = GPA( "glGetPointerv" );
+	qglGetPolygonStipple         = 	dllGetPolygonStipple         = GPA( "glGetPolygonStipple" );
+	qglGetString                 = 	dllGetString                 = GPA( "glGetString" );
+	qglGetTexEnvfv               = 	dllGetTexEnvfv               = GPA( "glGetTexEnvfv" );
+	qglGetTexEnviv               = 	dllGetTexEnviv               = GPA( "glGetTexEnviv" );
+	qglGetTexGendv               = 	dllGetTexGendv               = GPA( "glGetTexGendv" );
+	qglGetTexGenfv               = 	dllGetTexGenfv               = GPA( "glGetTexGenfv" );
+	qglGetTexGeniv               = 	dllGetTexGeniv               = GPA( "glGetTexGeniv" );
+	qglGetTexImage               = 	dllGetTexImage               = GPA( "glGetTexImage" );
+	qglGetTexLevelParameterfv    = 	dllGetTexLevelParameterfv    = GPA( "glGetLevelParameterfv" );
+	qglGetTexLevelParameteriv    = 	dllGetTexLevelParameteriv    = GPA( "glGetLevelParameteriv" );
+	qglGetTexParameterfv         = 	dllGetTexParameterfv         = GPA( "glGetTexParameterfv" );
+	qglGetTexParameteriv         = 	dllGetTexParameteriv         = GPA( "glGetTexParameteriv" );
+	qglHint                      = 	dllHint                      = GPA( "glHint" );
+	qglIndexMask                 = 	dllIndexMask                 = GPA( "glIndexMask" );
+	qglIndexPointer              = 	dllIndexPointer              = GPA( "glIndexPointer" );
+	qglIndexd                    = 	dllIndexd                    = GPA( "glIndexd" );
+	qglIndexdv                   = 	dllIndexdv                   = GPA( "glIndexdv" );
+	qglIndexf                    = 	dllIndexf                    = GPA( "glIndexf" );
+	qglIndexfv                   = 	dllIndexfv                   = GPA( "glIndexfv" );
+	qglIndexi                    = 	dllIndexi                    = GPA( "glIndexi" );
+	qglIndexiv                   = 	dllIndexiv                   = GPA( "glIndexiv" );
+	qglIndexs                    = 	dllIndexs                    = GPA( "glIndexs" );
+	qglIndexsv                   = 	dllIndexsv                   = GPA( "glIndexsv" );
+	qglIndexub                   = 	dllIndexub                   = GPA( "glIndexub" );
+	qglIndexubv                  = 	dllIndexubv                  = GPA( "glIndexubv" );
+	qglInitNames                 = 	dllInitNames                 = GPA( "glInitNames" );
+	qglInterleavedArrays         = 	dllInterleavedArrays         = GPA( "glInterleavedArrays" );
+	qglIsEnabled                 = 	dllIsEnabled                 = GPA( "glIsEnabled" );
+	qglIsList                    = 	dllIsList                    = GPA( "glIsList" );
+	qglIsTexture                 = 	dllIsTexture                 = GPA( "glIsTexture" );
+	qglLightModelf               = 	dllLightModelf               = GPA( "glLightModelf" );
+	qglLightModelfv              = 	dllLightModelfv              = GPA( "glLightModelfv" );
+	qglLightModeli               = 	dllLightModeli               = GPA( "glLightModeli" );
+	qglLightModeliv              = 	dllLightModeliv              = GPA( "glLightModeliv" );
+	qglLightf                    = 	dllLightf                    = GPA( "glLightf" );
+	qglLightfv                   = 	dllLightfv                   = GPA( "glLightfv" );
+	qglLighti                    = 	dllLighti                    = GPA( "glLighti" );
+	qglLightiv                   = 	dllLightiv                   = GPA( "glLightiv" );
+	qglLineStipple               = 	dllLineStipple               = GPA( "glLineStipple" );
+	qglLineWidth                 = 	dllLineWidth                 = GPA( "glLineWidth" );
+	qglListBase                  = 	dllListBase                  = GPA( "glListBase" );
+	qglLoadIdentity              = 	dllLoadIdentity              = GPA( "glLoadIdentity" );
+	qglLoadMatrixd               = 	dllLoadMatrixd               = GPA( "glLoadMatrixd" );
+	qglLoadMatrixf               = 	dllLoadMatrixf               = GPA( "glLoadMatrixf" );
+	qglLoadName                  = 	dllLoadName                  = GPA( "glLoadName" );
+	qglLogicOp                   = 	dllLogicOp                   = GPA( "glLogicOp" );
+	qglMap1d                     = 	dllMap1d                     = GPA( "glMap1d" );
+	qglMap1f                     = 	dllMap1f                     = GPA( "glMap1f" );
+	qglMap2d                     = 	dllMap2d                     = GPA( "glMap2d" );
+	qglMap2f                     = 	dllMap2f                     = GPA( "glMap2f" );
+	qglMapGrid1d                 = 	dllMapGrid1d                 = GPA( "glMapGrid1d" );
+	qglMapGrid1f                 = 	dllMapGrid1f                 = GPA( "glMapGrid1f" );
+	qglMapGrid2d                 = 	dllMapGrid2d                 = GPA( "glMapGrid2d" );
+	qglMapGrid2f                 = 	dllMapGrid2f                 = GPA( "glMapGrid2f" );
+	qglMaterialf                 = 	dllMaterialf                 = GPA( "glMaterialf" );
+	qglMaterialfv                = 	dllMaterialfv                = GPA( "glMaterialfv" );
+	qglMateriali                 = 	dllMateriali                 = GPA( "glMateriali" );
+	qglMaterialiv                = 	dllMaterialiv                = GPA( "glMaterialiv" );
+	qglMatrixMode                = 	dllMatrixMode                = GPA( "glMatrixMode" );
+	qglMultMatrixd               = 	dllMultMatrixd               = GPA( "glMultMatrixd" );
+	qglMultMatrixf               = 	dllMultMatrixf               = GPA( "glMultMatrixf" );
+	qglNewList                   = 	dllNewList                   = GPA( "glNewList" );
+	qglNormal3b                  = 	dllNormal3b                  = GPA( "glNormal3b" );
+	qglNormal3bv                 = 	dllNormal3bv                 = GPA( "glNormal3bv" );
+	qglNormal3d                  = 	dllNormal3d                  = GPA( "glNormal3d" );
+	qglNormal3dv                 = 	dllNormal3dv                 = GPA( "glNormal3dv" );
+	qglNormal3f                  = 	dllNormal3f                  = GPA( "glNormal3f" );
+	qglNormal3fv                 = 	dllNormal3fv                 = GPA( "glNormal3fv" );
+	qglNormal3i                  = 	dllNormal3i                  = GPA( "glNormal3i" );
+	qglNormal3iv                 = 	dllNormal3iv                 = GPA( "glNormal3iv" );
+	qglNormal3s                  = 	dllNormal3s                  = GPA( "glNormal3s" );
+	qglNormal3sv                 = 	dllNormal3sv                 = GPA( "glNormal3sv" );
+	qglNormalPointer             = 	dllNormalPointer             = GPA( "glNormalPointer" );
+	qglOrtho                     = 	dllOrtho                     = GPA( "glOrtho" );
+	qglPassThrough               = 	dllPassThrough               = GPA( "glPassThrough" );
+	qglPixelMapfv                = 	dllPixelMapfv                = GPA( "glPixelMapfv" );
+	qglPixelMapuiv               = 	dllPixelMapuiv               = GPA( "glPixelMapuiv" );
+	qglPixelMapusv               = 	dllPixelMapusv               = GPA( "glPixelMapusv" );
+	qglPixelStoref               = 	dllPixelStoref               = GPA( "glPixelStoref" );
+	qglPixelStorei               = 	dllPixelStorei               = GPA( "glPixelStorei" );
+	qglPixelTransferf            = 	dllPixelTransferf            = GPA( "glPixelTransferf" );
+	qglPixelTransferi            = 	dllPixelTransferi            = GPA( "glPixelTransferi" );
+	qglPixelZoom                 = 	dllPixelZoom                 = GPA( "glPixelZoom" );
+	qglPointSize                 = 	dllPointSize                 = GPA( "glPointSize" );
+	qglPolygonMode               = 	dllPolygonMode               = GPA( "glPolygonMode" );
+	qglPolygonOffset             = 	dllPolygonOffset             = GPA( "glPolygonOffset" );
+	qglPolygonStipple            = 	dllPolygonStipple            = GPA( "glPolygonStipple" );
+	qglPopAttrib                 = 	dllPopAttrib                 = GPA( "glPopAttrib" );
+	qglPopClientAttrib           = 	dllPopClientAttrib           = GPA( "glPopClientAttrib" );
+	qglPopMatrix                 = 	dllPopMatrix                 = GPA( "glPopMatrix" );
+	qglPopName                   = 	dllPopName                   = GPA( "glPopName" );
+	qglPrioritizeTextures        = 	dllPrioritizeTextures        = GPA( "glPrioritizeTextures" );
+	qglPushAttrib                = 	dllPushAttrib                = GPA( "glPushAttrib" );
+	qglPushClientAttrib          = 	dllPushClientAttrib          = GPA( "glPushClientAttrib" );
+	qglPushMatrix                = 	dllPushMatrix                = GPA( "glPushMatrix" );
+	qglPushName                  = 	dllPushName                  = GPA( "glPushName" );
+	qglRasterPos2d               = 	dllRasterPos2d               = GPA( "glRasterPos2d" );
+	qglRasterPos2dv              = 	dllRasterPos2dv              = GPA( "glRasterPos2dv" );
+	qglRasterPos2f               = 	dllRasterPos2f               = GPA( "glRasterPos2f" );
+	qglRasterPos2fv              = 	dllRasterPos2fv              = GPA( "glRasterPos2fv" );
+	qglRasterPos2i               = 	dllRasterPos2i               = GPA( "glRasterPos2i" );
+	qglRasterPos2iv              = 	dllRasterPos2iv              = GPA( "glRasterPos2iv" );
+	qglRasterPos2s               = 	dllRasterPos2s               = GPA( "glRasterPos2s" );
+	qglRasterPos2sv              = 	dllRasterPos2sv              = GPA( "glRasterPos2sv" );
+	qglRasterPos3d               = 	dllRasterPos3d               = GPA( "glRasterPos3d" );
+	qglRasterPos3dv              = 	dllRasterPos3dv              = GPA( "glRasterPos3dv" );
+	qglRasterPos3f               = 	dllRasterPos3f               = GPA( "glRasterPos3f" );
+	qglRasterPos3fv              = 	dllRasterPos3fv              = GPA( "glRasterPos3fv" );
+	qglRasterPos3i               = 	dllRasterPos3i               = GPA( "glRasterPos3i" );
+	qglRasterPos3iv              = 	dllRasterPos3iv              = GPA( "glRasterPos3iv" );
+	qglRasterPos3s               = 	dllRasterPos3s               = GPA( "glRasterPos3s" );
+	qglRasterPos3sv              = 	dllRasterPos3sv              = GPA( "glRasterPos3sv" );
+	qglRasterPos4d               = 	dllRasterPos4d               = GPA( "glRasterPos4d" );
+	qglRasterPos4dv              = 	dllRasterPos4dv              = GPA( "glRasterPos4dv" );
+	qglRasterPos4f               = 	dllRasterPos4f               = GPA( "glRasterPos4f" );
+	qglRasterPos4fv              = 	dllRasterPos4fv              = GPA( "glRasterPos4fv" );
+	qglRasterPos4i               = 	dllRasterPos4i               = GPA( "glRasterPos4i" );
+	qglRasterPos4iv              = 	dllRasterPos4iv              = GPA( "glRasterPos4iv" );
+	qglRasterPos4s               = 	dllRasterPos4s               = GPA( "glRasterPos4s" );
+	qglRasterPos4sv              = 	dllRasterPos4sv              = GPA( "glRasterPos4sv" );
+	qglReadBuffer                = 	dllReadBuffer                = GPA( "glReadBuffer" );
+	qglReadPixels                = 	dllReadPixels                = GPA( "glReadPixels" );
+	qglRectd                     = 	dllRectd                     = GPA( "glRectd" );
+	qglRectdv                    = 	dllRectdv                    = GPA( "glRectdv" );
+	qglRectf                     = 	dllRectf                     = GPA( "glRectf" );
+	qglRectfv                    = 	dllRectfv                    = GPA( "glRectfv" );
+	qglRecti                     = 	dllRecti                     = GPA( "glRecti" );
+	qglRectiv                    = 	dllRectiv                    = GPA( "glRectiv" );
+	qglRects                     = 	dllRects                     = GPA( "glRects" );
+	qglRectsv                    = 	dllRectsv                    = GPA( "glRectsv" );
+	qglRenderMode                = 	dllRenderMode                = GPA( "glRenderMode" );
+	qglRotated                   = 	dllRotated                   = GPA( "glRotated" );
+	qglRotatef                   = 	dllRotatef                   = GPA( "glRotatef" );
+	qglScaled                    = 	dllScaled                    = GPA( "glScaled" );
+	qglScalef                    = 	dllScalef                    = GPA( "glScalef" );
+	qglScissor                   = 	dllScissor                   = GPA( "glScissor" );
+	qglSelectBuffer              = 	dllSelectBuffer              = GPA( "glSelectBuffer" );
+	qglShadeModel                = 	dllShadeModel                = GPA( "glShadeModel" );
+	qglStencilFunc               = 	dllStencilFunc               = GPA( "glStencilFunc" );
+	qglStencilMask               = 	dllStencilMask               = GPA( "glStencilMask" );
+	qglStencilOp                 = 	dllStencilOp                 = GPA( "glStencilOp" );
+	qglTexCoord1d                = 	dllTexCoord1d                = GPA( "glTexCoord1d" );
+	qglTexCoord1dv               = 	dllTexCoord1dv               = GPA( "glTexCoord1dv" );
+	qglTexCoord1f                = 	dllTexCoord1f                = GPA( "glTexCoord1f" );
+	qglTexCoord1fv               = 	dllTexCoord1fv               = GPA( "glTexCoord1fv" );
+	qglTexCoord1i                = 	dllTexCoord1i                = GPA( "glTexCoord1i" );
+	qglTexCoord1iv               = 	dllTexCoord1iv               = GPA( "glTexCoord1iv" );
+	qglTexCoord1s                = 	dllTexCoord1s                = GPA( "glTexCoord1s" );
+	qglTexCoord1sv               = 	dllTexCoord1sv               = GPA( "glTexCoord1sv" );
+	qglTexCoord2d                = 	dllTexCoord2d                = GPA( "glTexCoord2d" );
+	qglTexCoord2dv               = 	dllTexCoord2dv               = GPA( "glTexCoord2dv" );
+	qglTexCoord2f                = 	dllTexCoord2f                = GPA( "glTexCoord2f" );
+	qglTexCoord2fv               = 	dllTexCoord2fv               = GPA( "glTexCoord2fv" );
+	qglTexCoord2i                = 	dllTexCoord2i                = GPA( "glTexCoord2i" );
+	qglTexCoord2iv               = 	dllTexCoord2iv               = GPA( "glTexCoord2iv" );
+	qglTexCoord2s                = 	dllTexCoord2s                = GPA( "glTexCoord2s" );
+	qglTexCoord2sv               = 	dllTexCoord2sv               = GPA( "glTexCoord2sv" );
+	qglTexCoord3d                = 	dllTexCoord3d                = GPA( "glTexCoord3d" );
+	qglTexCoord3dv               = 	dllTexCoord3dv               = GPA( "glTexCoord3dv" );
+	qglTexCoord3f                = 	dllTexCoord3f                = GPA( "glTexCoord3f" );
+	qglTexCoord3fv               = 	dllTexCoord3fv               = GPA( "glTexCoord3fv" );
+	qglTexCoord3i                = 	dllTexCoord3i                = GPA( "glTexCoord3i" );
+	qglTexCoord3iv               = 	dllTexCoord3iv               = GPA( "glTexCoord3iv" );
+	qglTexCoord3s                = 	dllTexCoord3s                = GPA( "glTexCoord3s" );
+	qglTexCoord3sv               = 	dllTexCoord3sv               = GPA( "glTexCoord3sv" );
+	qglTexCoord4d                = 	dllTexCoord4d                = GPA( "glTexCoord4d" );
+	qglTexCoord4dv               = 	dllTexCoord4dv               = GPA( "glTexCoord4dv" );
+	qglTexCoord4f                = 	dllTexCoord4f                = GPA( "glTexCoord4f" );
+	qglTexCoord4fv               = 	dllTexCoord4fv               = GPA( "glTexCoord4fv" );
+	qglTexCoord4i                = 	dllTexCoord4i                = GPA( "glTexCoord4i" );
+	qglTexCoord4iv               = 	dllTexCoord4iv               = GPA( "glTexCoord4iv" );
+	qglTexCoord4s                = 	dllTexCoord4s                = GPA( "glTexCoord4s" );
+	qglTexCoord4sv               = 	dllTexCoord4sv               = GPA( "glTexCoord4sv" );
+	qglTexCoordPointer           = 	dllTexCoordPointer           = GPA( "glTexCoordPointer" );
+	qglTexEnvf                   = 	dllTexEnvf                   = GPA( "glTexEnvf" );
+	qglTexEnvfv                  = 	dllTexEnvfv                  = GPA( "glTexEnvfv" );
+	qglTexEnvi                   = 	dllTexEnvi                   = GPA( "glTexEnvi" );
+	qglTexEnviv                  = 	dllTexEnviv                  = GPA( "glTexEnviv" );
+	qglTexGend                   = 	dllTexGend                   = GPA( "glTexGend" );
+	qglTexGendv                  = 	dllTexGendv                  = GPA( "glTexGendv" );
+	qglTexGenf                   = 	dllTexGenf                   = GPA( "glTexGenf" );
+	qglTexGenfv                  = 	dllTexGenfv                  = GPA( "glTexGenfv" );
+	qglTexGeni                   = 	dllTexGeni                   = GPA( "glTexGeni" );
+	qglTexGeniv                  = 	dllTexGeniv                  = GPA( "glTexGeniv" );
+	qglTexImage1D                = 	dllTexImage1D                = GPA( "glTexImage1D" );
+	qglTexImage2D                = 	dllTexImage2D                = GPA( "glTexImage2D" );
+	qglTexParameterf             = 	dllTexParameterf             = GPA( "glTexParameterf" );
+	qglTexParameterfv            = 	dllTexParameterfv            = GPA( "glTexParameterfv" );
+	qglTexParameteri             = 	dllTexParameteri             = GPA( "glTexParameteri" );
+	qglTexParameteriv            = 	dllTexParameteriv            = GPA( "glTexParameteriv" );
+	qglTexSubImage1D             = 	dllTexSubImage1D             = GPA( "glTexSubImage1D" );
+	qglTexSubImage2D             = 	dllTexSubImage2D             = GPA( "glTexSubImage2D" );
+	qglTranslated                = 	dllTranslated                = GPA( "glTranslated" );
+	qglTranslatef                = 	dllTranslatef                = GPA( "glTranslatef" );
+	qglVertex2d                  = 	dllVertex2d                  = GPA( "glVertex2d" );
+	qglVertex2dv                 = 	dllVertex2dv                 = GPA( "glVertex2dv" );
+	qglVertex2f                  = 	dllVertex2f                  = GPA( "glVertex2f" );
+	qglVertex2fv                 = 	dllVertex2fv                 = GPA( "glVertex2fv" );
+	qglVertex2i                  = 	dllVertex2i                  = GPA( "glVertex2i" );
+	qglVertex2iv                 = 	dllVertex2iv                 = GPA( "glVertex2iv" );
+	qglVertex2s                  = 	dllVertex2s                  = GPA( "glVertex2s" );
+	qglVertex2sv                 = 	dllVertex2sv                 = GPA( "glVertex2sv" );
+	qglVertex3d                  = 	dllVertex3d                  = GPA( "glVertex3d" );
+	qglVertex3dv                 = 	dllVertex3dv                 = GPA( "glVertex3dv" );
+	qglVertex3f                  = 	dllVertex3f                  = GPA( "glVertex3f" );
+	qglVertex3fv                 = 	dllVertex3fv                 = GPA( "glVertex3fv" );
+	qglVertex3i                  = 	dllVertex3i                  = GPA( "glVertex3i" );
+	qglVertex3iv                 = 	dllVertex3iv                 = GPA( "glVertex3iv" );
+	qglVertex3s                  = 	dllVertex3s                  = GPA( "glVertex3s" );
+	qglVertex3sv                 = 	dllVertex3sv                 = GPA( "glVertex3sv" );
+	qglVertex4d                  = 	dllVertex4d                  = GPA( "glVertex4d" );
+	qglVertex4dv                 = 	dllVertex4dv                 = GPA( "glVertex4dv" );
+	qglVertex4f                  = 	dllVertex4f                  = GPA( "glVertex4f" );
+	qglVertex4fv                 = 	dllVertex4fv                 = GPA( "glVertex4fv" );
+	qglVertex4i                  = 	dllVertex4i                  = GPA( "glVertex4i" );
+	qglVertex4iv                 = 	dllVertex4iv                 = GPA( "glVertex4iv" );
+	qglVertex4s                  = 	dllVertex4s                  = GPA( "glVertex4s" );
+	qglVertex4sv                 = 	dllVertex4sv                 = GPA( "glVertex4sv" );
+	qglVertexPointer             = 	dllVertexPointer             = GPA( "glVertexPointer" );
+	qglViewport                  = 	dllViewport                  = GPA( "glViewport" );
+
+	qwglCopyContext              = GPA( "wglCopyContext" );
+	qwglCreateContext            = GPA( "wglCreateContext" );
+	qwglCreateLayerContext       = GPA( "wglCreateLayerContext" );
+	qwglDeleteContext            = GPA( "wglDeleteContext" );
+	qwglDescribeLayerPlane       = GPA( "wglDescribeLayerPlane" );
+	qwglGetCurrentContext        = GPA( "wglGetCurrentContext" );
+	qwglGetCurrentDC             = GPA( "wglGetCurrentDC" );
+	qwglGetLayerPaletteEntries   = GPA( "wglGetLayerPaletteEntries" );
+	qwglGetProcAddress           = GPA( "wglGetProcAddress" );
+	qwglMakeCurrent              = GPA( "wglMakeCurrent" );
+	qwglRealizeLayerPalette      = GPA( "wglRealizeLayerPalette" );
+	qwglSetLayerPaletteEntries   = GPA( "wglSetLayerPaletteEntries" );
+	qwglShareLists               = GPA( "wglShareLists" );
+	qwglSwapLayerBuffers         = GPA( "wglSwapLayerBuffers" );
+	qwglUseFontBitmaps           = GPA( "wglUseFontBitmapsA" );
+	qwglUseFontOutlines          = GPA( "wglUseFontOutlinesA" );
+
+	qwglChoosePixelFormat        = GPA( "wglChoosePixelFormat" );
+	qwglDescribePixelFormat      = GPA( "wglDescribePixelFormat" );
+	qwglGetPixelFormat           = GPA( "wglGetPixelFormat" );
+	qwglSetPixelFormat           = GPA( "wglSetPixelFormat" );
+	qwglSwapBuffers              = GPA( "wglSwapBuffers" );
+
+	qwglSwapIntervalEXT = 0;
+	qglPointParameterfEXT = 0;
+	qglPointParameterfvEXT = 0;
+	qglColorTableEXT = 0;
+	qglSelectTextureSGIS = 0;
+	qglMTexCoord2fSGIS = 0;
+
+	return true;
+}
+
+void GLimp_EnableLogging( qboolean enable )
+{
+	if ( enable )
+	{
+		if ( !glw_state.log_fp )
+		{
+			struct tm *newtime;
+			time_t aclock;
+			char buffer[1024];
+
+			time( &aclock );
+			newtime = localtime( &aclock );
+
+			asctime( newtime );
+
+			Com_sprintf( buffer, sizeof(buffer), "%s/gl.log", ri.FS_Gamedir() ); 
+			glw_state.log_fp = fopen( buffer, "wt" );
+
+			fprintf( glw_state.log_fp, "%s\n", asctime( newtime ) );
+		}
+
+		qglAccum                     = logAccum;
+		qglAlphaFunc                 = logAlphaFunc;
+		qglAreTexturesResident       = logAreTexturesResident;
+		qglArrayElement              = logArrayElement;
+		qglBegin                     = logBegin;
+		qglBindTexture               = logBindTexture;
+		qglBitmap                    = logBitmap;
+		qglBlendFunc                 = logBlendFunc;
+		qglCallList                  = logCallList;
+		qglCallLists                 = logCallLists;
+		qglClear                     = logClear;
+		qglClearAccum                = logClearAccum;
+		qglClearColor                = logClearColor;
+		qglClearDepth                = logClearDepth;
+		qglClearIndex                = logClearIndex;
+		qglClearStencil              = logClearStencil;
+		qglClipPlane                 = logClipPlane;
+		qglColor3b                   = logColor3b;
+		qglColor3bv                  = logColor3bv;
+		qglColor3d                   = logColor3d;
+		qglColor3dv                  = logColor3dv;
+		qglColor3f                   = logColor3f;
+		qglColor3fv                  = logColor3fv;
+		qglColor3i                   = logColor3i;
+		qglColor3iv                  = logColor3iv;
+		qglColor3s                   = logColor3s;
+		qglColor3sv                  = logColor3sv;
+		qglColor3ub                  = logColor3ub;
+		qglColor3ubv                 = logColor3ubv;
+		qglColor3ui                  = logColor3ui;
+		qglColor3uiv                 = logColor3uiv;
+		qglColor3us                  = logColor3us;
+		qglColor3usv                 = logColor3usv;
+		qglColor4b                   = logColor4b;
+		qglColor4bv                  = logColor4bv;
+		qglColor4d                   = logColor4d;
+		qglColor4dv                  = logColor4dv;
+		qglColor4f                   = logColor4f;
+		qglColor4fv                  = logColor4fv;
+		qglColor4i                   = logColor4i;
+		qglColor4iv                  = logColor4iv;
+		qglColor4s                   = logColor4s;
+		qglColor4sv                  = logColor4sv;
+		qglColor4ub                  = logColor4ub;
+		qglColor4ubv                 = logColor4ubv;
+		qglColor4ui                  = logColor4ui;
+		qglColor4uiv                 = logColor4uiv;
+		qglColor4us                  = logColor4us;
+		qglColor4usv                 = logColor4usv;
+		qglColorMask                 = logColorMask;
+		qglColorMaterial             = logColorMaterial;
+		qglColorPointer              = logColorPointer;
+		qglCopyPixels                = logCopyPixels;
+		qglCopyTexImage1D            = logCopyTexImage1D;
+		qglCopyTexImage2D            = logCopyTexImage2D;
+		qglCopyTexSubImage1D         = logCopyTexSubImage1D;
+		qglCopyTexSubImage2D         = logCopyTexSubImage2D;
+		qglCullFace                  = logCullFace;
+		qglDeleteLists               = logDeleteLists ;
+		qglDeleteTextures            = logDeleteTextures ;
+		qglDepthFunc                 = logDepthFunc ;
+		qglDepthMask                 = logDepthMask ;
+		qglDepthRange                = logDepthRange ;
+		qglDisable                   = logDisable ;
+		qglDisableClientState        = logDisableClientState ;
+		qglDrawArrays                = logDrawArrays ;
+		qglDrawBuffer                = logDrawBuffer ;
+		qglDrawElements              = logDrawElements ;
+		qglDrawPixels                = logDrawPixels ;
+		qglEdgeFlag                  = logEdgeFlag ;
+		qglEdgeFlagPointer           = logEdgeFlagPointer ;
+		qglEdgeFlagv                 = logEdgeFlagv ;
+		qglEnable                    = 	logEnable                    ;
+		qglEnableClientState         = 	logEnableClientState         ;
+		qglEnd                       = 	logEnd                       ;
+		qglEndList                   = 	logEndList                   ;
+		qglEvalCoord1d				 = 	logEvalCoord1d				 ;
+		qglEvalCoord1dv              = 	logEvalCoord1dv              ;
+		qglEvalCoord1f               = 	logEvalCoord1f               ;
+		qglEvalCoord1fv              = 	logEvalCoord1fv              ;
+		qglEvalCoord2d               = 	logEvalCoord2d               ;
+		qglEvalCoord2dv              = 	logEvalCoord2dv              ;
+		qglEvalCoord2f               = 	logEvalCoord2f               ;
+		qglEvalCoord2fv              = 	logEvalCoord2fv              ;
+		qglEvalMesh1                 = 	logEvalMesh1                 ;
+		qglEvalMesh2                 = 	logEvalMesh2                 ;
+		qglEvalPoint1                = 	logEvalPoint1                ;
+		qglEvalPoint2                = 	logEvalPoint2                ;
+		qglFeedbackBuffer            = 	logFeedbackBuffer            ;
+		qglFinish                    = 	logFinish                    ;
+		qglFlush                     = 	logFlush                     ;
+		qglFogf                      = 	logFogf                      ;
+		qglFogfv                     = 	logFogfv                     ;
+		qglFogi                      = 	logFogi                      ;
+		qglFogiv                     = 	logFogiv                     ;
+		qglFrontFace                 = 	logFrontFace                 ;
+		qglFrustum                   = 	logFrustum                   ;
+		qglGenLists                  = 	logGenLists                  ;
+		qglGenTextures               = 	logGenTextures               ;
+		qglGetBooleanv               = 	logGetBooleanv               ;
+		qglGetClipPlane              = 	logGetClipPlane              ;
+		qglGetDoublev                = 	logGetDoublev                ;
+		qglGetError                  = 	logGetError                  ;
+		qglGetFloatv                 = 	logGetFloatv                 ;
+		qglGetIntegerv               = 	logGetIntegerv               ;
+		qglGetLightfv                = 	logGetLightfv                ;
+		qglGetLightiv                = 	logGetLightiv                ;
+		qglGetMapdv                  = 	logGetMapdv                  ;
+		qglGetMapfv                  = 	logGetMapfv                  ;
+		qglGetMapiv                  = 	logGetMapiv                  ;
+		qglGetMaterialfv             = 	logGetMaterialfv             ;
+		qglGetMaterialiv             = 	logGetMaterialiv             ;
+		qglGetPixelMapfv             = 	logGetPixelMapfv             ;
+		qglGetPixelMapuiv            = 	logGetPixelMapuiv            ;
+		qglGetPixelMapusv            = 	logGetPixelMapusv            ;
+		qglGetPointerv               = 	logGetPointerv               ;
+		qglGetPolygonStipple         = 	logGetPolygonStipple         ;
+		qglGetString                 = 	logGetString                 ;
+		qglGetTexEnvfv               = 	logGetTexEnvfv               ;
+		qglGetTexEnviv               = 	logGetTexEnviv               ;
+		qglGetTexGendv               = 	logGetTexGendv               ;
+		qglGetTexGenfv               = 	logGetTexGenfv               ;
+		qglGetTexGeniv               = 	logGetTexGeniv               ;
+		qglGetTexImage               = 	logGetTexImage               ;
+		qglGetTexLevelParameterfv    = 	logGetTexLevelParameterfv    ;
+		qglGetTexLevelParameteriv    = 	logGetTexLevelParameteriv    ;
+		qglGetTexParameterfv         = 	logGetTexParameterfv         ;
+		qglGetTexParameteriv         = 	logGetTexParameteriv         ;
+		qglHint                      = 	logHint                      ;
+		qglIndexMask                 = 	logIndexMask                 ;
+		qglIndexPointer              = 	logIndexPointer              ;
+		qglIndexd                    = 	logIndexd                    ;
+		qglIndexdv                   = 	logIndexdv                   ;
+		qglIndexf                    = 	logIndexf                    ;
+		qglIndexfv                   = 	logIndexfv                   ;
+		qglIndexi                    = 	logIndexi                    ;
+		qglIndexiv                   = 	logIndexiv                   ;
+		qglIndexs                    = 	logIndexs                    ;
+		qglIndexsv                   = 	logIndexsv                   ;
+		qglIndexub                   = 	logIndexub                   ;
+		qglIndexubv                  = 	logIndexubv                  ;
+		qglInitNames                 = 	logInitNames                 ;
+		qglInterleavedArrays         = 	logInterleavedArrays         ;
+		qglIsEnabled                 = 	logIsEnabled                 ;
+		qglIsList                    = 	logIsList                    ;
+		qglIsTexture                 = 	logIsTexture                 ;
+		qglLightModelf               = 	logLightModelf               ;
+		qglLightModelfv              = 	logLightModelfv              ;
+		qglLightModeli               = 	logLightModeli               ;
+		qglLightModeliv              = 	logLightModeliv              ;
+		qglLightf                    = 	logLightf                    ;
+		qglLightfv                   = 	logLightfv                   ;
+		qglLighti                    = 	logLighti                    ;
+		qglLightiv                   = 	logLightiv                   ;
+		qglLineStipple               = 	logLineStipple               ;
+		qglLineWidth                 = 	logLineWidth                 ;
+		qglListBase                  = 	logListBase                  ;
+		qglLoadIdentity              = 	logLoadIdentity              ;
+		qglLoadMatrixd               = 	logLoadMatrixd               ;
+		qglLoadMatrixf               = 	logLoadMatrixf               ;
+		qglLoadName                  = 	logLoadName                  ;
+		qglLogicOp                   = 	logLogicOp                   ;
+		qglMap1d                     = 	logMap1d                     ;
+		qglMap1f                     = 	logMap1f                     ;
+		qglMap2d                     = 	logMap2d                     ;
+		qglMap2f                     = 	logMap2f                     ;
+		qglMapGrid1d                 = 	logMapGrid1d                 ;
+		qglMapGrid1f                 = 	logMapGrid1f                 ;
+		qglMapGrid2d                 = 	logMapGrid2d                 ;
+		qglMapGrid2f                 = 	logMapGrid2f                 ;
+		qglMaterialf                 = 	logMaterialf                 ;
+		qglMaterialfv                = 	logMaterialfv                ;
+		qglMateriali                 = 	logMateriali                 ;
+		qglMaterialiv                = 	logMaterialiv                ;
+		qglMatrixMode                = 	logMatrixMode                ;
+		qglMultMatrixd               = 	logMultMatrixd               ;
+		qglMultMatrixf               = 	logMultMatrixf               ;
+		qglNewList                   = 	logNewList                   ;
+		qglNormal3b                  = 	logNormal3b                  ;
+		qglNormal3bv                 = 	logNormal3bv                 ;
+		qglNormal3d                  = 	logNormal3d                  ;
+		qglNormal3dv                 = 	logNormal3dv                 ;
+		qglNormal3f                  = 	logNormal3f                  ;
+		qglNormal3fv                 = 	logNormal3fv                 ;
+		qglNormal3i                  = 	logNormal3i                  ;
+		qglNormal3iv                 = 	logNormal3iv                 ;
+		qglNormal3s                  = 	logNormal3s                  ;
+		qglNormal3sv                 = 	logNormal3sv                 ;
+		qglNormalPointer             = 	logNormalPointer             ;
+		qglOrtho                     = 	logOrtho                     ;
+		qglPassThrough               = 	logPassThrough               ;
+		qglPixelMapfv                = 	logPixelMapfv                ;
+		qglPixelMapuiv               = 	logPixelMapuiv               ;
+		qglPixelMapusv               = 	logPixelMapusv               ;
+		qglPixelStoref               = 	logPixelStoref               ;
+		qglPixelStorei               = 	logPixelStorei               ;
+		qglPixelTransferf            = 	logPixelTransferf            ;
+		qglPixelTransferi            = 	logPixelTransferi            ;
+		qglPixelZoom                 = 	logPixelZoom                 ;
+		qglPointSize                 = 	logPointSize                 ;
+		qglPolygonMode               = 	logPolygonMode               ;
+		qglPolygonOffset             = 	logPolygonOffset             ;
+		qglPolygonStipple            = 	logPolygonStipple            ;
+		qglPopAttrib                 = 	logPopAttrib                 ;
+		qglPopClientAttrib           = 	logPopClientAttrib           ;
+		qglPopMatrix                 = 	logPopMatrix                 ;
+		qglPopName                   = 	logPopName                   ;
+		qglPrioritizeTextures        = 	logPrioritizeTextures        ;
+		qglPushAttrib                = 	logPushAttrib                ;
+		qglPushClientAttrib          = 	logPushClientAttrib          ;
+		qglPushMatrix                = 	logPushMatrix                ;
+		qglPushName                  = 	logPushName                  ;
+		qglRasterPos2d               = 	logRasterPos2d               ;
+		qglRasterPos2dv              = 	logRasterPos2dv              ;
+		qglRasterPos2f               = 	logRasterPos2f               ;
+		qglRasterPos2fv              = 	logRasterPos2fv              ;
+		qglRasterPos2i               = 	logRasterPos2i               ;
+		qglRasterPos2iv              = 	logRasterPos2iv              ;
+		qglRasterPos2s               = 	logRasterPos2s               ;
+		qglRasterPos2sv              = 	logRasterPos2sv              ;
+		qglRasterPos3d               = 	logRasterPos3d               ;
+		qglRasterPos3dv              = 	logRasterPos3dv              ;
+		qglRasterPos3f               = 	logRasterPos3f               ;
+		qglRasterPos3fv              = 	logRasterPos3fv              ;
+		qglRasterPos3i               = 	logRasterPos3i               ;
+		qglRasterPos3iv              = 	logRasterPos3iv              ;
+		qglRasterPos3s               = 	logRasterPos3s               ;
+		qglRasterPos3sv              = 	logRasterPos3sv              ;
+		qglRasterPos4d               = 	logRasterPos4d               ;
+		qglRasterPos4dv              = 	logRasterPos4dv              ;
+		qglRasterPos4f               = 	logRasterPos4f               ;
+		qglRasterPos4fv              = 	logRasterPos4fv              ;
+		qglRasterPos4i               = 	logRasterPos4i               ;
+		qglRasterPos4iv              = 	logRasterPos4iv              ;
+		qglRasterPos4s               = 	logRasterPos4s               ;
+		qglRasterPos4sv              = 	logRasterPos4sv              ;
+		qglReadBuffer                = 	logReadBuffer                ;
+		qglReadPixels                = 	logReadPixels                ;
+		qglRectd                     = 	logRectd                     ;
+		qglRectdv                    = 	logRectdv                    ;
+		qglRectf                     = 	logRectf                     ;
+		qglRectfv                    = 	logRectfv                    ;
+		qglRecti                     = 	logRecti                     ;
+		qglRectiv                    = 	logRectiv                    ;
+		qglRects                     = 	logRects                     ;
+		qglRectsv                    = 	logRectsv                    ;
+		qglRenderMode                = 	logRenderMode                ;
+		qglRotated                   = 	logRotated                   ;
+		qglRotatef                   = 	logRotatef                   ;
+		qglScaled                    = 	logScaled                    ;
+		qglScalef                    = 	logScalef                    ;
+		qglScissor                   = 	logScissor                   ;
+		qglSelectBuffer              = 	logSelectBuffer              ;
+		qglShadeModel                = 	logShadeModel                ;
+		qglStencilFunc               = 	logStencilFunc               ;
+		qglStencilMask               = 	logStencilMask               ;
+		qglStencilOp                 = 	logStencilOp                 ;
+		qglTexCoord1d                = 	logTexCoord1d                ;
+		qglTexCoord1dv               = 	logTexCoord1dv               ;
+		qglTexCoord1f                = 	logTexCoord1f                ;
+		qglTexCoord1fv               = 	logTexCoord1fv               ;
+		qglTexCoord1i                = 	logTexCoord1i                ;
+		qglTexCoord1iv               = 	logTexCoord1iv               ;
+		qglTexCoord1s                = 	logTexCoord1s                ;
+		qglTexCoord1sv               = 	logTexCoord1sv               ;
+		qglTexCoord2d                = 	logTexCoord2d                ;
+		qglTexCoord2dv               = 	logTexCoord2dv               ;
+		qglTexCoord2f                = 	logTexCoord2f                ;
+		qglTexCoord2fv               = 	logTexCoord2fv               ;
+		qglTexCoord2i                = 	logTexCoord2i                ;
+		qglTexCoord2iv               = 	logTexCoord2iv               ;
+		qglTexCoord2s                = 	logTexCoord2s                ;
+		qglTexCoord2sv               = 	logTexCoord2sv               ;
+		qglTexCoord3d                = 	logTexCoord3d                ;
+		qglTexCoord3dv               = 	logTexCoord3dv               ;
+		qglTexCoord3f                = 	logTexCoord3f                ;
+		qglTexCoord3fv               = 	logTexCoord3fv               ;
+		qglTexCoord3i                = 	logTexCoord3i                ;
+		qglTexCoord3iv               = 	logTexCoord3iv               ;
+		qglTexCoord3s                = 	logTexCoord3s                ;
+		qglTexCoord3sv               = 	logTexCoord3sv               ;
+		qglTexCoord4d                = 	logTexCoord4d                ;
+		qglTexCoord4dv               = 	logTexCoord4dv               ;
+		qglTexCoord4f                = 	logTexCoord4f                ;
+		qglTexCoord4fv               = 	logTexCoord4fv               ;
+		qglTexCoord4i                = 	logTexCoord4i                ;
+		qglTexCoord4iv               = 	logTexCoord4iv               ;
+		qglTexCoord4s                = 	logTexCoord4s                ;
+		qglTexCoord4sv               = 	logTexCoord4sv               ;
+		qglTexCoordPointer           = 	logTexCoordPointer           ;
+		qglTexEnvf                   = 	logTexEnvf                   ;
+		qglTexEnvfv                  = 	logTexEnvfv                  ;
+		qglTexEnvi                   = 	logTexEnvi                   ;
+		qglTexEnviv                  = 	logTexEnviv                  ;
+		qglTexGend                   = 	logTexGend                   ;
+		qglTexGendv                  = 	logTexGendv                  ;
+		qglTexGenf                   = 	logTexGenf                   ;
+		qglTexGenfv                  = 	logTexGenfv                  ;
+		qglTexGeni                   = 	logTexGeni                   ;
+		qglTexGeniv                  = 	logTexGeniv                  ;
+		qglTexImage1D                = 	logTexImage1D                ;
+		qglTexImage2D                = 	logTexImage2D                ;
+		qglTexParameterf             = 	logTexParameterf             ;
+		qglTexParameterfv            = 	logTexParameterfv            ;
+		qglTexParameteri             = 	logTexParameteri             ;
+		qglTexParameteriv            = 	logTexParameteriv            ;
+		qglTexSubImage1D             = 	logTexSubImage1D             ;
+		qglTexSubImage2D             = 	logTexSubImage2D             ;
+		qglTranslated                = 	logTranslated                ;
+		qglTranslatef                = 	logTranslatef                ;
+		qglVertex2d                  = 	logVertex2d                  ;
+		qglVertex2dv                 = 	logVertex2dv                 ;
+		qglVertex2f                  = 	logVertex2f                  ;
+		qglVertex2fv                 = 	logVertex2fv                 ;
+		qglVertex2i                  = 	logVertex2i                  ;
+		qglVertex2iv                 = 	logVertex2iv                 ;
+		qglVertex2s                  = 	logVertex2s                  ;
+		qglVertex2sv                 = 	logVertex2sv                 ;
+		qglVertex3d                  = 	logVertex3d                  ;
+		qglVertex3dv                 = 	logVertex3dv                 ;
+		qglVertex3f                  = 	logVertex3f                  ;
+		qglVertex3fv                 = 	logVertex3fv                 ;
+		qglVertex3i                  = 	logVertex3i                  ;
+		qglVertex3iv                 = 	logVertex3iv                 ;
+		qglVertex3s                  = 	logVertex3s                  ;
+		qglVertex3sv                 = 	logVertex3sv                 ;
+		qglVertex4d                  = 	logVertex4d                  ;
+		qglVertex4dv                 = 	logVertex4dv                 ;
+		qglVertex4f                  = 	logVertex4f                  ;
+		qglVertex4fv                 = 	logVertex4fv                 ;
+		qglVertex4i                  = 	logVertex4i                  ;
+		qglVertex4iv                 = 	logVertex4iv                 ;
+		qglVertex4s                  = 	logVertex4s                  ;
+		qglVertex4sv                 = 	logVertex4sv                 ;
+		qglVertexPointer             = 	logVertexPointer             ;
+		qglViewport                  = 	logViewport                  ;
+	}
+	else
+	{
+		qglAccum                     = dllAccum;
+		qglAlphaFunc                 = dllAlphaFunc;
+		qglAreTexturesResident       = dllAreTexturesResident;
+		qglArrayElement              = dllArrayElement;
+		qglBegin                     = dllBegin;
+		qglBindTexture               = dllBindTexture;
+		qglBitmap                    = dllBitmap;
+		qglBlendFunc                 = dllBlendFunc;
+		qglCallList                  = dllCallList;
+		qglCallLists                 = dllCallLists;
+		qglClear                     = dllClear;
+		qglClearAccum                = dllClearAccum;
+		qglClearColor                = dllClearColor;
+		qglClearDepth                = dllClearDepth;
+		qglClearIndex                = dllClearIndex;
+		qglClearStencil              = dllClearStencil;
+		qglClipPlane                 = dllClipPlane;
+		qglColor3b                   = dllColor3b;
+		qglColor3bv                  = dllColor3bv;
+		qglColor3d                   = dllColor3d;
+		qglColor3dv                  = dllColor3dv;
+		qglColor3f                   = dllColor3f;
+		qglColor3fv                  = dllColor3fv;
+		qglColor3i                   = dllColor3i;
+		qglColor3iv                  = dllColor3iv;
+		qglColor3s                   = dllColor3s;
+		qglColor3sv                  = dllColor3sv;
+		qglColor3ub                  = dllColor3ub;
+		qglColor3ubv                 = dllColor3ubv;
+		qglColor3ui                  = dllColor3ui;
+		qglColor3uiv                 = dllColor3uiv;
+		qglColor3us                  = dllColor3us;
+		qglColor3usv                 = dllColor3usv;
+		qglColor4b                   = dllColor4b;
+		qglColor4bv                  = dllColor4bv;
+		qglColor4d                   = dllColor4d;
+		qglColor4dv                  = dllColor4dv;
+		qglColor4f                   = dllColor4f;
+		qglColor4fv                  = dllColor4fv;
+		qglColor4i                   = dllColor4i;
+		qglColor4iv                  = dllColor4iv;
+		qglColor4s                   = dllColor4s;
+		qglColor4sv                  = dllColor4sv;
+		qglColor4ub                  = dllColor4ub;
+		qglColor4ubv                 = dllColor4ubv;
+		qglColor4ui                  = dllColor4ui;
+		qglColor4uiv                 = dllColor4uiv;
+		qglColor4us                  = dllColor4us;
+		qglColor4usv                 = dllColor4usv;
+		qglColorMask                 = dllColorMask;
+		qglColorMaterial             = dllColorMaterial;
+		qglColorPointer              = dllColorPointer;
+		qglCopyPixels                = dllCopyPixels;
+		qglCopyTexImage1D            = dllCopyTexImage1D;
+		qglCopyTexImage2D            = dllCopyTexImage2D;
+		qglCopyTexSubImage1D         = dllCopyTexSubImage1D;
+		qglCopyTexSubImage2D         = dllCopyTexSubImage2D;
+		qglCullFace                  = dllCullFace;
+		qglDeleteLists               = dllDeleteLists ;
+		qglDeleteTextures            = dllDeleteTextures ;
+		qglDepthFunc                 = dllDepthFunc ;
+		qglDepthMask                 = dllDepthMask ;
+		qglDepthRange                = dllDepthRange ;
+		qglDisable                   = dllDisable ;
+		qglDisableClientState        = dllDisableClientState ;
+		qglDrawArrays                = dllDrawArrays ;
+		qglDrawBuffer                = dllDrawBuffer ;
+		qglDrawElements              = dllDrawElements ;
+		qglDrawPixels                = dllDrawPixels ;
+		qglEdgeFlag                  = dllEdgeFlag ;
+		qglEdgeFlagPointer           = dllEdgeFlagPointer ;
+		qglEdgeFlagv                 = dllEdgeFlagv ;
+		qglEnable                    = 	dllEnable                    ;
+		qglEnableClientState         = 	dllEnableClientState         ;
+		qglEnd                       = 	dllEnd                       ;
+		qglEndList                   = 	dllEndList                   ;
+		qglEvalCoord1d				 = 	dllEvalCoord1d				 ;
+		qglEvalCoord1dv              = 	dllEvalCoord1dv              ;
+		qglEvalCoord1f               = 	dllEvalCoord1f               ;
+		qglEvalCoord1fv              = 	dllEvalCoord1fv              ;
+		qglEvalCoord2d               = 	dllEvalCoord2d               ;
+		qglEvalCoord2dv              = 	dllEvalCoord2dv              ;
+		qglEvalCoord2f               = 	dllEvalCoord2f               ;
+		qglEvalCoord2fv              = 	dllEvalCoord2fv              ;
+		qglEvalMesh1                 = 	dllEvalMesh1                 ;
+		qglEvalMesh2                 = 	dllEvalMesh2                 ;
+		qglEvalPoint1                = 	dllEvalPoint1                ;
+		qglEvalPoint2                = 	dllEvalPoint2                ;
+		qglFeedbackBuffer            = 	dllFeedbackBuffer            ;
+		qglFinish                    = 	dllFinish                    ;
+		qglFlush                     = 	dllFlush                     ;
+		qglFogf                      = 	dllFogf                      ;
+		qglFogfv                     = 	dllFogfv                     ;
+		qglFogi                      = 	dllFogi                      ;
+		qglFogiv                     = 	dllFogiv                     ;
+		qglFrontFace                 = 	dllFrontFace                 ;
+		qglFrustum                   = 	dllFrustum                   ;
+		qglGenLists                  = 	dllGenLists                  ;
+		qglGenTextures               = 	dllGenTextures               ;
+		qglGetBooleanv               = 	dllGetBooleanv               ;
+		qglGetClipPlane              = 	dllGetClipPlane              ;
+		qglGetDoublev                = 	dllGetDoublev                ;
+		qglGetError                  = 	dllGetError                  ;
+		qglGetFloatv                 = 	dllGetFloatv                 ;
+		qglGetIntegerv               = 	dllGetIntegerv               ;
+		qglGetLightfv                = 	dllGetLightfv                ;
+		qglGetLightiv                = 	dllGetLightiv                ;
+		qglGetMapdv                  = 	dllGetMapdv                  ;
+		qglGetMapfv                  = 	dllGetMapfv                  ;
+		qglGetMapiv                  = 	dllGetMapiv                  ;
+		qglGetMaterialfv             = 	dllGetMaterialfv             ;
+		qglGetMaterialiv             = 	dllGetMaterialiv             ;
+		qglGetPixelMapfv             = 	dllGetPixelMapfv             ;
+		qglGetPixelMapuiv            = 	dllGetPixelMapuiv            ;
+		qglGetPixelMapusv            = 	dllGetPixelMapusv            ;
+		qglGetPointerv               = 	dllGetPointerv               ;
+		qglGetPolygonStipple         = 	dllGetPolygonStipple         ;
+		qglGetString                 = 	dllGetString                 ;
+		qglGetTexEnvfv               = 	dllGetTexEnvfv               ;
+		qglGetTexEnviv               = 	dllGetTexEnviv               ;
+		qglGetTexGendv               = 	dllGetTexGendv               ;
+		qglGetTexGenfv               = 	dllGetTexGenfv               ;
+		qglGetTexGeniv               = 	dllGetTexGeniv               ;
+		qglGetTexImage               = 	dllGetTexImage               ;
+		qglGetTexLevelParameterfv    = 	dllGetTexLevelParameterfv    ;
+		qglGetTexLevelParameteriv    = 	dllGetTexLevelParameteriv    ;
+		qglGetTexParameterfv         = 	dllGetTexParameterfv         ;
+		qglGetTexParameteriv         = 	dllGetTexParameteriv         ;
+		qglHint                      = 	dllHint                      ;
+		qglIndexMask                 = 	dllIndexMask                 ;
+		qglIndexPointer              = 	dllIndexPointer              ;
+		qglIndexd                    = 	dllIndexd                    ;
+		qglIndexdv                   = 	dllIndexdv                   ;
+		qglIndexf                    = 	dllIndexf                    ;
+		qglIndexfv                   = 	dllIndexfv                   ;
+		qglIndexi                    = 	dllIndexi                    ;
+		qglIndexiv                   = 	dllIndexiv                   ;
+		qglIndexs                    = 	dllIndexs                    ;
+		qglIndexsv                   = 	dllIndexsv                   ;
+		qglIndexub                   = 	dllIndexub                   ;
+		qglIndexubv                  = 	dllIndexubv                  ;
+		qglInitNames                 = 	dllInitNames                 ;
+		qglInterleavedArrays         = 	dllInterleavedArrays         ;
+		qglIsEnabled                 = 	dllIsEnabled                 ;
+		qglIsList                    = 	dllIsList                    ;
+		qglIsTexture                 = 	dllIsTexture                 ;
+		qglLightModelf               = 	dllLightModelf               ;
+		qglLightModelfv              = 	dllLightModelfv              ;
+		qglLightModeli               = 	dllLightModeli               ;
+		qglLightModeliv              = 	dllLightModeliv              ;
+		qglLightf                    = 	dllLightf                    ;
+		qglLightfv                   = 	dllLightfv                   ;
+		qglLighti                    = 	dllLighti                    ;
+		qglLightiv                   = 	dllLightiv                   ;
+		qglLineStipple               = 	dllLineStipple               ;
+		qglLineWidth                 = 	dllLineWidth                 ;
+		qglListBase                  = 	dllListBase                  ;
+		qglLoadIdentity              = 	dllLoadIdentity              ;
+		qglLoadMatrixd               = 	dllLoadMatrixd               ;
+		qglLoadMatrixf               = 	dllLoadMatrixf               ;
+		qglLoadName                  = 	dllLoadName                  ;
+		qglLogicOp                   = 	dllLogicOp                   ;
+		qglMap1d                     = 	dllMap1d                     ;
+		qglMap1f                     = 	dllMap1f                     ;
+		qglMap2d                     = 	dllMap2d                     ;
+		qglMap2f                     = 	dllMap2f                     ;
+		qglMapGrid1d                 = 	dllMapGrid1d                 ;
+		qglMapGrid1f                 = 	dllMapGrid1f                 ;
+		qglMapGrid2d                 = 	dllMapGrid2d                 ;
+		qglMapGrid2f                 = 	dllMapGrid2f                 ;
+		qglMaterialf                 = 	dllMaterialf                 ;
+		qglMaterialfv                = 	dllMaterialfv                ;
+		qglMateriali                 = 	dllMateriali                 ;
+		qglMaterialiv                = 	dllMaterialiv                ;
+		qglMatrixMode                = 	dllMatrixMode                ;
+		qglMultMatrixd               = 	dllMultMatrixd               ;
+		qglMultMatrixf               = 	dllMultMatrixf               ;
+		qglNewList                   = 	dllNewList                   ;
+		qglNormal3b                  = 	dllNormal3b                  ;
+		qglNormal3bv                 = 	dllNormal3bv                 ;
+		qglNormal3d                  = 	dllNormal3d                  ;
+		qglNormal3dv                 = 	dllNormal3dv                 ;
+		qglNormal3f                  = 	dllNormal3f                  ;
+		qglNormal3fv                 = 	dllNormal3fv                 ;
+		qglNormal3i                  = 	dllNormal3i                  ;
+		qglNormal3iv                 = 	dllNormal3iv                 ;
+		qglNormal3s                  = 	dllNormal3s                  ;
+		qglNormal3sv                 = 	dllNormal3sv                 ;
+		qglNormalPointer             = 	dllNormalPointer             ;
+		qglOrtho                     = 	dllOrtho                     ;
+		qglPassThrough               = 	dllPassThrough               ;
+		qglPixelMapfv                = 	dllPixelMapfv                ;
+		qglPixelMapuiv               = 	dllPixelMapuiv               ;
+		qglPixelMapusv               = 	dllPixelMapusv               ;
+		qglPixelStoref               = 	dllPixelStoref               ;
+		qglPixelStorei               = 	dllPixelStorei               ;
+		qglPixelTransferf            = 	dllPixelTransferf            ;
+		qglPixelTransferi            = 	dllPixelTransferi            ;
+		qglPixelZoom                 = 	dllPixelZoom                 ;
+		qglPointSize                 = 	dllPointSize                 ;
+		qglPolygonMode               = 	dllPolygonMode               ;
+		qglPolygonOffset             = 	dllPolygonOffset             ;
+		qglPolygonStipple            = 	dllPolygonStipple            ;
+		qglPopAttrib                 = 	dllPopAttrib                 ;
+		qglPopClientAttrib           = 	dllPopClientAttrib           ;
+		qglPopMatrix                 = 	dllPopMatrix                 ;
+		qglPopName                   = 	dllPopName                   ;
+		qglPrioritizeTextures        = 	dllPrioritizeTextures        ;
+		qglPushAttrib                = 	dllPushAttrib                ;
+		qglPushClientAttrib          = 	dllPushClientAttrib          ;
+		qglPushMatrix                = 	dllPushMatrix                ;
+		qglPushName                  = 	dllPushName                  ;
+		qglRasterPos2d               = 	dllRasterPos2d               ;
+		qglRasterPos2dv              = 	dllRasterPos2dv              ;
+		qglRasterPos2f               = 	dllRasterPos2f               ;
+		qglRasterPos2fv              = 	dllRasterPos2fv              ;
+		qglRasterPos2i               = 	dllRasterPos2i               ;
+		qglRasterPos2iv              = 	dllRasterPos2iv              ;
+		qglRasterPos2s               = 	dllRasterPos2s               ;
+		qglRasterPos2sv              = 	dllRasterPos2sv              ;
+		qglRasterPos3d               = 	dllRasterPos3d               ;
+		qglRasterPos3dv              = 	dllRasterPos3dv              ;
+		qglRasterPos3f               = 	dllRasterPos3f               ;
+		qglRasterPos3fv              = 	dllRasterPos3fv              ;
+		qglRasterPos3i               = 	dllRasterPos3i               ;
+		qglRasterPos3iv              = 	dllRasterPos3iv              ;
+		qglRasterPos3s               = 	dllRasterPos3s               ;
+		qglRasterPos3sv              = 	dllRasterPos3sv              ;
+		qglRasterPos4d               = 	dllRasterPos4d               ;
+		qglRasterPos4dv              = 	dllRasterPos4dv              ;
+		qglRasterPos4f               = 	dllRasterPos4f               ;
+		qglRasterPos4fv              = 	dllRasterPos4fv              ;
+		qglRasterPos4i               = 	dllRasterPos4i               ;
+		qglRasterPos4iv              = 	dllRasterPos4iv              ;
+		qglRasterPos4s               = 	dllRasterPos4s               ;
+		qglRasterPos4sv              = 	dllRasterPos4sv              ;
+		qglReadBuffer                = 	dllReadBuffer                ;
+		qglReadPixels                = 	dllReadPixels                ;
+		qglRectd                     = 	dllRectd                     ;
+		qglRectdv                    = 	dllRectdv                    ;
+		qglRectf                     = 	dllRectf                     ;
+		qglRectfv                    = 	dllRectfv                    ;
+		qglRecti                     = 	dllRecti                     ;
+		qglRectiv                    = 	dllRectiv                    ;
+		qglRects                     = 	dllRects                     ;
+		qglRectsv                    = 	dllRectsv                    ;
+		qglRenderMode                = 	dllRenderMode                ;
+		qglRotated                   = 	dllRotated                   ;
+		qglRotatef                   = 	dllRotatef                   ;
+		qglScaled                    = 	dllScaled                    ;
+		qglScalef                    = 	dllScalef                    ;
+		qglScissor                   = 	dllScissor                   ;
+		qglSelectBuffer              = 	dllSelectBuffer              ;
+		qglShadeModel                = 	dllShadeModel                ;
+		qglStencilFunc               = 	dllStencilFunc               ;
+		qglStencilMask               = 	dllStencilMask               ;
+		qglStencilOp                 = 	dllStencilOp                 ;
+		qglTexCoord1d                = 	dllTexCoord1d                ;
+		qglTexCoord1dv               = 	dllTexCoord1dv               ;
+		qglTexCoord1f                = 	dllTexCoord1f                ;
+		qglTexCoord1fv               = 	dllTexCoord1fv               ;
+		qglTexCoord1i                = 	dllTexCoord1i                ;
+		qglTexCoord1iv               = 	dllTexCoord1iv               ;
+		qglTexCoord1s                = 	dllTexCoord1s                ;
+		qglTexCoord1sv               = 	dllTexCoord1sv               ;
+		qglTexCoord2d                = 	dllTexCoord2d                ;
+		qglTexCoord2dv               = 	dllTexCoord2dv               ;
+		qglTexCoord2f                = 	dllTexCoord2f                ;
+		qglTexCoord2fv               = 	dllTexCoord2fv               ;
+		qglTexCoord2i                = 	dllTexCoord2i                ;
+		qglTexCoord2iv               = 	dllTexCoord2iv               ;
+		qglTexCoord2s                = 	dllTexCoord2s                ;
+		qglTexCoord2sv               = 	dllTexCoord2sv               ;
+		qglTexCoord3d                = 	dllTexCoord3d                ;
+		qglTexCoord3dv               = 	dllTexCoord3dv               ;
+		qglTexCoord3f                = 	dllTexCoord3f                ;
+		qglTexCoord3fv               = 	dllTexCoord3fv               ;
+		qglTexCoord3i                = 	dllTexCoord3i                ;
+		qglTexCoord3iv               = 	dllTexCoord3iv               ;
+		qglTexCoord3s                = 	dllTexCoord3s                ;
+		qglTexCoord3sv               = 	dllTexCoord3sv               ;
+		qglTexCoord4d                = 	dllTexCoord4d                ;
+		qglTexCoord4dv               = 	dllTexCoord4dv               ;
+		qglTexCoord4f                = 	dllTexCoord4f                ;
+		qglTexCoord4fv               = 	dllTexCoord4fv               ;
+		qglTexCoord4i                = 	dllTexCoord4i                ;
+		qglTexCoord4iv               = 	dllTexCoord4iv               ;
+		qglTexCoord4s                = 	dllTexCoord4s                ;
+		qglTexCoord4sv               = 	dllTexCoord4sv               ;
+		qglTexCoordPointer           = 	dllTexCoordPointer           ;
+		qglTexEnvf                   = 	dllTexEnvf                   ;
+		qglTexEnvfv                  = 	dllTexEnvfv                  ;
+		qglTexEnvi                   = 	dllTexEnvi                   ;
+		qglTexEnviv                  = 	dllTexEnviv                  ;
+		qglTexGend                   = 	dllTexGend                   ;
+		qglTexGendv                  = 	dllTexGendv                  ;
+		qglTexGenf                   = 	dllTexGenf                   ;
+		qglTexGenfv                  = 	dllTexGenfv                  ;
+		qglTexGeni                   = 	dllTexGeni                   ;
+		qglTexGeniv                  = 	dllTexGeniv                  ;
+		qglTexImage1D                = 	dllTexImage1D                ;
+		qglTexImage2D                = 	dllTexImage2D                ;
+		qglTexParameterf             = 	dllTexParameterf             ;
+		qglTexParameterfv            = 	dllTexParameterfv            ;
+		qglTexParameteri             = 	dllTexParameteri             ;
+		qglTexParameteriv            = 	dllTexParameteriv            ;
+		qglTexSubImage1D             = 	dllTexSubImage1D             ;
+		qglTexSubImage2D             = 	dllTexSubImage2D             ;
+		qglTranslated                = 	dllTranslated                ;
+		qglTranslatef                = 	dllTranslatef                ;
+		qglVertex2d                  = 	dllVertex2d                  ;
+		qglVertex2dv                 = 	dllVertex2dv                 ;
+		qglVertex2f                  = 	dllVertex2f                  ;
+		qglVertex2fv                 = 	dllVertex2fv                 ;
+		qglVertex2i                  = 	dllVertex2i                  ;
+		qglVertex2iv                 = 	dllVertex2iv                 ;
+		qglVertex2s                  = 	dllVertex2s                  ;
+		qglVertex2sv                 = 	dllVertex2sv                 ;
+		qglVertex3d                  = 	dllVertex3d                  ;
+		qglVertex3dv                 = 	dllVertex3dv                 ;
+		qglVertex3f                  = 	dllVertex3f                  ;
+		qglVertex3fv                 = 	dllVertex3fv                 ;
+		qglVertex3i                  = 	dllVertex3i                  ;
+		qglVertex3iv                 = 	dllVertex3iv                 ;
+		qglVertex3s                  = 	dllVertex3s                  ;
+		qglVertex3sv                 = 	dllVertex3sv                 ;
+		qglVertex4d                  = 	dllVertex4d                  ;
+		qglVertex4dv                 = 	dllVertex4dv                 ;
+		qglVertex4f                  = 	dllVertex4f                  ;
+		qglVertex4fv                 = 	dllVertex4fv                 ;
+		qglVertex4i                  = 	dllVertex4i                  ;
+		qglVertex4iv                 = 	dllVertex4iv                 ;
+		qglVertex4s                  = 	dllVertex4s                  ;
+		qglVertex4sv                 = 	dllVertex4sv                 ;
+		qglVertexPointer             = 	dllVertexPointer             ;
+		qglViewport                  = 	dllViewport                  ;
+	}
+}
+
+
+void GLimp_LogNewFrame( void )
+{
+	fprintf( glw_state.log_fp, "*** R_BeginFrame ***\n" );
+}
+
+#pragma warning (default : 4113 4133 4047 )
+
+
+
--- /dev/null
+++ b/win32/resource.h
@@ -1,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by q2.rc
+//
+#define IDI_ICON1                       101
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        103
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
--- /dev/null
+++ b/win32/rw_ddraw.c
@@ -1,0 +1,556 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+** RW_DDRAW.C
+**
+** This handles DirecTDraw management under Windows.
+*/
+#ifndef _WIN32
+#  error You should not be compiling this file on this platform
+#endif
+
+#include <float.h>
+
+#include "..\ref_soft\r_local.h"
+#define INITGUID
+#include "rw_win.h"
+
+static const char *DDrawError( int code );
+
+/*
+** DDRAW_Init
+**
+** Builds our DDRAW stuff
+*/
+qboolean DDRAW_Init( unsigned char **ppbuffer, int *ppitch )
+{
+	HRESULT ddrval;
+	DDSURFACEDESC ddsd;
+	DDSCAPS ddscaps;
+	PALETTEENTRY palentries[256];
+	int i;
+	extern cvar_t *sw_allow_modex;
+
+	HRESULT (WINAPI *QDirectDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR * lplpDDRAW, IUnknown FAR * pUnkOuter );
+
+ri.Con_Printf( PRINT_ALL, "Initializing DirectDraw\n");
+
+
+	for ( i = 0; i < 256; i++ )
+	{
+		palentries[i].peRed		= ( d_8to24table[i] >> 0  ) & 0xff;
+		palentries[i].peGreen	= ( d_8to24table[i] >> 8  ) & 0xff;
+		palentries[i].peBlue	= ( d_8to24table[i] >> 16 ) & 0xff;
+	}
+
+	/*
+	** load DLL and fetch pointer to entry point
+	*/
+	if ( !sww_state.hinstDDRAW )
+	{
+		ri.Con_Printf( PRINT_ALL, "...loading DDRAW.DLL: ");
+		if ( ( sww_state.hinstDDRAW = LoadLibrary( "ddraw.dll" ) ) == NULL )
+		{
+			ri.Con_Printf( PRINT_ALL, "failed\n" );
+			goto fail;
+		}
+		ri.Con_Printf( PRINT_ALL, "ok\n" );
+	}
+
+	if ( ( QDirectDrawCreate = ( HRESULT (WINAPI *)( GUID FAR *, LPDIRECTDRAW FAR *, IUnknown FAR * ) ) GetProcAddress( sww_state.hinstDDRAW, "DirectDrawCreate" ) ) == NULL )
+	{
+		ri.Con_Printf( PRINT_ALL, "*** DirectDrawCreate == NULL ***\n" );
+		goto fail;
+	}
+
+	/*
+	** create the direct draw object
+	*/
+	ri.Con_Printf( PRINT_ALL, "...creating DirectDraw object: ");
+	if ( ( ddrval = QDirectDrawCreate( NULL, &sww_state.lpDirectDraw, NULL ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	/*
+	** see if linear modes exist first
+	*/
+	sww_state.modex = false;
+
+	ri.Con_Printf( PRINT_ALL, "...setting exclusive mode: ");
+	if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw, 
+																		 sww_state.hWnd,
+																		 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n",DDrawError (ddrval) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	/*
+	** try changing the display mode normally
+	*/
+	ri.Con_Printf( PRINT_ALL, "...finding display mode\n" );
+	ri.Con_Printf( PRINT_ALL, "...setting linear mode: " );
+	if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetDisplayMode( sww_state.lpDirectDraw, vid.width, vid.height, 8 ) ) == DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "ok\n" );
+	}
+	/*
+	** if no linear mode found, go for modex if we're trying 320x240
+	*/
+	else if ( ( sw_mode->value == 0 ) && sw_allow_modex->value )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed\n" );
+		ri.Con_Printf( PRINT_ALL, "...attempting ModeX 320x240: ");
+
+		/*
+		** reset to normal cooperative level
+		*/
+		sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw, 
+															 sww_state.hWnd,
+															 DDSCL_NORMAL );
+
+		/*															 
+		** set exclusive mode
+		*/
+		if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw, 
+																			 sww_state.hWnd,
+																			 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES | DDSCL_ALLOWMODEX ) ) != DD_OK )
+		{
+			ri.Con_Printf( PRINT_ALL, "failed SCL - %s\n",DDrawError (ddrval) );
+			goto fail;
+		}
+
+		/*
+		** change our display mode
+		*/
+		if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetDisplayMode( sww_state.lpDirectDraw, vid.width, vid.height, 8 ) ) != DD_OK )
+		{
+			ri.Con_Printf( PRINT_ALL, "failed SDM - %s\n", DDrawError( ddrval ) );
+			goto fail;
+		}
+		ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+		sww_state.modex = true;
+	}
+	else
+	{
+		ri.Con_Printf( PRINT_ALL, "failed\n" );
+		goto fail;
+	}
+
+	/*
+	** create our front buffer
+	*/
+	memset( &ddsd, 0, sizeof( ddsd ) );
+	ddsd.dwSize = sizeof( ddsd );
+	ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+	ddsd.dwBackBufferCount = 1;
+
+	ri.Con_Printf( PRINT_ALL, "...creating front buffer: ");
+	if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreateSurface( sww_state.lpDirectDraw, &ddsd, &sww_state.lpddsFrontBuffer, NULL ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	/*
+	** see if we're a ModeX mode
+	*/
+	sww_state.lpddsFrontBuffer->lpVtbl->GetCaps( sww_state.lpddsFrontBuffer, &ddscaps );
+	if ( ddscaps.dwCaps & DDSCAPS_MODEX )
+		ri.Con_Printf( PRINT_ALL, "...using ModeX\n" );
+
+	/*
+	** create our back buffer
+	*/
+	ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+	ri.Con_Printf( PRINT_ALL, "...creating back buffer: " );
+	if ( ( ddrval = sww_state.lpddsFrontBuffer->lpVtbl->GetAttachedSurface( sww_state.lpddsFrontBuffer, &ddsd.ddsCaps, &sww_state.lpddsBackBuffer ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	/*
+	** create our rendering buffer
+	*/
+	memset( &ddsd, 0, sizeof( ddsd ) );
+	ddsd.dwSize = sizeof( ddsd );
+	ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
+	ddsd.dwHeight = vid.height;
+	ddsd.dwWidth = vid.width;
+	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
+
+	ri.Con_Printf( PRINT_ALL, "...creating offscreen buffer: " );
+	if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreateSurface( sww_state.lpDirectDraw, &ddsd, &sww_state.lpddsOffScreenBuffer, NULL ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	/*
+	** create our DIRECTDRAWPALETTE
+	*/
+	ri.Con_Printf( PRINT_ALL, "...creating palette: " );
+	if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreatePalette( sww_state.lpDirectDraw,
+														DDPCAPS_8BIT | DDPCAPS_ALLOW256,
+														palentries,
+														&sww_state.lpddpPalette,
+														NULL ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	ri.Con_Printf( PRINT_ALL, "...setting palette: " );
+	if ( ( ddrval = sww_state.lpddsFrontBuffer->lpVtbl->SetPalette( sww_state.lpddsFrontBuffer,
+														 sww_state.lpddpPalette ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+	ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	DDRAW_SetPalette( ( const unsigned char * ) sw_state.currentpalette );
+
+	/*
+	** lock the back buffer
+	*/
+	memset( &ddsd, 0, sizeof( ddsd ) );
+	ddsd.dwSize = sizeof( ddsd );
+	
+ri.Con_Printf( PRINT_ALL, "...locking backbuffer: " );
+	if ( ( ddrval = sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ) ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
+		goto fail;
+	}
+ri.Con_Printf( PRINT_ALL, "ok\n" );
+
+	*ppbuffer = ddsd.lpSurface;
+	*ppitch   = ddsd.lPitch;
+
+	for ( i = 0; i < vid.height; i++ )
+	{
+		memset( *ppbuffer + i * *ppitch, 0, *ppitch );
+	}
+
+	sww_state.palettized = true;
+
+	return true;
+fail:
+	ri.Con_Printf( PRINT_ALL, "*** DDraw init failure ***\n" );
+
+	DDRAW_Shutdown();
+	return false;
+}
+
+/*
+** DDRAW_SetPalette
+**
+** Sets the color table in our DIB section, and also sets the system palette
+** into an identity mode if we're running in an 8-bit palettized display mode.
+**
+** The palette is expected to be 1024 bytes, in the format:
+**
+** R = offset 0
+** G = offset 1
+** B = offset 2
+** A = offset 3
+*/
+void DDRAW_SetPalette( const unsigned char *pal )
+{
+	PALETTEENTRY palentries[256];
+	int i;
+
+	if (!sww_state.lpddpPalette)
+		return;
+
+	for ( i = 0; i < 256; i++, pal += 4 )
+	{
+		palentries[i].peRed   = pal[0];
+		palentries[i].peGreen = pal[1];
+		palentries[i].peBlue  = pal[2];
+		palentries[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
+	}
+
+	if ( sww_state.lpddpPalette->lpVtbl->SetEntries( sww_state.lpddpPalette,
+		                                        0,
+												0,
+												256,
+												palentries ) != DD_OK )
+	{
+		ri.Con_Printf( PRINT_ALL, "DDRAW_SetPalette() - SetEntries failed\n" );
+	}
+}
+
+/*
+** DDRAW_Shutdown
+*/
+void DDRAW_Shutdown( void )
+{
+	if ( sww_state.lpddsOffScreenBuffer )
+	{
+		ri.Con_Printf( PRINT_ALL, "...releasing offscreen buffer\n");
+		sww_state.lpddsOffScreenBuffer->lpVtbl->Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer );
+		sww_state.lpddsOffScreenBuffer->lpVtbl->Release( sww_state.lpddsOffScreenBuffer );
+		sww_state.lpddsOffScreenBuffer = NULL;
+	}
+
+	if ( sww_state.lpddsBackBuffer )
+	{
+		ri.Con_Printf( PRINT_ALL, "...releasing back buffer\n");
+		sww_state.lpddsBackBuffer->lpVtbl->Release( sww_state.lpddsBackBuffer );
+		sww_state.lpddsBackBuffer = NULL;
+	}
+
+	if ( sww_state.lpddsFrontBuffer )
+	{
+		ri.Con_Printf( PRINT_ALL, "...releasing front buffer\n");
+		sww_state.lpddsFrontBuffer->lpVtbl->Release( sww_state.lpddsFrontBuffer );
+		sww_state.lpddsFrontBuffer = NULL;
+	}
+
+	if (sww_state.lpddpPalette)
+	{
+		ri.Con_Printf( PRINT_ALL, "...releasing palette\n");
+		sww_state.lpddpPalette->lpVtbl->Release ( sww_state.lpddpPalette );
+		sww_state.lpddpPalette = NULL;
+	}
+
+	if ( sww_state.lpDirectDraw )
+	{
+		ri.Con_Printf( PRINT_ALL, "...restoring display mode\n");
+		sww_state.lpDirectDraw->lpVtbl->RestoreDisplayMode( sww_state.lpDirectDraw );
+		ri.Con_Printf( PRINT_ALL, "...restoring normal coop mode\n");
+	    sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw, sww_state.hWnd, DDSCL_NORMAL );
+		ri.Con_Printf( PRINT_ALL, "...releasing lpDirectDraw\n");
+		sww_state.lpDirectDraw->lpVtbl->Release( sww_state.lpDirectDraw );
+		sww_state.lpDirectDraw = NULL;
+	}
+
+	if ( sww_state.hinstDDRAW )
+	{
+		ri.Con_Printf( PRINT_ALL, "...freeing library\n");
+		FreeLibrary( sww_state.hinstDDRAW );
+		sww_state.hinstDDRAW = NULL;
+	}
+}
+
+static const char *DDrawError (int code)
+{
+    switch(code) {
+        case DD_OK:
+            return "DD_OK";
+        case DDERR_ALREADYINITIALIZED:
+            return "DDERR_ALREADYINITIALIZED";
+        case DDERR_BLTFASTCANTCLIP:
+            return "DDERR_BLTFASTCANTCLIP";
+        case DDERR_CANNOTATTACHSURFACE:
+            return "DDER_CANNOTATTACHSURFACE";
+        case DDERR_CANNOTDETACHSURFACE:
+            return "DDERR_CANNOTDETACHSURFACE";
+        case DDERR_CANTCREATEDC:
+            return "DDERR_CANTCREATEDC";
+        case DDERR_CANTDUPLICATE:
+            return "DDER_CANTDUPLICATE";
+        case DDERR_CLIPPERISUSINGHWND:
+            return "DDER_CLIPPERUSINGHWND";
+        case DDERR_COLORKEYNOTSET:
+            return "DDERR_COLORKEYNOTSET";
+        case DDERR_CURRENTLYNOTAVAIL:
+            return "DDERR_CURRENTLYNOTAVAIL";
+        case DDERR_DIRECTDRAWALREADYCREATED:
+            return "DDERR_DIRECTDRAWALREADYCREATED";
+        case DDERR_EXCEPTION:
+            return "DDERR_EXCEPTION";
+        case DDERR_EXCLUSIVEMODEALREADYSET:
+            return "DDERR_EXCLUSIVEMODEALREADYSET";
+        case DDERR_GENERIC:
+            return "DDERR_GENERIC";
+        case DDERR_HEIGHTALIGN:
+            return "DDERR_HEIGHTALIGN";
+        case DDERR_HWNDALREADYSET:
+            return "DDERR_HWNDALREADYSET";
+        case DDERR_HWNDSUBCLASSED:
+            return "DDERR_HWNDSUBCLASSED";
+        case DDERR_IMPLICITLYCREATED:
+            return "DDERR_IMPLICITLYCREATED";
+        case DDERR_INCOMPATIBLEPRIMARY:
+            return "DDERR_INCOMPATIBLEPRIMARY";
+        case DDERR_INVALIDCAPS:
+            return "DDERR_INVALIDCAPS";
+        case DDERR_INVALIDCLIPLIST:
+            return "DDERR_INVALIDCLIPLIST";
+        case DDERR_INVALIDDIRECTDRAWGUID:
+            return "DDERR_INVALIDDIRECTDRAWGUID";
+        case DDERR_INVALIDMODE:
+            return "DDERR_INVALIDMODE";
+        case DDERR_INVALIDOBJECT:
+            return "DDERR_INVALIDOBJECT";
+        case DDERR_INVALIDPARAMS:
+            return "DDERR_INVALIDPARAMS";
+        case DDERR_INVALIDPIXELFORMAT:
+            return "DDERR_INVALIDPIXELFORMAT";
+        case DDERR_INVALIDPOSITION:
+            return "DDERR_INVALIDPOSITION";
+        case DDERR_INVALIDRECT:
+            return "DDERR_INVALIDRECT";
+        case DDERR_LOCKEDSURFACES:
+            return "DDERR_LOCKEDSURFACES";
+        case DDERR_NO3D:
+            return "DDERR_NO3D";
+        case DDERR_NOALPHAHW:
+            return "DDERR_NOALPHAHW";
+        case DDERR_NOBLTHW:
+            return "DDERR_NOBLTHW";
+        case DDERR_NOCLIPLIST:
+            return "DDERR_NOCLIPLIST";
+        case DDERR_NOCLIPPERATTACHED:
+            return "DDERR_NOCLIPPERATTACHED";
+        case DDERR_NOCOLORCONVHW:
+            return "DDERR_NOCOLORCONVHW";
+        case DDERR_NOCOLORKEY:
+            return "DDERR_NOCOLORKEY";
+        case DDERR_NOCOLORKEYHW:
+            return "DDERR_NOCOLORKEYHW";
+        case DDERR_NOCOOPERATIVELEVELSET:
+            return "DDERR_NOCOOPERATIVELEVELSET";
+        case DDERR_NODC:
+            return "DDERR_NODC";
+        case DDERR_NODDROPSHW:
+            return "DDERR_NODDROPSHW";
+        case DDERR_NODIRECTDRAWHW:
+            return "DDERR_NODIRECTDRAWHW";
+        case DDERR_NOEMULATION:
+            return "DDERR_NOEMULATION";
+        case DDERR_NOEXCLUSIVEMODE:
+            return "DDERR_NOEXCLUSIVEMODE";
+        case DDERR_NOFLIPHW:
+            return "DDERR_NOFLIPHW";
+        case DDERR_NOGDI:
+            return "DDERR_NOGDI";
+        case DDERR_NOHWND:
+            return "DDERR_NOHWND";
+        case DDERR_NOMIRRORHW:
+            return "DDERR_NOMIRRORHW";
+        case DDERR_NOOVERLAYDEST:
+            return "DDERR_NOOVERLAYDEST";
+        case DDERR_NOOVERLAYHW:
+            return "DDERR_NOOVERLAYHW";
+        case DDERR_NOPALETTEATTACHED:
+            return "DDERR_NOPALETTEATTACHED";
+        case DDERR_NOPALETTEHW:
+            return "DDERR_NOPALETTEHW";
+        case DDERR_NORASTEROPHW:
+            return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0";
+        case DDERR_NOROTATIONHW:
+            return "Operation could not be carried out because there is no rotation hardware present or available.\0";
+        case DDERR_NOSTRETCHHW:
+            return "Operation could not be carried out because there is no hardware support for stretching.\0";
+        case DDERR_NOT4BITCOLOR:
+            return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0";
+        case DDERR_NOT4BITCOLORINDEX:
+            return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0";
+        case DDERR_NOT8BITCOLOR:
+            return "DDERR_NOT8BITCOLOR";
+        case DDERR_NOTAOVERLAYSURFACE:
+            return "Returned when an overlay member is called for a non-overlay surface.\0";
+        case DDERR_NOTEXTUREHW:
+            return "Operation could not be carried out because there is no texture mapping hardware present or available.\0";
+        case DDERR_NOTFLIPPABLE:
+            return "DDERR_NOTFLIPPABLE";
+        case DDERR_NOTFOUND:
+            return "DDERR_NOTFOUND";
+        case DDERR_NOTLOCKED:
+            return "DDERR_NOTLOCKED";
+        case DDERR_NOTPALETTIZED:
+            return "DDERR_NOTPALETTIZED";
+        case DDERR_NOVSYNCHW:
+            return "DDERR_NOVSYNCHW";
+        case DDERR_NOZBUFFERHW:
+            return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0";
+        case DDERR_NOZOVERLAYHW:
+            return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0";
+        case DDERR_OUTOFCAPS:
+            return "The hardware needed for the requested operation has already been allocated.\0";
+        case DDERR_OUTOFMEMORY:
+            return "DDERR_OUTOFMEMORY";
+        case DDERR_OUTOFVIDEOMEMORY:
+            return "DDERR_OUTOFVIDEOMEMORY";
+        case DDERR_OVERLAYCANTCLIP:
+            return "The hardware does not support clipped overlays.\0";
+        case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
+            return "Can only have ony color key active at one time for overlays.\0";
+        case DDERR_OVERLAYNOTVISIBLE:
+            return "Returned when GetOverlayPosition is called on a hidden overlay.\0";
+        case DDERR_PALETTEBUSY:
+            return "DDERR_PALETTEBUSY";
+        case DDERR_PRIMARYSURFACEALREADYEXISTS:
+            return "DDERR_PRIMARYSURFACEALREADYEXISTS";
+        case DDERR_REGIONTOOSMALL:
+            return "Region passed to Clipper::GetClipList is too small.\0";
+        case DDERR_SURFACEALREADYATTACHED:
+            return "DDERR_SURFACEALREADYATTACHED";
+        case DDERR_SURFACEALREADYDEPENDENT:
+            return "DDERR_SURFACEALREADYDEPENDENT";
+        case DDERR_SURFACEBUSY:
+            return "DDERR_SURFACEBUSY";
+        case DDERR_SURFACEISOBSCURED:
+            return "Access to surface refused because the surface is obscured.\0";
+        case DDERR_SURFACELOST:
+            return "DDERR_SURFACELOST";
+        case DDERR_SURFACENOTATTACHED:
+            return "DDERR_SURFACENOTATTACHED";
+        case DDERR_TOOBIGHEIGHT:
+            return "Height requested by DirectDraw is too large.\0";
+        case DDERR_TOOBIGSIZE:
+            return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0";
+        case DDERR_TOOBIGWIDTH:
+            return "Width requested by DirectDraw is too large.\0";
+        case DDERR_UNSUPPORTED:
+            return "DDERR_UNSUPPORTED";
+        case DDERR_UNSUPPORTEDFORMAT:
+            return "FOURCC format requested is unsupported by DirectDraw.\0";
+        case DDERR_UNSUPPORTEDMASK:
+            return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0";
+        case DDERR_VERTICALBLANKINPROGRESS:
+            return "Vertical blank is in progress.\0";
+        case DDERR_WASSTILLDRAWING:
+            return "DDERR_WASSTILLDRAWING";
+        case DDERR_WRONGMODE:
+            return "This surface can not be restored because it was created in a different mode.\0";
+        case DDERR_XALIGN:
+            return "Rectangle provided was not horizontally aligned on required boundary.\0";
+        default:
+            return "UNKNOWN\0";
+	}
+}
+
--- /dev/null
+++ b/win32/rw_dib.c
@@ -1,0 +1,375 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+** RW_DIB.C
+**
+** This handles DIB section management under Windows.
+**
+*/
+#include "..\ref_soft\r_local.h"
+#include "rw_win.h"
+
+#ifndef _WIN32
+#  error You should not be trying to compile this file on this platform
+#endif
+
+static qboolean s_systemcolors_saved;
+
+static HGDIOBJ previously_selected_GDI_obj;
+
+static int s_syspalindices[] = 
+{
+  COLOR_ACTIVEBORDER,
+  COLOR_ACTIVECAPTION,
+  COLOR_APPWORKSPACE,
+  COLOR_BACKGROUND,
+  COLOR_BTNFACE,
+  COLOR_BTNSHADOW,
+  COLOR_BTNTEXT,
+  COLOR_CAPTIONTEXT,
+  COLOR_GRAYTEXT,
+  COLOR_HIGHLIGHT,
+  COLOR_HIGHLIGHTTEXT,
+  COLOR_INACTIVEBORDER,
+
+  COLOR_INACTIVECAPTION,
+  COLOR_MENU,
+  COLOR_MENUTEXT,
+  COLOR_SCROLLBAR,
+  COLOR_WINDOW,
+  COLOR_WINDOWFRAME,
+  COLOR_WINDOWTEXT
+};
+
+#define NUM_SYS_COLORS ( sizeof( s_syspalindices ) / sizeof( int ) )
+
+static int s_oldsyscolors[NUM_SYS_COLORS];
+
+typedef struct dibinfo
+{
+	BITMAPINFOHEADER	header;
+	RGBQUAD				acolors[256];
+} dibinfo_t;
+
+typedef struct
+{
+	WORD palVersion;
+	WORD palNumEntries;
+	PALETTEENTRY palEntries[256];
+} identitypalette_t;
+
+static identitypalette_t s_ipal;
+
+static void DIB_SaveSystemColors( void );
+static void DIB_RestoreSystemColors( void );
+
+/*
+** DIB_Init
+**
+** Builds our DIB section
+*/
+qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch )
+{
+	dibinfo_t   dibheader;
+	BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader;
+	int i;
+
+	memset( &dibheader, 0, sizeof( dibheader ) );
+
+	/*
+	** grab a DC
+	*/
+	if ( !sww_state.hDC )
+	{
+		if ( ( sww_state.hDC = GetDC( sww_state.hWnd ) ) == NULL )
+			return false;
+	}
+
+	/*
+	** figure out if we're running in an 8-bit display mode
+	*/
+ 	if ( GetDeviceCaps( sww_state.hDC, RASTERCAPS ) & RC_PALETTE )
+	{
+		sww_state.palettized = true;
+
+		// save system colors
+		if ( !s_systemcolors_saved )
+		{
+			DIB_SaveSystemColors();
+			s_systemcolors_saved = true;
+		}
+	}
+	else
+	{
+		sww_state.palettized = false;
+	}
+
+	/*
+	** fill in the BITMAPINFO struct
+	*/
+	pbmiDIB->bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
+	pbmiDIB->bmiHeader.biWidth         = vid.width;
+	pbmiDIB->bmiHeader.biHeight        = vid.height;
+	pbmiDIB->bmiHeader.biPlanes        = 1;
+	pbmiDIB->bmiHeader.biBitCount      = 8;
+	pbmiDIB->bmiHeader.biCompression   = BI_RGB;
+	pbmiDIB->bmiHeader.biSizeImage     = 0;
+	pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
+	pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
+	pbmiDIB->bmiHeader.biClrUsed       = 256;
+	pbmiDIB->bmiHeader.biClrImportant  = 256;
+
+	/*
+	** fill in the palette
+	*/
+	for ( i = 0; i < 256; i++ )
+	{
+		dibheader.acolors[i].rgbRed   = ( d_8to24table[i] >> 0 )  & 0xff;
+		dibheader.acolors[i].rgbGreen = ( d_8to24table[i] >> 8 )  & 0xff;
+		dibheader.acolors[i].rgbBlue  = ( d_8to24table[i] >> 16 ) & 0xff;
+	}
+
+	/*
+	** create the DIB section
+	*/
+	sww_state.hDIBSection = CreateDIBSection( sww_state.hDC,
+		                                     pbmiDIB,
+											 DIB_RGB_COLORS,
+											 &sww_state.pDIBBase,
+											 NULL,
+											 0 );
+
+	if ( sww_state.hDIBSection == NULL )
+	{
+		ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateDIBSection failed\n" );
+		goto fail;
+	}
+
+	if ( pbmiDIB->bmiHeader.biHeight > 0 )
+    {
+		// bottom up
+		*ppbuffer	= sww_state.pDIBBase + ( vid.height - 1 ) * vid.width;
+		*ppitch		= -vid.width;
+    }
+    else
+    {
+		// top down
+		*ppbuffer	= sww_state.pDIBBase;
+		*ppitch		= vid.width;
+    }
+
+	/*
+	** clear the DIB memory buffer
+	*/
+	memset( sww_state.pDIBBase, 0xff, vid.width * vid.height );
+
+	if ( ( sww_state.hdcDIBSection = CreateCompatibleDC( sww_state.hDC ) ) == NULL )
+	{
+		ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateCompatibleDC failed\n" );
+		goto fail;
+	}
+	if ( ( previously_selected_GDI_obj = SelectObject( sww_state.hdcDIBSection, sww_state.hDIBSection ) ) == NULL )
+	{
+		ri.Con_Printf( PRINT_ALL, "DIB_Init() - SelectObject failed\n" );
+		goto fail;
+	}
+
+	return true;
+
+fail:
+	DIB_Shutdown();
+	return false;
+	
+}
+
+/*
+** DIB_SetPalette
+**
+** Sets the color table in our DIB section, and also sets the system palette
+** into an identity mode if we're running in an 8-bit palettized display mode.
+**
+** The palette is expected to be 1024 bytes, in the format:
+**
+** R = offset 0
+** G = offset 1
+** B = offset 2
+** A = offset 3
+*/
+void DIB_SetPalette( const unsigned char *_pal )
+{
+	const unsigned char *pal = _pal;
+  	LOGPALETTE		*pLogPal = ( LOGPALETTE * ) &s_ipal;
+	RGBQUAD			colors[256];
+	int				i;
+	int				ret;
+	HDC				hDC = sww_state.hDC;
+
+	/*
+	** set the DIB color table
+	*/
+	if ( sww_state.hdcDIBSection )
+	{
+		for ( i = 0; i < 256; i++, pal += 4 )
+		{
+			colors[i].rgbRed   = pal[0];
+			colors[i].rgbGreen = pal[1];
+			colors[i].rgbBlue  = pal[2];
+			colors[i].rgbReserved = 0;
+		}
+
+		colors[0].rgbRed = 0;
+		colors[0].rgbGreen = 0;
+		colors[0].rgbBlue = 0;
+
+		colors[255].rgbRed = 0xff;
+		colors[255].rgbGreen = 0xff;
+		colors[255].rgbBlue = 0xff;
+
+		if ( SetDIBColorTable( sww_state.hdcDIBSection, 0, 256, colors ) == 0 )
+		{
+			ri.Con_Printf( PRINT_ALL, "DIB_SetPalette() - SetDIBColorTable failed\n" );
+		}
+	}
+
+	/*
+	** for 8-bit color desktop modes we set up the palette for maximum
+	** speed by going into an identity palette mode.
+	*/
+	if ( sww_state.palettized )
+	{
+		int i;
+		HPALETTE hpalOld;
+
+		if ( SetSystemPaletteUse( hDC, SYSPAL_NOSTATIC ) == SYSPAL_ERROR )
+		{
+			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SetSystemPaletteUse() failed\n" );
+		}
+
+		/*
+		** destroy our old palette
+		*/
+		if ( sww_state.hPal )
+		{
+			DeleteObject( sww_state.hPal );
+			sww_state.hPal = 0;
+		}
+
+		/*
+		** take up all physical palette entries to flush out anything that's currently
+		** in the palette
+		*/
+		pLogPal->palVersion		= 0x300;
+		pLogPal->palNumEntries	= 256;
+
+		for ( i = 0, pal = _pal; i < 256; i++, pal += 4 )
+		{
+			pLogPal->palPalEntry[i].peRed	= pal[0];
+			pLogPal->palPalEntry[i].peGreen	= pal[1];
+			pLogPal->palPalEntry[i].peBlue	= pal[2];
+			pLogPal->palPalEntry[i].peFlags	= PC_RESERVED | PC_NOCOLLAPSE;
+		}
+		pLogPal->palPalEntry[0].peRed		= 0;
+		pLogPal->palPalEntry[0].peGreen		= 0;
+		pLogPal->palPalEntry[0].peBlue		= 0;
+		pLogPal->palPalEntry[0].peFlags		= 0;
+		pLogPal->palPalEntry[255].peRed		= 0xff;
+		pLogPal->palPalEntry[255].peGreen	= 0xff;
+		pLogPal->palPalEntry[255].peBlue	= 0xff;
+		pLogPal->palPalEntry[255].peFlags	= 0;
+
+		if ( ( sww_state.hPal = CreatePalette( pLogPal ) ) == NULL )
+		{
+			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - CreatePalette failed(%x)\n", GetLastError() );
+		}
+
+		if ( ( hpalOld = SelectPalette( hDC, sww_state.hPal, FALSE ) ) == NULL )
+		{
+			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SelectPalette failed(%x)\n",GetLastError() );
+		}
+
+		if ( sww_state.hpalOld == NULL )
+			sww_state.hpalOld = hpalOld;
+
+		if ( ( ret = RealizePalette( hDC ) ) != pLogPal->palNumEntries ) 
+		{
+			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - RealizePalette set %d entries\n", ret );
+		}
+	}
+}
+
+/*
+** DIB_Shutdown
+*/
+void DIB_Shutdown( void )
+{
+	if ( sww_state.palettized && s_systemcolors_saved )
+		DIB_RestoreSystemColors();
+
+	if ( sww_state.hPal )
+	{
+		DeleteObject( sww_state.hPal );
+		sww_state.hPal = 0;
+	}
+
+	if ( sww_state.hpalOld )
+	{
+		SelectPalette( sww_state.hDC, sww_state.hpalOld, FALSE );
+		RealizePalette( sww_state.hDC );
+		sww_state.hpalOld = NULL;
+	}
+
+	if ( sww_state.hdcDIBSection )
+	{
+		SelectObject( sww_state.hdcDIBSection, previously_selected_GDI_obj );
+		DeleteDC( sww_state.hdcDIBSection );
+		sww_state.hdcDIBSection = NULL;
+	}
+
+	if ( sww_state.hDIBSection )
+	{
+		DeleteObject( sww_state.hDIBSection );
+		sww_state.hDIBSection = NULL;
+		sww_state.pDIBBase = NULL;
+	}
+
+	if ( sww_state.hDC )
+	{
+		ReleaseDC( sww_state.hWnd, sww_state.hDC );
+		sww_state.hDC = 0;
+	}
+}
+
+
+/*
+** DIB_Save/RestoreSystemColors
+*/
+static void DIB_RestoreSystemColors( void )
+{
+    SetSystemPaletteUse( sww_state.hDC, SYSPAL_STATIC );
+    SetSysColors( NUM_SYS_COLORS, s_syspalindices, s_oldsyscolors );
+}
+
+static void DIB_SaveSystemColors( void )
+{
+	int i;
+
+	for ( i = 0; i < NUM_SYS_COLORS; i++ )
+		s_oldsyscolors[i] = GetSysColor( s_syspalindices[i] );
+}
--- /dev/null
+++ b/win32/rw_imp.c
@@ -1,0 +1,471 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+/*
+** RW_IMP.C
+**
+** This file contains ALL Win32 specific stuff having to do with the
+** software refresh.  When a port is being made the following functions
+** must be implemented by the port:
+**
+** SWimp_EndFrame
+** SWimp_Init
+** SWimp_SetPalette
+** SWimp_Shutdown
+*/
+#include "..\ref_soft\r_local.h"
+#include "rw_win.h"
+#include "winquake.h"
+
+// Console variables that we need to access from this module
+
+swwstate_t sww_state;
+
+/*
+** VID_CreateWindow
+*/
+#define	WINDOW_CLASS_NAME "Quake 2"
+
+void VID_CreateWindow( int width, int height, int stylebits )
+{
+	WNDCLASS		wc;
+	RECT			r;
+	cvar_t			*vid_xpos, *vid_ypos, *vid_fullscreen;
+	int				x, y, w, h;
+	int				exstyle;
+
+	vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
+	vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
+	vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE );
+
+	if ( vid_fullscreen->value )
+		exstyle = WS_EX_TOPMOST;
+	else
+		exstyle = 0;
+
+	/* Register the frame class */
+    wc.style         = 0;
+    wc.lpfnWndProc   = (WNDPROC)sww_state.wndproc;
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = sww_state.hInstance;
+    wc.hIcon         = 0;
+    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
+	wc.hbrBackground = (void *)COLOR_GRAYTEXT;
+    wc.lpszMenuName  = 0;
+    wc.lpszClassName = WINDOW_CLASS_NAME;
+
+    if (!RegisterClass (&wc) )
+		ri.Sys_Error (ERR_FATAL, "Couldn't register window class");
+
+	r.left = 0;
+	r.top = 0;
+	r.right  = width;
+	r.bottom = height;
+
+	AdjustWindowRect (&r, stylebits, FALSE);
+
+	w = r.right - r.left;
+	h = r.bottom - r.top;
+	x = vid_xpos->value;
+	y = vid_ypos->value;
+
+	sww_state.hWnd = CreateWindowEx (
+		exstyle,
+		 WINDOW_CLASS_NAME,
+		 "Quake 2",
+		 stylebits,
+		 x, y, w, h,
+		 NULL,
+		 NULL,
+		 sww_state.hInstance,
+		 NULL);
+
+	if (!sww_state.hWnd)
+		ri.Sys_Error (ERR_FATAL, "Couldn't create window");
+	
+	ShowWindow( sww_state.hWnd, SW_SHOWNORMAL );
+	UpdateWindow( sww_state.hWnd );
+	SetForegroundWindow( sww_state.hWnd );
+	SetFocus( sww_state.hWnd );
+
+	// let the sound and input subsystems know about the new window
+	ri.Vid_NewWindow (width, height);
+}
+
+/*
+** SWimp_Init
+**
+** This routine is responsible for initializing the implementation
+** specific stuff in a software rendering subsystem.
+*/
+int SWimp_Init( void *hInstance, void *wndProc )
+{
+	sww_state.hInstance = ( HINSTANCE ) hInstance;
+	sww_state.wndproc = wndProc;
+
+	return true;
+}
+
+/*
+** SWimp_InitGraphics
+**
+** This initializes the software refresh's implementation specific
+** graphics subsystem.  In the case of Windows it creates DIB or
+** DDRAW surfaces.
+**
+** The necessary width and height parameters are grabbed from
+** vid.width and vid.height.
+*/
+static qboolean SWimp_InitGraphics( qboolean fullscreen )
+{
+	// free resources in use
+	SWimp_Shutdown ();
+
+	// create a new window
+	VID_CreateWindow (vid.width, vid.height, WINDOW_STYLE);
+
+	// initialize the appropriate subsystem
+	if ( !fullscreen )
+	{
+		if ( !DIB_Init( &vid.buffer, &vid.rowbytes ) )
+		{
+			vid.buffer = 0;
+			vid.rowbytes = 0;
+
+			return false;
+		}
+	}
+	else
+	{
+		if ( !DDRAW_Init( &vid.buffer, &vid.rowbytes ) )
+		{
+			vid.buffer = 0;
+			vid.rowbytes = 0;
+
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+** SWimp_EndFrame
+**
+** This does an implementation specific copy from the backbuffer to the
+** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
+** on whether we're using DIB sections/GDI or DDRAW.
+*/
+void SWimp_EndFrame (void)
+{
+	if ( !sw_state.fullscreen )
+	{
+		if ( sww_state.palettized )
+		{
+//			holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE);
+//			RealizePalette(hdcScreen);
+		}
+
+	    
+		BitBlt( sww_state.hDC,
+			    0, 0,
+				vid.width,
+				vid.height,
+				sww_state.hdcDIBSection,
+				0, 0,
+				SRCCOPY );
+
+		if ( sww_state.palettized )
+		{
+//			SelectPalette(hdcScreen, holdpal, FALSE);
+		}
+	}
+	else
+	{
+		RECT r;
+		HRESULT rval;
+		DDSURFACEDESC ddsd;
+
+		r.left = 0;
+		r.top = 0;
+		r.right = vid.width;
+		r.bottom = vid.height;
+
+		sww_state.lpddsOffScreenBuffer->lpVtbl->Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer );
+
+		if ( sww_state.modex )
+		{
+			if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer,
+																	0, 0,
+																	sww_state.lpddsOffScreenBuffer, 
+																	&r, 
+																	DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
+			{
+				sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsBackBuffer );
+				sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer,
+															0, 0,
+															sww_state.lpddsOffScreenBuffer, 
+															&r, 
+															DDBLTFAST_WAIT );
+			}
+
+			if ( ( rval = sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer,
+															 NULL, DDFLIP_WAIT ) ) == DDERR_SURFACELOST )
+			{
+				sww_state.lpddsFrontBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer );
+				sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer, NULL, DDFLIP_WAIT );
+			}
+		}
+		else
+		{
+			if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer,
+																	0, 0,
+																	sww_state.lpddsOffScreenBuffer, 
+																	&r, 
+																	DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
+			{
+				sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer );
+				sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer,
+															0, 0,
+															sww_state.lpddsOffScreenBuffer, 
+															&r, 
+															DDBLTFAST_WAIT );
+			}
+		}
+
+		memset( &ddsd, 0, sizeof( ddsd ) );
+		ddsd.dwSize = sizeof( ddsd );
+	
+		sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL );
+
+		vid.buffer = ddsd.lpSurface;
+		vid.rowbytes = ddsd.lPitch;
+	}
+}
+
+/*
+** SWimp_SetMode
+*/
+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+	const char *win_fs[] = { "W", "FS" };
+	rserr_t retval = rserr_ok;
+
+	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
+
+	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
+	{
+		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+		return rserr_invalid_mode;
+	}
+
+	ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] );
+
+	sww_state.initializing = true;
+	if ( fullscreen )
+	{
+		if ( !SWimp_InitGraphics( 1 ) )
+		{
+			if ( SWimp_InitGraphics( 0 ) )
+			{
+				// mode is legal but not as fullscreen
+				fullscreen = 0;
+				retval = rserr_invalid_fullscreen;
+			}
+			else
+			{
+				// failed to set a valid mode in windowed mode
+				retval = rserr_unknown;
+			}
+		}
+	}
+	else
+	{
+		// failure to set a valid mode in windowed mode
+		if ( !SWimp_InitGraphics( fullscreen ) )
+		{
+			sww_state.initializing = true;
+			return rserr_unknown;
+		}
+	}
+
+	sw_state.fullscreen = fullscreen;
+#if 0
+	if ( retval != rserr_unknown )
+	{
+		if ( retval == rserr_invalid_fullscreen ||
+			 ( retval == rserr_ok && !fullscreen ) )
+		{
+			SetWindowLong( sww_state.hWnd, GWL_STYLE, WINDOW_STYLE );
+		}
+	}
+#endif
+	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+	sww_state.initializing = true;
+
+	return retval;
+}
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine.  A NULL palette means
+** to use the existing palette.  The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+void SWimp_SetPalette( const unsigned char *palette )
+{
+	// MGL - what the fuck was kendall doing here?!
+	// clear screen to black and change palette
+	//	for (i=0 ; i<vid.height ; i++)
+	//		memset (vid.buffer + i*vid.rowbytes, 0, vid.width);
+
+	if ( !palette )
+		palette = ( const unsigned char * ) sw_state.currentpalette;
+
+	if ( !sw_state.fullscreen )
+	{
+		DIB_SetPalette( ( const unsigned char * ) palette );
+	}
+	else
+	{
+		DDRAW_SetPalette( ( const unsigned char * ) palette );
+	}
+}
+
+/*
+** SWimp_Shutdown
+**
+** System specific graphics subsystem shutdown routine.  Destroys
+** DIBs or DDRAW surfaces as appropriate.
+*/
+void SWimp_Shutdown( void )
+{
+	ri.Con_Printf( PRINT_ALL, "Shutting down SW imp\n" );
+	DIB_Shutdown();
+	DDRAW_Shutdown();
+
+	if ( sww_state.hWnd )
+	{
+		ri.Con_Printf( PRINT_ALL, "...destroying window\n" );
+		ShowWindow( sww_state.hWnd, SW_SHOWNORMAL );	// prevents leaving empty slots in the taskbar
+		DestroyWindow (sww_state.hWnd);
+		sww_state.hWnd = NULL;
+		UnregisterClass (WINDOW_CLASS_NAME, sww_state.hInstance);
+	}
+}
+
+/*
+** SWimp_AppActivate
+*/
+void SWimp_AppActivate( qboolean active )
+{
+	if ( active )
+	{
+		if ( sww_state.hWnd )
+		{
+			SetForegroundWindow( sww_state.hWnd );
+			ShowWindow( sww_state.hWnd, SW_RESTORE );
+		}
+	}
+	else
+	{
+		if ( sww_state.hWnd )
+		{
+			if ( sww_state.initializing )
+				return;
+			if ( vid_fullscreen->value )
+				ShowWindow( sww_state.hWnd, SW_MINIMIZE );
+		}
+	}
+}
+
+//===============================================================================
+
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+	DWORD  flOldProtect;
+
+	if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
+ 		ri.Sys_Error(ERR_FATAL, "Protection change failed\n");
+}
+
+/*
+** Sys_SetFPCW
+**
+** For reference:
+**
+** 1
+** 5               0
+** xxxxRRPP.xxxxxxxx
+**
+** PP = 00 = 24-bit single precision
+** PP = 01 = reserved
+** PP = 10 = 53-bit double precision
+** PP = 11 = 64-bit extended precision
+**
+** RR = 00 = round to nearest
+** RR = 01 = round down (towards -inf, floor)
+** RR = 10 = round up (towards +inf, ceil)
+** RR = 11 = round to zero (truncate/towards 0)
+**
+*/
+#if !id386
+void Sys_SetFPCW (void)
+{
+}
+#else
+unsigned fpu_ceil_cw, fpu_chop_cw, fpu_full_cw, fpu_cw, fpu_pushed_cw;
+unsigned fpu_sp24_cw, fpu_sp24_ceil_cw;
+
+void Sys_SetFPCW( void )
+{
+	__asm xor eax, eax
+
+	__asm fnstcw  word ptr fpu_cw
+	__asm mov ax, word ptr fpu_cw
+
+	__asm and ah, 0f0h
+	__asm or  ah, 003h          ; round to nearest mode, extended precision
+	__asm mov fpu_full_cw, eax
+
+	__asm and ah, 0f0h
+	__asm or  ah, 00fh          ; RTZ/truncate/chop mode, extended precision
+	__asm mov fpu_chop_cw, eax
+
+	__asm and ah, 0f0h
+	__asm or  ah, 00bh          ; ceil mode, extended precision
+	__asm mov fpu_ceil_cw, eax
+
+	__asm and ah, 0f0h          ; round to nearest, 24-bit single precision
+	__asm mov fpu_sp24_cw, eax
+
+	__asm and ah, 0f0h          ; ceil mode, 24-bit single precision
+	__asm or  ah, 008h          ; 
+	__asm mov fpu_sp24_ceil_cw, eax
+}
+#endif
+
--- /dev/null
+++ b/win32/rw_win.h
@@ -1,0 +1,68 @@
+/*
+Copyright (C) 1997-2001 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 __RW_WIN_H__
+#define __RW_WIN_H__
+
+#include <windows.h>
+#include <ddraw.h>
+
+typedef struct
+{
+	HINSTANCE		hInstance;
+	void			*wndproc;
+	HDC				hDC;				// global DC we're using
+	HWND			hWnd;				// HWND of parent window
+
+	HDC				hdcDIBSection;		// DC compatible with DIB section
+	HBITMAP			hDIBSection;		// DIB section
+	unsigned char	*pDIBBase;			// DIB base pointer, NOT used directly for rendering!
+
+	HPALETTE		hPal;				// palette we're using
+	HPALETTE		hpalOld;			// original system palette
+	COLORREF		oldsyscolors[20];	// original system colors
+
+	HINSTANCE		hinstDDRAW;			// library instance for DDRAW.DLL
+	LPDIRECTDRAW 	lpDirectDraw;		// pointer to DirectDraw object
+
+	LPDIRECTDRAWSURFACE lpddsFrontBuffer;	// video card display memory front buffer
+	LPDIRECTDRAWSURFACE lpddsBackBuffer;	// system memory backbuffer
+	LPDIRECTDRAWSURFACE lpddsOffScreenBuffer;	// system memory backbuffer
+	LPDIRECTDRAWPALETTE	lpddpPalette;		// DirectDraw palette
+
+	qboolean		palettized;			// true if desktop is paletted
+	qboolean		modex;
+
+	qboolean		initializing;
+} swwstate_t;
+
+extern swwstate_t sww_state;
+
+/*
+** DIB code
+*/
+qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch );
+void     DIB_Shutdown( void );
+void     DIB_SetPalette( const unsigned char *palette );
+
+qboolean DDRAW_Init( unsigned char **ppbuffer, int *ppitch );
+void     DDRAW_Shutdown( void );
+void     DDRAW_SetPalette( const unsigned char *palette );
+
+#endif
--- /dev/null
+++ b/win32/snd_win.c
@@ -1,0 +1,861 @@
+/*
+Copyright (C) 1997-2001 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 <float.h>
+
+#include "../client/client.h"
+#include "../client/snd_loc.h"
+#include "winquake.h"
+
+#define iDirectSoundCreate(a,b,c)	pDirectSoundCreate(a,b,c)
+
+HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
+
+// 64K is > 1 second at 16-bit, 22050 Hz
+#define	WAV_BUFFERS				64
+#define	WAV_MASK				0x3F
+#define	WAV_BUFFER_SIZE			0x0400
+#define SECONDARY_BUFFER_SIZE	0x10000
+
+typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
+
+cvar_t	*s_wavonly;
+
+static qboolean	dsound_init;
+static qboolean	wav_init;
+static qboolean	snd_firsttime = true, snd_isdirect, snd_iswave;
+static qboolean	primary_format_set;
+
+// starts at 0 for disabled
+static int	snd_buffer_count = 0;
+static int	sample16;
+static int	snd_sent, snd_completed;
+
+/* 
+ * Global variables. Must be visible to window-procedure function 
+ *  so it can unlock and free the data block after it has been played. 
+ */ 
+
+
+HANDLE		hData;
+HPSTR		lpData, lpData2;
+
+HGLOBAL		hWaveHdr;
+LPWAVEHDR	lpWaveHdr;
+
+HWAVEOUT    hWaveOut; 
+
+WAVEOUTCAPS	wavecaps;
+
+DWORD	gSndBufSize;
+
+MMTIME		mmstarttime;
+
+LPDIRECTSOUND pDS;
+LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
+
+HINSTANCE hInstDS;
+
+qboolean SNDDMA_InitDirect (void);
+qboolean SNDDMA_InitWav (void);
+
+void FreeSound( void );
+
+static const char *DSoundError( int error )
+{
+	switch ( error )
+	{
+	case DSERR_BUFFERLOST:
+		return "DSERR_BUFFERLOST";
+	case DSERR_INVALIDCALL:
+		return "DSERR_INVALIDCALLS";
+	case DSERR_INVALIDPARAM:
+		return "DSERR_INVALIDPARAM";
+	case DSERR_PRIOLEVELNEEDED:
+		return "DSERR_PRIOLEVELNEEDED";
+	}
+
+	return "unknown";
+}
+
+/*
+** DS_CreateBuffers
+*/
+static qboolean DS_CreateBuffers( void )
+{
+	DSBUFFERDESC	dsbuf;
+	DSBCAPS			dsbcaps;
+	WAVEFORMATEX	pformat, format;
+	DWORD			dwWrite;
+
+	memset (&format, 0, sizeof(format));
+	format.wFormatTag = WAVE_FORMAT_PCM;
+    format.nChannels = dma.channels;
+    format.wBitsPerSample = dma.samplebits;
+    format.nSamplesPerSec = dma.speed;
+    format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
+    format.cbSize = 0;
+    format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign; 
+
+	Com_Printf( "Creating DS buffers\n" );
+
+	Com_DPrintf("...setting EXCLUSIVE coop level: " );
+	if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_EXCLUSIVE ) )
+	{
+		Com_Printf ("failed\n");
+		FreeSound ();
+		return false;
+	}
+	Com_DPrintf("ok\n" );
+
+// get access to the primary buffer, if possible, so we can set the
+// sound hardware format
+	memset (&dsbuf, 0, sizeof(dsbuf));
+	dsbuf.dwSize = sizeof(DSBUFFERDESC);
+	dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
+	dsbuf.dwBufferBytes = 0;
+	dsbuf.lpwfxFormat = NULL;
+
+	memset(&dsbcaps, 0, sizeof(dsbcaps));
+	dsbcaps.dwSize = sizeof(dsbcaps);
+	primary_format_set = false;
+
+	Com_DPrintf( "...creating primary buffer: " );
+	if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
+	{
+		pformat = format;
+
+		Com_DPrintf( "ok\n" );
+		if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
+		{
+			if (snd_firsttime)
+				Com_DPrintf ("...setting primary sound format: failed\n");
+		}
+		else
+		{
+			if (snd_firsttime)
+				Com_DPrintf ("...setting primary sound format: ok\n");
+
+			primary_format_set = true;
+		}
+	}
+	else
+		Com_Printf( "failed\n" );
+
+	if ( !primary_format_set || !s_primary->value)
+	{
+	// create the secondary buffer we'll actually work with
+		memset (&dsbuf, 0, sizeof(dsbuf));
+		dsbuf.dwSize = sizeof(DSBUFFERDESC);
+		dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
+		dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
+		dsbuf.lpwfxFormat = &format;
+
+		memset(&dsbcaps, 0, sizeof(dsbcaps));
+		dsbcaps.dwSize = sizeof(dsbcaps);
+
+		Com_DPrintf( "...creating secondary buffer: " );
+		if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
+		{
+			Com_Printf( "failed\n" );
+			FreeSound ();
+			return false;
+		}
+		Com_DPrintf( "ok\n" );
+
+		dma.channels = format.nChannels;
+		dma.samplebits = format.wBitsPerSample;
+		dma.speed = format.nSamplesPerSec;
+
+		if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
+		{
+			Com_Printf ("*** GetCaps failed ***\n");
+			FreeSound ();
+			return false;
+		}
+
+		Com_Printf ("...using secondary sound buffer\n");
+	}
+	else
+	{
+		Com_Printf( "...using primary buffer\n" );
+
+		Com_DPrintf( "...setting WRITEPRIMARY coop level: " );
+		if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, cl_hwnd, DSSCL_WRITEPRIMARY))
+		{
+			Com_Printf( "failed\n" );
+			FreeSound ();
+			return false;
+		}
+		Com_DPrintf( "ok\n" );
+
+		if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
+		{
+			Com_Printf ("*** GetCaps failed ***\n");
+			return false;
+		}
+
+		pDSBuf = pDSPBuf;
+	}
+
+	// Make sure mixer is active
+	pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
+
+	if (snd_firsttime)
+		Com_Printf("   %d channel(s)\n"
+		               "   %d bits/sample\n"
+					   "   %d bytes/sec\n",
+					   dma.channels, dma.samplebits, dma.speed);
+	
+	gSndBufSize = dsbcaps.dwBufferBytes;
+
+	/* we don't want anyone to access the buffer directly w/o locking it first. */
+	lpData = NULL; 
+
+	pDSBuf->lpVtbl->Stop(pDSBuf);
+	pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
+	pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
+
+	dma.samples = gSndBufSize/(dma.samplebits/8);
+	dma.samplepos = 0;
+	dma.submission_chunk = 1;
+	dma.buffer = (unsigned char *) lpData;
+	sample16 = (dma.samplebits/8) - 1;
+
+	return true;
+}
+
+/*
+** DS_DestroyBuffers
+*/
+static void DS_DestroyBuffers( void )
+{
+	Com_DPrintf( "Destroying DS buffers\n" );
+	if ( pDS )
+	{
+		Com_DPrintf( "...setting NORMAL coop level\n" );
+		pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_NORMAL );
+	}
+
+	if ( pDSBuf )
+	{
+		Com_DPrintf( "...stopping and releasing sound buffer\n" );
+		pDSBuf->lpVtbl->Stop( pDSBuf );
+		pDSBuf->lpVtbl->Release( pDSBuf );
+	}
+
+	// only release primary buffer if it's not also the mixing buffer we just released
+	if ( pDSPBuf && ( pDSBuf != pDSPBuf ) )
+	{
+		Com_DPrintf( "...releasing primary buffer\n" );
+		pDSPBuf->lpVtbl->Release( pDSPBuf );
+	}
+	pDSBuf = NULL;
+	pDSPBuf = NULL;
+
+	dma.buffer = NULL;
+}
+
+/*
+==================
+FreeSound
+==================
+*/
+void FreeSound (void)
+{
+	int		i;
+
+	Com_DPrintf( "Shutting down sound system\n" );
+
+	if ( pDS )
+		DS_DestroyBuffers();
+
+	if ( hWaveOut )
+	{
+		Com_DPrintf( "...resetting waveOut\n" );
+		waveOutReset (hWaveOut);
+
+		if (lpWaveHdr)
+		{
+			Com_DPrintf( "...unpreparing headers\n" );
+			for (i=0 ; i< WAV_BUFFERS ; i++)
+				waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
+		}
+
+		Com_DPrintf( "...closing waveOut\n" );
+		waveOutClose (hWaveOut);
+
+		if (hWaveHdr)
+		{
+			Com_DPrintf( "...freeing WAV header\n" );
+			GlobalUnlock(hWaveHdr);
+			GlobalFree(hWaveHdr);
+		}
+
+		if (hData)
+		{
+			Com_DPrintf( "...freeing WAV buffer\n" );
+			GlobalUnlock(hData);
+			GlobalFree(hData);
+		}
+
+	}
+
+	if ( pDS )
+	{
+		Com_DPrintf( "...releasing DS object\n" );
+		pDS->lpVtbl->Release( pDS );
+	}
+
+	if ( hInstDS )
+	{
+		Com_DPrintf( "...freeing DSOUND.DLL\n" );
+		FreeLibrary( hInstDS );
+		hInstDS = NULL;
+	}
+
+	pDS = NULL;
+	pDSBuf = NULL;
+	pDSPBuf = NULL;
+	hWaveOut = 0;
+	hData = 0;
+	hWaveHdr = 0;
+	lpData = NULL;
+	lpWaveHdr = NULL;
+	dsound_init = false;
+	wav_init = false;
+}
+
+/*
+==================
+SNDDMA_InitDirect
+
+Direct-Sound support
+==================
+*/
+sndinitstat SNDDMA_InitDirect (void)
+{
+	DSCAPS			dscaps;
+	HRESULT			hresult;
+
+	dma.channels = 2;
+	dma.samplebits = 16;
+
+	if (s_khz->value == 44)
+		dma.speed = 44100;
+	if (s_khz->value == 22)
+		dma.speed = 22050;
+	else
+		dma.speed = 11025;
+
+	Com_Printf( "Initializing DirectSound\n");
+
+	if ( !hInstDS )
+	{
+		Com_DPrintf( "...loading dsound.dll: " );
+
+		hInstDS = LoadLibrary("dsound.dll");
+		
+		if (hInstDS == NULL)
+		{
+			Com_Printf ("failed\n");
+			return SIS_FAILURE;
+		}
+
+		Com_DPrintf ("ok\n");
+		pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
+
+		if (!pDirectSoundCreate)
+		{
+			Com_Printf ("*** couldn't get DS proc addr ***\n");
+			return SIS_FAILURE;
+		}
+	}
+
+	Com_DPrintf( "...creating DS object: " );
+	while ( ( hresult = iDirectSoundCreate( NULL, &pDS, NULL ) ) != DS_OK )
+	{
+		if (hresult != DSERR_ALLOCATED)
+		{
+			Com_Printf( "failed\n" );
+			return SIS_FAILURE;
+		}
+
+		if (MessageBox (NULL,
+						"The sound hardware is in use by another app.\n\n"
+					    "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
+						"Sound not available",
+						MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
+		{
+			Com_Printf ("failed, hardware already in use\n" );
+			return SIS_NOTAVAIL;
+		}
+	}
+	Com_DPrintf( "ok\n" );
+
+	dscaps.dwSize = sizeof(dscaps);
+
+	if ( DS_OK != pDS->lpVtbl->GetCaps( pDS, &dscaps ) )
+	{
+		Com_Printf ("*** couldn't get DS caps ***\n");
+	}
+
+	if ( dscaps.dwFlags & DSCAPS_EMULDRIVER )
+	{
+		Com_DPrintf ("...no DSound driver found\n" );
+		FreeSound();
+		return SIS_FAILURE;
+	}
+
+	if ( !DS_CreateBuffers() )
+		return SIS_FAILURE;
+
+	dsound_init = true;
+
+	Com_DPrintf("...completed successfully\n" );
+
+	return SIS_SUCCESS;
+}
+
+
+/*
+==================
+SNDDM_InitWav
+
+Crappy windows multimedia base
+==================
+*/
+qboolean SNDDMA_InitWav (void)
+{
+	WAVEFORMATEX  format; 
+	int				i;
+	HRESULT			hr;
+
+	Com_Printf( "Initializing wave sound\n" );
+	
+	snd_sent = 0;
+	snd_completed = 0;
+
+	dma.channels = 2;
+	dma.samplebits = 16;
+
+	if (s_khz->value == 44)
+		dma.speed = 44100;
+	if (s_khz->value == 22)
+		dma.speed = 22050;
+	else
+		dma.speed = 11025;
+
+	memset (&format, 0, sizeof(format));
+	format.wFormatTag = WAVE_FORMAT_PCM;
+	format.nChannels = dma.channels;
+	format.wBitsPerSample = dma.samplebits;
+	format.nSamplesPerSec = dma.speed;
+	format.nBlockAlign = format.nChannels
+		*format.wBitsPerSample / 8;
+	format.cbSize = 0;
+	format.nAvgBytesPerSec = format.nSamplesPerSec
+		*format.nBlockAlign; 
+	
+	/* Open a waveform device for output using window callback. */ 
+	Com_DPrintf ("...opening waveform device: ");
+	while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, 
+					&format, 
+					0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
+	{
+		if (hr != MMSYSERR_ALLOCATED)
+		{
+			Com_Printf ("failed\n");
+			return false;
+		}
+
+		if (MessageBox (NULL,
+						"The sound hardware is in use by another app.\n\n"
+					    "Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.",
+						"Sound not available",
+						MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
+		{
+			Com_Printf ("hw in use\n" );
+			return false;
+		}
+	} 
+	Com_DPrintf( "ok\n" );
+
+	/* 
+	 * Allocate and lock memory for the waveform data. The memory 
+	 * for waveform data must be globally allocated with 
+	 * GMEM_MOVEABLE and GMEM_SHARE flags. 
+
+	*/ 
+	Com_DPrintf ("...allocating waveform buffer: ");
+	gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
+	hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize); 
+	if (!hData) 
+	{ 
+		Com_Printf( " failed\n" );
+		FreeSound ();
+		return false; 
+	}
+	Com_DPrintf( "ok\n" );
+
+	Com_DPrintf ("...locking waveform buffer: ");
+	lpData = GlobalLock(hData);
+	if (!lpData)
+	{ 
+		Com_Printf( " failed\n" );
+		FreeSound ();
+		return false; 
+	} 
+	memset (lpData, 0, gSndBufSize);
+	Com_DPrintf( "ok\n" );
+
+	/* 
+	 * Allocate and lock memory for the header. This memory must 
+	 * also be globally allocated with GMEM_MOVEABLE and 
+	 * GMEM_SHARE flags. 
+	 */ 
+	Com_DPrintf ("...allocating waveform header: ");
+	hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 
+		(DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); 
+
+	if (hWaveHdr == NULL)
+	{ 
+		Com_Printf( "failed\n" );
+		FreeSound ();
+		return false; 
+	} 
+	Com_DPrintf( "ok\n" );
+
+	Com_DPrintf ("...locking waveform header: ");
+	lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr); 
+
+	if (lpWaveHdr == NULL)
+	{ 
+		Com_Printf( "failed\n" );
+		FreeSound ();
+		return false; 
+	}
+	memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
+	Com_DPrintf( "ok\n" );
+
+	/* After allocation, set up and prepare headers. */ 
+	Com_DPrintf ("...preparing headers: ");
+	for (i=0 ; i<WAV_BUFFERS ; i++)
+	{
+		lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE; 
+		lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
+
+		if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
+				MMSYSERR_NOERROR)
+		{
+			Com_Printf ("failed\n");
+			FreeSound ();
+			return false;
+		}
+	}
+	Com_DPrintf ("ok\n");
+
+	dma.samples = gSndBufSize/(dma.samplebits/8);
+	dma.samplepos = 0;
+	dma.submission_chunk = 512;
+	dma.buffer = (unsigned char *) lpData;
+	sample16 = (dma.samplebits/8) - 1;
+
+	wav_init = true;
+
+	return true;
+}
+
+/*
+==================
+SNDDMA_Init
+
+Try to find a sound device to mix for.
+Returns false if nothing is found.
+==================
+*/
+int SNDDMA_Init(void)
+{
+	sndinitstat	stat;
+
+	memset ((void *)&dma, 0, sizeof (dma));
+
+	s_wavonly = Cvar_Get ("s_wavonly", "0", 0);
+
+	dsound_init = wav_init = 0;
+
+	stat = SIS_FAILURE;	// assume DirectSound won't initialize
+
+	/* Init DirectSound */
+	if (!s_wavonly->value)
+	{
+		if (snd_firsttime || snd_isdirect)
+		{
+			stat = SNDDMA_InitDirect ();
+
+			if (stat == SIS_SUCCESS)
+			{
+				snd_isdirect = true;
+
+				if (snd_firsttime)
+					Com_Printf ("dsound init succeeded\n" );
+			}
+			else
+			{
+				snd_isdirect = false;
+				Com_Printf ("*** dsound init failed ***\n");
+			}
+		}
+	}
+
+// if DirectSound didn't succeed in initializing, try to initialize
+// waveOut sound, unless DirectSound failed because the hardware is
+// already allocated (in which case the user has already chosen not
+// to have sound)
+	if (!dsound_init && (stat != SIS_NOTAVAIL))
+	{
+		if (snd_firsttime || snd_iswave)
+		{
+
+			snd_iswave = SNDDMA_InitWav ();
+
+			if (snd_iswave)
+			{
+				if (snd_firsttime)
+					Com_Printf ("Wave sound init succeeded\n");
+			}
+			else
+			{
+				Com_Printf ("Wave sound init failed\n");
+			}
+		}
+	}
+
+	snd_firsttime = false;
+
+	snd_buffer_count = 1;
+
+	if (!dsound_init && !wav_init)
+	{
+		if (snd_firsttime)
+			Com_Printf ("*** No sound device initialized ***\n");
+
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+==============
+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)
+{
+	MMTIME	mmtime;
+	int		s;
+	DWORD	dwWrite;
+
+	if (dsound_init) 
+	{
+		mmtime.wType = TIME_SAMPLES;
+		pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
+		s = mmtime.u.sample - mmstarttime.u.sample;
+	}
+	else if (wav_init)
+	{
+		s = snd_sent * WAV_BUFFER_SIZE;
+	}
+
+
+	s >>= sample16;
+
+	s &= (dma.samples-1);
+
+	return s;
+}
+
+/*
+==============
+SNDDMA_BeginPainting
+
+Makes sure dma.buffer is valid
+===============
+*/
+DWORD	locksize;
+void SNDDMA_BeginPainting (void)
+{
+	int		reps;
+	DWORD	dwSize2;
+	DWORD	*pbuf, *pbuf2;
+	HRESULT	hresult;
+	DWORD	dwStatus;
+
+	if (!pDSBuf)
+		return;
+
+	// if the buffer was lost or stopped, restore it and/or restart it
+	if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK)
+		Com_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);
+
+	// lock the dsound buffer
+
+	reps = 0;
+	dma.buffer = NULL;
+
+	while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &locksize, 
+								   &pbuf2, &dwSize2, 0)) != DS_OK)
+	{
+		if (hresult != DSERR_BUFFERLOST)
+		{
+			Com_Printf( "S_TransferStereo16: Lock failed with error '%s'\n", DSoundError( hresult ) );
+			S_Shutdown ();
+			return;
+		}
+		else
+		{
+			pDSBuf->lpVtbl->Restore( pDSBuf );
+		}
+
+		if (++reps > 2)
+			return;
+	}
+	dma.buffer = (unsigned char *)pbuf;
+}
+
+/*
+==============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+Also unlocks the dsound buffer
+===============
+*/
+void SNDDMA_Submit(void)
+{
+	LPWAVEHDR	h;
+	int			wResult;
+
+	if (!dma.buffer)
+		return;
+
+	// unlock the dsound buffer
+	if (pDSBuf)
+		pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
+
+	if (!wav_init)
+		return;
+
+	//
+	// find which sound blocks have completed
+	//
+	while (1)
+	{
+		if ( snd_completed == snd_sent )
+		{
+			Com_DPrintf ("Sound overrun\n");
+			break;
+		}
+
+		if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
+		{
+			break;
+		}
+
+		snd_completed++;	// this buffer has been played
+	}
+
+//Com_Printf ("completed %i\n", snd_completed);
+	//
+	// submit a few new sound blocks
+	//
+	while (((snd_sent - snd_completed) >> sample16) < 8)
+	{
+		h = lpWaveHdr + ( snd_sent&WAV_MASK );
+	if (paintedtime/256 <= snd_sent)
+		break;	//	Com_Printf ("submit overrun\n");
+//Com_Printf ("send %i\n", snd_sent);
+		snd_sent++;
+		/* 
+		 * Now the data block can be sent to the output device. The 
+		 * waveOutWrite function returns immediately and waveform 
+		 * data is sent to the output device in the background. 
+		 */ 
+		wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR)); 
+
+		if (wResult != MMSYSERR_NOERROR)
+		{ 
+			Com_Printf ("Failed to write block to device\n");
+			FreeSound ();
+			return; 
+		} 
+	}
+}
+
+/*
+==============
+SNDDMA_Shutdown
+
+Reset the sound device for exiting
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+	FreeSound ();
+}
+
+
+/*
+===========
+S_Activate
+
+Called when the main window gains or loses focus.
+The window have been destroyed and recreated
+between a deactivate and an activate.
+===========
+*/
+void S_Activate (qboolean active)
+{
+	if ( active )
+	{
+		if ( pDS && cl_hwnd && snd_isdirect )
+		{
+			DS_CreateBuffers();
+		}
+	}
+	else
+	{
+		if ( pDS && cl_hwnd && snd_isdirect )
+		{
+			DS_DestroyBuffers();
+		}
+	}
+}
+
--- /dev/null
+++ b/win32/sys_win.c
@@ -1,0 +1,663 @@
+/*
+Copyright (C) 1997-2001 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_win.h
+
+#include "../qcommon/qcommon.h"
+#include "winquake.h"
+#include "resource.h"
+#include <errno.h>
+#include <float.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <direct.h>
+#include <io.h>
+#include <conio.h>
+#include "../win32/conproc.h"
+
+#define MINIMUM_WIN_MEMORY	0x0a00000
+#define MAXIMUM_WIN_MEMORY	0x1000000
+
+//#define DEMO
+
+qboolean s_win95;
+
+int			starttime;
+int			ActiveApp;
+qboolean	Minimized;
+
+static HANDLE		hinput, houtput;
+
+unsigned	sys_msg_time;
+unsigned	sys_frame_time;
+
+
+static HANDLE		qwclsemaphore;
+
+#define	MAX_NUM_ARGVS	128
+int			argc;
+char		*argv[MAX_NUM_ARGVS];
+
+
+/*
+===============================================================================
+
+SYSTEM IO
+
+===============================================================================
+*/
+
+
+void Sys_Error (char *error, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+
+	CL_Shutdown ();
+	Qcommon_Shutdown ();
+
+	va_start (argptr, error);
+	vsprintf (text, error, argptr);
+	va_end (argptr);
+
+	MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
+
+	if (qwclsemaphore)
+		CloseHandle (qwclsemaphore);
+
+// shut down QHOST hooks if necessary
+	DeinitConProc ();
+
+	exit (1);
+}
+
+void Sys_Quit (void)
+{
+	timeEndPeriod( 1 );
+
+	CL_Shutdown();
+	Qcommon_Shutdown ();
+	CloseHandle (qwclsemaphore);
+	if (dedicated && dedicated->value)
+		FreeConsole ();
+
+// shut down QHOST hooks if necessary
+	DeinitConProc ();
+
+	exit (0);
+}
+
+
+void WinError (void)
+{
+	LPVOID lpMsgBuf;
+
+	FormatMessage( 
+		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL,
+		GetLastError(),
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+		(LPTSTR) &lpMsgBuf,
+		0,
+		NULL 
+	);
+
+	// Display the string.
+	MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
+
+	// Free the buffer.
+	LocalFree( lpMsgBuf );
+}
+
+//================================================================
+
+
+/*
+================
+Sys_ScanForCD
+
+================
+*/
+char *Sys_ScanForCD (void)
+{
+	static char	cddir[MAX_OSPATH];
+	static qboolean	done;
+#ifndef DEMO
+	char		drive[4];
+	FILE		*f;
+	char		test[MAX_QPATH];
+
+	if (done)		// don't re-check
+		return cddir;
+
+	// no abort/retry/fail errors
+	SetErrorMode (SEM_FAILCRITICALERRORS);
+
+	drive[0] = 'c';
+	drive[1] = ':';
+	drive[2] = '\\';
+	drive[3] = 0;
+
+	done = true;
+
+	// scan the drives
+	for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++)
+	{
+		// where activision put the stuff...
+		sprintf (cddir, "%sinstall\\data", drive);
+		sprintf (test, "%sinstall\\data\\quake2.exe", drive);
+		f = fopen(test, "r");
+		if (f)
+		{
+			fclose (f);
+			if (GetDriveType (drive) == DRIVE_CDROM)
+				return cddir;
+		}
+	}
+#endif
+
+	cddir[0] = 0;
+	
+	return NULL;
+}
+
+/*
+================
+Sys_CopyProtect
+
+================
+*/
+void	Sys_CopyProtect (void)
+{
+#ifndef DEMO
+	char	*cddir;
+
+	cddir = Sys_ScanForCD();
+	if (!cddir[0])
+		Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play.");
+#endif
+}
+
+
+//================================================================
+
+
+/*
+================
+Sys_Init
+================
+*/
+void Sys_Init (void)
+{
+	OSVERSIONINFO	vinfo;
+
+#if 0
+	// allocate a named semaphore on the client so the
+	// front end can tell if it is alive
+
+	// mutex will fail if semephore already exists
+    qwclsemaphore = CreateMutex(
+        NULL,         /* Security attributes */
+        0,            /* owner       */
+        "qwcl"); /* Semaphore name      */
+	if (!qwclsemaphore)
+		Sys_Error ("QWCL is already running on this system");
+	CloseHandle (qwclsemaphore);
+
+    qwclsemaphore = CreateSemaphore(
+        NULL,         /* Security attributes */
+        0,            /* Initial count       */
+        1,            /* Maximum count       */
+        "qwcl"); /* Semaphore name      */
+#endif
+
+	timeBeginPeriod( 1 );
+
+	vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+
+	if (!GetVersionEx (&vinfo))
+		Sys_Error ("Couldn't get OS info");
+
+	if (vinfo.dwMajorVersion < 4)
+		Sys_Error ("Quake2 requires windows version 4 or greater");
+	if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
+		Sys_Error ("Quake2 doesn't run on Win32s");
+	else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+		s_win95 = true;
+
+	if (dedicated->value)
+	{
+		if (!AllocConsole ())
+			Sys_Error ("Couldn't create dedicated server console");
+		hinput = GetStdHandle (STD_INPUT_HANDLE);
+		houtput = GetStdHandle (STD_OUTPUT_HANDLE);
+	
+		// let QHOST hook in
+		InitConProc (argc, argv);
+	}
+}
+
+
+static char	console_text[256];
+static int	console_textlen;
+
+/*
+================
+Sys_ConsoleInput
+================
+*/
+char *Sys_ConsoleInput (void)
+{
+	INPUT_RECORD	recs[1024];
+	int		dummy;
+	int		ch, numread, numevents;
+
+	if (!dedicated || !dedicated->value)
+		return NULL;
+
+
+	for ( ;; )
+	{
+		if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
+			Sys_Error ("Error getting # of console events");
+
+		if (numevents <= 0)
+			break;
+
+		if (!ReadConsoleInput(hinput, recs, 1, &numread))
+			Sys_Error ("Error reading console input");
+
+		if (numread != 1)
+			Sys_Error ("Couldn't read console input");
+
+		if (recs[0].EventType == KEY_EVENT)
+		{
+			if (!recs[0].Event.KeyEvent.bKeyDown)
+			{
+				ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
+
+				switch (ch)
+				{
+					case '\r':
+						WriteFile(houtput, "\r\n", 2, &dummy, NULL);	
+
+						if (console_textlen)
+						{
+							console_text[console_textlen] = 0;
+							console_textlen = 0;
+							return console_text;
+						}
+						break;
+
+					case '\b':
+						if (console_textlen)
+						{
+							console_textlen--;
+							WriteFile(houtput, "\b \b", 3, &dummy, NULL);	
+						}
+						break;
+
+					default:
+						if (ch >= ' ')
+						{
+							if (console_textlen < sizeof(console_text)-2)
+							{
+								WriteFile(houtput, &ch, 1, &dummy, NULL);	
+								console_text[console_textlen] = ch;
+								console_textlen++;
+							}
+						}
+
+						break;
+
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+
+/*
+================
+Sys_ConsoleOutput
+
+Print text to the dedicated console
+================
+*/
+void Sys_ConsoleOutput (char *string)
+{
+	int		dummy;
+	char	text[256];
+
+	if (!dedicated || !dedicated->value)
+		return;
+
+	if (console_textlen)
+	{
+		text[0] = '\r';
+		memset(&text[1], ' ', console_textlen);
+		text[console_textlen+1] = '\r';
+		text[console_textlen+2] = 0;
+		WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
+	}
+
+	WriteFile(houtput, string, strlen(string), &dummy, NULL);
+
+	if (console_textlen)
+		WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
+}
+
+
+/*
+================
+Sys_SendKeyEvents
+
+Send Key_Event calls
+================
+*/
+void Sys_SendKeyEvents (void)
+{
+    MSG        msg;
+
+	while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
+	{
+		if (!GetMessage (&msg, NULL, 0, 0))
+			Sys_Quit ();
+		sys_msg_time = msg.time;
+      	TranslateMessage (&msg);
+      	DispatchMessage (&msg);
+	}
+
+	// grab frame time 
+	sys_frame_time = timeGetTime();	// FIXME: should this be at start?
+}
+
+
+
+/*
+================
+Sys_GetClipboardData
+
+================
+*/
+char *Sys_GetClipboardData( void )
+{
+	char *data = NULL;
+	char *cliptext;
+
+	if ( OpenClipboard( NULL ) != 0 )
+	{
+		HANDLE hClipboardData;
+
+		if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
+		{
+			if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) 
+			{
+				data = malloc( GlobalSize( hClipboardData ) + 1 );
+				strcpy( data, cliptext );
+				GlobalUnlock( hClipboardData );
+			}
+		}
+		CloseClipboard();
+	}
+	return data;
+}
+
+/*
+==============================================================================
+
+ WINDOWS CRAP
+
+==============================================================================
+*/
+
+/*
+=================
+Sys_AppActivate
+=================
+*/
+void Sys_AppActivate (void)
+{
+	ShowWindow ( cl_hwnd, SW_RESTORE);
+	SetForegroundWindow ( cl_hwnd );
+}
+
+/*
+========================================================================
+
+GAME DLL
+
+========================================================================
+*/
+
+static HINSTANCE	game_library;
+
+/*
+=================
+Sys_UnloadGame
+=================
+*/
+void Sys_UnloadGame (void)
+{
+	if (!FreeLibrary (game_library))
+		Com_Error (ERR_FATAL, "FreeLibrary failed for game library");
+	game_library = NULL;
+}
+
+/*
+=================
+Sys_GetGameAPI
+
+Loads the game dll
+=================
+*/
+void *Sys_GetGameAPI (void *parms)
+{
+	void	*(*GetGameAPI) (void *);
+	char	name[MAX_OSPATH];
+	char	*path;
+	char	cwd[MAX_OSPATH];
+#if defined _M_IX86
+	const char *gamename = "gamex86.dll";
+
+#ifdef NDEBUG
+	const char *debugdir = "release";
+#else
+	const char *debugdir = "debug";
+#endif
+
+#elif defined _M_ALPHA
+	const char *gamename = "gameaxp.dll";
+
+#ifdef NDEBUG
+	const char *debugdir = "releaseaxp";
+#else
+	const char *debugdir = "debugaxp";
+#endif
+
+#endif
+
+	if (game_library)
+		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
+
+	// check the current debug directory first for development purposes
+	_getcwd (cwd, sizeof(cwd));
+	Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
+	game_library = LoadLibrary ( name );
+	if (game_library)
+	{
+		Com_DPrintf ("LoadLibrary (%s)\n", name);
+	}
+	else
+	{
+		// check the current directory for other development purposes
+		Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
+		game_library = LoadLibrary ( name );
+		if (game_library)
+		{
+			Com_DPrintf ("LoadLibrary (%s)\n", name);
+		}
+		else
+		{
+			// now run through the search paths
+			path = NULL;
+			while (1)
+			{
+				path = FS_NextPath (path);
+				if (!path)
+					return NULL;		// couldn't find one anywhere
+				Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
+				game_library = LoadLibrary (name);
+				if (game_library)
+				{
+					Com_DPrintf ("LoadLibrary (%s)\n",name);
+					break;
+				}
+			}
+		}
+	}
+
+	GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI");
+	if (!GetGameAPI)
+	{
+		Sys_UnloadGame ();		
+		return NULL;
+	}
+
+	return GetGameAPI (parms);
+}
+
+//=======================================================================
+
+
+/*
+==================
+ParseCommandLine
+
+==================
+*/
+void ParseCommandLine (LPSTR lpCmdLine)
+{
+	argc = 1;
+	argv[0] = "exe";
+
+	while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
+	{
+		while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
+			lpCmdLine++;
+
+		if (*lpCmdLine)
+		{
+			argv[argc] = lpCmdLine;
+			argc++;
+
+			while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
+				lpCmdLine++;
+
+			if (*lpCmdLine)
+			{
+				*lpCmdLine = 0;
+				lpCmdLine++;
+			}
+			
+		}
+	}
+
+}
+
+/*
+==================
+WinMain
+
+==================
+*/
+HINSTANCE	global_hInstance;
+
+int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+    MSG				msg;
+	int				time, oldtime, newtime;
+	char			*cddir;
+
+    /* previous instances do not exist in Win32 */
+    if (hPrevInstance)
+        return 0;
+
+	global_hInstance = hInstance;
+
+	ParseCommandLine (lpCmdLine);
+
+	// if we find the CD, add a +set cddir xxx command line
+	cddir = Sys_ScanForCD ();
+	if (cddir && argc < MAX_NUM_ARGVS - 3)
+	{
+		int		i;
+
+		// don't override a cddir on the command line
+		for (i=0 ; i<argc ; i++)
+			if (!strcmp(argv[i], "cddir"))
+				break;
+		if (i == argc)
+		{
+			argv[argc++] = "+set";
+			argv[argc++] = "cddir";
+			argv[argc++] = cddir;
+		}
+	}
+
+	Qcommon_Init (argc, argv);
+	oldtime = Sys_Milliseconds ();
+
+    /* main window message loop */
+	while (1)
+	{
+		// if at a full screen console, don't update unless needed
+		if (Minimized || (dedicated && dedicated->value) )
+		{
+			Sleep (1);
+		}
+
+		while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
+		{
+			if (!GetMessage (&msg, NULL, 0, 0))
+				Com_Quit ();
+			sys_msg_time = msg.time;
+			TranslateMessage (&msg);
+   			DispatchMessage (&msg);
+		}
+
+		do
+		{
+			newtime = Sys_Milliseconds ();
+			time = newtime - oldtime;
+		} while (time < 1);
+//			Con_Printf ("time:%5.2f - %5.2f = %5.2f\n", newtime, oldtime, time);
+
+		//	_controlfp( ~( _EM_ZERODIVIDE /*| _EM_INVALID*/ ), _MCW_EM );
+		_controlfp( _PC_24, _MCW_PC );
+		Qcommon_Frame (time);
+
+		oldtime = newtime;
+	}
+
+	// never gets here
+    return TRUE;
+}
--- /dev/null
+++ b/win32/vid_dll.c
@@ -1,0 +1,760 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// Main windowed and fullscreen graphics interface module. This module
+// is used for both the software and OpenGL rendering versions of the
+// Quake refresh engine.
+#include <assert.h>
+#include <float.h>
+
+#include "..\client\client.h"
+#include "winquake.h"
+//#include "zmouse.h"
+
+// Structure containing functions exported from refresh DLL
+refexport_t	re;
+
+cvar_t *win_noalttab;
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL (WM_MOUSELAST+1)  // message that will be supported by the OS 
+#endif
+
+static UINT MSH_MOUSEWHEEL;
+
+// Console variables that we need to access from this module
+cvar_t		*vid_gamma;
+cvar_t		*vid_ref;			// Name of Refresh DLL loaded
+cvar_t		*vid_xpos;			// X coordinate of window position
+cvar_t		*vid_ypos;			// Y coordinate of window position
+cvar_t		*vid_fullscreen;
+
+// Global variables used internally by this module
+viddef_t	viddef;				// global video state; used by other modules
+HINSTANCE	reflib_library;		// Handle to refresh DLL 
+qboolean	reflib_active = 0;
+
+HWND        cl_hwnd;            // Main window handle for life of program
+
+#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
+
+LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
+
+static qboolean s_alttab_disabled;
+
+extern	unsigned	sys_msg_time;
+
+/*
+** WIN32 helper functions
+*/
+extern qboolean s_win95;
+
+static void WIN_DisableAltTab( void )
+{
+	if ( s_alttab_disabled )
+		return;
+
+	if ( s_win95 )
+	{
+		BOOL old;
+
+		SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
+	}
+	else
+	{
+		RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
+		RegisterHotKey( 0, 1, MOD_ALT, VK_RETURN );
+	}
+	s_alttab_disabled = true;
+}
+
+static void WIN_EnableAltTab( void )
+{
+	if ( s_alttab_disabled )
+	{
+		if ( s_win95 )
+		{
+			BOOL old;
+
+			SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
+		}
+		else
+		{
+			UnregisterHotKey( 0, 0 );
+			UnregisterHotKey( 0, 1 );
+		}
+
+		s_alttab_disabled = false;
+	}
+}
+
+/*
+==========================================================================
+
+DLL GLUE
+
+==========================================================================
+*/
+
+#define	MAXPRINTMSG	4096
+void VID_Printf (int print_level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	if (print_level == PRINT_ALL)
+	{
+		Com_Printf ("%s", msg);
+	}
+	else if ( print_level == PRINT_DEVELOPER )
+	{
+		Com_DPrintf ("%s", msg);
+	}
+	else if ( print_level == PRINT_ALERT )
+	{
+		MessageBox( 0, msg, "PRINT_ALERT", MB_ICONWARNING );
+		OutputDebugString( msg );
+	}
+}
+
+void VID_Error (int err_level, char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	Com_Error (err_level,"%s", msg);
+}
+
+//==========================================================================
+
+byte        scantokey[128] = 
+					{ 
+//  0           1       2       3       4       5       6       7 
+//  8           9       A       B       C       D       E       F 
+	0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6', 
+	'7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0 
+	'q',    'w',    'e',    'r',    't',    'y',    'u',    'i', 
+	'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1 
+	'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';', 
+	'\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2 
+	'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*', 
+	K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3 
+	K_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    0  , K_HOME, 
+	K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4 
+	K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, 
+	K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
+	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
+	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 
+	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
+	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7 
+}; 
+
+/*
+=======
+MapKey
+
+Map from windows to quake keynums
+=======
+*/
+int MapKey (int key)
+{
+	int result;
+	int modified = ( key >> 16 ) & 255;
+	qboolean is_extended = false;
+
+	if ( modified > 127)
+		return 0;
+
+	if ( key & ( 1 << 24 ) )
+		is_extended = true;
+
+	result = scantokey[modified];
+
+	if ( !is_extended )
+	{
+		switch ( result )
+		{
+		case K_HOME:
+			return K_KP_HOME;
+		case K_UPARROW:
+			return K_KP_UPARROW;
+		case K_PGUP:
+			return K_KP_PGUP;
+		case K_LEFTARROW:
+			return K_KP_LEFTARROW;
+		case K_RIGHTARROW:
+			return K_KP_RIGHTARROW;
+		case K_END:
+			return K_KP_END;
+		case K_DOWNARROW:
+			return K_KP_DOWNARROW;
+		case K_PGDN:
+			return K_KP_PGDN;
+		case K_INS:
+			return K_KP_INS;
+		case K_DEL:
+			return K_KP_DEL;
+		default:
+			return result;
+		}
+	}
+	else
+	{
+		switch ( result )
+		{
+		case 0x0D:
+			return K_KP_ENTER;
+		case 0x2F:
+			return K_KP_SLASH;
+		case 0xAF:
+			return K_KP_PLUS;
+		}
+		return result;
+	}
+}
+
+void AppActivate(BOOL fActive, BOOL minimize)
+{
+	Minimized = minimize;
+
+	Key_ClearStates();
+
+	// we don't want to act like we're active if we're minimized
+	if (fActive && !Minimized)
+		ActiveApp = true;
+	else
+		ActiveApp = false;
+
+	// minimize/restore mouse-capture on demand
+	if (!ActiveApp)
+	{
+		IN_Activate (false);
+		CDAudio_Activate (false);
+		S_Activate (false);
+
+		if ( win_noalttab->value )
+		{
+			WIN_EnableAltTab();
+		}
+	}
+	else
+	{
+		IN_Activate (true);
+		CDAudio_Activate (true);
+		S_Activate (true);
+		if ( win_noalttab->value )
+		{
+			WIN_DisableAltTab();
+		}
+	}
+}
+
+/*
+====================
+MainWndProc
+
+main window procedure
+====================
+*/
+LONG WINAPI MainWndProc (
+    HWND    hWnd,
+    UINT    uMsg,
+    WPARAM  wParam,
+    LPARAM  lParam)
+{
+	LONG			lRet = 0;
+
+	if ( uMsg == MSH_MOUSEWHEEL )
+	{
+		if ( ( ( int ) wParam ) > 0 )
+		{
+			Key_Event( K_MWHEELUP, true, sys_msg_time );
+			Key_Event( K_MWHEELUP, false, sys_msg_time );
+		}
+		else
+		{
+			Key_Event( K_MWHEELDOWN, true, sys_msg_time );
+			Key_Event( K_MWHEELDOWN, false, sys_msg_time );
+		}
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+	}
+
+	switch (uMsg)
+	{
+	case WM_MOUSEWHEEL:
+		/*
+		** this chunk of code theoretically only works under NT4 and Win98
+		** since this message doesn't exist under Win95
+		*/
+		if ( ( short ) HIWORD( wParam ) > 0 )
+		{
+			Key_Event( K_MWHEELUP, true, sys_msg_time );
+			Key_Event( K_MWHEELUP, false, sys_msg_time );
+		}
+		else
+		{
+			Key_Event( K_MWHEELDOWN, true, sys_msg_time );
+			Key_Event( K_MWHEELDOWN, false, sys_msg_time );
+		}
+		break;
+
+	case WM_HOTKEY:
+		return 0;
+
+	case WM_CREATE:
+		cl_hwnd = hWnd;
+
+		MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG"); 
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+
+	case WM_PAINT:
+		SCR_DirtyScreen ();	// force entire screen to update next frame
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+
+	case WM_DESTROY:
+		// let sound and input know about this?
+		cl_hwnd = NULL;
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+
+	case WM_ACTIVATE:
+		{
+			int	fActive, fMinimized;
+
+			// KJB: Watch this for problems in fullscreen modes with Alt-tabbing.
+			fActive = LOWORD(wParam);
+			fMinimized = (BOOL) HIWORD(wParam);
+
+			AppActivate( fActive != WA_INACTIVE, fMinimized);
+
+			if ( reflib_active )
+				re.AppActivate( !( fActive == WA_INACTIVE ) );
+		}
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+
+	case WM_MOVE:
+		{
+			int		xPos, yPos;
+			RECT r;
+			int		style;
+
+			if (!vid_fullscreen->value)
+			{
+				xPos = (short) LOWORD(lParam);    // horizontal position 
+				yPos = (short) HIWORD(lParam);    // vertical position 
+
+				r.left   = 0;
+				r.top    = 0;
+				r.right  = 1;
+				r.bottom = 1;
+
+				style = GetWindowLong( hWnd, GWL_STYLE );
+				AdjustWindowRect( &r, style, FALSE );
+
+				Cvar_SetValue( "vid_xpos", xPos + r.left);
+				Cvar_SetValue( "vid_ypos", yPos + r.top);
+				vid_xpos->modified = false;
+				vid_ypos->modified = false;
+				if (ActiveApp)
+					IN_Activate (true);
+			}
+		}
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+
+// this is complicated because Win32 seems to pack multiple mouse events into
+// one update sometimes, so we always check all states and look for events
+	case WM_LBUTTONDOWN:
+	case WM_LBUTTONUP:
+	case WM_RBUTTONDOWN:
+	case WM_RBUTTONUP:
+	case WM_MBUTTONDOWN:
+	case WM_MBUTTONUP:
+	case WM_MOUSEMOVE:
+		{
+			int	temp;
+
+			temp = 0;
+
+			if (wParam & MK_LBUTTON)
+				temp |= 1;
+
+			if (wParam & MK_RBUTTON)
+				temp |= 2;
+
+			if (wParam & MK_MBUTTON)
+				temp |= 4;
+
+			IN_MouseEvent (temp);
+		}
+		break;
+
+	case WM_SYSCOMMAND:
+		if ( wParam == SC_SCREENSAVE )
+			return 0;
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+	case WM_SYSKEYDOWN:
+		if ( wParam == 13 )
+		{
+			if ( vid_fullscreen )
+			{
+				Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value );
+			}
+			return 0;
+		}
+		// fall through
+	case WM_KEYDOWN:
+		Key_Event( MapKey( lParam ), true, sys_msg_time);
+		break;
+
+	case WM_SYSKEYUP:
+	case WM_KEYUP:
+		Key_Event( MapKey( lParam ), false, sys_msg_time);
+		break;
+
+	case MM_MCINOTIFY:
+		{
+			LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+			lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
+		}
+		break;
+
+	default:	// pass all unhandled messages to DefWindowProc
+        return DefWindowProc (hWnd, uMsg, wParam, lParam);
+    }
+
+    /* return 0 if handled message, 1 if not */
+    return DefWindowProc( hWnd, uMsg, wParam, lParam );
+}
+
+/*
+============
+VID_Restart_f
+
+Console command to re-start the video mode and refresh DLL. We do this
+simply by setting the modified flag for the vid_ref variable, which will
+cause the entire video mode and refresh DLL to be reset on the next frame.
+============
+*/
+void VID_Restart_f (void)
+{
+	vid_ref->modified = true;
+}
+
+void VID_Front_f( void )
+{
+	SetWindowLong( cl_hwnd, GWL_EXSTYLE, WS_EX_TOPMOST );
+	SetForegroundWindow( cl_hwnd );
+}
+
+/*
+** VID_GetModeInfo
+*/
+typedef struct vidmode_s
+{
+	const char *description;
+	int         width, height;
+	int         mode;
+} vidmode_t;
+
+vidmode_t vid_modes[] =
+{
+	{ "Mode 0: 320x240",   320, 240,   0 },
+	{ "Mode 1: 400x300",   400, 300,   1 },
+	{ "Mode 2: 512x384",   512, 384,   2 },
+	{ "Mode 3: 640x480",   640, 480,   3 },
+	{ "Mode 4: 800x600",   800, 600,   4 },
+	{ "Mode 5: 960x720",   960, 720,   5 },
+	{ "Mode 6: 1024x768",  1024, 768,  6 },
+	{ "Mode 7: 1152x864",  1152, 864,  7 },
+	{ "Mode 8: 1280x960",  1280, 960, 8 },
+	{ "Mode 9: 1600x1200", 1600, 1200, 9 }
+};
+
+qboolean VID_GetModeInfo( int *width, int *height, int mode )
+{
+	if ( mode < 0 || mode >= VID_NUM_MODES )
+		return false;
+
+	*width  = vid_modes[mode].width;
+	*height = vid_modes[mode].height;
+
+	return true;
+}
+
+/*
+** VID_UpdateWindowPosAndSize
+*/
+void VID_UpdateWindowPosAndSize( int x, int y )
+{
+	RECT r;
+	int		style;
+	int		w, h;
+
+	r.left   = 0;
+	r.top    = 0;
+	r.right  = viddef.width;
+	r.bottom = viddef.height;
+
+	style = GetWindowLong( cl_hwnd, GWL_STYLE );
+	AdjustWindowRect( &r, style, FALSE );
+
+	w = r.right - r.left;
+	h = r.bottom - r.top;
+
+	MoveWindow( cl_hwnd, vid_xpos->value, vid_ypos->value, w, h, TRUE );
+}
+
+/*
+** VID_NewWindow
+*/
+void VID_NewWindow ( int width, int height)
+{
+	viddef.width  = width;
+	viddef.height = height;
+
+	cl.force_refdef = true;		// can't use a paused refdef
+}
+
+void VID_FreeReflib (void)
+{
+	if ( !FreeLibrary( reflib_library ) )
+		Com_Error( ERR_FATAL, "Reflib FreeLibrary failed" );
+	memset (&re, 0, sizeof(re));
+	reflib_library = NULL;
+	reflib_active  = false;
+}
+
+/*
+==============
+VID_LoadRefresh
+==============
+*/
+qboolean VID_LoadRefresh( char *name )
+{
+	refimport_t	ri;
+	GetRefAPI_t	GetRefAPI;
+	
+	if ( reflib_active )
+	{
+		re.Shutdown();
+		VID_FreeReflib ();
+	}
+
+	Com_Printf( "------- Loading %s -------\n", name );
+
+	if ( ( reflib_library = LoadLibrary( name ) ) == 0 )
+	{
+		Com_Printf( "LoadLibrary(\"%s\") failed\n", name );
+
+		return false;
+	}
+
+	ri.Cmd_AddCommand = Cmd_AddCommand;
+	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+	ri.Cmd_Argc = Cmd_Argc;
+	ri.Cmd_Argv = Cmd_Argv;
+	ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+	ri.Con_Printf = VID_Printf;
+	ri.Sys_Error = VID_Error;
+	ri.FS_LoadFile = FS_LoadFile;
+	ri.FS_FreeFile = FS_FreeFile;
+	ri.FS_Gamedir = FS_Gamedir;
+	ri.Cvar_Get = Cvar_Get;
+	ri.Cvar_Set = Cvar_Set;
+	ri.Cvar_SetValue = Cvar_SetValue;
+	ri.Vid_GetModeInfo = VID_GetModeInfo;
+	ri.Vid_MenuInit = VID_MenuInit;
+	ri.Vid_NewWindow = VID_NewWindow;
+
+	if ( ( GetRefAPI = (void *) GetProcAddress( reflib_library, "GetRefAPI" ) ) == 0 )
+		Com_Error( ERR_FATAL, "GetProcAddress failed on %s", name );
+
+	re = GetRefAPI( ri );
+
+	if (re.api_version != API_VERSION)
+	{
+		VID_FreeReflib ();
+		Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
+	}
+
+	if ( re.Init( global_hInstance, MainWndProc ) == -1 )
+	{
+		re.Shutdown();
+		VID_FreeReflib ();
+		return false;
+	}
+
+	Com_Printf( "------------------------------------\n");
+	reflib_active = true;
+
+//======
+//PGM
+	vidref_val = VIDREF_OTHER;
+	if(vid_ref)
+	{
+		if(!strcmp (vid_ref->string, "gl"))
+			vidref_val = VIDREF_GL;
+		else if(!strcmp(vid_ref->string, "soft"))
+			vidref_val = VIDREF_SOFT;
+	}
+//PGM
+//======
+
+	return true;
+}
+
+/*
+============
+VID_CheckChanges
+
+This function gets called once just before drawing each frame, and it's sole purpose in life
+is to check to see if any of the video mode parameters have changed, and if they have to 
+update the rendering DLL and/or video mode to match.
+============
+*/
+void VID_CheckChanges (void)
+{
+	char name[100];
+
+	if ( win_noalttab->modified )
+	{
+		if ( win_noalttab->value )
+		{
+			WIN_DisableAltTab();
+		}
+		else
+		{
+			WIN_EnableAltTab();
+		}
+		win_noalttab->modified = false;
+	}
+
+	if ( vid_ref->modified )
+	{
+		cl.force_refdef = true;		// can't use a paused refdef
+		S_StopAllSounds();
+	}
+	while (vid_ref->modified)
+	{
+		/*
+		** refresh has changed
+		*/
+		vid_ref->modified = false;
+		vid_fullscreen->modified = true;
+		cl.refresh_prepped = false;
+		cls.disable_screen = true;
+
+		Com_sprintf( name, sizeof(name), "ref_%s.dll", vid_ref->string );
+		if ( !VID_LoadRefresh( name ) )
+		{
+			if ( strcmp (vid_ref->string, "soft") == 0 )
+				Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
+			Cvar_Set( "vid_ref", "soft" );
+
+			/*
+			** drop the console if we fail to load a refresh
+			*/
+			if ( cls.key_dest != key_console )
+			{
+				Con_ToggleConsole_f();
+			}
+		}
+		cls.disable_screen = false;
+	}
+
+	/*
+	** update our window position
+	*/
+	if ( vid_xpos->modified || vid_ypos->modified )
+	{
+		if (!vid_fullscreen->value)
+			VID_UpdateWindowPosAndSize( vid_xpos->value, vid_ypos->value );
+
+		vid_xpos->modified = false;
+		vid_ypos->modified = false;
+	}
+}
+
+/*
+============
+VID_Init
+============
+*/
+void VID_Init (void)
+{
+	/* Create the video variables so we know how to start the graphics drivers */
+	vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
+	vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
+	vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
+	vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
+	vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
+	win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
+
+	/* Add some console commands that we want to handle */
+	Cmd_AddCommand ("vid_restart", VID_Restart_f);
+	Cmd_AddCommand ("vid_front", VID_Front_f);
+
+	/*
+	** this is a gross hack but necessary to clamp the mode for 3Dfx
+	*/
+#if 0
+	{
+		cvar_t *gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
+		cvar_t *gl_mode = Cvar_Get( "gl_mode", "3", 0 );
+
+		if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
+		{
+			Cvar_SetValue( "gl_mode", 3 );
+			viddef.width  = 640;
+			viddef.height = 480;
+		}
+	}
+#endif
+
+	/* Disable the 3Dfx splash screen */
+	putenv("FX_GLIDE_NO_SPLASH=0");
+		
+	/* Start the graphics mode and load refresh DLL */
+	VID_CheckChanges();
+}
+
+/*
+============
+VID_Shutdown
+============
+*/
+void VID_Shutdown (void)
+{
+	if ( reflib_active )
+	{
+		re.Shutdown ();
+		VID_FreeReflib ();
+	}
+}
+
+
--- /dev/null
+++ b/win32/vid_menu.c
@@ -1,0 +1,473 @@
+/*
+Copyright (C) 1997-2001 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 "../client/client.h"
+#include "../client/qmenu.h"
+
+#define REF_SOFT	0
+#define REF_OPENGL	1
+#define REF_3DFX	2
+#define REF_POWERVR	3
+#define REF_VERITE	4
+
+extern cvar_t *vid_ref;
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+
+static cvar_t *gl_mode;
+static cvar_t *gl_driver;
+static cvar_t *gl_picmip;
+static cvar_t *gl_ext_palettedtexture;
+static cvar_t *gl_finish;
+
+static cvar_t *sw_mode;
+static cvar_t *sw_stipplealpha;
+
+extern void M_ForceMenuOff( void );
+
+/*
+====================================================================
+
+MENU INTERACTION
+
+====================================================================
+*/
+#define SOFTWARE_MENU 0
+#define OPENGL_MENU   1
+
+static menuframework_s  s_software_menu;
+static menuframework_s	s_opengl_menu;
+static menuframework_s *s_current_menu;
+static int				s_current_menu_index;
+
+static menulist_s		s_mode_list[2];
+static menulist_s		s_ref_list[2];
+static menuslider_s		s_tq_slider;
+static menuslider_s		s_screensize_slider[2];
+static menuslider_s		s_brightness_slider[2];
+static menulist_s  		s_fs_box[2];
+static menulist_s  		s_stipple_box;
+static menulist_s  		s_paletted_texture_box;
+static menulist_s  		s_finish_box;
+static menuaction_s		s_cancel_action[2];
+static menuaction_s		s_defaults_action[2];
+
+static void DriverCallback( void *unused )
+{
+	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+	if ( s_ref_list[s_current_menu_index].curvalue == 0 )
+	{
+		s_current_menu = &s_software_menu;
+		s_current_menu_index = 0;
+	}
+	else
+	{
+		s_current_menu = &s_opengl_menu;
+		s_current_menu_index = 1;
+	}
+
+}
+
+static void ScreenSizeCallback( void *s )
+{
+	menuslider_s *slider = ( menuslider_s * ) s;
+
+	Cvar_SetValue( "viewsize", slider->curvalue * 10 );
+}
+
+static void BrightnessCallback( void *s )
+{
+	menuslider_s *slider = ( menuslider_s * ) s;
+
+	if ( s_current_menu_index == SOFTWARE_MENU )
+		s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
+	else
+		s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
+
+	if ( stricmp( vid_ref->string, "soft" ) == 0 )
+	{
+		float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5;
+
+		Cvar_SetValue( "vid_gamma", gamma );
+	}
+}
+
+static void ResetDefaults( void *unused )
+{
+	VID_MenuInit();
+}
+
+static void ApplyChanges( void *unused )
+{
+	float gamma;
+
+	/*
+	** make values consistent
+	*/
+	s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
+	s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
+	s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+	/*
+	** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+	*/
+	gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5;
+
+	Cvar_SetValue( "vid_gamma", gamma );
+	Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
+	Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
+	Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
+	Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
+	Cvar_SetValue( "gl_finish", s_finish_box.curvalue );
+	Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
+	Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
+
+	switch ( s_ref_list[s_current_menu_index].curvalue )
+	{
+	case REF_SOFT:
+		Cvar_Set( "vid_ref", "soft" );
+		break;
+	case REF_OPENGL:
+		Cvar_Set( "vid_ref", "gl" );
+		Cvar_Set( "gl_driver", "opengl32" );
+		break;
+	case REF_3DFX:
+		Cvar_Set( "vid_ref", "gl" );
+		Cvar_Set( "gl_driver", "3dfxgl" );
+		break;
+	case REF_POWERVR:
+		Cvar_Set( "vid_ref", "gl" );
+		Cvar_Set( "gl_driver", "pvrgl" );
+		break;
+	case REF_VERITE:
+		Cvar_Set( "vid_ref", "gl" );
+		Cvar_Set( "gl_driver", "veritegl" );
+		break;
+	}
+
+	/*
+	** update appropriate stuff if we're running OpenGL and gamma
+	** has been modified
+	*/
+	if ( stricmp( vid_ref->string, "gl" ) == 0 )
+	{
+		if ( vid_gamma->modified )
+		{
+			vid_ref->modified = true;
+			if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
+			{
+				char envbuffer[1024];
+				float g;
+
+				vid_ref->modified = true;
+
+				g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
+				Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g );
+				putenv( envbuffer );
+				Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
+				putenv( envbuffer );
+
+				vid_gamma->modified = false;
+			}
+		}
+
+		if ( gl_driver->modified )
+			vid_ref->modified = true;
+	}
+
+	M_ForceMenuOff();
+}
+
+static void CancelChanges( void *unused )
+{
+	extern void M_PopMenu( void );
+
+	M_PopMenu();
+}
+
+/*
+** VID_MenuInit
+*/
+void VID_MenuInit( void )
+{
+	static const char *resolutions[] = 
+	{
+		"[320 240  ]",
+		"[400 300  ]",
+		"[512 384  ]",
+		"[640 480  ]",
+		"[800 600  ]",
+		"[960 720  ]",
+		"[1024 768 ]",
+		"[1152 864 ]",
+		"[1280 960 ]",
+		"[1600 1200]",
+		0
+	};
+	static const char *refs[] =
+	{
+		"[software      ]",
+		"[default OpenGL]",
+		"[3Dfx OpenGL   ]",
+		"[PowerVR OpenGL]",
+//		"[Rendition OpenGL]",
+		0
+	};
+	static const char *yesno_names[] =
+	{
+		"no",
+		"yes",
+		0
+	};
+	int i;
+
+	if ( !gl_driver )
+		gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
+	if ( !gl_picmip )
+		gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
+	if ( !gl_mode )
+		gl_mode = Cvar_Get( "gl_mode", "3", 0 );
+	if ( !sw_mode )
+		sw_mode = Cvar_Get( "sw_mode", "0", 0 );
+	if ( !gl_ext_palettedtexture )
+		gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
+	if ( !gl_finish )
+		gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE );
+
+	if ( !sw_stipplealpha )
+		sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+
+	s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value;
+	s_mode_list[OPENGL_MENU].curvalue = gl_mode->value;
+
+	if ( !scr_viewsize )
+		scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+
+	s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10;
+	s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10;
+
+	if ( strcmp( vid_ref->string, "soft" ) == 0 )
+	{
+		s_current_menu_index = SOFTWARE_MENU;
+		s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
+	}
+	else if ( strcmp( vid_ref->string, "gl" ) == 0 )
+	{
+		s_current_menu_index = OPENGL_MENU;
+		if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_3DFX;
+		else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_POWERVR;
+		else if ( strcmp( gl_driver->string, "opengl32" ) == 0 )
+			s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+		else
+//			s_ref_list[s_current_menu_index].curvalue = REF_VERITE;
+			s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
+	}
+
+	s_software_menu.x = viddef.width * 0.50;
+	s_software_menu.nitems = 0;
+	s_opengl_menu.x = viddef.width * 0.50;
+	s_opengl_menu.nitems = 0;
+
+	for ( i = 0; i < 2; i++ )
+	{
+		s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
+		s_ref_list[i].generic.name = "driver";
+		s_ref_list[i].generic.x = 0;
+		s_ref_list[i].generic.y = 0;
+		s_ref_list[i].generic.callback = DriverCallback;
+		s_ref_list[i].itemnames = refs;
+
+		s_mode_list[i].generic.type = MTYPE_SPINCONTROL;
+		s_mode_list[i].generic.name = "video mode";
+		s_mode_list[i].generic.x = 0;
+		s_mode_list[i].generic.y = 10;
+		s_mode_list[i].itemnames = resolutions;
+
+		s_screensize_slider[i].generic.type	= MTYPE_SLIDER;
+		s_screensize_slider[i].generic.x		= 0;
+		s_screensize_slider[i].generic.y		= 20;
+		s_screensize_slider[i].generic.name	= "screen size";
+		s_screensize_slider[i].minvalue = 3;
+		s_screensize_slider[i].maxvalue = 12;
+		s_screensize_slider[i].generic.callback = ScreenSizeCallback;
+
+		s_brightness_slider[i].generic.type	= MTYPE_SLIDER;
+		s_brightness_slider[i].generic.x	= 0;
+		s_brightness_slider[i].generic.y	= 30;
+		s_brightness_slider[i].generic.name	= "brightness";
+		s_brightness_slider[i].generic.callback = BrightnessCallback;
+		s_brightness_slider[i].minvalue = 5;
+		s_brightness_slider[i].maxvalue = 13;
+		s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10;
+
+		s_fs_box[i].generic.type = MTYPE_SPINCONTROL;
+		s_fs_box[i].generic.x	= 0;
+		s_fs_box[i].generic.y	= 40;
+		s_fs_box[i].generic.name	= "fullscreen";
+		s_fs_box[i].itemnames = yesno_names;
+		s_fs_box[i].curvalue = vid_fullscreen->value;
+
+		s_defaults_action[i].generic.type = MTYPE_ACTION;
+		s_defaults_action[i].generic.name = "reset to defaults";
+		s_defaults_action[i].generic.x    = 0;
+		s_defaults_action[i].generic.y    = 90;
+		s_defaults_action[i].generic.callback = ResetDefaults;
+
+		s_cancel_action[i].generic.type = MTYPE_ACTION;
+		s_cancel_action[i].generic.name = "cancel";
+		s_cancel_action[i].generic.x    = 0;
+		s_cancel_action[i].generic.y    = 100;
+		s_cancel_action[i].generic.callback = CancelChanges;
+	}
+
+	s_stipple_box.generic.type = MTYPE_SPINCONTROL;
+	s_stipple_box.generic.x	= 0;
+	s_stipple_box.generic.y	= 60;
+	s_stipple_box.generic.name	= "stipple alpha";
+	s_stipple_box.curvalue = sw_stipplealpha->value;
+	s_stipple_box.itemnames = yesno_names;
+
+	s_tq_slider.generic.type	= MTYPE_SLIDER;
+	s_tq_slider.generic.x		= 0;
+	s_tq_slider.generic.y		= 60;
+	s_tq_slider.generic.name	= "texture quality";
+	s_tq_slider.minvalue = 0;
+	s_tq_slider.maxvalue = 3;
+	s_tq_slider.curvalue = 3-gl_picmip->value;
+
+	s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL;
+	s_paletted_texture_box.generic.x	= 0;
+	s_paletted_texture_box.generic.y	= 70;
+	s_paletted_texture_box.generic.name	= "8-bit textures";
+	s_paletted_texture_box.itemnames = yesno_names;
+	s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value;
+
+	s_finish_box.generic.type = MTYPE_SPINCONTROL;
+	s_finish_box.generic.x	= 0;
+	s_finish_box.generic.y	= 80;
+	s_finish_box.generic.name	= "sync every frame";
+	s_finish_box.curvalue = gl_finish->value;
+	s_finish_box.itemnames = yesno_names;
+
+	Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box );
+
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_finish_box );
+
+	Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] );
+	Menu_AddItem( &s_software_menu, ( void * ) &s_cancel_action[SOFTWARE_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] );
+	Menu_AddItem( &s_opengl_menu, ( void * ) &s_cancel_action[OPENGL_MENU] );
+
+	Menu_Center( &s_software_menu );
+	Menu_Center( &s_opengl_menu );
+	s_opengl_menu.x -= 8;
+	s_software_menu.x -= 8;
+}
+
+/*
+================
+VID_MenuDraw
+================
+*/
+void VID_MenuDraw (void)
+{
+	int w, h;
+
+	if ( s_current_menu_index == 0 )
+		s_current_menu = &s_software_menu;
+	else
+		s_current_menu = &s_opengl_menu;
+
+	/*
+	** draw the banner
+	*/
+	re.DrawGetPicSize( &w, &h, "m_banner_video" );
+	re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
+
+	/*
+	** move cursor to a reasonable starting position
+	*/
+	Menu_AdjustCursor( s_current_menu, 1 );
+
+	/*
+	** draw the menu
+	*/
+	Menu_Draw( s_current_menu );
+}
+
+/*
+================
+VID_MenuKey
+================
+*/
+const char *VID_MenuKey( int key )
+{
+	menuframework_s *m = s_current_menu;
+	static const char *sound = "misc/menu1.wav";
+
+	switch ( key )
+	{
+	case K_ESCAPE:
+		ApplyChanges( 0 );
+		return NULL;
+	case K_KP_UPARROW:
+	case K_UPARROW:
+		m->cursor--;
+		Menu_AdjustCursor( m, -1 );
+		break;
+	case K_KP_DOWNARROW:
+	case K_DOWNARROW:
+		m->cursor++;
+		Menu_AdjustCursor( m, 1 );
+		break;
+	case K_KP_LEFTARROW:
+	case K_LEFTARROW:
+		Menu_SlideItem( m, -1 );
+		break;
+	case K_KP_RIGHTARROW:
+	case K_RIGHTARROW:
+		Menu_SlideItem( m, 1 );
+		break;
+	case K_KP_ENTER:
+	case K_ENTER:
+		if ( !Menu_SelectItem( m ) )
+			ApplyChanges( NULL );
+		break;
+	}
+
+	return sound;
+}
+
+
binary files /dev/null b/win32/winquake.aps differ
--- /dev/null
+++ b/win32/winquake.h
@@ -1,0 +1,44 @@
+/*
+Copyright (C) 1997-2001 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.
+
+*/
+// winquake.h: Win32-specific Quake header file
+
+#pragma warning( disable : 4229 )  // mgraph gets this
+
+#include <windows.h>
+
+#include <dsound.h>
+
+#define	WINDOW_STYLE	(WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE)
+
+extern	HINSTANCE	global_hInstance;
+
+extern LPDIRECTSOUND pDS;
+extern LPDIRECTSOUNDBUFFER pDSBuf;
+
+extern DWORD gSndBufSize;
+
+extern HWND			cl_hwnd;
+extern qboolean		ActiveApp, Minimized;
+
+void IN_Activate (qboolean active);
+void IN_MouseEvent (int mstate);
+
+extern int		window_center_x, window_center_y;
+extern RECT		window_rect;
--- /dev/null
+++ b/win32/winquake.rc
@@ -1,0 +1,98 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1               ICON    DISCARDABLE     "q2.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DIALOG1 DIALOGEX 0, 0, 62, 21
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP | 
+    WS_VISIBLE
+EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
+FONT 16, "Times New Roman", 0, 0, 0x1
+BEGIN
+    CTEXT           "Starting QW...",IDC_STATIC,4,6,54,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_STRING1             "WinQuake"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+