ref: 372afde46e7defc9dd2d719a1732b8ace1fa096e
author: Travis Bradshaw <travis.bradshaw@idsoftware.com>
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.
--- /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 <zoid@idsoftware.com>
+#
+# 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"> </td>
+ <td> </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"><]> is
+ used to move to the next menu selection</font></li>
+ <li><font size="2" face="Arial"><[> is
+ used to move to the previous menu
+ selection</font></li>
+ <li><font size="2" face="Arial"><ENTER>
+ is used to make a menu selection</font></li>
+ <li><font size="2" face="Arial"><ESC>
+ will remove the menu (in this case,
+ you'll be left in an "observer"
+ mode and can freely move around the map,
+ but you can not interact with the game)</font></li>
+ <li><font size="2" face="Arial"><TAB>
+ 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> </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> </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
+ <[> and <]> keys to change the player
+ you are trailing (same keys as the menu
+ selection). To get out of Chase Camera mode, hit
+ <TAB> to bring up the menu again and select
+ "Leave Chase Camera."</font></dd>
+ <dt> </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> </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> </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
+ "use grapple"</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> </td>
+ <td><dl>
+ <dt> </dt>
+ </dl>
+ </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> </td>
+ <td> </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> </td>
+ <td> </td>
+ </tr>
+ </table>
+ </center></div><dl>
+ <dd> </dd>
+ <dd> </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 "say_team" or
+ "messagemode2". It is like the regular
+ communication of Quake2, but you need to bind a key in
+ order to use it. I use the <R> key myself, since
+ its right beside the normal <T> key used for
+ communication. To bind it, use the following:</font></p>
+ <p><font face="Arial"><code>bind r
+ "messagemode2"</code></font></p>
+ <p><font face="Arial">When you want to say a message to
+ your team, just hit <R> 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 "say_team Base
+ secure"<br>
+ bind x "say_team Base overrun! Recover"<br>
+ bind c "say_team Incoming!"<br>
+ bind v "say_team I'm going offensive"<br>
+ bind g "say_team Going to base"<br>
+ bind b "say_team At base, defending"</code></font></p>
+ <p><font face="Arial">So when I want to say "At
+ base, defending" to my teammates, I just hit my
+ <B> 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 "auto macros". 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 "say_team I'm %L,
+ %H and %A, and have %T."</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>
+ "near the Red Flag"<br>
+ "above the Red Armor"<br>
+ "near the Blue Railgun"</font></td>
+ </tr>
+ <tr>
+ <td valign="top"> </td>
+ <td> </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>
+ "Power Shield with 100 cells"<br>
+ "50 units of Yellow Armor"<br>
+ "Power Shield with 154 cells and 108 units
+ of Red Armor"<br>
+ "no armor"</font></td>
+ </tr>
+ <tr>
+ <td valign="top"> </td>
+ <td> </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>
+ "106 health"</font></td>
+ </tr>
+ <tr>
+ <td valign="top"> </td>
+ <td> </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>
+ "the Disruptor Shield"<br>
+ "the Power Amplifier"<br>
+ "no powerup"</font></td>
+ </tr>
+ <tr>
+ <td valign="top"> </td>
+ <td> </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>
+ "Railgun"<br>
+ "Rocket Launcher"<br>
+ "Grapple"</font></td>
+ </tr>
+ <tr>
+ <td valign="top"> </td>
+ <td> </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>
+ "Zoid, Disruptor and Hellrot"<br>
+ ">BC>Casey and >BC>Mutha"<br>
+ "no one"</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> </td>
+ <td><font face="Arial">One point</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td valign="top"><font face="Arial">Fragging
+ emery player within your base</font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td valign="top"><font face="Arial">Fragging
+ enemy player within sight of your flag carrier</font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td valign="top"><font face="Arial">Fragging
+ enemy player who has hurt your flag carrier</font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td valign="top"><font face="Arial">Fragging
+ enemy flag carrier</font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td valign="top"><font face="Arial">Returning
+ your flag (after enemy player has lost it)</font></td>
+ <td> </td>
+ <td><font face="Arial">One point.</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </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> </td>
+ <td><font face="Arial">One point.</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </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> </td>
+ <td><font face="Arial">One point.</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td valign="top"><font face="Arial">Capturing the
+ enemy flag (you are the flag carrier)</font></td>
+ <td> </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 "warp <map
+ name>" 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
+ "yes" 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
+ "ghost 22632" 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 "stats" 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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td width="30%"><font color="#00FF40"
+ face="Arial"><strong>Console Command and syntax</strong></font></td>
+ <td> </td>
+ <td><font face="Arial"><strong>Description</strong></font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td nowrap><font color="#00FF40" face="Arial"><code><strong>team {
+ red | blue }</strong></code></font></td>
+ <td> </td>
+ <td><font face="Arial">Switches to the team the
+ player indicates</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>id</strong></code></font></td>
+ <td> </td>
+ <td><font face="Arial">Enables HUD identification
+ of the player you are looking at.</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>yes</strong></code></font></td>
+ <td> </td>
+ <td><font face="Arial">Vote yes on an election.</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>no</strong></code></font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>ready</strong></code></font></td>
+ <td> </td>
+ <td><font face="Arial">Commit to the match in
+ match setup</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>notready</strong></code></font></td>
+ <td> </td>
+ <td><font face="Arial">Cease commitment (will
+ abort match countdown)</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </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> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>admin [
+ </strong></code><code><em><strong>password</strong></em></code><code><strong> ]</strong></code></font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>stats</strong></code></font></td>
+ <td> </td>
+ <td><font face="Arial">Show the statistics of any
+ matches recently completed or in progress.</font></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>warp
+ </strong></code><code><em><strong>level</strong></em></code></font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </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> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>playerlist</strong></code></font></td>
+ <td> </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> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td><font color="#00FF40" face="Arial"><code><strong>observer<br>
+ </strong></code></font></td>
+ <td> </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
+ "admin" at the console and starting an election
+ or by typing the admin password at the console with
+ "admin <password>" 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 "admin" 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 "ready" 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, "map" and
+ "gamemap". Both take a map as a
+ parameter. They differ in CTF in that when a
+ "map" command is used, all player teams
+ are reset (and players must either select or be
+ assigned to new teams), where as the
+ "gamemap" 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 "set competition 3" 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
+ "blue" or "red" 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 "ready" 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
+ "ready" 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 "admin
+ <password>" to gain direct access to
+ the admin menu, assuming the password was
+ correct.<br>
+ For example, "set admin_password bob"
+ in a start up config file for the server would
+ set the password to "bob" and any
+ player could become an admin by typing
+ "admin bob" 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>"q2ctf1 q2ctf2 q2ctf3
+ q2ctf4 q2ctf5"</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> </td>
+ <td bgcolor="#400000"> </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 = ¶site_move_end_fidget;
+}
+
+void parasite_do_fidget (edict_t *self)
+{
+ self->monsterinfo.currentmove = ¶site_move_fidget;
+}
+
+void parasite_refidget (edict_t *self)
+{
+ if (random() <= 0.8)
+ self->monsterinfo.currentmove = ¶site_move_fidget;
+ else
+ self->monsterinfo.currentmove = ¶site_move_end_fidget;
+}
+
+void parasite_idle (edict_t *self)
+{
+ self->monsterinfo.currentmove = ¶site_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 = ¶site_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 = ¶site_move_stand;
+ else
+ self->monsterinfo.currentmove = ¶site_move_start_run;
+}
+
+void parasite_run (edict_t *self)
+{
+ if (self->monsterinfo.aiflags & AI_STAND_GROUND)
+ self->monsterinfo.currentmove = ¶site_move_stand;
+ else
+ self->monsterinfo.currentmove = ¶site_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 = ¶site_move_start_walk;
+}
+
+void parasite_walk (edict_t *self)
+{
+ self->monsterinfo.currentmove = ¶site_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 = ¶site_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 = ¶site_move_break;
+// else
+ self->monsterinfo.currentmove = ¶site_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 = ¶site_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 = ¶site_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 <zoid@idsoftware.com>
+#
+# 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 <zoid@idsoftware.com>
+#
+# 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 = ¤tmodel->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 <zoid@idsoftware.com>
+#
+
+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 <zoid@idsoftware.com>
+#
+# 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 (¤t_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
+