aboutsummaryrefslogtreecommitdiffstats
path: root/code/cgame
diff options
context:
space:
mode:
Diffstat (limited to 'code/cgame')
-rwxr-xr-xcode/cgame/Conscript276
-rwxr-xr-xcode/cgame/cg_consolecmds.c1156
-rwxr-xr-xcode/cgame/cg_draw.c5318
-rwxr-xr-xcode/cgame/cg_drawtools.c1648
-rwxr-xr-xcode/cgame/cg_effects.c1436
-rwxr-xr-xcode/cgame/cg_ents.c2074
-rwxr-xr-xcode/cgame/cg_event.c2410
-rwxr-xr-xcode/cgame/cg_info.c594
-rwxr-xr-xcode/cgame/cg_local.h3338
-rwxr-xr-xcode/cgame/cg_localents.c1772
-rwxr-xr-xcode/cgame/cg_main.c3994
-rwxr-xr-xcode/cgame/cg_marks.c4548
-rwxr-xr-xcode/cgame/cg_newdraw.c3704
-rwxr-xr-xcode/cgame/cg_particles.c4036
-rwxr-xr-xcode/cgame/cg_players.c5238
-rwxr-xr-xcode/cgame/cg_playerstate.c1052
-rwxr-xr-xcode/cgame/cg_predict.c1256
-rwxr-xr-xcode/cgame/cg_public.h476
-rwxr-xr-xcode/cgame/cg_scoreboard.c1068
-rwxr-xr-xcode/cgame/cg_servercmds.c2196
-rwxr-xr-xcode/cgame/cg_snapshot.c806
-rwxr-xr-xcode/cgame/cg_syscalls.asm212
-rwxr-xr-xcode/cgame/cg_syscalls.c890
-rwxr-xr-xcode/cgame/cg_view.c1752
-rwxr-xr-xcode/cgame/cg_weapons.c4554
-rwxr-xr-xcode/cgame/cgame.bat126
-rwxr-xr-xcode/cgame/cgame.def6
-rwxr-xr-xcode/cgame/cgame.plg248
-rwxr-xr-xcode/cgame/cgame.q3asm52
-rwxr-xr-xcode/cgame/cgame.sh72
-rwxr-xr-xcode/cgame/cgame.vcproj2442
-rwxr-xr-xcode/cgame/cgame_ta.bat130
-rwxr-xr-xcode/cgame/cgame_ta.q3asm56
-rwxr-xr-xcode/cgame/cgame_ta.sh76
-rwxr-xr-xcode/cgame/tr_types.h458
35 files changed, 29735 insertions, 29735 deletions
diff --git a/code/cgame/Conscript b/code/cgame/Conscript
index 887a2a1..0cac8ff 100755
--- a/code/cgame/Conscript
+++ b/code/cgame/Conscript
@@ -1,138 +1,138 @@
-# cgame building
-# builds the cgame for vanilla Q3 and TA
-
-# there are slight differences between Q3 and TA build:
-# -DMISSIONPACK
-# TA has cg_newdraw.c and ../ui/ui_shared.c
-# the config is passed in the imported variable TARGET_DIR
-
-# qvm building against native:
-# only native has cg_syscalls.c
-# only qvm has ../game/bg_lib.c
-# qvm uses a custom cg_syscalls.asm with equ stubs
-
-Import qw( BASE_CFLAGS TARGET_DIR INSTALL_DIR NO_VM NO_SO CC CXX LINK );
-
-$env = new cons(
- # the code has the very bad habit of doing things like #include "../ui/ui_shared.h"
- # this seems to confuse the dependency analysis, explicit toplevel includes seem to fix
- CPPPATH => '#cgame:#game:#q3_ui',
- CC => $CC,
- CXX => $CXX,
- LINK => $LINK,
- ENV => { PATH => $ENV{PATH}, HOME => $ENV{HOME} },
- CFLAGS => $BASE_CFLAGS . '-fPIC',
- LDFLAGS => '-shared -ldl -lm'
-);
-
-# for TA, use -DMISSIONPACK
-%ta_env_hash = $env->copy(
- CPPPATH => '#cgame:#game:#ui'
- );
-$ta_env_hash{CFLAGS} = '-DMISSIONPACK ' . $ta_env_hash{CFLAGS};
-$ta_env = new cons(%ta_env_hash);
-
-# qvm building
-# we heavily customize the cons environment
-$vm_env = new cons(
- # the code has the very bad habit of doing things like #include "../ui/ui_shared.h"
- # this seems to confuse the dependency analysis, explicit toplevel includes seem to fix
- CPPPATH => '#cgame:#game:#q3_ui',
- CC => 'q3lcc',
- CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
- SUFOBJ => '.asm',
- LINK => 'q3asm',
- CFLAGS => '-DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g',
- # need to know where to find the compiler tools
- ENV => { PATH => $ENV{PATH} . ":./qvmtools", },
-);
-
-# TA qvm building
-%vm_ta_env_hash = $vm_env->copy(
- CPPPATH => '#cgame:#game:#ui'
- );
-$vm_ta_env_hash{CFLAGS} = '-DMISSIONPACK ' . $vm_ta_env_hash{CFLAGS};
-$vm_ta_env = new cons(%vm_ta_env_hash);
-
-# the file with vmMain function MUST be the first one of the list
-@FILES = qw(
- cg_main.c
- ../game/bg_misc.c
- ../game/bg_pmove.c
- ../game/bg_slidemove.c
- ../game/q_math.c
- ../game/q_shared.c
- cg_consolecmds.c
- cg_draw.c
- cg_drawtools.c
- cg_effects.c
- cg_ents.c
- cg_event.c
- cg_info.c
- cg_localents.c
- cg_marks.c
- cg_players.c
- cg_playerstate.c
- cg_predict.c
- cg_scoreboard.c
- cg_servercmds.c
- cg_snapshot.c
- cg_view.c
- cg_weapons.c
- );
-$FILESREF = \@FILES;
-
-# only in .so
-# (VM uses a custom .asm with equ stubs)
-@SO_FILES = qw(
- cg_syscalls.c
- );
-$SO_FILESREF = \@SO_FILES;
-
-# only for VM
-@VM_FILES = qw(
- ../game/bg_lib.c
- cg_syscalls.asm
- );
-$VM_FILESREF = \@VM_FILES;
-
-# common additionals for TA
-@TA_FILES = qw(
- cg_newdraw.c
- ../ui/ui_shared.c
- );
-$TA_FILESREF = \@TA_FILES;
-
-# FIXME CPU string
-if ($TARGET_DIR eq 'Q3')
-{
- if ($NO_SO eq 0)
- {
- Program $env 'cgamei386.so', @$FILESREF, @$SO_FILESREF;
- Install $env $INSTALL_DIR, 'cgamei386.so';
- }
- if ($NO_VM eq 0)
- {
- Depends $vm_env 'cgame.qvm', '#qvmtools/q3lcc';
- Depends $vm_env 'cgame.qvm', '#qvmtools/q3asm';
- Program $vm_env 'cgame.qvm', @$FILESREF, @$VM_FILESREF;
- Install $vm_env $INSTALL_DIR . '/vm', 'cgame.qvm';
- }
-}
-else
-{
- if ($NO_SO eq 0)
- {
- Program $ta_env 'cgamei386.so',
- @$FILESREF, @$SO_FILESREF, @$TA_FILESREF;
- Install $ta_env $INSTALL_DIR, 'cgamei386.so';
- }
- if ($NO_VM eq 0)
- {
- Depends $vm_env 'cgame.qvm', '#qvmtools/q3lcc';
- Depends $vm_env 'cgame.qvm', '#qvmtools/q3asm';
- Program $vm_ta_env 'cgame.qvm',
- @$FILESREF, @$VM_FILESREF, @$TA_FILESREF;
- Install $vm_ta_env $INSTALL_DIR . '/vm', 'cgame.qvm';
- }
-}
+# cgame building
+# builds the cgame for vanilla Q3 and TA
+
+# there are slight differences between Q3 and TA build:
+# -DMISSIONPACK
+# TA has cg_newdraw.c and ../ui/ui_shared.c
+# the config is passed in the imported variable TARGET_DIR
+
+# qvm building against native:
+# only native has cg_syscalls.c
+# only qvm has ../game/bg_lib.c
+# qvm uses a custom cg_syscalls.asm with equ stubs
+
+Import qw( BASE_CFLAGS TARGET_DIR INSTALL_DIR NO_VM NO_SO CC CXX LINK );
+
+$env = new cons(
+ # the code has the very bad habit of doing things like #include "../ui/ui_shared.h"
+ # this seems to confuse the dependency analysis, explicit toplevel includes seem to fix
+ CPPPATH => '#cgame:#game:#q3_ui',
+ CC => $CC,
+ CXX => $CXX,
+ LINK => $LINK,
+ ENV => { PATH => $ENV{PATH}, HOME => $ENV{HOME} },
+ CFLAGS => $BASE_CFLAGS . '-fPIC',
+ LDFLAGS => '-shared -ldl -lm'
+);
+
+# for TA, use -DMISSIONPACK
+%ta_env_hash = $env->copy(
+ CPPPATH => '#cgame:#game:#ui'
+ );
+$ta_env_hash{CFLAGS} = '-DMISSIONPACK ' . $ta_env_hash{CFLAGS};
+$ta_env = new cons(%ta_env_hash);
+
+# qvm building
+# we heavily customize the cons environment
+$vm_env = new cons(
+ # the code has the very bad habit of doing things like #include "../ui/ui_shared.h"
+ # this seems to confuse the dependency analysis, explicit toplevel includes seem to fix
+ CPPPATH => '#cgame:#game:#q3_ui',
+ CC => 'q3lcc',
+ CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
+ SUFOBJ => '.asm',
+ LINK => 'q3asm',
+ CFLAGS => '-DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g',
+ # need to know where to find the compiler tools
+ ENV => { PATH => $ENV{PATH} . ":./qvmtools", },
+);
+
+# TA qvm building
+%vm_ta_env_hash = $vm_env->copy(
+ CPPPATH => '#cgame:#game:#ui'
+ );
+$vm_ta_env_hash{CFLAGS} = '-DMISSIONPACK ' . $vm_ta_env_hash{CFLAGS};
+$vm_ta_env = new cons(%vm_ta_env_hash);
+
+# the file with vmMain function MUST be the first one of the list
+@FILES = qw(
+ cg_main.c
+ ../game/bg_misc.c
+ ../game/bg_pmove.c
+ ../game/bg_slidemove.c
+ ../game/q_math.c
+ ../game/q_shared.c
+ cg_consolecmds.c
+ cg_draw.c
+ cg_drawtools.c
+ cg_effects.c
+ cg_ents.c
+ cg_event.c
+ cg_info.c
+ cg_localents.c
+ cg_marks.c
+ cg_players.c
+ cg_playerstate.c
+ cg_predict.c
+ cg_scoreboard.c
+ cg_servercmds.c
+ cg_snapshot.c
+ cg_view.c
+ cg_weapons.c
+ );
+$FILESREF = \@FILES;
+
+# only in .so
+# (VM uses a custom .asm with equ stubs)
+@SO_FILES = qw(
+ cg_syscalls.c
+ );
+$SO_FILESREF = \@SO_FILES;
+
+# only for VM
+@VM_FILES = qw(
+ ../game/bg_lib.c
+ cg_syscalls.asm
+ );
+$VM_FILESREF = \@VM_FILES;
+
+# common additionals for TA
+@TA_FILES = qw(
+ cg_newdraw.c
+ ../ui/ui_shared.c
+ );
+$TA_FILESREF = \@TA_FILES;
+
+# FIXME CPU string
+if ($TARGET_DIR eq 'Q3')
+{
+ if ($NO_SO eq 0)
+ {
+ Program $env 'cgamei386.so', @$FILESREF, @$SO_FILESREF;
+ Install $env $INSTALL_DIR, 'cgamei386.so';
+ }
+ if ($NO_VM eq 0)
+ {
+ Depends $vm_env 'cgame.qvm', '#qvmtools/q3lcc';
+ Depends $vm_env 'cgame.qvm', '#qvmtools/q3asm';
+ Program $vm_env 'cgame.qvm', @$FILESREF, @$VM_FILESREF;
+ Install $vm_env $INSTALL_DIR . '/vm', 'cgame.qvm';
+ }
+}
+else
+{
+ if ($NO_SO eq 0)
+ {
+ Program $ta_env 'cgamei386.so',
+ @$FILESREF, @$SO_FILESREF, @$TA_FILESREF;
+ Install $ta_env $INSTALL_DIR, 'cgamei386.so';
+ }
+ if ($NO_VM eq 0)
+ {
+ Depends $vm_env 'cgame.qvm', '#qvmtools/q3lcc';
+ Depends $vm_env 'cgame.qvm', '#qvmtools/q3asm';
+ Program $vm_ta_env 'cgame.qvm',
+ @$FILESREF, @$VM_FILESREF, @$TA_FILESREF;
+ Install $vm_ta_env $INSTALL_DIR . '/vm', 'cgame.qvm';
+ }
+}
diff --git a/code/cgame/cg_consolecmds.c b/code/cgame/cg_consolecmds.c
index 6f13a22..584ebd4 100755
--- a/code/cgame/cg_consolecmds.c
+++ b/code/cgame/cg_consolecmds.c
@@ -1,578 +1,578 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_consolecmds.c -- text commands typed in at the local console, or
-// executed by a key binding
-
-#include "cg_local.h"
-#include "../ui/ui_shared.h"
-#ifdef MISSIONPACK
-extern menuDef_t *menuScoreboard;
-#endif
-
-
-
-void CG_TargetCommand_f( void ) {
- int targetNum;
- char test[4];
-
- targetNum = CG_CrosshairPlayer();
- if (!targetNum ) {
- return;
- }
-
- trap_Argv( 1, test, 4 );
- trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
-}
-
-
-
-/*
-=================
-CG_SizeUp_f
-
-Keybinding command
-=================
-*/
-static void CG_SizeUp_f (void) {
- trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer+10)));
-}
-
-
-/*
-=================
-CG_SizeDown_f
-
-Keybinding command
-=================
-*/
-static void CG_SizeDown_f (void) {
- trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer-10)));
-}
-
-
-/*
-=============
-CG_Viewpos_f
-
-Debugging command to print the current position
-=============
-*/
-static void CG_Viewpos_f (void) {
- CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
- (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
- (int)cg.refdefViewAngles[YAW]);
-}
-
-
-static void CG_ScoresDown_f( void ) {
-
-#ifdef MISSIONPACK
- CG_BuildSpectatorString();
-#endif
- if ( cg.scoresRequestTime + 2000 < cg.time ) {
- // the scores are more than two seconds out of data,
- // so request new ones
- cg.scoresRequestTime = cg.time;
- trap_SendClientCommand( "score" );
-
- // leave the current scores up if they were already
- // displayed, but if this is the first hit, clear them out
- if ( !cg.showScores ) {
- cg.showScores = qtrue;
- cg.numScores = 0;
- }
- } else {
- // show the cached contents even if they just pressed if it
- // is within two seconds
- cg.showScores = qtrue;
- }
-}
-
-static void CG_ScoresUp_f( void ) {
- if ( cg.showScores ) {
- cg.showScores = qfalse;
- cg.scoreFadeTime = cg.time;
- }
-}
-
-#ifdef MISSIONPACK
-extern menuDef_t *menuScoreboard;
-void Menu_Reset(); // FIXME: add to right include file
-
-static void CG_LoadHud_f( void) {
- char buff[1024];
- const char *hudSet;
- memset(buff, 0, sizeof(buff));
-
- String_Init();
- Menu_Reset();
-
- trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
- hudSet = buff;
- if (hudSet[0] == '\0') {
- hudSet = "ui/hud.txt";
- }
-
- CG_LoadMenus(hudSet);
- menuScoreboard = NULL;
-}
-
-
-static void CG_scrollScoresDown_f( void) {
- if (menuScoreboard && cg.scoreBoardShowing) {
- Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
- }
-}
-
-
-static void CG_scrollScoresUp_f( void) {
- if (menuScoreboard && cg.scoreBoardShowing) {
- Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
- Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
- }
-}
-
-
-static void CG_spWin_f( void) {
- trap_Cvar_Set("cg_cameraOrbit", "2");
- trap_Cvar_Set("cg_cameraOrbitDelay", "35");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- CG_AddBufferedSound(cgs.media.winnerSound);
- //trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER);
- CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0);
-}
-
-static void CG_spLose_f( void) {
- trap_Cvar_Set("cg_cameraOrbit", "2");
- trap_Cvar_Set("cg_cameraOrbitDelay", "35");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- CG_AddBufferedSound(cgs.media.loserSound);
- //trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER);
- CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0);
-}
-
-#endif
-
-static void CG_TellTarget_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_TellAttacker_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_LastAttacker();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "tell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_VoiceTellTarget_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-static void CG_VoiceTellAttacker_f( void ) {
- int clientNum;
- char command[128];
- char message[128];
-
- clientNum = CG_LastAttacker();
- if ( clientNum == -1 ) {
- return;
- }
-
- trap_Args( message, 128 );
- Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
- trap_SendClientCommand( command );
-}
-
-#ifdef MISSIONPACK
-static void CG_NextTeamMember_f( void ) {
- CG_SelectNextPlayer();
-}
-
-static void CG_PrevTeamMember_f( void ) {
- CG_SelectPrevPlayer();
-}
-
-// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last
-//
-static void CG_NextOrder_f( void ) {
- clientInfo_t *ci = cgs.clientinfo + cg.snap->ps.clientNum;
- if (ci) {
- if (!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum) {
- return;
- }
- }
- if (cgs.currentOrder < TEAMTASK_CAMP) {
- cgs.currentOrder++;
-
- if (cgs.currentOrder == TEAMTASK_RETRIEVE) {
- if (!CG_OtherTeamHasFlag()) {
- cgs.currentOrder++;
- }
- }
-
- if (cgs.currentOrder == TEAMTASK_ESCORT) {
- if (!CG_YourTeamHasFlag()) {
- cgs.currentOrder++;
- }
- }
-
- } else {
- cgs.currentOrder = TEAMTASK_OFFENSE;
- }
- cgs.orderPending = qtrue;
- cgs.orderTime = cg.time + 3000;
-}
-
-
-static void CG_ConfirmOrder_f (void ) {
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES));
- trap_SendConsoleCommand("+button5; wait; -button5");
- if (cg.time < cgs.acceptOrderTime) {
- trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask));
- cgs.acceptOrderTime = 0;
- }
-}
-
-static void CG_DenyOrder_f (void ) {
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO));
- trap_SendConsoleCommand("+button6; wait; -button6");
- if (cg.time < cgs.acceptOrderTime) {
- cgs.acceptOrderTime = 0;
- }
-}
-
-static void CG_TaskOffense_f (void ) {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG));
- } else {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE));
- }
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE));
-}
-
-static void CG_TaskDefense_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE));
-}
-
-static void CG_TaskPatrol_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL));
-}
-
-static void CG_TaskCamp_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP));
-}
-
-static void CG_TaskFollow_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW));
-}
-
-static void CG_TaskRetrieve_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE));
-}
-
-static void CG_TaskEscort_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER));
- trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT));
-}
-
-static void CG_TaskOwnFlag_f (void ) {
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG));
-}
-
-static void CG_TauntKillInsult_f (void ) {
- trap_SendConsoleCommand("cmd vsay kill_insult\n");
-}
-
-static void CG_TauntPraise_f (void ) {
- trap_SendConsoleCommand("cmd vsay praise\n");
-}
-
-static void CG_TauntTaunt_f (void ) {
- trap_SendConsoleCommand("cmd vtaunt\n");
-}
-
-static void CG_TauntDeathInsult_f (void ) {
- trap_SendConsoleCommand("cmd vsay death_insult\n");
-}
-
-static void CG_TauntGauntlet_f (void ) {
- trap_SendConsoleCommand("cmd vsay kill_guantlet\n");
-}
-
-static void CG_TaskSuicide_f (void ) {
- int clientNum;
- char command[128];
-
- clientNum = CG_CrosshairPlayer();
- if ( clientNum == -1 ) {
- return;
- }
-
- Com_sprintf( command, 128, "tell %i suicide", clientNum );
- trap_SendClientCommand( command );
-}
-
-
-
-/*
-==================
-CG_TeamMenu_f
-==================
-*/
-/*
-static void CG_TeamMenu_f( void ) {
- if (trap_Key_GetCatcher() & KEYCATCH_CGAME) {
- CG_EventHandling(CGAME_EVENT_NONE);
- trap_Key_SetCatcher(0);
- } else {
- CG_EventHandling(CGAME_EVENT_TEAMMENU);
- //trap_Key_SetCatcher(KEYCATCH_CGAME);
- }
-}
-*/
-
-/*
-==================
-CG_EditHud_f
-==================
-*/
-/*
-static void CG_EditHud_f( void ) {
- //cls.keyCatchers ^= KEYCATCH_CGAME;
- //VM_Call (cgvm, CG_EVENT_HANDLING, (cls.keyCatchers & KEYCATCH_CGAME) ? CGAME_EVENT_EDITHUD : CGAME_EVENT_NONE);
-}
-*/
-
-#endif
-
-/*
-==================
-CG_StartOrbit_f
-==================
-*/
-
-static void CG_StartOrbit_f( void ) {
- char var[MAX_TOKEN_CHARS];
-
- trap_Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
- if ( !atoi(var) ) {
- return;
- }
- if (cg_cameraOrbit.value != 0) {
- trap_Cvar_Set ("cg_cameraOrbit", "0");
- trap_Cvar_Set("cg_thirdPerson", "0");
- } else {
- trap_Cvar_Set("cg_cameraOrbit", "5");
- trap_Cvar_Set("cg_thirdPerson", "1");
- trap_Cvar_Set("cg_thirdPersonAngle", "0");
- trap_Cvar_Set("cg_thirdPersonRange", "100");
- }
-}
-
-/*
-static void CG_Camera_f( void ) {
- char name[1024];
- trap_Argv( 1, name, sizeof(name));
- if (trap_loadCamera(name)) {
- cg.cameraMode = qtrue;
- trap_startCamera(cg.time);
- } else {
- CG_Printf ("Unable to load camera %s\n",name);
- }
-}
-*/
-
-
-typedef struct {
- char *cmd;
- void (*function)(void);
-} consoleCommand_t;
-
-static consoleCommand_t commands[] = {
- { "testgun", CG_TestGun_f },
- { "testmodel", CG_TestModel_f },
- { "nextframe", CG_TestModelNextFrame_f },
- { "prevframe", CG_TestModelPrevFrame_f },
- { "nextskin", CG_TestModelNextSkin_f },
- { "prevskin", CG_TestModelPrevSkin_f },
- { "viewpos", CG_Viewpos_f },
- { "+scores", CG_ScoresDown_f },
- { "-scores", CG_ScoresUp_f },
- { "+zoom", CG_ZoomDown_f },
- { "-zoom", CG_ZoomUp_f },
- { "sizeup", CG_SizeUp_f },
- { "sizedown", CG_SizeDown_f },
- { "weapnext", CG_NextWeapon_f },
- { "weapprev", CG_PrevWeapon_f },
- { "weapon", CG_Weapon_f },
- { "tell_target", CG_TellTarget_f },
- { "tell_attacker", CG_TellAttacker_f },
- { "vtell_target", CG_VoiceTellTarget_f },
- { "vtell_attacker", CG_VoiceTellAttacker_f },
- { "tcmd", CG_TargetCommand_f },
-#ifdef MISSIONPACK
- { "loadhud", CG_LoadHud_f },
- { "nextTeamMember", CG_NextTeamMember_f },
- { "prevTeamMember", CG_PrevTeamMember_f },
- { "nextOrder", CG_NextOrder_f },
- { "confirmOrder", CG_ConfirmOrder_f },
- { "denyOrder", CG_DenyOrder_f },
- { "taskOffense", CG_TaskOffense_f },
- { "taskDefense", CG_TaskDefense_f },
- { "taskPatrol", CG_TaskPatrol_f },
- { "taskCamp", CG_TaskCamp_f },
- { "taskFollow", CG_TaskFollow_f },
- { "taskRetrieve", CG_TaskRetrieve_f },
- { "taskEscort", CG_TaskEscort_f },
- { "taskSuicide", CG_TaskSuicide_f },
- { "taskOwnFlag", CG_TaskOwnFlag_f },
- { "tauntKillInsult", CG_TauntKillInsult_f },
- { "tauntPraise", CG_TauntPraise_f },
- { "tauntTaunt", CG_TauntTaunt_f },
- { "tauntDeathInsult", CG_TauntDeathInsult_f },
- { "tauntGauntlet", CG_TauntGauntlet_f },
- { "spWin", CG_spWin_f },
- { "spLose", CG_spLose_f },
- { "scoresDown", CG_scrollScoresDown_f },
- { "scoresUp", CG_scrollScoresUp_f },
-#endif
- { "startOrbit", CG_StartOrbit_f },
- //{ "camera", CG_Camera_f },
- { "loaddeferred", CG_LoadDeferredPlayers }
-};
-
-
-/*
-=================
-CG_ConsoleCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
-=================
-*/
-qboolean CG_ConsoleCommand( void ) {
- const char *cmd;
- int i;
-
- cmd = CG_Argv(0);
-
- for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
- if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
- commands[i].function();
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-/*
-=================
-CG_InitConsoleCommands
-
-Let the client system know about all of our commands
-so it can perform tab completion
-=================
-*/
-void CG_InitConsoleCommands( void ) {
- int i;
-
- for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
- trap_AddCommand( commands[i].cmd );
- }
-
- //
- // the game server will interpret these commands, which will be automatically
- // forwarded to the server after they are not recognized locally
- //
- trap_AddCommand ("kill");
- trap_AddCommand ("say");
- trap_AddCommand ("say_team");
- trap_AddCommand ("tell");
- trap_AddCommand ("vsay");
- trap_AddCommand ("vsay_team");
- trap_AddCommand ("vtell");
- trap_AddCommand ("vtaunt");
- trap_AddCommand ("vosay");
- trap_AddCommand ("vosay_team");
- trap_AddCommand ("votell");
- trap_AddCommand ("give");
- trap_AddCommand ("god");
- trap_AddCommand ("notarget");
- trap_AddCommand ("noclip");
- trap_AddCommand ("team");
- trap_AddCommand ("follow");
- trap_AddCommand ("levelshot");
- trap_AddCommand ("addbot");
- trap_AddCommand ("setviewpos");
- trap_AddCommand ("callvote");
- trap_AddCommand ("vote");
- trap_AddCommand ("callteamvote");
- trap_AddCommand ("teamvote");
- trap_AddCommand ("stats");
- trap_AddCommand ("teamtask");
- trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_consolecmds.c -- text commands typed in at the local console, or
+// executed by a key binding
+
+#include "cg_local.h"
+#include "../ui/ui_shared.h"
+#ifdef MISSIONPACK
+extern menuDef_t *menuScoreboard;
+#endif
+
+
+
+void CG_TargetCommand_f( void ) {
+ int targetNum;
+ char test[4];
+
+ targetNum = CG_CrosshairPlayer();
+ if (!targetNum ) {
+ return;
+ }
+
+ trap_Argv( 1, test, 4 );
+ trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
+}
+
+
+
+/*
+=================
+CG_SizeUp_f
+
+Keybinding command
+=================
+*/
+static void CG_SizeUp_f (void) {
+ trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer+10)));
+}
+
+
+/*
+=================
+CG_SizeDown_f
+
+Keybinding command
+=================
+*/
+static void CG_SizeDown_f (void) {
+ trap_Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize.integer-10)));
+}
+
+
+/*
+=============
+CG_Viewpos_f
+
+Debugging command to print the current position
+=============
+*/
+static void CG_Viewpos_f (void) {
+ CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
+ (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
+ (int)cg.refdefViewAngles[YAW]);
+}
+
+
+static void CG_ScoresDown_f( void ) {
+
+#ifdef MISSIONPACK
+ CG_BuildSpectatorString();
+#endif
+ if ( cg.scoresRequestTime + 2000 < cg.time ) {
+ // the scores are more than two seconds out of data,
+ // so request new ones
+ cg.scoresRequestTime = cg.time;
+ trap_SendClientCommand( "score" );
+
+ // leave the current scores up if they were already
+ // displayed, but if this is the first hit, clear them out
+ if ( !cg.showScores ) {
+ cg.showScores = qtrue;
+ cg.numScores = 0;
+ }
+ } else {
+ // show the cached contents even if they just pressed if it
+ // is within two seconds
+ cg.showScores = qtrue;
+ }
+}
+
+static void CG_ScoresUp_f( void ) {
+ if ( cg.showScores ) {
+ cg.showScores = qfalse;
+ cg.scoreFadeTime = cg.time;
+ }
+}
+
+#ifdef MISSIONPACK
+extern menuDef_t *menuScoreboard;
+void Menu_Reset(); // FIXME: add to right include file
+
+static void CG_LoadHud_f( void) {
+ char buff[1024];
+ const char *hudSet;
+ memset(buff, 0, sizeof(buff));
+
+ String_Init();
+ Menu_Reset();
+
+ trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
+ hudSet = buff;
+ if (hudSet[0] == '\0') {
+ hudSet = "ui/hud.txt";
+ }
+
+ CG_LoadMenus(hudSet);
+ menuScoreboard = NULL;
+}
+
+
+static void CG_scrollScoresDown_f( void) {
+ if (menuScoreboard && cg.scoreBoardShowing) {
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
+ }
+}
+
+
+static void CG_scrollScoresUp_f( void) {
+ if (menuScoreboard && cg.scoreBoardShowing) {
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
+ Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
+ }
+}
+
+
+static void CG_spWin_f( void) {
+ trap_Cvar_Set("cg_cameraOrbit", "2");
+ trap_Cvar_Set("cg_cameraOrbitDelay", "35");
+ trap_Cvar_Set("cg_thirdPerson", "1");
+ trap_Cvar_Set("cg_thirdPersonAngle", "0");
+ trap_Cvar_Set("cg_thirdPersonRange", "100");
+ CG_AddBufferedSound(cgs.media.winnerSound);
+ //trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER);
+ CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0);
+}
+
+static void CG_spLose_f( void) {
+ trap_Cvar_Set("cg_cameraOrbit", "2");
+ trap_Cvar_Set("cg_cameraOrbitDelay", "35");
+ trap_Cvar_Set("cg_thirdPerson", "1");
+ trap_Cvar_Set("cg_thirdPersonAngle", "0");
+ trap_Cvar_Set("cg_thirdPersonRange", "100");
+ CG_AddBufferedSound(cgs.media.loserSound);
+ //trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER);
+ CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0);
+}
+
+#endif
+
+static void CG_TellTarget_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_CrosshairPlayer();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "tell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+static void CG_TellAttacker_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_LastAttacker();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "tell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+static void CG_VoiceTellTarget_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_CrosshairPlayer();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+static void CG_VoiceTellAttacker_f( void ) {
+ int clientNum;
+ char command[128];
+ char message[128];
+
+ clientNum = CG_LastAttacker();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ trap_Args( message, 128 );
+ Com_sprintf( command, 128, "vtell %i %s", clientNum, message );
+ trap_SendClientCommand( command );
+}
+
+#ifdef MISSIONPACK
+static void CG_NextTeamMember_f( void ) {
+ CG_SelectNextPlayer();
+}
+
+static void CG_PrevTeamMember_f( void ) {
+ CG_SelectPrevPlayer();
+}
+
+// ASS U ME's enumeration order as far as task specific orders, OFFENSE is zero, CAMP is last
+//
+static void CG_NextOrder_f( void ) {
+ clientInfo_t *ci = cgs.clientinfo + cg.snap->ps.clientNum;
+ if (ci) {
+ if (!ci->teamLeader && sortedTeamPlayers[cg_currentSelectedPlayer.integer] != cg.snap->ps.clientNum) {
+ return;
+ }
+ }
+ if (cgs.currentOrder < TEAMTASK_CAMP) {
+ cgs.currentOrder++;
+
+ if (cgs.currentOrder == TEAMTASK_RETRIEVE) {
+ if (!CG_OtherTeamHasFlag()) {
+ cgs.currentOrder++;
+ }
+ }
+
+ if (cgs.currentOrder == TEAMTASK_ESCORT) {
+ if (!CG_YourTeamHasFlag()) {
+ cgs.currentOrder++;
+ }
+ }
+
+ } else {
+ cgs.currentOrder = TEAMTASK_OFFENSE;
+ }
+ cgs.orderPending = qtrue;
+ cgs.orderTime = cg.time + 3000;
+}
+
+
+static void CG_ConfirmOrder_f (void ) {
+ trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_YES));
+ trap_SendConsoleCommand("+button5; wait; -button5");
+ if (cg.time < cgs.acceptOrderTime) {
+ trap_SendClientCommand(va("teamtask %d\n", cgs.acceptTask));
+ cgs.acceptOrderTime = 0;
+ }
+}
+
+static void CG_DenyOrder_f (void ) {
+ trap_SendConsoleCommand(va("cmd vtell %d %s\n", cgs.acceptLeader, VOICECHAT_NO));
+ trap_SendConsoleCommand("+button6; wait; -button6");
+ if (cg.time < cgs.acceptOrderTime) {
+ cgs.acceptOrderTime = 0;
+ }
+}
+
+static void CG_TaskOffense_f (void ) {
+ if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONGETFLAG));
+ } else {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONOFFENSE));
+ }
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_OFFENSE));
+}
+
+static void CG_TaskDefense_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONDEFENSE));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_DEFENSE));
+}
+
+static void CG_TaskPatrol_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONPATROL));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_PATROL));
+}
+
+static void CG_TaskCamp_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONCAMPING));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_CAMP));
+}
+
+static void CG_TaskFollow_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOW));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_FOLLOW));
+}
+
+static void CG_TaskRetrieve_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONRETURNFLAG));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_RETRIEVE));
+}
+
+static void CG_TaskEscort_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_ONFOLLOWCARRIER));
+ trap_SendClientCommand(va("teamtask %d\n", TEAMTASK_ESCORT));
+}
+
+static void CG_TaskOwnFlag_f (void ) {
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", VOICECHAT_IHAVEFLAG));
+}
+
+static void CG_TauntKillInsult_f (void ) {
+ trap_SendConsoleCommand("cmd vsay kill_insult\n");
+}
+
+static void CG_TauntPraise_f (void ) {
+ trap_SendConsoleCommand("cmd vsay praise\n");
+}
+
+static void CG_TauntTaunt_f (void ) {
+ trap_SendConsoleCommand("cmd vtaunt\n");
+}
+
+static void CG_TauntDeathInsult_f (void ) {
+ trap_SendConsoleCommand("cmd vsay death_insult\n");
+}
+
+static void CG_TauntGauntlet_f (void ) {
+ trap_SendConsoleCommand("cmd vsay kill_guantlet\n");
+}
+
+static void CG_TaskSuicide_f (void ) {
+ int clientNum;
+ char command[128];
+
+ clientNum = CG_CrosshairPlayer();
+ if ( clientNum == -1 ) {
+ return;
+ }
+
+ Com_sprintf( command, 128, "tell %i suicide", clientNum );
+ trap_SendClientCommand( command );
+}
+
+
+
+/*
+==================
+CG_TeamMenu_f
+==================
+*/
+/*
+static void CG_TeamMenu_f( void ) {
+ if (trap_Key_GetCatcher() & KEYCATCH_CGAME) {
+ CG_EventHandling(CGAME_EVENT_NONE);
+ trap_Key_SetCatcher(0);
+ } else {
+ CG_EventHandling(CGAME_EVENT_TEAMMENU);
+ //trap_Key_SetCatcher(KEYCATCH_CGAME);
+ }
+}
+*/
+
+/*
+==================
+CG_EditHud_f
+==================
+*/
+/*
+static void CG_EditHud_f( void ) {
+ //cls.keyCatchers ^= KEYCATCH_CGAME;
+ //VM_Call (cgvm, CG_EVENT_HANDLING, (cls.keyCatchers & KEYCATCH_CGAME) ? CGAME_EVENT_EDITHUD : CGAME_EVENT_NONE);
+}
+*/
+
+#endif
+
+/*
+==================
+CG_StartOrbit_f
+==================
+*/
+
+static void CG_StartOrbit_f( void ) {
+ char var[MAX_TOKEN_CHARS];
+
+ trap_Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
+ if ( !atoi(var) ) {
+ return;
+ }
+ if (cg_cameraOrbit.value != 0) {
+ trap_Cvar_Set ("cg_cameraOrbit", "0");
+ trap_Cvar_Set("cg_thirdPerson", "0");
+ } else {
+ trap_Cvar_Set("cg_cameraOrbit", "5");
+ trap_Cvar_Set("cg_thirdPerson", "1");
+ trap_Cvar_Set("cg_thirdPersonAngle", "0");
+ trap_Cvar_Set("cg_thirdPersonRange", "100");
+ }
+}
+
+/*
+static void CG_Camera_f( void ) {
+ char name[1024];
+ trap_Argv( 1, name, sizeof(name));
+ if (trap_loadCamera(name)) {
+ cg.cameraMode = qtrue;
+ trap_startCamera(cg.time);
+ } else {
+ CG_Printf ("Unable to load camera %s\n",name);
+ }
+}
+*/
+
+
+typedef struct {
+ char *cmd;
+ void (*function)(void);
+} consoleCommand_t;
+
+static consoleCommand_t commands[] = {
+ { "testgun", CG_TestGun_f },
+ { "testmodel", CG_TestModel_f },
+ { "nextframe", CG_TestModelNextFrame_f },
+ { "prevframe", CG_TestModelPrevFrame_f },
+ { "nextskin", CG_TestModelNextSkin_f },
+ { "prevskin", CG_TestModelPrevSkin_f },
+ { "viewpos", CG_Viewpos_f },
+ { "+scores", CG_ScoresDown_f },
+ { "-scores", CG_ScoresUp_f },
+ { "+zoom", CG_ZoomDown_f },
+ { "-zoom", CG_ZoomUp_f },
+ { "sizeup", CG_SizeUp_f },
+ { "sizedown", CG_SizeDown_f },
+ { "weapnext", CG_NextWeapon_f },
+ { "weapprev", CG_PrevWeapon_f },
+ { "weapon", CG_Weapon_f },
+ { "tell_target", CG_TellTarget_f },
+ { "tell_attacker", CG_TellAttacker_f },
+ { "vtell_target", CG_VoiceTellTarget_f },
+ { "vtell_attacker", CG_VoiceTellAttacker_f },
+ { "tcmd", CG_TargetCommand_f },
+#ifdef MISSIONPACK
+ { "loadhud", CG_LoadHud_f },
+ { "nextTeamMember", CG_NextTeamMember_f },
+ { "prevTeamMember", CG_PrevTeamMember_f },
+ { "nextOrder", CG_NextOrder_f },
+ { "confirmOrder", CG_ConfirmOrder_f },
+ { "denyOrder", CG_DenyOrder_f },
+ { "taskOffense", CG_TaskOffense_f },
+ { "taskDefense", CG_TaskDefense_f },
+ { "taskPatrol", CG_TaskPatrol_f },
+ { "taskCamp", CG_TaskCamp_f },
+ { "taskFollow", CG_TaskFollow_f },
+ { "taskRetrieve", CG_TaskRetrieve_f },
+ { "taskEscort", CG_TaskEscort_f },
+ { "taskSuicide", CG_TaskSuicide_f },
+ { "taskOwnFlag", CG_TaskOwnFlag_f },
+ { "tauntKillInsult", CG_TauntKillInsult_f },
+ { "tauntPraise", CG_TauntPraise_f },
+ { "tauntTaunt", CG_TauntTaunt_f },
+ { "tauntDeathInsult", CG_TauntDeathInsult_f },
+ { "tauntGauntlet", CG_TauntGauntlet_f },
+ { "spWin", CG_spWin_f },
+ { "spLose", CG_spLose_f },
+ { "scoresDown", CG_scrollScoresDown_f },
+ { "scoresUp", CG_scrollScoresUp_f },
+#endif
+ { "startOrbit", CG_StartOrbit_f },
+ //{ "camera", CG_Camera_f },
+ { "loaddeferred", CG_LoadDeferredPlayers }
+};
+
+
+/*
+=================
+CG_ConsoleCommand
+
+The string has been tokenized and can be retrieved with
+Cmd_Argc() / Cmd_Argv()
+=================
+*/
+qboolean CG_ConsoleCommand( void ) {
+ const char *cmd;
+ int i;
+
+ cmd = CG_Argv(0);
+
+ for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
+ if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
+ commands[i].function();
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+
+/*
+=================
+CG_InitConsoleCommands
+
+Let the client system know about all of our commands
+so it can perform tab completion
+=================
+*/
+void CG_InitConsoleCommands( void ) {
+ int i;
+
+ for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
+ trap_AddCommand( commands[i].cmd );
+ }
+
+ //
+ // the game server will interpret these commands, which will be automatically
+ // forwarded to the server after they are not recognized locally
+ //
+ trap_AddCommand ("kill");
+ trap_AddCommand ("say");
+ trap_AddCommand ("say_team");
+ trap_AddCommand ("tell");
+ trap_AddCommand ("vsay");
+ trap_AddCommand ("vsay_team");
+ trap_AddCommand ("vtell");
+ trap_AddCommand ("vtaunt");
+ trap_AddCommand ("vosay");
+ trap_AddCommand ("vosay_team");
+ trap_AddCommand ("votell");
+ trap_AddCommand ("give");
+ trap_AddCommand ("god");
+ trap_AddCommand ("notarget");
+ trap_AddCommand ("noclip");
+ trap_AddCommand ("team");
+ trap_AddCommand ("follow");
+ trap_AddCommand ("levelshot");
+ trap_AddCommand ("addbot");
+ trap_AddCommand ("setviewpos");
+ trap_AddCommand ("callvote");
+ trap_AddCommand ("vote");
+ trap_AddCommand ("callteamvote");
+ trap_AddCommand ("teamvote");
+ trap_AddCommand ("stats");
+ trap_AddCommand ("teamtask");
+ trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo
+}
diff --git a/code/cgame/cg_draw.c b/code/cgame/cg_draw.c
index e29c10f..5575aaf 100755
--- a/code/cgame/cg_draw.c
+++ b/code/cgame/cg_draw.c
@@ -1,2659 +1,2659 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_draw.c -- draw all of the graphical elements during
-// active (after loading) gameplay
-
-#include "cg_local.h"
-
-#ifdef MISSIONPACK
-#include "../ui/ui_shared.h"
-
-// used for scoreboard
-extern displayContextDef_t cgDC;
-menuDef_t *menuScoreboard = NULL;
-#else
-int drawTeamOverlayModificationCount = -1;
-#endif
-
-int sortedTeamPlayers[TEAM_MAXOVERLAY];
-int numSortedTeamPlayers;
-
-char systemChat[256];
-char teamChat1[256];
-char teamChat2[256];
-
-#ifdef MISSIONPACK
-
-int CG_Text_Width(const char *text, float scale, int limit) {
- int count,len;
- float out;
- glyphInfo_t *glyph;
- float useScale;
-// FIXME: see ui_main.c, same problem
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- out = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- out += glyph->xSkip;
- s++;
- count++;
- }
- }
- }
- return out * useScale;
-}
-
-int CG_Text_Height(const char *text, float scale, int limit) {
- int len, count;
- float max;
- glyphInfo_t *glyph;
- float useScale;
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- max = 0;
- if (text) {
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- if ( Q_IsColorString(s) ) {
- s += 2;
- continue;
- } else {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if (max < glyph->height) {
- max = glyph->height;
- }
- s++;
- count++;
- }
- }
- }
- return max * useScale;
-}
-
-void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
- float w, h;
- w = width * scale;
- h = height * scale;
- CG_AdjustFrom640( &x, &y, &w, &h );
- trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
-}
-
-void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- if (text) {
-// TTimo: FIXME
-// const unsigned char *s = text;
- const char *s = text;
- trap_R_SetColor( color );
- memcpy(&newColor[0], &color[0], sizeof(vec4_t));
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
- //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
- int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
- colorBlack[3] = newColor[3];
- trap_R_SetColor( colorBlack );
- CG_Text_PaintChar(x + ofs, y - yadj + ofs,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- colorBlack[3] = 1.0;
- trap_R_SetColor( newColor );
- }
- CG_Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph);
- x += (glyph->xSkip * useScale) + adjust;
- s++;
- count++;
- }
- }
- trap_R_SetColor( NULL );
- }
-}
-
-
-#endif
-
-/*
-==============
-CG_DrawField
-
-Draws large numbers for status bar and powerups
-==============
-*/
-#ifndef MISSIONPACK
-static void CG_DrawField (int x, int y, int width, int value) {
- char num[16], *ptr;
- int l;
- int frame;
-
- if ( width < 1 ) {
- return;
- }
-
- // draw number string
- if ( width > 5 ) {
- width = 5;
- }
-
- switch ( width ) {
- case 1:
- value = value > 9 ? 9 : value;
- value = value < 0 ? 0 : value;
- break;
- case 2:
- value = value > 99 ? 99 : value;
- value = value < -9 ? -9 : value;
- break;
- case 3:
- value = value > 999 ? 999 : value;
- value = value < -99 ? -99 : value;
- break;
- case 4:
- value = value > 9999 ? 9999 : value;
- value = value < -999 ? -999 : value;
- break;
- }
-
- 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';
-
- CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
- x += CHAR_WIDTH;
- ptr++;
- l--;
- }
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_Draw3DModel
-
-================
-*/
-void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
- refdef_t refdef;
- refEntity_t ent;
-
- if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
- return;
- }
-
- CG_AdjustFrom640( &x, &y, &w, &h );
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- memset( &ent, 0, sizeof( ent ) );
- AnglesToAxis( angles, ent.axis );
- VectorCopy( origin, ent.origin );
- ent.hModel = model;
- ent.customSkin = skin;
- ent.renderfx = RF_NOSHADOW; // no stencil shadows
-
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- AxisClear( refdef.viewaxis );
-
- refdef.fov_x = 30;
- refdef.fov_y = 30;
-
- refdef.x = x;
- refdef.y = y;
- refdef.width = w;
- refdef.height = h;
-
- refdef.time = cg.time;
-
- trap_R_ClearScene();
- trap_R_AddRefEntityToScene( &ent );
- trap_R_RenderScene( &refdef );
-}
-
-/*
-================
-CG_DrawHead
-
-Used for both the status bar and the scoreboard
-================
-*/
-void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
- clipHandle_t cm;
- clientInfo_t *ci;
- float len;
- vec3_t origin;
- vec3_t mins, maxs;
-
- ci = &cgs.clientinfo[ clientNum ];
-
- if ( cg_draw3dIcons.integer ) {
- cm = ci->headModel;
- if ( !cm ) {
- return;
- }
-
- // offset the origin y and z to center the head
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the head nearly fills the box
- // assume heads are taller than wide
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- // allow per-model tweaking
- VectorAdd( origin, ci->headOffset, origin );
-
- CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
- } else if ( cg_drawIcons.integer ) {
- CG_DrawPic( x, y, w, h, ci->modelIcon );
- }
-
- // if they are deferred, draw a cross out
- if ( ci->deferred ) {
- CG_DrawPic( x, y, w, h, cgs.media.deferShader );
- }
-}
-
-/*
-================
-CG_DrawFlagModel
-
-Used for both the status bar and the scoreboard
-================
-*/
-void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
- qhandle_t cm;
- float len;
- vec3_t origin, angles;
- vec3_t mins, maxs;
- qhandle_t handle;
-
- if ( !force2D && cg_draw3dIcons.integer ) {
-
- VectorClear( angles );
-
- cm = cgs.media.redFlagModel;
-
- // offset the origin y and z to center the flag
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the flag nearly fills the box
- // assume heads are taller than wide
- len = 0.5 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- angles[YAW] = 60 * sin( cg.time / 2000.0 );;
-
- if( team == TEAM_RED ) {
- handle = cgs.media.redFlagModel;
- } else if( team == TEAM_BLUE ) {
- handle = cgs.media.blueFlagModel;
- } else if( team == TEAM_FREE ) {
- handle = cgs.media.neutralFlagModel;
- } else {
- return;
- }
- CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
- } else if ( cg_drawIcons.integer ) {
- gitem_t *item;
-
- if( team == TEAM_RED ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- } else if( team == TEAM_BLUE ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- } else if( team == TEAM_FREE ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- } else {
- return;
- }
- if (item) {
- CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
- }
- }
-}
-
-/*
-================
-CG_DrawStatusBarHead
-
-================
-*/
-#ifndef MISSIONPACK
-
-static void CG_DrawStatusBarHead( float x ) {
- vec3_t angles;
- float size, stretch;
- float frac;
-
- VectorClear( angles );
-
- if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
- frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
- size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
-
- stretch = size - ICON_SIZE * 1.25;
- // kick in the direction of damage
- x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
-
- cg.headStartYaw = 180 + cg.damageX * 45;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
-
- cg.headStartTime = cg.time;
- cg.headEndTime = cg.time + 100 + random() * 2000;
- } else {
- if ( cg.time >= cg.headEndTime ) {
- // select a new head angle
- cg.headStartYaw = cg.headEndYaw;
- cg.headStartPitch = cg.headEndPitch;
- cg.headStartTime = cg.headEndTime;
- cg.headEndTime = cg.time + 100 + random() * 2000;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
- }
-
- size = ICON_SIZE * 1.25;
- }
-
- // if the server was frozen for a while we may have a bad head start time
- if ( cg.headStartTime > cg.time ) {
- cg.headStartTime = cg.time;
- }
-
- frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
- frac = frac * frac * ( 3 - 2 * frac );
- angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
- angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
-
- CG_DrawHead( x, 480 - size, size, size,
- cg.snap->ps.clientNum, angles );
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawStatusBarFlag
-
-================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawStatusBarFlag( float x, int team ) {
- CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawTeamBackground
-
-================
-*/
-void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
-{
- vec4_t hcolor;
-
- hcolor[3] = alpha;
- if ( team == TEAM_RED ) {
- hcolor[0] = 1;
- hcolor[1] = 0;
- hcolor[2] = 0;
- } else if ( team == TEAM_BLUE ) {
- hcolor[0] = 0;
- hcolor[1] = 0;
- hcolor[2] = 1;
- } else {
- return;
- }
- trap_R_SetColor( hcolor );
- CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-CG_DrawStatusBar
-
-================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawStatusBar( void ) {
- int color;
- centity_t *cent;
- playerState_t *ps;
- int value;
- vec4_t hcolor;
- vec3_t angles;
- vec3_t origin;
-#ifdef MISSIONPACK
- qhandle_t handle;
-#endif
- static float colors[4][4] = {
-// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
- { 1.0f, 0.69f, 0.0f, 1.0f }, // normal
- { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
- { 0.5f, 0.5f, 0.5f, 1.0f }, // weapon firing
- { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- // draw the team background
- CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- VectorClear( angles );
-
- // draw any 3D icons first, so the changes back to 2D are minimized
- if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
- origin[0] = 70;
- origin[1] = 0;
- origin[2] = 0;
- angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
- CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
- cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
- }
-
- CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
-
- if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
- } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
- } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
- CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
- }
-
- if ( ps->stats[ STAT_ARMOR ] ) {
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
- cgs.media.armorModel, 0, origin, angles );
- }
-#ifdef MISSIONPACK
- if( cgs.gametype == GT_HARVESTER ) {
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeModel;
- } else {
- handle = cgs.media.blueCubeModel;
- }
- CG_Draw3DModel( 640 - (TEXT_ICON_SPACE + ICON_SIZE), 416, ICON_SIZE, ICON_SIZE, handle, 0, origin, angles );
- }
-#endif
- //
- // ammo
- //
- if ( cent->currentState.weapon ) {
- value = ps->ammo[cent->currentState.weapon];
- if ( value > -1 ) {
- if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
- && cg.predictedPlayerState.weaponTime > 100 ) {
- // draw as dark grey when reloading
- color = 2; // dark grey
- } else {
- if ( value >= 0 ) {
- color = 0; // green
- } else {
- color = 1; // red
- }
- }
- trap_R_SetColor( colors[color] );
-
- CG_DrawField (0, 432, 3, value);
- trap_R_SetColor( NULL );
-
- // if we didn't draw a 3D icon, draw a 2D icon for ammo
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- qhandle_t icon;
-
- icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
- if ( icon ) {
- CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
- }
- }
- }
- }
-
- //
- // health
- //
- value = ps->stats[STAT_HEALTH];
- if ( value > 100 ) {
- trap_R_SetColor( colors[3] ); // white
- } else if (value > 25) {
- trap_R_SetColor( colors[0] ); // green
- } else if (value > 0) {
- color = (cg.time >> 8) & 1; // flash
- trap_R_SetColor( colors[color] );
- } else {
- trap_R_SetColor( colors[1] ); // red
- }
-
- // stretch the health up when taking damage
- CG_DrawField ( 185, 432, 3, value);
- CG_ColorForHealth( hcolor );
- trap_R_SetColor( hcolor );
-
-
- //
- // armor
- //
- value = ps->stats[STAT_ARMOR];
- if (value > 0 ) {
- trap_R_SetColor( colors[0] );
- CG_DrawField (370, 432, 3, value);
- trap_R_SetColor( NULL );
- // if we didn't draw a 3D icon, draw a 2D icon for armor
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
- }
-
- }
-#ifdef MISSIONPACK
- //
- // cubes
- //
- if( cgs.gametype == GT_HARVESTER ) {
- value = ps->generic1;
- if( value > 99 ) {
- value = 99;
- }
- trap_R_SetColor( colors[0] );
- CG_DrawField (640 - (CHAR_WIDTH*2 + TEXT_ICON_SPACE + ICON_SIZE), 432, 2, value);
- trap_R_SetColor( NULL );
- // if we didn't draw a 3D icon, draw a 2D icon for armor
- if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeIcon;
- } else {
- handle = cgs.media.blueCubeIcon;
- }
- CG_DrawPic( 640 - (TEXT_ICON_SPACE + ICON_SIZE), 432, ICON_SIZE, ICON_SIZE, handle );
- }
- }
-#endif
-}
-#endif
-
-/*
-===========================================================================================
-
- UPPER RIGHT CORNER
-
-===========================================================================================
-*/
-
-/*
-================
-CG_DrawAttacker
-
-================
-*/
-static float CG_DrawAttacker( float y ) {
- int t;
- float size;
- vec3_t angles;
- const char *info;
- const char *name;
- int clientNum;
-
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- if ( !cg.attackerTime ) {
- return y;
- }
-
- clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
- return y;
- }
-
- t = cg.time - cg.attackerTime;
- if ( t > ATTACKER_HEAD_TIME ) {
- cg.attackerTime = 0;
- return y;
- }
-
- size = ICON_SIZE * 1.25;
-
- angles[PITCH] = 0;
- angles[YAW] = 180;
- angles[ROLL] = 0;
- CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
-
- info = CG_ConfigString( CS_PLAYERS + clientNum );
- name = Info_ValueForKey( info, "n" );
- y += size;
- CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
-
- return y + BIGCHAR_HEIGHT + 2;
-}
-
-/*
-==================
-CG_DrawSnapshot
-==================
-*/
-static float CG_DrawSnapshot( float y ) {
- char *s;
- int w;
-
- s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
- cg.latestSnapshotNum, cgs.serverCommandSequence );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-==================
-CG_DrawFPS
-==================
-*/
-#define FPS_FRAMES 4
-static float CG_DrawFPS( float y ) {
- char *s;
- int w;
- static int previousTimes[FPS_FRAMES];
- static int index;
- int i, total;
- int fps;
- static int previous;
- int t, frameTime;
-
- // don't use serverTime, because that will be drifting to
- // correct for internet lag changes, timescales, timedemos, etc
- t = trap_Milliseconds();
- frameTime = t - previous;
- previous = t;
-
- previousTimes[index % FPS_FRAMES] = frameTime;
- index++;
- if ( index > FPS_FRAMES ) {
- // average multiple frames together to smooth changes out a bit
- total = 0;
- for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
- total += previousTimes[i];
- }
- if ( !total ) {
- total = 1;
- }
- fps = 1000 * FPS_FRAMES / total;
-
- s = va( "%ifps", fps );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
- }
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-/*
-=================
-CG_DrawTimer
-=================
-*/
-static float CG_DrawTimer( float y ) {
- char *s;
- int w;
- int mins, seconds, tens;
- int msec;
-
- msec = cg.time - cgs.levelStartTime;
-
- seconds = msec / 1000;
- mins = seconds / 60;
- seconds -= mins * 60;
- tens = seconds / 10;
- seconds -= tens * 10;
-
- s = va( "%i:%i%i", mins, tens, seconds );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
-
- CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
-
- return y + BIGCHAR_HEIGHT + 4;
-}
-
-
-/*
-=================
-CG_DrawTeamOverlay
-=================
-*/
-
-static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
- int x, w, h, xx;
- int i, j, len;
- const char *p;
- vec4_t hcolor;
- int pwidth, lwidth;
- int plyrs;
- char st[16];
- clientInfo_t *ci;
- gitem_t *item;
- int ret_y, count;
-
- if ( !cg_drawTeamOverlay.integer ) {
- return y;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
- return y; // Not on any team
- }
-
- plyrs = 0;
-
- // max player name width
- pwidth = 0;
- count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
- plyrs++;
- len = CG_DrawStrlen(ci->name);
- if (len > pwidth)
- pwidth = len;
- }
- }
-
- if (!plyrs)
- return y;
-
- if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
- pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
-
- // max location name width
- lwidth = 0;
- for (i = 1; i < MAX_LOCATIONS; i++) {
- p = CG_ConfigString(CS_LOCATIONS + i);
- if (p && *p) {
- len = CG_DrawStrlen(p);
- if (len > lwidth)
- lwidth = len;
- }
- }
-
- if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
- lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
-
- w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
-
- if ( right )
- x = 640 - w;
- else
- x = 0;
-
- h = plyrs * TINYCHAR_HEIGHT;
-
- if ( upper ) {
- ret_y = y + h;
- } else {
- y -= h;
- ret_y = y;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- hcolor[0] = 1.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
- hcolor[0] = 0.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 1.0f;
- hcolor[3] = 0.33f;
- }
- trap_R_SetColor( hcolor );
- CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
-
- hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
-
- xx = x + TINYCHAR_WIDTH;
-
- CG_DrawStringExt( xx, y,
- ci->name, hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
-
- if (lwidth) {
- p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p)
- p = "unknown";
- len = CG_DrawStrlen(p);
- if (len > lwidth)
- len = lwidth;
-
-// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
-// ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
- xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
- CG_DrawStringExt( xx, y,
- p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- TEAM_OVERLAY_MAXLOCATION_WIDTH);
- }
-
- CG_GetColorForHealth( ci->health, ci->armor, hcolor );
-
- Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
-
- xx = x + TINYCHAR_WIDTH * 3 +
- TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
-
- CG_DrawStringExt( xx, y,
- st, hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
-
- // draw weapon icon
- xx += TINYCHAR_WIDTH * 3;
-
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- cgs.media.deferShader );
- }
-
- // Draw powerup icons
- if (right) {
- xx = x;
- } else {
- xx = x + w - TINYCHAR_WIDTH;
- }
- for (j = 0; j <= PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
-
- item = BG_FindItemForPowerup( j );
-
- if (item) {
- CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
- trap_R_RegisterShader( item->icon ) );
- if (right) {
- xx -= TINYCHAR_WIDTH;
- } else {
- xx += TINYCHAR_WIDTH;
- }
- }
- }
- }
-
- y += TINYCHAR_HEIGHT;
- }
- }
-
- return ret_y;
-//#endif
-}
-
-
-/*
-=====================
-CG_DrawUpperRight
-
-=====================
-*/
-static void CG_DrawUpperRight( void ) {
- float y;
-
- y = 0;
-
- if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {
- y = CG_DrawTeamOverlay( y, qtrue, qtrue );
- }
- if ( cg_drawSnapshot.integer ) {
- y = CG_DrawSnapshot( y );
- }
- if ( cg_drawFPS.integer ) {
- y = CG_DrawFPS( y );
- }
- if ( cg_drawTimer.integer ) {
- y = CG_DrawTimer( y );
- }
- if ( cg_drawAttacker.integer ) {
- y = CG_DrawAttacker( y );
- }
-
-}
-
-/*
-===========================================================================================
-
- LOWER RIGHT CORNER
-
-===========================================================================================
-*/
-
-/*
-=================
-CG_DrawScores
-
-Draw the small two score display
-=================
-*/
-#ifndef MISSIONPACK
-static float CG_DrawScores( float y ) {
- const char *s;
- int s1, s2, score;
- int x, w;
- int v;
- vec4_t color;
- float y1;
- gitem_t *item;
-
- s1 = cgs.scores1;
- s2 = cgs.scores2;
-
- y -= BIGCHAR_HEIGHT + 8;
-
- y1 = y;
-
- // draw from the right side to left
- if ( cgs.gametype >= GT_TEAM ) {
- x = 640;
- color[0] = 0.0f;
- color[1] = 0.0f;
- color[2] = 1.0f;
- color[3] = 0.33f;
- s = va( "%2i", s2 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
-
- if ( cgs.gametype == GT_CTF ) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
- }
- }
- }
- color[0] = 1.0f;
- color[1] = 0.0f;
- color[2] = 0.0f;
- color[3] = 0.33f;
- s = va( "%2i", s1 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
-
- if ( cgs.gametype == GT_CTF ) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_REDFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
- }
- }
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_1FCTF ) {
- // Display flag status
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
-
- if (item) {
- y1 = y - BIGCHAR_HEIGHT - 8;
- if( cgs.flagStatus >= 0 && cgs.flagStatus <= 3 ) {
- CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.flagShader[cgs.flagStatus] );
- }
- }
- }
-#endif
- if ( cgs.gametype >= GT_CTF ) {
- v = cgs.capturelimit;
- } else {
- v = cgs.fraglimit;
- }
- if ( v ) {
- s = va( "%2i", v );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- } else {
- qboolean spectator;
-
- x = 640;
- score = cg.snap->ps.persistant[PERS_SCORE];
- spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
-
- // always show your score in the second box if not in first place
- if ( s1 != score ) {
- s2 = score;
- }
- if ( s2 != SCORE_NOT_PRESENT ) {
- s = va( "%2i", s2 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- if ( !spectator && score == s2 && score != s1 ) {
- color[0] = 1.0f;
- color[1] = 0.0f;
- color[2] = 0.0f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- } else {
- color[0] = 0.5f;
- color[1] = 0.5f;
- color[2] = 0.5f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- // first place
- if ( s1 != SCORE_NOT_PRESENT ) {
- s = va( "%2i", s1 );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- if ( !spectator && score == s1 ) {
- color[0] = 0.0f;
- color[1] = 0.0f;
- color[2] = 1.0f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
- } else {
- color[0] = 0.5f;
- color[1] = 0.5f;
- color[2] = 0.5f;
- color[3] = 0.33f;
- CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
- }
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- if ( cgs.fraglimit ) {
- s = va( "%2i", cgs.fraglimit );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
- x -= w;
- CG_DrawBigString( x + 4, y, s, 1.0F);
- }
-
- }
-
- return y1 - 8;
-}
-#endif // MISSIONPACK
-
-/*
-================
-CG_DrawPowerups
-================
-*/
-#ifndef MISSIONPACK
-static float CG_DrawPowerups( float y ) {
- int sorted[MAX_POWERUPS];
- int sortedTime[MAX_POWERUPS];
- int i, j, k;
- int active;
- playerState_t *ps;
- int t;
- gitem_t *item;
- int x;
- int color;
- float size;
- float f;
- static float colors[2][4] = {
- { 0.2f, 1.0f, 0.2f, 1.0f } ,
- { 1.0f, 0.2f, 0.2f, 1.0f }
- };
-
- ps = &cg.snap->ps;
-
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- // sort the list by time remaining
- active = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( !ps->powerups[ i ] ) {
- continue;
- }
- t = ps->powerups[ i ] - cg.time;
- // ZOID--don't draw if the power up has unlimited time (999 seconds)
- // This is true of the CTF flags
- if ( t < 0 || t > 999000) {
- continue;
- }
-
- // insert into the list
- for ( j = 0 ; j < active ; j++ ) {
- if ( sortedTime[j] >= t ) {
- for ( k = active - 1 ; k >= j ; k-- ) {
- sorted[k+1] = sorted[k];
- sortedTime[k+1] = sortedTime[k];
- }
- break;
- }
- }
- sorted[j] = i;
- sortedTime[j] = t;
- active++;
- }
-
- // draw the icons and timers
- x = 640 - ICON_SIZE - CHAR_WIDTH * 2;
- for ( i = 0 ; i < active ; i++ ) {
- item = BG_FindItemForPowerup( sorted[i] );
-
- if (item) {
-
- color = 1;
-
- y -= ICON_SIZE;
-
- trap_R_SetColor( colors[color] );
- CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );
-
- t = ps->powerups[ sorted[i] ];
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- trap_R_SetColor( NULL );
- } else {
- vec4_t modulate;
-
- f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
- f -= (int)f;
- modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
- trap_R_SetColor( modulate );
- }
-
- if ( cg.powerupActive == sorted[i] &&
- cg.time - cg.powerupTime < PULSE_TIME ) {
- f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );
- size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );
- } else {
- size = ICON_SIZE;
- }
-
- CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2,
- size, size, trap_R_RegisterShader( item->icon ) );
- }
- }
- trap_R_SetColor( NULL );
-
- return y;
-}
-#endif // MISSIONPACK
-
-/*
-=====================
-CG_DrawLowerRight
-
-=====================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawLowerRight( void ) {
- float y;
-
- y = 480 - ICON_SIZE;
-
- if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) {
- y = CG_DrawTeamOverlay( y, qtrue, qfalse );
- }
-
- y = CG_DrawScores( y );
- y = CG_DrawPowerups( y );
-}
-#endif // MISSIONPACK
-
-/*
-===================
-CG_DrawPickupItem
-===================
-*/
-#ifndef MISSIONPACK
-static int CG_DrawPickupItem( int y ) {
- int value;
- float *fadeColor;
-
- if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
- return y;
- }
-
- y -= ICON_SIZE;
-
- value = cg.itemPickup;
- if ( value ) {
- fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
- if ( fadeColor ) {
- CG_RegisterItemVisuals( value );
- trap_R_SetColor( fadeColor );
- CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
- trap_R_SetColor( NULL );
- }
- }
-
- return y;
-}
-#endif // MISSIONPACK
-
-/*
-=====================
-CG_DrawLowerLeft
-
-=====================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawLowerLeft( void ) {
- float y;
-
- y = 480 - ICON_SIZE;
-
- if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 3 ) {
- y = CG_DrawTeamOverlay( y, qfalse, qfalse );
- }
-
-
- y = CG_DrawPickupItem( y );
-}
-#endif // MISSIONPACK
-
-
-//===========================================================================================
-
-/*
-=================
-CG_DrawTeamInfo
-=================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawTeamInfo( void ) {
- int w, h;
- int i, len;
- vec4_t hcolor;
- int chatHeight;
-
-#define CHATLOC_Y 420 // bottom end
-#define CHATLOC_X 0
-
- if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)
- chatHeight = cg_teamChatHeight.integer;
- else
- chatHeight = TEAMCHAT_HEIGHT;
- if (chatHeight <= 0)
- return; // disabled
-
- if (cgs.teamLastChatPos != cgs.teamChatPos) {
- if (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {
- cgs.teamLastChatPos++;
- }
-
- h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;
-
- w = 0;
-
- for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {
- len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);
- if (len > w)
- w = len;
- }
- w *= TINYCHAR_WIDTH;
- w += TINYCHAR_WIDTH * 2;
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
- hcolor[0] = 1.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- hcolor[0] = 0.0f;
- hcolor[1] = 0.0f;
- hcolor[2] = 1.0f;
- hcolor[3] = 0.33f;
- } else {
- hcolor[0] = 0.0f;
- hcolor[1] = 1.0f;
- hcolor[2] = 0.0f;
- hcolor[3] = 0.33f;
- }
-
- trap_R_SetColor( hcolor );
- CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );
- trap_R_SetColor( NULL );
-
- hcolor[0] = hcolor[1] = hcolor[2] = 1.0f;
- hcolor[3] = 1.0f;
-
- for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {
- CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH,
- CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT,
- cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,
- TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
- }
- }
-}
-#endif // MISSIONPACK
-
-/*
-===================
-CG_DrawHoldableItem
-===================
-*/
-#ifndef MISSIONPACK
-static void CG_DrawHoldableItem( void ) {
- int value;
-
- value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- }
-
-}
-#endif // MISSIONPACK
-
-#ifdef MISSIONPACK
-/*
-===================
-CG_DrawPersistantPowerup
-===================
-*/
-#if 0 // sos001208 - DEAD
-static void CG_DrawPersistantPowerup( void ) {
- int value;
-
- value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
- }
-}
-#endif
-#endif // MISSIONPACK
-
-
-/*
-===================
-CG_DrawReward
-===================
-*/
-static void CG_DrawReward( void ) {
- float *color;
- int i, count;
- float x, y;
- char buf[32];
-
- if ( !cg_drawRewards.integer ) {
- return;
- }
-
- color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
- if ( !color ) {
- if (cg.rewardStack > 0) {
- for(i = 0; i < cg.rewardStack; i++) {
- cg.rewardSound[i] = cg.rewardSound[i+1];
- cg.rewardShader[i] = cg.rewardShader[i+1];
- cg.rewardCount[i] = cg.rewardCount[i+1];
- }
- cg.rewardTime = cg.time;
- cg.rewardStack--;
- color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
- trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
- } else {
- return;
- }
- }
-
- trap_R_SetColor( color );
-
- /*
- count = cg.rewardCount[0]/10; // number of big rewards to draw
-
- if (count) {
- y = 4;
- x = 320 - count * ICON_SIZE;
- for ( i = 0 ; i < count ; i++ ) {
- CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
- x += (ICON_SIZE*2);
- }
- }
-
- count = cg.rewardCount[0] - count*10; // number of small rewards to draw
- */
-
- if ( cg.rewardCount[0] >= 10 ) {
- y = 56;
- x = 320 - ICON_SIZE/2;
- CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
- Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
- x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
- CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
- SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
- }
- else {
-
- count = cg.rewardCount[0];
-
- y = 56;
- x = 320 - count * ICON_SIZE/2;
- for ( i = 0 ; i < count ; i++ ) {
- CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
- x += ICON_SIZE;
- }
- }
- trap_R_SetColor( NULL );
-}
-
-
-/*
-===============================================================================
-
-LAGOMETER
-
-===============================================================================
-*/
-
-#define LAG_SAMPLES 128
-
-
-typedef struct {
- int frameSamples[LAG_SAMPLES];
- int frameCount;
- int snapshotFlags[LAG_SAMPLES];
- int snapshotSamples[LAG_SAMPLES];
- int snapshotCount;
-} lagometer_t;
-
-lagometer_t lagometer;
-
-/*
-==============
-CG_AddLagometerFrameInfo
-
-Adds the current interpolate / extrapolate bar for this frame
-==============
-*/
-void CG_AddLagometerFrameInfo( void ) {
- int offset;
-
- offset = cg.time - cg.latestSnapshotTime;
- lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
- lagometer.frameCount++;
-}
-
-/*
-==============
-CG_AddLagometerSnapshotInfo
-
-Each time a snapshot is received, log its ping time and
-the number of snapshots that were dropped before it.
-
-Pass NULL for a dropped packet.
-==============
-*/
-void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
- // dropped packet
- if ( !snap ) {
- lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
- lagometer.snapshotCount++;
- return;
- }
-
- // add this snapshot's info
- lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
- lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
- lagometer.snapshotCount++;
-}
-
-/*
-==============
-CG_DrawDisconnect
-
-Should we draw something differnet for long lag vs no packets?
-==============
-*/
-static void CG_DrawDisconnect( void ) {
- float x, y;
- int cmdNum;
- usercmd_t cmd;
- const char *s;
- int w; // bk010215 - FIXME char message[1024];
-
- // draw the phone jack if we are completely past our buffers
- cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
- trap_GetUserCmd( cmdNum, &cmd );
- if ( cmd.serverTime <= cg.snap->ps.commandTime
- || cmd.serverTime > cg.time ) { // special check for map_restart // bk 0102165 - FIXME
- return;
- }
-
- // also add text in center of screen
- s = "Connection Interrupted"; // bk 010215 - FIXME
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
-
- // blink the icon
- if ( ( cg.time >> 9 ) & 1 ) {
- return;
- }
-
- x = 640 - 48;
- y = 480 - 48;
-
- CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
-}
-
-
-#define MAX_LAGOMETER_PING 900
-#define MAX_LAGOMETER_RANGE 300
-
-/*
-==============
-CG_DrawLagometer
-==============
-*/
-static void CG_DrawLagometer( void ) {
- int a, x, y, i;
- float v;
- float ax, ay, aw, ah, mid, range;
- int color;
- float vscale;
-
- if ( !cg_lagometer.integer || cgs.localServer ) {
- CG_DrawDisconnect();
- return;
- }
-
- //
- // draw the graph
- //
-#ifdef MISSIONPACK
- x = 640 - 48;
- y = 480 - 144;
-#else
- x = 640 - 48;
- y = 480 - 48;
-#endif
-
- trap_R_SetColor( NULL );
- CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
-
- ax = x;
- ay = y;
- aw = 48;
- ah = 48;
- CG_AdjustFrom640( &ax, &ay, &aw, &ah );
-
- color = -1;
- range = ah / 3;
- mid = ay + range;
-
- vscale = range / MAX_LAGOMETER_RANGE;
-
- // draw the frame interpoalte / extrapolate graph
- for ( a = 0 ; a < aw ; a++ ) {
- i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
- v = lagometer.frameSamples[i];
- v *= vscale;
- if ( v > 0 ) {
- if ( color != 1 ) {
- color = 1;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
- }
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- } else if ( v < 0 ) {
- if ( color != 2 ) {
- color = 2;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
- }
- v = -v;
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- }
- }
-
- // draw the snapshot latency / drop graph
- range = ah / 2;
- vscale = range / MAX_LAGOMETER_PING;
-
- for ( a = 0 ; a < aw ; a++ ) {
- i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
- v = lagometer.snapshotSamples[i];
- if ( v > 0 ) {
- if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
- if ( color != 5 ) {
- color = 5; // YELLOW for rate delay
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
- }
- } else {
- if ( color != 3 ) {
- color = 3;
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
- }
- }
- v = v * vscale;
- if ( v > range ) {
- v = range;
- }
- trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
- } else if ( v < 0 ) {
- if ( color != 4 ) {
- color = 4; // RED for dropped snapshots
- trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
- }
- trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
- }
- }
-
- trap_R_SetColor( NULL );
-
- if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_DrawBigString( ax, ay, "snc", 1.0 );
- }
-
- CG_DrawDisconnect();
-}
-
-
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-
-/*
-==============
-CG_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void CG_CenterPrint( const char *str, int y, int charWidth ) {
- char *s;
-
- Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
-
- cg.centerPrintTime = cg.time;
- cg.centerPrintY = y;
- cg.centerPrintCharWidth = charWidth;
-
- // count the number of lines for centering
- cg.centerPrintLines = 1;
- s = cg.centerPrint;
- while( *s ) {
- if (*s == '\n')
- cg.centerPrintLines++;
- s++;
- }
-}
-
-
-/*
-===================
-CG_DrawCenterString
-===================
-*/
-static void CG_DrawCenterString( void ) {
- char *start;
- int l;
- int x, y, w;
-#ifdef MISSIONPACK // bk010221 - unused else
- int h;
-#endif
- float *color;
-
- if ( !cg.centerPrintTime ) {
- return;
- }
-
- color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
- if ( !color ) {
- return;
- }
-
- trap_R_SetColor( color );
-
- start = cg.centerPrint;
-
- y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
-
- while ( 1 ) {
- char linebuffer[1024];
-
- for ( l = 0; l < 50; l++ ) {
- if ( !start[l] || start[l] == '\n' ) {
- break;
- }
- linebuffer[l] = start[l];
- }
- linebuffer[l] = 0;
-
-#ifdef MISSIONPACK
- w = CG_Text_Width(linebuffer, 0.5, 0);
- h = CG_Text_Height(linebuffer, 0.5, 0);
- x = (SCREEN_WIDTH - w) / 2;
- CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
- y += h + 6;
-#else
- w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
-
- x = ( SCREEN_WIDTH - w ) / 2;
-
- CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,
- cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
-
- y += cg.centerPrintCharWidth * 1.5;
-#endif
- while ( *start && ( *start != '\n' ) ) {
- start++;
- }
- if ( !*start ) {
- break;
- }
- start++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-
-
-/*
-================================================================================
-
-CROSSHAIR
-
-================================================================================
-*/
-
-
-/*
-=================
-CG_DrawCrosshair
-=================
-*/
-static void CG_DrawCrosshair(void) {
- float w, h;
- qhandle_t hShader;
- float f;
- float x, y;
- int ca;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
- return;
- }
-
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- // set color based on health
- if ( cg_crosshairHealth.integer ) {
- vec4_t hcolor;
-
- CG_ColorForHealth( hcolor );
- trap_R_SetColor( hcolor );
- } else {
- trap_R_SetColor( NULL );
- }
-
- w = h = cg_crosshairSize.value;
-
- // pulse the size of the crosshair when picking up items
- f = cg.time - cg.itemPickupBlendTime;
- if ( f > 0 && f < ITEM_BLOB_TIME ) {
- f /= ITEM_BLOB_TIME;
- w *= ( 1 + f );
- h *= ( 1 + f );
- }
-
- x = cg_crosshairX.integer;
- y = cg_crosshairY.integer;
- CG_AdjustFrom640( &x, &y, &w, &h );
-
- ca = cg_drawCrosshair.integer;
- if (ca < 0) {
- ca = 0;
- }
- hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
-
- trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
- y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
- w, h, 0, 0, 1, 1, hShader );
-}
-
-
-
-/*
-=================
-CG_ScanForCrosshairEntity
-=================
-*/
-static void CG_ScanForCrosshairEntity( void ) {
- trace_t trace;
- vec3_t start, end;
- int content;
-
- VectorCopy( cg.refdef.vieworg, start );
- VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
-
- CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
- cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
- if ( trace.entityNum >= MAX_CLIENTS ) {
- return;
- }
-
- // if the player is in fog, don't show it
- content = trap_CM_PointContents( trace.endpos, 0 );
- if ( content & CONTENTS_FOG ) {
- return;
- }
-
- // if the player is invisible, don't show it
- if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {
- return;
- }
-
- // update the fade timer
- cg.crosshairClientNum = trace.entityNum;
- cg.crosshairClientTime = cg.time;
-}
-
-
-/*
-=====================
-CG_DrawCrosshairNames
-=====================
-*/
-static void CG_DrawCrosshairNames( void ) {
- float *color;
- char *name;
- float w;
-
- if ( !cg_drawCrosshair.integer ) {
- return;
- }
- if ( !cg_drawCrosshairNames.integer ) {
- return;
- }
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
- // scan the known entities to see if the crosshair is sighted on one
- CG_ScanForCrosshairEntity();
-
- // draw the name of the player being looked at
- color = CG_FadeColor( cg.crosshairClientTime, 1000 );
- if ( !color ) {
- trap_R_SetColor( NULL );
- return;
- }
-
- name = cgs.clientinfo[ cg.crosshairClientNum ].name;
-#ifdef MISSIONPACK
- color[3] *= 0.5f;
- w = CG_Text_Width(name, 0.3f, 0);
- CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
-#else
- w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
- CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );
-#endif
- trap_R_SetColor( NULL );
-}
-
-
-//==============================================================================
-
-/*
-=================
-CG_DrawSpectator
-=================
-*/
-static void CG_DrawSpectator(void) {
- CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F);
- if ( cgs.gametype == GT_TOURNAMENT ) {
- CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F);
- }
- else if ( cgs.gametype >= GT_TEAM ) {
- CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F);
- }
-}
-
-/*
-=================
-CG_DrawVote
-=================
-*/
-static void CG_DrawVote(void) {
- char *s;
- int sec;
-
- if ( !cgs.voteTime ) {
- return;
- }
-
- // play a talk beep whenever it is modified
- if ( cgs.voteModified ) {
- cgs.voteModified = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
-
- sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
- if ( sec < 0 ) {
- sec = 0;
- }
-#ifdef MISSIONPACK
- s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo);
- CG_DrawSmallString( 0, 58, s, 1.0F );
- s = "or press ESC then click Vote";
- CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
-#else
- s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );
- CG_DrawSmallString( 0, 58, s, 1.0F );
-#endif
-}
-
-/*
-=================
-CG_DrawTeamVote
-=================
-*/
-static void CG_DrawTeamVote(void) {
- char *s;
- int sec, cs_offset;
-
- if ( cgs.clientinfo->team == TEAM_RED )
- cs_offset = 0;
- else if ( cgs.clientinfo->team == TEAM_BLUE )
- cs_offset = 1;
- else
- return;
-
- if ( !cgs.teamVoteTime[cs_offset] ) {
- return;
- }
-
- // play a talk beep whenever it is modified
- if ( cgs.teamVoteModified[cs_offset] ) {
- cgs.teamVoteModified[cs_offset] = qfalse;
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- }
-
- sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
- if ( sec < 0 ) {
- sec = 0;
- }
- s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
- cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
- CG_DrawSmallString( 0, 90, s, 1.0F );
-}
-
-
-static qboolean CG_DrawScoreboard() {
-#ifdef MISSIONPACK
- static qboolean firstTime = qtrue;
- float fade, *fadeColor;
-
- if (menuScoreboard) {
- menuScoreboard->window.flags &= ~WINDOW_FORCED;
- }
- if (cg_paused.integer) {
- cg.deferredPlayerLoading = 0;
- firstTime = qtrue;
- return qfalse;
- }
-
- // should never happen in Team Arena
- if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- cg.deferredPlayerLoading = 0;
- firstTime = qtrue;
- return qfalse;
- }
-
- // don't draw scoreboard during death while warmup up
- if ( cg.warmup && !cg.showScores ) {
- return qfalse;
- }
-
- if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- fade = 1.0;
- fadeColor = colorWhite;
- } else {
- fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
- if ( !fadeColor ) {
- // next time scoreboard comes up, don't print killer
- cg.deferredPlayerLoading = 0;
- cg.killerName[0] = 0;
- firstTime = qtrue;
- return qfalse;
- }
- fade = *fadeColor;
- }
-
-
- if (menuScoreboard == NULL) {
- if ( cgs.gametype >= GT_TEAM ) {
- menuScoreboard = Menus_FindByName("teamscore_menu");
- } else {
- menuScoreboard = Menus_FindByName("score_menu");
- }
- }
-
- if (menuScoreboard) {
- if (firstTime) {
- CG_SetScoreSelection(menuScoreboard);
- firstTime = qfalse;
- }
- Menu_Paint(menuScoreboard, qtrue);
- }
-
- // load any models that have been deferred
- if ( ++cg.deferredPlayerLoading > 10 ) {
- CG_LoadDeferredPlayers();
- }
-
- return qtrue;
-#else
- return CG_DrawOldScoreboard();
-#endif
-}
-
-/*
-=================
-CG_DrawIntermission
-=================
-*/
-static void CG_DrawIntermission( void ) {
-// int key;
-#ifdef MISSIONPACK
- //if (cg_singlePlayer.integer) {
- // CG_DrawCenterString();
- // return;
- //}
-#else
- if ( cgs.gametype == GT_SINGLE_PLAYER ) {
- CG_DrawCenterString();
- return;
- }
-#endif
- cg.scoreFadeTime = cg.time;
- cg.scoreBoardShowing = CG_DrawScoreboard();
-}
-
-/*
-=================
-CG_DrawFollow
-=================
-*/
-static qboolean CG_DrawFollow( void ) {
- float x;
- vec4_t color;
- const char *name;
-
- if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
- return qfalse;
- }
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
-
- CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F );
-
- name = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
-
- x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );
-
- CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-
- return qtrue;
-}
-
-
-
-/*
-=================
-CG_DrawAmmoWarning
-=================
-*/
-static void CG_DrawAmmoWarning( void ) {
- const char *s;
- int w;
-
- if ( cg_drawAmmoWarning.integer == 0 ) {
- return;
- }
-
- if ( !cg.lowAmmoWarning ) {
- return;
- }
-
- if ( cg.lowAmmoWarning == 2 ) {
- s = "OUT OF AMMO";
- } else {
- s = "LOW AMMO WARNING";
- }
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
-}
-
-
-#ifdef MISSIONPACK
-/*
-=================
-CG_DrawProxWarning
-=================
-*/
-static void CG_DrawProxWarning( void ) {
- char s [32];
- int w;
- static int proxTime;
- static int proxCounter;
- static int proxTick;
-
- if( !(cg.snap->ps.eFlags & EF_TICKING ) ) {
- proxTime = 0;
- return;
- }
-
- if (proxTime == 0) {
- proxTime = cg.time + 5000;
- proxCounter = 5;
- proxTick = 0;
- }
-
- if (cg.time > proxTime) {
- proxTick = proxCounter--;
- proxTime = cg.time + 1000;
- }
-
- if (proxTick != 0) {
- Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick);
- } else {
- Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED");
- }
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] );
-}
-#endif
-
-
-/*
-=================
-CG_DrawWarmup
-=================
-*/
-static void CG_DrawWarmup( void ) {
- int w;
- int sec;
- int i;
- float scale;
- clientInfo_t *ci1, *ci2;
- int cw;
- const char *s;
-
- sec = cg.warmup;
- if ( !sec ) {
- return;
- }
-
- if ( sec < 0 ) {
- s = "Waiting for players";
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
- cg.warmupCount = 0;
- return;
- }
-
- if (cgs.gametype == GT_TOURNAMENT) {
- // find the two active players
- ci1 = NULL;
- ci2 = NULL;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
- if ( !ci1 ) {
- ci1 = &cgs.clientinfo[i];
- } else {
- ci2 = &cgs.clientinfo[i];
- }
- }
- }
-
- if ( ci1 && ci2 ) {
- s = va( "%s vs %s", ci1->name, ci2->name );
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, 0.6f, 0);
- CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- if ( w > 640 / GIANT_WIDTH ) {
- cw = 640 / w;
- } else {
- cw = GIANT_WIDTH;
- }
- CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5f), 0 );
-#endif
- }
- } else {
- if ( cgs.gametype == GT_FFA ) {
- s = "Free For All";
- } else if ( cgs.gametype == GT_TEAM ) {
- s = "Team Deathmatch";
- } else if ( cgs.gametype == GT_CTF ) {
- s = "Capture the Flag";
-#ifdef MISSIONPACK
- } else if ( cgs.gametype == GT_1FCTF ) {
- s = "One Flag CTF";
- } else if ( cgs.gametype == GT_OBELISK ) {
- s = "Overload";
- } else if ( cgs.gametype == GT_HARVESTER ) {
- s = "Harvester";
-#endif
- } else {
- s = "";
- }
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, 0.6f, 0);
- CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- if ( w > 640 / GIANT_WIDTH ) {
- cw = 640 / w;
- } else {
- cw = GIANT_WIDTH;
- }
- CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.1f), 0 );
-#endif
- }
-
- sec = ( sec - cg.time ) / 1000;
- if ( sec < 0 ) {
- cg.warmup = 0;
- sec = 0;
- }
- s = va( "Starts in: %i", sec + 1 );
- if ( sec != cg.warmupCount ) {
- cg.warmupCount = sec;
- switch ( sec ) {
- case 0:
- trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
- break;
- case 1:
- trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
- break;
- case 2:
- trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
- break;
- default:
- break;
- }
- }
- scale = 0.45f;
- switch ( cg.warmupCount ) {
- case 0:
- cw = 28;
- scale = 0.54f;
- break;
- case 1:
- cw = 24;
- scale = 0.51f;
- break;
- case 2:
- cw = 20;
- scale = 0.48f;
- break;
- default:
- cw = 16;
- scale = 0.45f;
- break;
- }
-
-#ifdef MISSIONPACK
- w = CG_Text_Width(s, scale, 0);
- CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
-#else
- w = CG_DrawStrlen( s );
- CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite,
- qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
-#endif
-}
-
-//==================================================================================
-#ifdef MISSIONPACK
-/*
-=================
-CG_DrawTimedMenus
-=================
-*/
-void CG_DrawTimedMenus() {
- if (cg.voiceTime) {
- int t = cg.time - cg.voiceTime;
- if ( t > 2500 ) {
- Menus_CloseByName("voiceMenu");
- trap_Cvar_Set("cl_conXOffset", "0");
- cg.voiceTime = 0;
- }
- }
-}
-#endif
-/*
-=================
-CG_Draw2D
-=================
-*/
-static void CG_Draw2D( void ) {
-#ifdef MISSIONPACK
- if (cgs.orderPending && cg.time > cgs.orderTime) {
- CG_CheckOrderPending();
- }
-#endif
- // if we are taking a levelshot for the menu, don't draw anything
- if ( cg.levelShot ) {
- return;
- }
-
- if ( cg_draw2D.integer == 0 ) {
- return;
- }
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- CG_DrawIntermission();
- return;
- }
-
-/*
- if (cg.cameraMode) {
- return;
- }
-*/
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- CG_DrawSpectator();
- CG_DrawCrosshair();
- CG_DrawCrosshairNames();
- } else {
- // don't draw any status if dead or the scoreboard is being explicitly shown
- if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
-
-#ifdef MISSIONPACK
- if ( cg_drawStatus.integer ) {
- Menu_PaintAll();
- CG_DrawTimedMenus();
- }
-#else
- CG_DrawStatusBar();
-#endif
-
- CG_DrawAmmoWarning();
-
-#ifdef MISSIONPACK
- CG_DrawProxWarning();
-#endif
- CG_DrawCrosshair();
- CG_DrawCrosshairNames();
- CG_DrawWeaponSelect();
-
-#ifndef MISSIONPACK
- CG_DrawHoldableItem();
-#else
- //CG_DrawPersistantPowerup();
-#endif
- CG_DrawReward();
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
-#ifndef MISSIONPACK
- CG_DrawTeamInfo();
-#endif
- }
- }
-
- CG_DrawVote();
- CG_DrawTeamVote();
-
- CG_DrawLagometer();
-
-#ifdef MISSIONPACK
- if (!cg_paused.integer) {
- CG_DrawUpperRight();
- }
-#else
- CG_DrawUpperRight();
-#endif
-
-#ifndef MISSIONPACK
- CG_DrawLowerRight();
- CG_DrawLowerLeft();
-#endif
-
- if ( !CG_DrawFollow() ) {
- CG_DrawWarmup();
- }
-
- // don't draw center string if scoreboard is up
- cg.scoreBoardShowing = CG_DrawScoreboard();
- if ( !cg.scoreBoardShowing) {
- CG_DrawCenterString();
- }
-}
-
-
-static void CG_DrawTourneyScoreboard() {
-#ifdef MISSIONPACK
-#else
- CG_DrawOldTourneyScoreboard();
-#endif
-}
-
-/*
-=====================
-CG_DrawActive
-
-Perform all drawing needed to completely fill the screen
-=====================
-*/
-void CG_DrawActive( stereoFrame_t stereoView ) {
- float separation;
- vec3_t baseOrg;
-
- // optionally draw the info screen instead
- if ( !cg.snap ) {
- CG_DrawInformation();
- return;
- }
-
- // optionally draw the tournement scoreboard instead
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
- ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
- CG_DrawTourneyScoreboard();
- return;
- }
-
- switch ( stereoView ) {
- case STEREO_CENTER:
- separation = 0;
- break;
- case STEREO_LEFT:
- separation = -cg_stereoSeparation.value / 2;
- break;
- case STEREO_RIGHT:
- separation = cg_stereoSeparation.value / 2;
- break;
- default:
- separation = 0;
- CG_Error( "CG_DrawActive: Undefined stereoView" );
- }
-
-
- // clear around the rendered view if sized down
- CG_TileClear();
-
- // offset vieworg appropriately if we're doing stereo separation
- VectorCopy( cg.refdef.vieworg, baseOrg );
- if ( separation != 0 ) {
- VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
- }
-
- // draw 3D view
- trap_R_RenderScene( &cg.refdef );
-
- // restore original viewpoint if running stereo
- if ( separation != 0 ) {
- VectorCopy( baseOrg, cg.refdef.vieworg );
- }
-
- // draw status bar and other floating elements
- CG_Draw2D();
-}
-
-
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_draw.c -- draw all of the graphical elements during
+// active (after loading) gameplay
+
+#include "cg_local.h"
+
+#ifdef MISSIONPACK
+#include "../ui/ui_shared.h"
+
+// used for scoreboard
+extern displayContextDef_t cgDC;
+menuDef_t *menuScoreboard = NULL;
+#else
+int drawTeamOverlayModificationCount = -1;
+#endif
+
+int sortedTeamPlayers[TEAM_MAXOVERLAY];
+int numSortedTeamPlayers;
+
+char systemChat[256];
+char teamChat1[256];
+char teamChat2[256];
+
+#ifdef MISSIONPACK
+
+int CG_Text_Width(const char *text, float scale, int limit) {
+ int count,len;
+ float out;
+ glyphInfo_t *glyph;
+ float useScale;
+// FIXME: see ui_main.c, same problem
+// const unsigned char *s = text;
+ const char *s = text;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ out = 0;
+ if (text) {
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ if ( Q_IsColorString(s) ) {
+ s += 2;
+ continue;
+ } else {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ out += glyph->xSkip;
+ s++;
+ count++;
+ }
+ }
+ }
+ return out * useScale;
+}
+
+int CG_Text_Height(const char *text, float scale, int limit) {
+ int len, count;
+ float max;
+ glyphInfo_t *glyph;
+ float useScale;
+// TTimo: FIXME
+// const unsigned char *s = text;
+ const char *s = text;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ max = 0;
+ if (text) {
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ if ( Q_IsColorString(s) ) {
+ s += 2;
+ continue;
+ } else {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ if (max < glyph->height) {
+ max = glyph->height;
+ }
+ s++;
+ count++;
+ }
+ }
+ }
+ return max * useScale;
+}
+
+void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
+ float w, h;
+ w = width * scale;
+ h = height * scale;
+ CG_AdjustFrom640( &x, &y, &w, &h );
+ trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
+}
+
+void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
+ int len, count;
+ vec4_t newColor;
+ glyphInfo_t *glyph;
+ float useScale;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ if (text) {
+// TTimo: FIXME
+// const unsigned char *s = text;
+ const char *s = text;
+ trap_R_SetColor( color );
+ memcpy(&newColor[0], &color[0], sizeof(vec4_t));
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
+ //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
+ if ( Q_IsColorString( s ) ) {
+ memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
+ newColor[3] = color[3];
+ trap_R_SetColor( newColor );
+ s += 2;
+ continue;
+ } else {
+ float yadj = useScale * glyph->top;
+ if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
+ int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
+ colorBlack[3] = newColor[3];
+ trap_R_SetColor( colorBlack );
+ CG_Text_PaintChar(x + ofs, y - yadj + ofs,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ colorBlack[3] = 1.0;
+ trap_R_SetColor( newColor );
+ }
+ CG_Text_PaintChar(x, y - yadj,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph);
+ x += (glyph->xSkip * useScale) + adjust;
+ s++;
+ count++;
+ }
+ }
+ trap_R_SetColor( NULL );
+ }
+}
+
+
+#endif
+
+/*
+==============
+CG_DrawField
+
+Draws large numbers for status bar and powerups
+==============
+*/
+#ifndef MISSIONPACK
+static void CG_DrawField (int x, int y, int width, int value) {
+ char num[16], *ptr;
+ int l;
+ int frame;
+
+ if ( width < 1 ) {
+ return;
+ }
+
+ // draw number string
+ if ( width > 5 ) {
+ width = 5;
+ }
+
+ switch ( width ) {
+ case 1:
+ value = value > 9 ? 9 : value;
+ value = value < 0 ? 0 : value;
+ break;
+ case 2:
+ value = value > 99 ? 99 : value;
+ value = value < -9 ? -9 : value;
+ break;
+ case 3:
+ value = value > 999 ? 999 : value;
+ value = value < -99 ? -99 : value;
+ break;
+ case 4:
+ value = value > 9999 ? 9999 : value;
+ value = value < -999 ? -999 : value;
+ break;
+ }
+
+ 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';
+
+ CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
+ x += CHAR_WIDTH;
+ ptr++;
+ l--;
+ }
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_Draw3DModel
+
+================
+*/
+void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
+ refdef_t refdef;
+ refEntity_t ent;
+
+ if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
+ return;
+ }
+
+ CG_AdjustFrom640( &x, &y, &w, &h );
+
+ memset( &refdef, 0, sizeof( refdef ) );
+
+ memset( &ent, 0, sizeof( ent ) );
+ AnglesToAxis( angles, ent.axis );
+ VectorCopy( origin, ent.origin );
+ ent.hModel = model;
+ ent.customSkin = skin;
+ ent.renderfx = RF_NOSHADOW; // no stencil shadows
+
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ AxisClear( refdef.viewaxis );
+
+ refdef.fov_x = 30;
+ refdef.fov_y = 30;
+
+ refdef.x = x;
+ refdef.y = y;
+ refdef.width = w;
+ refdef.height = h;
+
+ refdef.time = cg.time;
+
+ trap_R_ClearScene();
+ trap_R_AddRefEntityToScene( &ent );
+ trap_R_RenderScene( &refdef );
+}
+
+/*
+================
+CG_DrawHead
+
+Used for both the status bar and the scoreboard
+================
+*/
+void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
+ clipHandle_t cm;
+ clientInfo_t *ci;
+ float len;
+ vec3_t origin;
+ vec3_t mins, maxs;
+
+ ci = &cgs.clientinfo[ clientNum ];
+
+ if ( cg_draw3dIcons.integer ) {
+ cm = ci->headModel;
+ if ( !cm ) {
+ return;
+ }
+
+ // offset the origin y and z to center the head
+ trap_R_ModelBounds( cm, mins, maxs );
+
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+
+ // calculate distance so the head nearly fills the box
+ // assume heads are taller than wide
+ len = 0.7 * ( maxs[2] - mins[2] );
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+
+ // allow per-model tweaking
+ VectorAdd( origin, ci->headOffset, origin );
+
+ CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
+ } else if ( cg_drawIcons.integer ) {
+ CG_DrawPic( x, y, w, h, ci->modelIcon );
+ }
+
+ // if they are deferred, draw a cross out
+ if ( ci->deferred ) {
+ CG_DrawPic( x, y, w, h, cgs.media.deferShader );
+ }
+}
+
+/*
+================
+CG_DrawFlagModel
+
+Used for both the status bar and the scoreboard
+================
+*/
+void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
+ qhandle_t cm;
+ float len;
+ vec3_t origin, angles;
+ vec3_t mins, maxs;
+ qhandle_t handle;
+
+ if ( !force2D && cg_draw3dIcons.integer ) {
+
+ VectorClear( angles );
+
+ cm = cgs.media.redFlagModel;
+
+ // offset the origin y and z to center the flag
+ trap_R_ModelBounds( cm, mins, maxs );
+
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+
+ // calculate distance so the flag nearly fills the box
+ // assume heads are taller than wide
+ len = 0.5 * ( maxs[2] - mins[2] );
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+
+ angles[YAW] = 60 * sin( cg.time / 2000.0 );;
+
+ if( team == TEAM_RED ) {
+ handle = cgs.media.redFlagModel;
+ } else if( team == TEAM_BLUE ) {
+ handle = cgs.media.blueFlagModel;
+ } else if( team == TEAM_FREE ) {
+ handle = cgs.media.neutralFlagModel;
+ } else {
+ return;
+ }
+ CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
+ } else if ( cg_drawIcons.integer ) {
+ gitem_t *item;
+
+ if( team == TEAM_RED ) {
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+ } else if( team == TEAM_BLUE ) {
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+ } else if( team == TEAM_FREE ) {
+ item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+ } else {
+ return;
+ }
+ if (item) {
+ CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
+ }
+ }
+}
+
+/*
+================
+CG_DrawStatusBarHead
+
+================
+*/
+#ifndef MISSIONPACK
+
+static void CG_DrawStatusBarHead( float x ) {
+ vec3_t angles;
+ float size, stretch;
+ float frac;
+
+ VectorClear( angles );
+
+ if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
+ frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
+ size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
+
+ stretch = size - ICON_SIZE * 1.25;
+ // kick in the direction of damage
+ x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
+
+ cg.headStartYaw = 180 + cg.damageX * 45;
+
+ cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
+ cg.headEndPitch = 5 * cos( crandom()*M_PI );
+
+ cg.headStartTime = cg.time;
+ cg.headEndTime = cg.time + 100 + random() * 2000;
+ } else {
+ if ( cg.time >= cg.headEndTime ) {
+ // select a new head angle
+ cg.headStartYaw = cg.headEndYaw;
+ cg.headStartPitch = cg.headEndPitch;
+ cg.headStartTime = cg.headEndTime;
+ cg.headEndTime = cg.time + 100 + random() * 2000;
+
+ cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
+ cg.headEndPitch = 5 * cos( crandom()*M_PI );
+ }
+
+ size = ICON_SIZE * 1.25;
+ }
+
+ // if the server was frozen for a while we may have a bad head start time
+ if ( cg.headStartTime > cg.time ) {
+ cg.headStartTime = cg.time;
+ }
+
+ frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
+ frac = frac * frac * ( 3 - 2 * frac );
+ angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
+ angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
+
+ CG_DrawHead( x, 480 - size, size, size,
+ cg.snap->ps.clientNum, angles );
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_DrawStatusBarFlag
+
+================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawStatusBarFlag( float x, int team ) {
+ CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_DrawTeamBackground
+
+================
+*/
+void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
+{
+ vec4_t hcolor;
+
+ hcolor[3] = alpha;
+ if ( team == TEAM_RED ) {
+ hcolor[0] = 1;
+ hcolor[1] = 0;
+ hcolor[2] = 0;
+ } else if ( team == TEAM_BLUE ) {
+ hcolor[0] = 0;
+ hcolor[1] = 0;
+ hcolor[2] = 1;
+ } else {
+ return;
+ }
+ trap_R_SetColor( hcolor );
+ CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
+ trap_R_SetColor( NULL );
+}
+
+/*
+================
+CG_DrawStatusBar
+
+================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawStatusBar( void ) {
+ int color;
+ centity_t *cent;
+ playerState_t *ps;
+ int value;
+ vec4_t hcolor;
+ vec3_t angles;
+ vec3_t origin;
+#ifdef MISSIONPACK
+ qhandle_t handle;
+#endif
+ static float colors[4][4] = {
+// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
+ { 1.0f, 0.69f, 0.0f, 1.0f }, // normal
+ { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
+ { 0.5f, 0.5f, 0.5f, 1.0f }, // weapon firing
+ { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
+
+ if ( cg_drawStatus.integer == 0 ) {
+ return;
+ }
+
+ // draw the team background
+ CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ VectorClear( angles );
+
+ // draw any 3D icons first, so the changes back to 2D are minimized
+ if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
+ origin[0] = 70;
+ origin[1] = 0;
+ origin[2] = 0;
+ angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
+ CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
+ cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
+ }
+
+ CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
+
+ if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
+ CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
+ } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
+ CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
+ } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
+ CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
+ }
+
+ if ( ps->stats[ STAT_ARMOR ] ) {
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+ CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
+ cgs.media.armorModel, 0, origin, angles );
+ }
+#ifdef MISSIONPACK
+ if( cgs.gametype == GT_HARVESTER ) {
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+ if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ handle = cgs.media.redCubeModel;
+ } else {
+ handle = cgs.media.blueCubeModel;
+ }
+ CG_Draw3DModel( 640 - (TEXT_ICON_SPACE + ICON_SIZE), 416, ICON_SIZE, ICON_SIZE, handle, 0, origin, angles );
+ }
+#endif
+ //
+ // ammo
+ //
+ if ( cent->currentState.weapon ) {
+ value = ps->ammo[cent->currentState.weapon];
+ if ( value > -1 ) {
+ if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
+ && cg.predictedPlayerState.weaponTime > 100 ) {
+ // draw as dark grey when reloading
+ color = 2; // dark grey
+ } else {
+ if ( value >= 0 ) {
+ color = 0; // green
+ } else {
+ color = 1; // red
+ }
+ }
+ trap_R_SetColor( colors[color] );
+
+ CG_DrawField (0, 432, 3, value);
+ trap_R_SetColor( NULL );
+
+ // if we didn't draw a 3D icon, draw a 2D icon for ammo
+ if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
+ qhandle_t icon;
+
+ icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
+ if ( icon ) {
+ CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
+ }
+ }
+ }
+ }
+
+ //
+ // health
+ //
+ value = ps->stats[STAT_HEALTH];
+ if ( value > 100 ) {
+ trap_R_SetColor( colors[3] ); // white
+ } else if (value > 25) {
+ trap_R_SetColor( colors[0] ); // green
+ } else if (value > 0) {
+ color = (cg.time >> 8) & 1; // flash
+ trap_R_SetColor( colors[color] );
+ } else {
+ trap_R_SetColor( colors[1] ); // red
+ }
+
+ // stretch the health up when taking damage
+ CG_DrawField ( 185, 432, 3, value);
+ CG_ColorForHealth( hcolor );
+ trap_R_SetColor( hcolor );
+
+
+ //
+ // armor
+ //
+ value = ps->stats[STAT_ARMOR];
+ if (value > 0 ) {
+ trap_R_SetColor( colors[0] );
+ CG_DrawField (370, 432, 3, value);
+ trap_R_SetColor( NULL );
+ // if we didn't draw a 3D icon, draw a 2D icon for armor
+ if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
+ CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
+ }
+
+ }
+#ifdef MISSIONPACK
+ //
+ // cubes
+ //
+ if( cgs.gametype == GT_HARVESTER ) {
+ value = ps->generic1;
+ if( value > 99 ) {
+ value = 99;
+ }
+ trap_R_SetColor( colors[0] );
+ CG_DrawField (640 - (CHAR_WIDTH*2 + TEXT_ICON_SPACE + ICON_SIZE), 432, 2, value);
+ trap_R_SetColor( NULL );
+ // if we didn't draw a 3D icon, draw a 2D icon for armor
+ if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
+ if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ handle = cgs.media.redCubeIcon;
+ } else {
+ handle = cgs.media.blueCubeIcon;
+ }
+ CG_DrawPic( 640 - (TEXT_ICON_SPACE + ICON_SIZE), 432, ICON_SIZE, ICON_SIZE, handle );
+ }
+ }
+#endif
+}
+#endif
+
+/*
+===========================================================================================
+
+ UPPER RIGHT CORNER
+
+===========================================================================================
+*/
+
+/*
+================
+CG_DrawAttacker
+
+================
+*/
+static float CG_DrawAttacker( float y ) {
+ int t;
+ float size;
+ vec3_t angles;
+ const char *info;
+ const char *name;
+ int clientNum;
+
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ return y;
+ }
+
+ if ( !cg.attackerTime ) {
+ return y;
+ }
+
+ clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
+ return y;
+ }
+
+ t = cg.time - cg.attackerTime;
+ if ( t > ATTACKER_HEAD_TIME ) {
+ cg.attackerTime = 0;
+ return y;
+ }
+
+ size = ICON_SIZE * 1.25;
+
+ angles[PITCH] = 0;
+ angles[YAW] = 180;
+ angles[ROLL] = 0;
+ CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
+
+ info = CG_ConfigString( CS_PLAYERS + clientNum );
+ name = Info_ValueForKey( info, "n" );
+ y += size;
+ CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
+
+ return y + BIGCHAR_HEIGHT + 2;
+}
+
+/*
+==================
+CG_DrawSnapshot
+==================
+*/
+static float CG_DrawSnapshot( float y ) {
+ char *s;
+ int w;
+
+ s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
+ cg.latestSnapshotNum, cgs.serverCommandSequence );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+/*
+==================
+CG_DrawFPS
+==================
+*/
+#define FPS_FRAMES 4
+static float CG_DrawFPS( float y ) {
+ char *s;
+ int w;
+ static int previousTimes[FPS_FRAMES];
+ static int index;
+ int i, total;
+ int fps;
+ static int previous;
+ int t, frameTime;
+
+ // don't use serverTime, because that will be drifting to
+ // correct for internet lag changes, timescales, timedemos, etc
+ t = trap_Milliseconds();
+ frameTime = t - previous;
+ previous = t;
+
+ previousTimes[index % FPS_FRAMES] = frameTime;
+ index++;
+ if ( index > FPS_FRAMES ) {
+ // average multiple frames together to smooth changes out a bit
+ total = 0;
+ for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
+ total += previousTimes[i];
+ }
+ if ( !total ) {
+ total = 1;
+ }
+ fps = 1000 * FPS_FRAMES / total;
+
+ s = va( "%ifps", fps );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+ }
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+/*
+=================
+CG_DrawTimer
+=================
+*/
+static float CG_DrawTimer( float y ) {
+ char *s;
+ int w;
+ int mins, seconds, tens;
+ int msec;
+
+ msec = cg.time - cgs.levelStartTime;
+
+ seconds = msec / 1000;
+ mins = seconds / 60;
+ seconds -= mins * 60;
+ tens = seconds / 10;
+ seconds -= tens * 10;
+
+ s = va( "%i:%i%i", mins, tens, seconds );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+
+ CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
+
+ return y + BIGCHAR_HEIGHT + 4;
+}
+
+
+/*
+=================
+CG_DrawTeamOverlay
+=================
+*/
+
+static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
+ int x, w, h, xx;
+ int i, j, len;
+ const char *p;
+ vec4_t hcolor;
+ int pwidth, lwidth;
+ int plyrs;
+ char st[16];
+ clientInfo_t *ci;
+ gitem_t *item;
+ int ret_y, count;
+
+ if ( !cg_drawTeamOverlay.integer ) {
+ return y;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
+ return y; // Not on any team
+ }
+
+ plyrs = 0;
+
+ // max player name width
+ pwidth = 0;
+ count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
+ for (i = 0; i < count; i++) {
+ ci = cgs.clientinfo + sortedTeamPlayers[i];
+ if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
+ plyrs++;
+ len = CG_DrawStrlen(ci->name);
+ if (len > pwidth)
+ pwidth = len;
+ }
+ }
+
+ if (!plyrs)
+ return y;
+
+ if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
+ pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
+
+ // max location name width
+ lwidth = 0;
+ for (i = 1; i < MAX_LOCATIONS; i++) {
+ p = CG_ConfigString(CS_LOCATIONS + i);
+ if (p && *p) {
+ len = CG_DrawStrlen(p);
+ if (len > lwidth)
+ lwidth = len;
+ }
+ }
+
+ if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
+ lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
+
+ w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
+
+ if ( right )
+ x = 640 - w;
+ else
+ x = 0;
+
+ h = plyrs * TINYCHAR_HEIGHT;
+
+ if ( upper ) {
+ ret_y = y + h;
+ } else {
+ y -= h;
+ ret_y = y;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
+ hcolor[0] = 1.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 0.0f;
+ hcolor[3] = 0.33f;
+ } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
+ hcolor[0] = 0.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 1.0f;
+ hcolor[3] = 0.33f;
+ }
+ trap_R_SetColor( hcolor );
+ CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
+ trap_R_SetColor( NULL );
+
+ for (i = 0; i < count; i++) {
+ ci = cgs.clientinfo + sortedTeamPlayers[i];
+ if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
+
+ hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
+
+ xx = x + TINYCHAR_WIDTH;
+
+ CG_DrawStringExt( xx, y,
+ ci->name, hcolor, qfalse, qfalse,
+ TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
+
+ if (lwidth) {
+ p = CG_ConfigString(CS_LOCATIONS + ci->location);
+ if (!p || !*p)
+ p = "unknown";
+ len = CG_DrawStrlen(p);
+ if (len > lwidth)
+ len = lwidth;
+
+// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
+// ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
+ xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
+ CG_DrawStringExt( xx, y,
+ p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ TEAM_OVERLAY_MAXLOCATION_WIDTH);
+ }
+
+ CG_GetColorForHealth( ci->health, ci->armor, hcolor );
+
+ Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
+
+ xx = x + TINYCHAR_WIDTH * 3 +
+ TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
+
+ CG_DrawStringExt( xx, y,
+ st, hcolor, qfalse, qfalse,
+ TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
+
+ // draw weapon icon
+ xx += TINYCHAR_WIDTH * 3;
+
+ if ( cg_weapons[ci->curWeapon].weaponIcon ) {
+ CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ cg_weapons[ci->curWeapon].weaponIcon );
+ } else {
+ CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ cgs.media.deferShader );
+ }
+
+ // Draw powerup icons
+ if (right) {
+ xx = x;
+ } else {
+ xx = x + w - TINYCHAR_WIDTH;
+ }
+ for (j = 0; j <= PW_NUM_POWERUPS; j++) {
+ if (ci->powerups & (1 << j)) {
+
+ item = BG_FindItemForPowerup( j );
+
+ if (item) {
+ CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
+ trap_R_RegisterShader( item->icon ) );
+ if (right) {
+ xx -= TINYCHAR_WIDTH;
+ } else {
+ xx += TINYCHAR_WIDTH;
+ }
+ }
+ }
+ }
+
+ y += TINYCHAR_HEIGHT;
+ }
+ }
+
+ return ret_y;
+//#endif
+}
+
+
+/*
+=====================
+CG_DrawUpperRight
+
+=====================
+*/
+static void CG_DrawUpperRight( void ) {
+ float y;
+
+ y = 0;
+
+ if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {
+ y = CG_DrawTeamOverlay( y, qtrue, qtrue );
+ }
+ if ( cg_drawSnapshot.integer ) {
+ y = CG_DrawSnapshot( y );
+ }
+ if ( cg_drawFPS.integer ) {
+ y = CG_DrawFPS( y );
+ }
+ if ( cg_drawTimer.integer ) {
+ y = CG_DrawTimer( y );
+ }
+ if ( cg_drawAttacker.integer ) {
+ y = CG_DrawAttacker( y );
+ }
+
+}
+
+/*
+===========================================================================================
+
+ LOWER RIGHT CORNER
+
+===========================================================================================
+*/
+
+/*
+=================
+CG_DrawScores
+
+Draw the small two score display
+=================
+*/
+#ifndef MISSIONPACK
+static float CG_DrawScores( float y ) {
+ const char *s;
+ int s1, s2, score;
+ int x, w;
+ int v;
+ vec4_t color;
+ float y1;
+ gitem_t *item;
+
+ s1 = cgs.scores1;
+ s2 = cgs.scores2;
+
+ y -= BIGCHAR_HEIGHT + 8;
+
+ y1 = y;
+
+ // draw from the right side to left
+ if ( cgs.gametype >= GT_TEAM ) {
+ x = 640;
+ color[0] = 0.0f;
+ color[1] = 0.0f;
+ color[2] = 1.0f;
+ color[3] = 0.33f;
+ s = va( "%2i", s2 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+
+ if ( cgs.gametype == GT_CTF ) {
+ // Display flag status
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+
+ if (item) {
+ y1 = y - BIGCHAR_HEIGHT - 8;
+ if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
+ CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
+ }
+ }
+ }
+ color[0] = 1.0f;
+ color[1] = 0.0f;
+ color[2] = 0.0f;
+ color[3] = 0.33f;
+ s = va( "%2i", s1 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+
+ if ( cgs.gametype == GT_CTF ) {
+ // Display flag status
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+
+ if (item) {
+ y1 = y - BIGCHAR_HEIGHT - 8;
+ if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
+ CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
+ }
+ }
+ }
+
+#ifdef MISSIONPACK
+ if ( cgs.gametype == GT_1FCTF ) {
+ // Display flag status
+ item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+
+ if (item) {
+ y1 = y - BIGCHAR_HEIGHT - 8;
+ if( cgs.flagStatus >= 0 && cgs.flagStatus <= 3 ) {
+ CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.flagShader[cgs.flagStatus] );
+ }
+ }
+ }
+#endif
+ if ( cgs.gametype >= GT_CTF ) {
+ v = cgs.capturelimit;
+ } else {
+ v = cgs.fraglimit;
+ }
+ if ( v ) {
+ s = va( "%2i", v );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ } else {
+ qboolean spectator;
+
+ x = 640;
+ score = cg.snap->ps.persistant[PERS_SCORE];
+ spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
+
+ // always show your score in the second box if not in first place
+ if ( s1 != score ) {
+ s2 = score;
+ }
+ if ( s2 != SCORE_NOT_PRESENT ) {
+ s = va( "%2i", s2 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ if ( !spectator && score == s2 && score != s1 ) {
+ color[0] = 1.0f;
+ color[1] = 0.0f;
+ color[2] = 0.0f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ } else {
+ color[0] = 0.5f;
+ color[1] = 0.5f;
+ color[2] = 0.5f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ // first place
+ if ( s1 != SCORE_NOT_PRESENT ) {
+ s = va( "%2i", s1 );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ if ( !spectator && score == s1 ) {
+ color[0] = 0.0f;
+ color[1] = 0.0f;
+ color[2] = 1.0f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
+ } else {
+ color[0] = 0.5f;
+ color[1] = 0.5f;
+ color[2] = 0.5f;
+ color[3] = 0.33f;
+ CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
+ }
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ if ( cgs.fraglimit ) {
+ s = va( "%2i", cgs.fraglimit );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
+ x -= w;
+ CG_DrawBigString( x + 4, y, s, 1.0F);
+ }
+
+ }
+
+ return y1 - 8;
+}
+#endif // MISSIONPACK
+
+/*
+================
+CG_DrawPowerups
+================
+*/
+#ifndef MISSIONPACK
+static float CG_DrawPowerups( float y ) {
+ int sorted[MAX_POWERUPS];
+ int sortedTime[MAX_POWERUPS];
+ int i, j, k;
+ int active;
+ playerState_t *ps;
+ int t;
+ gitem_t *item;
+ int x;
+ int color;
+ float size;
+ float f;
+ static float colors[2][4] = {
+ { 0.2f, 1.0f, 0.2f, 1.0f } ,
+ { 1.0f, 0.2f, 0.2f, 1.0f }
+ };
+
+ ps = &cg.snap->ps;
+
+ if ( ps->stats[STAT_HEALTH] <= 0 ) {
+ return y;
+ }
+
+ // sort the list by time remaining
+ active = 0;
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ if ( !ps->powerups[ i ] ) {
+ continue;
+ }
+ t = ps->powerups[ i ] - cg.time;
+ // ZOID--don't draw if the power up has unlimited time (999 seconds)
+ // This is true of the CTF flags
+ if ( t < 0 || t > 999000) {
+ continue;
+ }
+
+ // insert into the list
+ for ( j = 0 ; j < active ; j++ ) {
+ if ( sortedTime[j] >= t ) {
+ for ( k = active - 1 ; k >= j ; k-- ) {
+ sorted[k+1] = sorted[k];
+ sortedTime[k+1] = sortedTime[k];
+ }
+ break;
+ }
+ }
+ sorted[j] = i;
+ sortedTime[j] = t;
+ active++;
+ }
+
+ // draw the icons and timers
+ x = 640 - ICON_SIZE - CHAR_WIDTH * 2;
+ for ( i = 0 ; i < active ; i++ ) {
+ item = BG_FindItemForPowerup( sorted[i] );
+
+ if (item) {
+
+ color = 1;
+
+ y -= ICON_SIZE;
+
+ trap_R_SetColor( colors[color] );
+ CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );
+
+ t = ps->powerups[ sorted[i] ];
+ if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
+ trap_R_SetColor( NULL );
+ } else {
+ vec4_t modulate;
+
+ f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
+ f -= (int)f;
+ modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
+ trap_R_SetColor( modulate );
+ }
+
+ if ( cg.powerupActive == sorted[i] &&
+ cg.time - cg.powerupTime < PULSE_TIME ) {
+ f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );
+ size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );
+ } else {
+ size = ICON_SIZE;
+ }
+
+ CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2,
+ size, size, trap_R_RegisterShader( item->icon ) );
+ }
+ }
+ trap_R_SetColor( NULL );
+
+ return y;
+}
+#endif // MISSIONPACK
+
+/*
+=====================
+CG_DrawLowerRight
+
+=====================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawLowerRight( void ) {
+ float y;
+
+ y = 480 - ICON_SIZE;
+
+ if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) {
+ y = CG_DrawTeamOverlay( y, qtrue, qfalse );
+ }
+
+ y = CG_DrawScores( y );
+ y = CG_DrawPowerups( y );
+}
+#endif // MISSIONPACK
+
+/*
+===================
+CG_DrawPickupItem
+===================
+*/
+#ifndef MISSIONPACK
+static int CG_DrawPickupItem( int y ) {
+ int value;
+ float *fadeColor;
+
+ if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
+ return y;
+ }
+
+ y -= ICON_SIZE;
+
+ value = cg.itemPickup;
+ if ( value ) {
+ fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
+ if ( fadeColor ) {
+ CG_RegisterItemVisuals( value );
+ trap_R_SetColor( fadeColor );
+ CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
+ trap_R_SetColor( NULL );
+ }
+ }
+
+ return y;
+}
+#endif // MISSIONPACK
+
+/*
+=====================
+CG_DrawLowerLeft
+
+=====================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawLowerLeft( void ) {
+ float y;
+
+ y = 480 - ICON_SIZE;
+
+ if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 3 ) {
+ y = CG_DrawTeamOverlay( y, qfalse, qfalse );
+ }
+
+
+ y = CG_DrawPickupItem( y );
+}
+#endif // MISSIONPACK
+
+
+//===========================================================================================
+
+/*
+=================
+CG_DrawTeamInfo
+=================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawTeamInfo( void ) {
+ int w, h;
+ int i, len;
+ vec4_t hcolor;
+ int chatHeight;
+
+#define CHATLOC_Y 420 // bottom end
+#define CHATLOC_X 0
+
+ if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)
+ chatHeight = cg_teamChatHeight.integer;
+ else
+ chatHeight = TEAMCHAT_HEIGHT;
+ if (chatHeight <= 0)
+ return; // disabled
+
+ if (cgs.teamLastChatPos != cgs.teamChatPos) {
+ if (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {
+ cgs.teamLastChatPos++;
+ }
+
+ h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;
+
+ w = 0;
+
+ for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {
+ len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);
+ if (len > w)
+ w = len;
+ }
+ w *= TINYCHAR_WIDTH;
+ w += TINYCHAR_WIDTH * 2;
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
+ hcolor[0] = 1.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 0.0f;
+ hcolor[3] = 0.33f;
+ } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ hcolor[0] = 0.0f;
+ hcolor[1] = 0.0f;
+ hcolor[2] = 1.0f;
+ hcolor[3] = 0.33f;
+ } else {
+ hcolor[0] = 0.0f;
+ hcolor[1] = 1.0f;
+ hcolor[2] = 0.0f;
+ hcolor[3] = 0.33f;
+ }
+
+ trap_R_SetColor( hcolor );
+ CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );
+ trap_R_SetColor( NULL );
+
+ hcolor[0] = hcolor[1] = hcolor[2] = 1.0f;
+ hcolor[3] = 1.0f;
+
+ for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {
+ CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH,
+ CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT,
+ cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,
+ TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
+ }
+ }
+}
+#endif // MISSIONPACK
+
+/*
+===================
+CG_DrawHoldableItem
+===================
+*/
+#ifndef MISSIONPACK
+static void CG_DrawHoldableItem( void ) {
+ int value;
+
+ value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
+ if ( value ) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ }
+
+}
+#endif // MISSIONPACK
+
+#ifdef MISSIONPACK
+/*
+===================
+CG_DrawPersistantPowerup
+===================
+*/
+#if 0 // sos001208 - DEAD
+static void CG_DrawPersistantPowerup( void ) {
+ int value;
+
+ value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
+ if ( value ) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
+ }
+}
+#endif
+#endif // MISSIONPACK
+
+
+/*
+===================
+CG_DrawReward
+===================
+*/
+static void CG_DrawReward( void ) {
+ float *color;
+ int i, count;
+ float x, y;
+ char buf[32];
+
+ if ( !cg_drawRewards.integer ) {
+ return;
+ }
+
+ color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
+ if ( !color ) {
+ if (cg.rewardStack > 0) {
+ for(i = 0; i < cg.rewardStack; i++) {
+ cg.rewardSound[i] = cg.rewardSound[i+1];
+ cg.rewardShader[i] = cg.rewardShader[i+1];
+ cg.rewardCount[i] = cg.rewardCount[i+1];
+ }
+ cg.rewardTime = cg.time;
+ cg.rewardStack--;
+ color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
+ trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
+ } else {
+ return;
+ }
+ }
+
+ trap_R_SetColor( color );
+
+ /*
+ count = cg.rewardCount[0]/10; // number of big rewards to draw
+
+ if (count) {
+ y = 4;
+ x = 320 - count * ICON_SIZE;
+ for ( i = 0 ; i < count ; i++ ) {
+ CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
+ x += (ICON_SIZE*2);
+ }
+ }
+
+ count = cg.rewardCount[0] - count*10; // number of small rewards to draw
+ */
+
+ if ( cg.rewardCount[0] >= 10 ) {
+ y = 56;
+ x = 320 - ICON_SIZE/2;
+ CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
+ Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
+ x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
+ CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
+ SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
+ }
+ else {
+
+ count = cg.rewardCount[0];
+
+ y = 56;
+ x = 320 - count * ICON_SIZE/2;
+ for ( i = 0 ; i < count ; i++ ) {
+ CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
+ x += ICON_SIZE;
+ }
+ }
+ trap_R_SetColor( NULL );
+}
+
+
+/*
+===============================================================================
+
+LAGOMETER
+
+===============================================================================
+*/
+
+#define LAG_SAMPLES 128
+
+
+typedef struct {
+ int frameSamples[LAG_SAMPLES];
+ int frameCount;
+ int snapshotFlags[LAG_SAMPLES];
+ int snapshotSamples[LAG_SAMPLES];
+ int snapshotCount;
+} lagometer_t;
+
+lagometer_t lagometer;
+
+/*
+==============
+CG_AddLagometerFrameInfo
+
+Adds the current interpolate / extrapolate bar for this frame
+==============
+*/
+void CG_AddLagometerFrameInfo( void ) {
+ int offset;
+
+ offset = cg.time - cg.latestSnapshotTime;
+ lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
+ lagometer.frameCount++;
+}
+
+/*
+==============
+CG_AddLagometerSnapshotInfo
+
+Each time a snapshot is received, log its ping time and
+the number of snapshots that were dropped before it.
+
+Pass NULL for a dropped packet.
+==============
+*/
+void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
+ // dropped packet
+ if ( !snap ) {
+ lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
+ lagometer.snapshotCount++;
+ return;
+ }
+
+ // add this snapshot's info
+ lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
+ lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
+ lagometer.snapshotCount++;
+}
+
+/*
+==============
+CG_DrawDisconnect
+
+Should we draw something differnet for long lag vs no packets?
+==============
+*/
+static void CG_DrawDisconnect( void ) {
+ float x, y;
+ int cmdNum;
+ usercmd_t cmd;
+ const char *s;
+ int w; // bk010215 - FIXME char message[1024];
+
+ // draw the phone jack if we are completely past our buffers
+ cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
+ trap_GetUserCmd( cmdNum, &cmd );
+ if ( cmd.serverTime <= cg.snap->ps.commandTime
+ || cmd.serverTime > cg.time ) { // special check for map_restart // bk 0102165 - FIXME
+ return;
+ }
+
+ // also add text in center of screen
+ s = "Connection Interrupted"; // bk 010215 - FIXME
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
+
+ // blink the icon
+ if ( ( cg.time >> 9 ) & 1 ) {
+ return;
+ }
+
+ x = 640 - 48;
+ y = 480 - 48;
+
+ CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
+}
+
+
+#define MAX_LAGOMETER_PING 900
+#define MAX_LAGOMETER_RANGE 300
+
+/*
+==============
+CG_DrawLagometer
+==============
+*/
+static void CG_DrawLagometer( void ) {
+ int a, x, y, i;
+ float v;
+ float ax, ay, aw, ah, mid, range;
+ int color;
+ float vscale;
+
+ if ( !cg_lagometer.integer || cgs.localServer ) {
+ CG_DrawDisconnect();
+ return;
+ }
+
+ //
+ // draw the graph
+ //
+#ifdef MISSIONPACK
+ x = 640 - 48;
+ y = 480 - 144;
+#else
+ x = 640 - 48;
+ y = 480 - 48;
+#endif
+
+ trap_R_SetColor( NULL );
+ CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
+
+ ax = x;
+ ay = y;
+ aw = 48;
+ ah = 48;
+ CG_AdjustFrom640( &ax, &ay, &aw, &ah );
+
+ color = -1;
+ range = ah / 3;
+ mid = ay + range;
+
+ vscale = range / MAX_LAGOMETER_RANGE;
+
+ // draw the frame interpoalte / extrapolate graph
+ for ( a = 0 ; a < aw ; a++ ) {
+ i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
+ v = lagometer.frameSamples[i];
+ v *= vscale;
+ if ( v > 0 ) {
+ if ( color != 1 ) {
+ color = 1;
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
+ }
+ if ( v > range ) {
+ v = range;
+ }
+ trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
+ } else if ( v < 0 ) {
+ if ( color != 2 ) {
+ color = 2;
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
+ }
+ v = -v;
+ if ( v > range ) {
+ v = range;
+ }
+ trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
+ }
+ }
+
+ // draw the snapshot latency / drop graph
+ range = ah / 2;
+ vscale = range / MAX_LAGOMETER_PING;
+
+ for ( a = 0 ; a < aw ; a++ ) {
+ i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
+ v = lagometer.snapshotSamples[i];
+ if ( v > 0 ) {
+ if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
+ if ( color != 5 ) {
+ color = 5; // YELLOW for rate delay
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
+ }
+ } else {
+ if ( color != 3 ) {
+ color = 3;
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
+ }
+ }
+ v = v * vscale;
+ if ( v > range ) {
+ v = range;
+ }
+ trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
+ } else if ( v < 0 ) {
+ if ( color != 4 ) {
+ color = 4; // RED for dropped snapshots
+ trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
+ }
+ trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
+ }
+ }
+
+ trap_R_SetColor( NULL );
+
+ if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
+ CG_DrawBigString( ax, ay, "snc", 1.0 );
+ }
+
+ CG_DrawDisconnect();
+}
+
+
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+
+/*
+==============
+CG_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void CG_CenterPrint( const char *str, int y, int charWidth ) {
+ char *s;
+
+ Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
+
+ cg.centerPrintTime = cg.time;
+ cg.centerPrintY = y;
+ cg.centerPrintCharWidth = charWidth;
+
+ // count the number of lines for centering
+ cg.centerPrintLines = 1;
+ s = cg.centerPrint;
+ while( *s ) {
+ if (*s == '\n')
+ cg.centerPrintLines++;
+ s++;
+ }
+}
+
+
+/*
+===================
+CG_DrawCenterString
+===================
+*/
+static void CG_DrawCenterString( void ) {
+ char *start;
+ int l;
+ int x, y, w;
+#ifdef MISSIONPACK // bk010221 - unused else
+ int h;
+#endif
+ float *color;
+
+ if ( !cg.centerPrintTime ) {
+ return;
+ }
+
+ color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
+ if ( !color ) {
+ return;
+ }
+
+ trap_R_SetColor( color );
+
+ start = cg.centerPrint;
+
+ y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
+
+ while ( 1 ) {
+ char linebuffer[1024];
+
+ for ( l = 0; l < 50; l++ ) {
+ if ( !start[l] || start[l] == '\n' ) {
+ break;
+ }
+ linebuffer[l] = start[l];
+ }
+ linebuffer[l] = 0;
+
+#ifdef MISSIONPACK
+ w = CG_Text_Width(linebuffer, 0.5, 0);
+ h = CG_Text_Height(linebuffer, 0.5, 0);
+ x = (SCREEN_WIDTH - w) / 2;
+ CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+ y += h + 6;
+#else
+ w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
+
+ x = ( SCREEN_WIDTH - w ) / 2;
+
+ CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,
+ cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
+
+ y += cg.centerPrintCharWidth * 1.5;
+#endif
+ while ( *start && ( *start != '\n' ) ) {
+ start++;
+ }
+ if ( !*start ) {
+ break;
+ }
+ start++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+
+
+/*
+================================================================================
+
+CROSSHAIR
+
+================================================================================
+*/
+
+
+/*
+=================
+CG_DrawCrosshair
+=================
+*/
+static void CG_DrawCrosshair(void) {
+ float w, h;
+ qhandle_t hShader;
+ float f;
+ float x, y;
+ int ca;
+
+ if ( !cg_drawCrosshair.integer ) {
+ return;
+ }
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
+ return;
+ }
+
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+ // set color based on health
+ if ( cg_crosshairHealth.integer ) {
+ vec4_t hcolor;
+
+ CG_ColorForHealth( hcolor );
+ trap_R_SetColor( hcolor );
+ } else {
+ trap_R_SetColor( NULL );
+ }
+
+ w = h = cg_crosshairSize.value;
+
+ // pulse the size of the crosshair when picking up items
+ f = cg.time - cg.itemPickupBlendTime;
+ if ( f > 0 && f < ITEM_BLOB_TIME ) {
+ f /= ITEM_BLOB_TIME;
+ w *= ( 1 + f );
+ h *= ( 1 + f );
+ }
+
+ x = cg_crosshairX.integer;
+ y = cg_crosshairY.integer;
+ CG_AdjustFrom640( &x, &y, &w, &h );
+
+ ca = cg_drawCrosshair.integer;
+ if (ca < 0) {
+ ca = 0;
+ }
+ hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
+
+ trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
+ y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
+ w, h, 0, 0, 1, 1, hShader );
+}
+
+
+
+/*
+=================
+CG_ScanForCrosshairEntity
+=================
+*/
+static void CG_ScanForCrosshairEntity( void ) {
+ trace_t trace;
+ vec3_t start, end;
+ int content;
+
+ VectorCopy( cg.refdef.vieworg, start );
+ VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
+
+ CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
+ cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
+ if ( trace.entityNum >= MAX_CLIENTS ) {
+ return;
+ }
+
+ // if the player is in fog, don't show it
+ content = trap_CM_PointContents( trace.endpos, 0 );
+ if ( content & CONTENTS_FOG ) {
+ return;
+ }
+
+ // if the player is invisible, don't show it
+ if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {
+ return;
+ }
+
+ // update the fade timer
+ cg.crosshairClientNum = trace.entityNum;
+ cg.crosshairClientTime = cg.time;
+}
+
+
+/*
+=====================
+CG_DrawCrosshairNames
+=====================
+*/
+static void CG_DrawCrosshairNames( void ) {
+ float *color;
+ char *name;
+ float w;
+
+ if ( !cg_drawCrosshair.integer ) {
+ return;
+ }
+ if ( !cg_drawCrosshairNames.integer ) {
+ return;
+ }
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+ // scan the known entities to see if the crosshair is sighted on one
+ CG_ScanForCrosshairEntity();
+
+ // draw the name of the player being looked at
+ color = CG_FadeColor( cg.crosshairClientTime, 1000 );
+ if ( !color ) {
+ trap_R_SetColor( NULL );
+ return;
+ }
+
+ name = cgs.clientinfo[ cg.crosshairClientNum ].name;
+#ifdef MISSIONPACK
+ color[3] *= 0.5f;
+ w = CG_Text_Width(name, 0.3f, 0);
+ CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
+#else
+ w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
+ CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );
+#endif
+ trap_R_SetColor( NULL );
+}
+
+
+//==============================================================================
+
+/*
+=================
+CG_DrawSpectator
+=================
+*/
+static void CG_DrawSpectator(void) {
+ CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F);
+ if ( cgs.gametype == GT_TOURNAMENT ) {
+ CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F);
+ }
+ else if ( cgs.gametype >= GT_TEAM ) {
+ CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F);
+ }
+}
+
+/*
+=================
+CG_DrawVote
+=================
+*/
+static void CG_DrawVote(void) {
+ char *s;
+ int sec;
+
+ if ( !cgs.voteTime ) {
+ return;
+ }
+
+ // play a talk beep whenever it is modified
+ if ( cgs.voteModified ) {
+ cgs.voteModified = qfalse;
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ }
+
+ sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
+ if ( sec < 0 ) {
+ sec = 0;
+ }
+#ifdef MISSIONPACK
+ s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo);
+ CG_DrawSmallString( 0, 58, s, 1.0F );
+ s = "or press ESC then click Vote";
+ CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
+#else
+ s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );
+ CG_DrawSmallString( 0, 58, s, 1.0F );
+#endif
+}
+
+/*
+=================
+CG_DrawTeamVote
+=================
+*/
+static void CG_DrawTeamVote(void) {
+ char *s;
+ int sec, cs_offset;
+
+ if ( cgs.clientinfo->team == TEAM_RED )
+ cs_offset = 0;
+ else if ( cgs.clientinfo->team == TEAM_BLUE )
+ cs_offset = 1;
+ else
+ return;
+
+ if ( !cgs.teamVoteTime[cs_offset] ) {
+ return;
+ }
+
+ // play a talk beep whenever it is modified
+ if ( cgs.teamVoteModified[cs_offset] ) {
+ cgs.teamVoteModified[cs_offset] = qfalse;
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ }
+
+ sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
+ if ( sec < 0 ) {
+ sec = 0;
+ }
+ s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
+ cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
+ CG_DrawSmallString( 0, 90, s, 1.0F );
+}
+
+
+static qboolean CG_DrawScoreboard() {
+#ifdef MISSIONPACK
+ static qboolean firstTime = qtrue;
+ float fade, *fadeColor;
+
+ if (menuScoreboard) {
+ menuScoreboard->window.flags &= ~WINDOW_FORCED;
+ }
+ if (cg_paused.integer) {
+ cg.deferredPlayerLoading = 0;
+ firstTime = qtrue;
+ return qfalse;
+ }
+
+ // should never happen in Team Arena
+ if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ cg.deferredPlayerLoading = 0;
+ firstTime = qtrue;
+ return qfalse;
+ }
+
+ // don't draw scoreboard during death while warmup up
+ if ( cg.warmup && !cg.showScores ) {
+ return qfalse;
+ }
+
+ if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ fade = 1.0;
+ fadeColor = colorWhite;
+ } else {
+ fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
+ if ( !fadeColor ) {
+ // next time scoreboard comes up, don't print killer
+ cg.deferredPlayerLoading = 0;
+ cg.killerName[0] = 0;
+ firstTime = qtrue;
+ return qfalse;
+ }
+ fade = *fadeColor;
+ }
+
+
+ if (menuScoreboard == NULL) {
+ if ( cgs.gametype >= GT_TEAM ) {
+ menuScoreboard = Menus_FindByName("teamscore_menu");
+ } else {
+ menuScoreboard = Menus_FindByName("score_menu");
+ }
+ }
+
+ if (menuScoreboard) {
+ if (firstTime) {
+ CG_SetScoreSelection(menuScoreboard);
+ firstTime = qfalse;
+ }
+ Menu_Paint(menuScoreboard, qtrue);
+ }
+
+ // load any models that have been deferred
+ if ( ++cg.deferredPlayerLoading > 10 ) {
+ CG_LoadDeferredPlayers();
+ }
+
+ return qtrue;
+#else
+ return CG_DrawOldScoreboard();
+#endif
+}
+
+/*
+=================
+CG_DrawIntermission
+=================
+*/
+static void CG_DrawIntermission( void ) {
+// int key;
+#ifdef MISSIONPACK
+ //if (cg_singlePlayer.integer) {
+ // CG_DrawCenterString();
+ // return;
+ //}
+#else
+ if ( cgs.gametype == GT_SINGLE_PLAYER ) {
+ CG_DrawCenterString();
+ return;
+ }
+#endif
+ cg.scoreFadeTime = cg.time;
+ cg.scoreBoardShowing = CG_DrawScoreboard();
+}
+
+/*
+=================
+CG_DrawFollow
+=================
+*/
+static qboolean CG_DrawFollow( void ) {
+ float x;
+ vec4_t color;
+ const char *name;
+
+ if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
+ return qfalse;
+ }
+ color[0] = 1;
+ color[1] = 1;
+ color[2] = 1;
+ color[3] = 1;
+
+
+ CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F );
+
+ name = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
+
+ x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );
+
+ CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+
+ return qtrue;
+}
+
+
+
+/*
+=================
+CG_DrawAmmoWarning
+=================
+*/
+static void CG_DrawAmmoWarning( void ) {
+ const char *s;
+ int w;
+
+ if ( cg_drawAmmoWarning.integer == 0 ) {
+ return;
+ }
+
+ if ( !cg.lowAmmoWarning ) {
+ return;
+ }
+
+ if ( cg.lowAmmoWarning == 2 ) {
+ s = "OUT OF AMMO";
+ } else {
+ s = "LOW AMMO WARNING";
+ }
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
+}
+
+
+#ifdef MISSIONPACK
+/*
+=================
+CG_DrawProxWarning
+=================
+*/
+static void CG_DrawProxWarning( void ) {
+ char s [32];
+ int w;
+ static int proxTime;
+ static int proxCounter;
+ static int proxTick;
+
+ if( !(cg.snap->ps.eFlags & EF_TICKING ) ) {
+ proxTime = 0;
+ return;
+ }
+
+ if (proxTime == 0) {
+ proxTime = cg.time + 5000;
+ proxCounter = 5;
+ proxTick = 0;
+ }
+
+ if (cg.time > proxTime) {
+ proxTick = proxCounter--;
+ proxTime = cg.time + 1000;
+ }
+
+ if (proxTick != 0) {
+ Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick);
+ } else {
+ Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED");
+ }
+
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] );
+}
+#endif
+
+
+/*
+=================
+CG_DrawWarmup
+=================
+*/
+static void CG_DrawWarmup( void ) {
+ int w;
+ int sec;
+ int i;
+ float scale;
+ clientInfo_t *ci1, *ci2;
+ int cw;
+ const char *s;
+
+ sec = cg.warmup;
+ if ( !sec ) {
+ return;
+ }
+
+ if ( sec < 0 ) {
+ s = "Waiting for players";
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
+ cg.warmupCount = 0;
+ return;
+ }
+
+ if (cgs.gametype == GT_TOURNAMENT) {
+ // find the two active players
+ ci1 = NULL;
+ ci2 = NULL;
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
+ if ( !ci1 ) {
+ ci1 = &cgs.clientinfo[i];
+ } else {
+ ci2 = &cgs.clientinfo[i];
+ }
+ }
+ }
+
+ if ( ci1 && ci2 ) {
+ s = va( "%s vs %s", ci1->name, ci2->name );
+#ifdef MISSIONPACK
+ w = CG_Text_Width(s, 0.6f, 0);
+ CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+#else
+ w = CG_DrawStrlen( s );
+ if ( w > 640 / GIANT_WIDTH ) {
+ cw = 640 / w;
+ } else {
+ cw = GIANT_WIDTH;
+ }
+ CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.5f), 0 );
+#endif
+ }
+ } else {
+ if ( cgs.gametype == GT_FFA ) {
+ s = "Free For All";
+ } else if ( cgs.gametype == GT_TEAM ) {
+ s = "Team Deathmatch";
+ } else if ( cgs.gametype == GT_CTF ) {
+ s = "Capture the Flag";
+#ifdef MISSIONPACK
+ } else if ( cgs.gametype == GT_1FCTF ) {
+ s = "One Flag CTF";
+ } else if ( cgs.gametype == GT_OBELISK ) {
+ s = "Overload";
+ } else if ( cgs.gametype == GT_HARVESTER ) {
+ s = "Harvester";
+#endif
+ } else {
+ s = "";
+ }
+#ifdef MISSIONPACK
+ w = CG_Text_Width(s, 0.6f, 0);
+ CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+#else
+ w = CG_DrawStrlen( s );
+ if ( w > 640 / GIANT_WIDTH ) {
+ cw = 640 / w;
+ } else {
+ cw = GIANT_WIDTH;
+ }
+ CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.1f), 0 );
+#endif
+ }
+
+ sec = ( sec - cg.time ) / 1000;
+ if ( sec < 0 ) {
+ cg.warmup = 0;
+ sec = 0;
+ }
+ s = va( "Starts in: %i", sec + 1 );
+ if ( sec != cg.warmupCount ) {
+ cg.warmupCount = sec;
+ switch ( sec ) {
+ case 0:
+ trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
+ break;
+ case 1:
+ trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
+ break;
+ case 2:
+ trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
+ break;
+ default:
+ break;
+ }
+ }
+ scale = 0.45f;
+ switch ( cg.warmupCount ) {
+ case 0:
+ cw = 28;
+ scale = 0.54f;
+ break;
+ case 1:
+ cw = 24;
+ scale = 0.51f;
+ break;
+ case 2:
+ cw = 20;
+ scale = 0.48f;
+ break;
+ default:
+ cw = 16;
+ scale = 0.45f;
+ break;
+ }
+
+#ifdef MISSIONPACK
+ w = CG_Text_Width(s, scale, 0);
+ CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
+#else
+ w = CG_DrawStrlen( s );
+ CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite,
+ qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
+#endif
+}
+
+//==================================================================================
+#ifdef MISSIONPACK
+/*
+=================
+CG_DrawTimedMenus
+=================
+*/
+void CG_DrawTimedMenus() {
+ if (cg.voiceTime) {
+ int t = cg.time - cg.voiceTime;
+ if ( t > 2500 ) {
+ Menus_CloseByName("voiceMenu");
+ trap_Cvar_Set("cl_conXOffset", "0");
+ cg.voiceTime = 0;
+ }
+ }
+}
+#endif
+/*
+=================
+CG_Draw2D
+=================
+*/
+static void CG_Draw2D( void ) {
+#ifdef MISSIONPACK
+ if (cgs.orderPending && cg.time > cgs.orderTime) {
+ CG_CheckOrderPending();
+ }
+#endif
+ // if we are taking a levelshot for the menu, don't draw anything
+ if ( cg.levelShot ) {
+ return;
+ }
+
+ if ( cg_draw2D.integer == 0 ) {
+ return;
+ }
+
+ if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
+ CG_DrawIntermission();
+ return;
+ }
+
+/*
+ if (cg.cameraMode) {
+ return;
+ }
+*/
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
+ CG_DrawSpectator();
+ CG_DrawCrosshair();
+ CG_DrawCrosshairNames();
+ } else {
+ // don't draw any status if dead or the scoreboard is being explicitly shown
+ if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
+
+#ifdef MISSIONPACK
+ if ( cg_drawStatus.integer ) {
+ Menu_PaintAll();
+ CG_DrawTimedMenus();
+ }
+#else
+ CG_DrawStatusBar();
+#endif
+
+ CG_DrawAmmoWarning();
+
+#ifdef MISSIONPACK
+ CG_DrawProxWarning();
+#endif
+ CG_DrawCrosshair();
+ CG_DrawCrosshairNames();
+ CG_DrawWeaponSelect();
+
+#ifndef MISSIONPACK
+ CG_DrawHoldableItem();
+#else
+ //CG_DrawPersistantPowerup();
+#endif
+ CG_DrawReward();
+ }
+
+ if ( cgs.gametype >= GT_TEAM ) {
+#ifndef MISSIONPACK
+ CG_DrawTeamInfo();
+#endif
+ }
+ }
+
+ CG_DrawVote();
+ CG_DrawTeamVote();
+
+ CG_DrawLagometer();
+
+#ifdef MISSIONPACK
+ if (!cg_paused.integer) {
+ CG_DrawUpperRight();
+ }
+#else
+ CG_DrawUpperRight();
+#endif
+
+#ifndef MISSIONPACK
+ CG_DrawLowerRight();
+ CG_DrawLowerLeft();
+#endif
+
+ if ( !CG_DrawFollow() ) {
+ CG_DrawWarmup();
+ }
+
+ // don't draw center string if scoreboard is up
+ cg.scoreBoardShowing = CG_DrawScoreboard();
+ if ( !cg.scoreBoardShowing) {
+ CG_DrawCenterString();
+ }
+}
+
+
+static void CG_DrawTourneyScoreboard() {
+#ifdef MISSIONPACK
+#else
+ CG_DrawOldTourneyScoreboard();
+#endif
+}
+
+/*
+=====================
+CG_DrawActive
+
+Perform all drawing needed to completely fill the screen
+=====================
+*/
+void CG_DrawActive( stereoFrame_t stereoView ) {
+ float separation;
+ vec3_t baseOrg;
+
+ // optionally draw the info screen instead
+ if ( !cg.snap ) {
+ CG_DrawInformation();
+ return;
+ }
+
+ // optionally draw the tournement scoreboard instead
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
+ ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
+ CG_DrawTourneyScoreboard();
+ return;
+ }
+
+ switch ( stereoView ) {
+ case STEREO_CENTER:
+ separation = 0;
+ break;
+ case STEREO_LEFT:
+ separation = -cg_stereoSeparation.value / 2;
+ break;
+ case STEREO_RIGHT:
+ separation = cg_stereoSeparation.value / 2;
+ break;
+ default:
+ separation = 0;
+ CG_Error( "CG_DrawActive: Undefined stereoView" );
+ }
+
+
+ // clear around the rendered view if sized down
+ CG_TileClear();
+
+ // offset vieworg appropriately if we're doing stereo separation
+ VectorCopy( cg.refdef.vieworg, baseOrg );
+ if ( separation != 0 ) {
+ VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
+ }
+
+ // draw 3D view
+ trap_R_RenderScene( &cg.refdef );
+
+ // restore original viewpoint if running stereo
+ if ( separation != 0 ) {
+ VectorCopy( baseOrg, cg.refdef.vieworg );
+ }
+
+ // draw status bar and other floating elements
+ CG_Draw2D();
+}
+
+
+
diff --git a/code/cgame/cg_drawtools.c b/code/cgame/cg_drawtools.c
index 9c27606..2ec45ed 100755
--- a/code/cgame/cg_drawtools.c
+++ b/code/cgame/cg_drawtools.c
@@ -1,824 +1,824 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
-#include "cg_local.h"
-
-/*
-================
-CG_AdjustFrom640
-
-Adjusted for resolution and screen aspect ratio
-================
-*/
-void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
-#if 0
- // adjust for wide screens
- if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
- *x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
- }
-#endif
- // scale for screen sizes
- *x *= cgs.screenXScale;
- *y *= cgs.screenYScale;
- *w *= cgs.screenXScale;
- *h *= cgs.screenYScale;
-}
-
-/*
-================
-CG_FillRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void CG_FillRect( float x, float y, float width, float height, const float *color ) {
- trap_R_SetColor( color );
-
- CG_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
-
- trap_R_SetColor( NULL );
-}
-
-/*
-================
-CG_DrawSides
-
-Coords are virtual 640x480
-================
-*/
-void CG_DrawSides(float x, float y, float w, float h, float size) {
- CG_AdjustFrom640( &x, &y, &w, &h );
- size *= cgs.screenXScale;
- trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
- trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
-}
-
-void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
- CG_AdjustFrom640( &x, &y, &w, &h );
- size *= cgs.screenYScale;
- trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
- trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
-}
-/*
-================
-UI_DrawRect
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
- trap_R_SetColor( color );
-
- CG_DrawTopBottom(x, y, width, height, size);
- CG_DrawSides(x, y, width, height, size);
-
- trap_R_SetColor( NULL );
-}
-
-
-
-/*
-================
-CG_DrawPic
-
-Coordinates are 640*480 virtual values
-=================
-*/
-void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
- CG_AdjustFrom640( &x, &y, &width, &height );
- trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
-}
-
-
-
-/*
-===============
-CG_DrawChar
-
-Coordinates and size in 640*480 virtual screen size
-===============
-*/
-void CG_DrawChar( int x, int y, int width, int height, int ch ) {
- int row, col;
- float frow, fcol;
- float size;
- float ax, ay, aw, ah;
-
- ch &= 255;
-
- if ( ch == ' ' ) {
- return;
- }
-
- ax = x;
- ay = y;
- aw = width;
- ah = height;
- CG_AdjustFrom640( &ax, &ay, &aw, &ah );
-
- row = ch>>4;
- col = ch&15;
-
- frow = row*0.0625;
- fcol = col*0.0625;
- size = 0.0625;
-
- trap_R_DrawStretchPic( ax, ay, aw, ah,
- fcol, frow,
- fcol + size, frow + size,
- cgs.media.charsetShader );
-}
-
-
-/*
-==================
-CG_DrawStringExt
-
-Draws a multi-colored string with a drop shadow, optionally forcing
-to a fixed color.
-
-Coordinates are at 640 by 480 virtual resolution
-==================
-*/
-void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
- qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {
- vec4_t color;
- const char *s;
- int xx;
- int cnt;
-
- if (maxChars <= 0)
- maxChars = 32767; // do them all!
-
- // draw the drop shadow
- if (shadow) {
- color[0] = color[1] = color[2] = 0;
- color[3] = setColor[3];
- trap_R_SetColor( color );
- s = string;
- xx = x;
- cnt = 0;
- while ( *s && cnt < maxChars) {
- if ( Q_IsColorString( s ) ) {
- s += 2;
- continue;
- }
- CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s );
- cnt++;
- xx += charWidth;
- s++;
- }
- }
-
- // draw the colored text
- s = string;
- xx = x;
- cnt = 0;
- trap_R_SetColor( setColor );
- while ( *s && cnt < maxChars) {
- if ( Q_IsColorString( s ) ) {
- if ( !forceColor ) {
- memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
- color[3] = setColor[3];
- trap_R_SetColor( color );
- }
- s += 2;
- continue;
- }
- CG_DrawChar( xx, y, charWidth, charHeight, *s );
- xx += charWidth;
- cnt++;
- s++;
- }
- trap_R_SetColor( NULL );
-}
-
-void CG_DrawBigString( int x, int y, const char *s, float alpha ) {
- float color[4];
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = alpha;
- CG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
-}
-
-void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {
- CG_DrawStringExt( x, y, s, color, qtrue, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
-}
-
-void CG_DrawSmallString( int x, int y, const char *s, float alpha ) {
- float color[4];
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = alpha;
- CG_DrawStringExt( x, y, s, color, qfalse, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
-}
-
-void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ) {
- CG_DrawStringExt( x, y, s, color, qtrue, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
-}
-
-/*
-=================
-CG_DrawStrlen
-
-Returns character count, skiping color escape codes
-=================
-*/
-int CG_DrawStrlen( const char *str ) {
- const char *s = str;
- int count = 0;
-
- while ( *s ) {
- if ( Q_IsColorString( s ) ) {
- s += 2;
- } else {
- count++;
- s++;
- }
- }
-
- return count;
-}
-
-/*
-=============
-CG_TileClearBox
-
-This repeats a 64*64 tile graphic to fill the screen around a sized down
-refresh window.
-=============
-*/
-static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
- float s1, t1, s2, t2;
-
- s1 = x/64.0;
- t1 = y/64.0;
- s2 = (x+w)/64.0;
- t2 = (y+h)/64.0;
- trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
-}
-
-
-
-/*
-==============
-CG_TileClear
-
-Clear around a sized down screen
-==============
-*/
-void CG_TileClear( void ) {
- int top, bottom, left, right;
- int w, h;
-
- w = cgs.glconfig.vidWidth;
- h = cgs.glconfig.vidHeight;
-
- if ( cg.refdef.x == 0 && cg.refdef.y == 0 &&
- cg.refdef.width == w && cg.refdef.height == h ) {
- return; // full screen rendering
- }
-
- top = cg.refdef.y;
- bottom = top + cg.refdef.height-1;
- left = cg.refdef.x;
- right = left + cg.refdef.width-1;
-
- // clear above view screen
- CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
-
- // clear below view screen
- CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
-
- // clear left of view screen
- CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
-
- // clear right of view screen
- CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
-}
-
-
-
-/*
-================
-CG_FadeColor
-================
-*/
-float *CG_FadeColor( int startMsec, int totalMsec ) {
- static vec4_t color;
- int t;
-
- if ( startMsec == 0 ) {
- return NULL;
- }
-
- t = cg.time - startMsec;
-
- if ( t >= totalMsec ) {
- return NULL;
- }
-
- // fade out
- if ( totalMsec - t < FADE_TIME ) {
- color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
- } else {
- color[3] = 1.0;
- }
- color[0] = color[1] = color[2] = 1;
-
- return color;
-}
-
-
-/*
-================
-CG_TeamColor
-================
-*/
-float *CG_TeamColor( int team ) {
- static vec4_t red = {1, 0.2f, 0.2f, 1};
- static vec4_t blue = {0.2f, 0.2f, 1, 1};
- static vec4_t other = {1, 1, 1, 1};
- static vec4_t spectator = {0.7f, 0.7f, 0.7f, 1};
-
- switch ( team ) {
- case TEAM_RED:
- return red;
- case TEAM_BLUE:
- return blue;
- case TEAM_SPECTATOR:
- return spectator;
- default:
- return other;
- }
-}
-
-
-
-/*
-=================
-CG_GetColorForHealth
-=================
-*/
-void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ) {
- int count;
- int max;
-
- // calculate the total points of damage that can
- // be sustained at the current health / armor level
- if ( health <= 0 ) {
- VectorClear( hcolor ); // black
- hcolor[3] = 1;
- return;
- }
- count = armor;
- max = health * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION );
- if ( max < count ) {
- count = max;
- }
- health += count;
-
- // set the color based on health
- hcolor[0] = 1.0;
- hcolor[3] = 1.0;
- if ( health >= 100 ) {
- hcolor[2] = 1.0;
- } else if ( health < 66 ) {
- hcolor[2] = 0;
- } else {
- hcolor[2] = ( health - 66 ) / 33.0;
- }
-
- if ( health > 60 ) {
- hcolor[1] = 1.0;
- } else if ( health < 30 ) {
- hcolor[1] = 0;
- } else {
- hcolor[1] = ( health - 30 ) / 30.0;
- }
-}
-
-/*
-=================
-CG_ColorForHealth
-=================
-*/
-void CG_ColorForHealth( vec4_t hcolor ) {
-
- CG_GetColorForHealth( cg.snap->ps.stats[STAT_HEALTH],
- cg.snap->ps.stats[STAT_ARMOR], hcolor );
-}
-
-
-
-
-// bk001205 - code below duplicated in q3_ui/ui-atoms.c
-// bk001205 - FIXME: does this belong in ui_shared.c?
-// bk001205 - FIXME: HARD_LINKED flags not visible here
-#ifndef Q3_STATIC // bk001205 - q_shared defines not visible here
-/*
-=================
-UI_DrawProportionalString2
-=================
-*/
-static int propMap[128][3] = {
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
-
-{0, 0, PROP_SPACE_WIDTH}, // SPACE
-{11, 122, 7}, // !
-{154, 181, 14}, // "
-{55, 122, 17}, // #
-{79, 122, 18}, // $
-{101, 122, 23}, // %
-{153, 122, 18}, // &
-{9, 93, 7}, // '
-{207, 122, 8}, // (
-{230, 122, 9}, // )
-{177, 122, 18}, // *
-{30, 152, 18}, // +
-{85, 181, 7}, // ,
-{34, 93, 11}, // -
-{110, 181, 6}, // .
-{130, 152, 14}, // /
-
-{22, 64, 17}, // 0
-{41, 64, 12}, // 1
-{58, 64, 17}, // 2
-{78, 64, 18}, // 3
-{98, 64, 19}, // 4
-{120, 64, 18}, // 5
-{141, 64, 18}, // 6
-{204, 64, 16}, // 7
-{162, 64, 17}, // 8
-{182, 64, 18}, // 9
-{59, 181, 7}, // :
-{35,181, 7}, // ;
-{203, 152, 14}, // <
-{56, 93, 14}, // =
-{228, 152, 14}, // >
-{177, 181, 18}, // ?
-
-{28, 122, 22}, // @
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{60, 152, 7}, // [
-{106, 151, 13}, // '\'
-{83, 152, 7}, // ]
-{128, 122, 17}, // ^
-{4, 152, 21}, // _
-
-{134, 181, 5}, // '
-{5, 4, 18}, // A
-{27, 4, 18}, // B
-{48, 4, 18}, // C
-{69, 4, 17}, // D
-{90, 4, 13}, // E
-{106, 4, 13}, // F
-{121, 4, 18}, // G
-{143, 4, 17}, // H
-{164, 4, 8}, // I
-{175, 4, 16}, // J
-{195, 4, 18}, // K
-{216, 4, 12}, // L
-{230, 4, 23}, // M
-{6, 34, 18}, // N
-{27, 34, 18}, // O
-
-{48, 34, 18}, // P
-{68, 34, 18}, // Q
-{90, 34, 17}, // R
-{110, 34, 18}, // S
-{130, 34, 14}, // T
-{146, 34, 18}, // U
-{166, 34, 19}, // V
-{185, 34, 29}, // W
-{215, 34, 18}, // X
-{234, 34, 18}, // Y
-{5, 64, 14}, // Z
-{153, 152, 13}, // {
-{11, 181, 5}, // |
-{180, 152, 13}, // }
-{79, 93, 17}, // ~
-{0, 0, -1} // DEL
-};
-
-static int propMapB[26][3] = {
-{11, 12, 33},
-{49, 12, 31},
-{85, 12, 31},
-{120, 12, 30},
-{156, 12, 21},
-{183, 12, 21},
-{207, 12, 32},
-
-{13, 55, 30},
-{49, 55, 13},
-{66, 55, 29},
-{101, 55, 31},
-{135, 55, 21},
-{158, 55, 40},
-{204, 55, 32},
-
-{12, 97, 31},
-{48, 97, 31},
-{82, 97, 30},
-{118, 97, 30},
-{153, 97, 30},
-{185, 97, 25},
-{213, 97, 30},
-
-{11, 139, 32},
-{42, 139, 51},
-{93, 139, 32},
-{126, 139, 31},
-{158, 139, 25},
-};
-
-#define PROPB_GAP_WIDTH 4
-#define PROPB_SPACE_WIDTH 12
-#define PROPB_HEIGHT 36
-
-/*
-=================
-UI_DrawBannerString
-=================
-*/
-static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
-{
- const char* s;
- unsigned char ch; // bk001204 : array subscript
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * cgs.screenXScale + cgs.screenXBias;
- ay = y * cgs.screenXScale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* cgs.screenXScale;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- ch -= 'A';
- fcol = (float)propMapB[ch][0] / 256.0f;
- frow = (float)propMapB[ch][1] / 256.0f;
- fwidth = (float)propMapB[ch][2] / 256.0f;
- fheight = (float)PROPB_HEIGHT / 256.0f;
- aw = (float)propMapB[ch][2] * cgs.screenXScale;
- ah = (float)PROPB_HEIGHT * cgs.screenXScale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, cgs.media.charsetPropB );
- ax += (aw + (float)PROPB_GAP_WIDTH * cgs.screenXScale);
- }
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
- const char * s;
- int ch;
- int width;
- vec4_t drawcolor;
-
- // find the width of the drawn text
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s;
- if ( ch == ' ' ) {
- width += PROPB_SPACE_WIDTH;
- }
- else if ( ch >= 'A' && ch <= 'Z' ) {
- width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
- }
- s++;
- }
- width -= PROPB_GAP_WIDTH;
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawBannerString2( x+2, y+2, str, drawcolor );
- }
-
- UI_DrawBannerString2( x, y, str, color );
-}
-
-
-int UI_ProportionalStringWidth( const char* str ) {
- const char * s;
- int ch;
- int charWidth;
- int width;
-
- s = str;
- width = 0;
- while ( *s ) {
- ch = *s & 127;
- charWidth = propMap[ch][2];
- if ( charWidth != -1 ) {
- width += charWidth;
- width += PROP_GAP_WIDTH;
- }
- s++;
- }
-
- width -= PROP_GAP_WIDTH;
- return width;
-}
-
-static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
-{
- const char* s;
- unsigned char ch; // bk001204 - unsigned
- float ax;
- float ay;
- float aw;
- float ah;
- float frow;
- float fcol;
- float fwidth;
- float fheight;
-
- // draw the colored text
- trap_R_SetColor( color );
-
- ax = x * cgs.screenXScale + cgs.screenXBias;
- ay = y * cgs.screenXScale;
-
- s = str;
- while ( *s )
- {
- ch = *s & 127;
- if ( ch == ' ' ) {
- aw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale;
- } else if ( propMap[ch][2] != -1 ) {
- fcol = (float)propMap[ch][0] / 256.0f;
- frow = (float)propMap[ch][1] / 256.0f;
- fwidth = (float)propMap[ch][2] / 256.0f;
- fheight = (float)PROP_HEIGHT / 256.0f;
- aw = (float)propMap[ch][2] * cgs.screenXScale * sizeScale;
- ah = (float)PROP_HEIGHT * cgs.screenXScale * sizeScale;
- trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
- } else {
- aw = 0;
- }
-
- ax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale);
- s++;
- }
-
- trap_R_SetColor( NULL );
-}
-
-/*
-=================
-UI_ProportionalSizeScale
-=================
-*/
-float UI_ProportionalSizeScale( int style ) {
- if( style & UI_SMALLFONT ) {
- return 0.75;
- }
-
- return 1.00;
-}
-
-
-/*
-=================
-UI_DrawProportionalString
-=================
-*/
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
- vec4_t drawcolor;
- int width;
- float sizeScale;
-
- sizeScale = UI_ProportionalSizeScale( style );
-
- switch( style & UI_FORMATMASK ) {
- case UI_CENTER:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width / 2;
- break;
-
- case UI_RIGHT:
- width = UI_ProportionalStringWidth( str ) * sizeScale;
- x -= width;
- break;
-
- case UI_LEFT:
- default:
- break;
- }
-
- if ( style & UI_DROPSHADOW ) {
- drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, cgs.media.charsetProp );
- }
-
- if ( style & UI_INVERSE ) {
- drawcolor[0] = color[0] * 0.8;
- drawcolor[1] = color[1] * 0.8;
- drawcolor[2] = color[2] * 0.8;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetProp );
- return;
- }
-
- if ( style & UI_PULSE ) {
- drawcolor[0] = color[0] * 0.8;
- drawcolor[1] = color[1] * 0.8;
- drawcolor[2] = color[2] * 0.8;
- drawcolor[3] = color[3];
- UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
-
- drawcolor[0] = color[0];
- drawcolor[1] = color[1];
- drawcolor[2] = color[2];
- drawcolor[3] = 0.5 + 0.5 * sin( cg.time / PULSE_DIVISOR );
- UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetPropGlow );
- return;
- }
-
- UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
-}
-#endif // Q3STATIC
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
+#include "cg_local.h"
+
+/*
+================
+CG_AdjustFrom640
+
+Adjusted for resolution and screen aspect ratio
+================
+*/
+void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
+#if 0
+ // adjust for wide screens
+ if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
+ *x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
+ }
+#endif
+ // scale for screen sizes
+ *x *= cgs.screenXScale;
+ *y *= cgs.screenYScale;
+ *w *= cgs.screenXScale;
+ *h *= cgs.screenYScale;
+}
+
+/*
+================
+CG_FillRect
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void CG_FillRect( float x, float y, float width, float height, const float *color ) {
+ trap_R_SetColor( color );
+
+ CG_AdjustFrom640( &x, &y, &width, &height );
+ trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+================
+CG_DrawSides
+
+Coords are virtual 640x480
+================
+*/
+void CG_DrawSides(float x, float y, float w, float h, float size) {
+ CG_AdjustFrom640( &x, &y, &w, &h );
+ size *= cgs.screenXScale;
+ trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
+ trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
+}
+
+void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
+ CG_AdjustFrom640( &x, &y, &w, &h );
+ size *= cgs.screenYScale;
+ trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
+ trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
+}
+/*
+================
+UI_DrawRect
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
+ trap_R_SetColor( color );
+
+ CG_DrawTopBottom(x, y, width, height, size);
+ CG_DrawSides(x, y, width, height, size);
+
+ trap_R_SetColor( NULL );
+}
+
+
+
+/*
+================
+CG_DrawPic
+
+Coordinates are 640*480 virtual values
+=================
+*/
+void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
+ CG_AdjustFrom640( &x, &y, &width, &height );
+ trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
+}
+
+
+
+/*
+===============
+CG_DrawChar
+
+Coordinates and size in 640*480 virtual screen size
+===============
+*/
+void CG_DrawChar( int x, int y, int width, int height, int ch ) {
+ int row, col;
+ float frow, fcol;
+ float size;
+ float ax, ay, aw, ah;
+
+ ch &= 255;
+
+ if ( ch == ' ' ) {
+ return;
+ }
+
+ ax = x;
+ ay = y;
+ aw = width;
+ ah = height;
+ CG_AdjustFrom640( &ax, &ay, &aw, &ah );
+
+ row = ch>>4;
+ col = ch&15;
+
+ frow = row*0.0625;
+ fcol = col*0.0625;
+ size = 0.0625;
+
+ trap_R_DrawStretchPic( ax, ay, aw, ah,
+ fcol, frow,
+ fcol + size, frow + size,
+ cgs.media.charsetShader );
+}
+
+
+/*
+==================
+CG_DrawStringExt
+
+Draws a multi-colored string with a drop shadow, optionally forcing
+to a fixed color.
+
+Coordinates are at 640 by 480 virtual resolution
+==================
+*/
+void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
+ qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {
+ vec4_t color;
+ const char *s;
+ int xx;
+ int cnt;
+
+ if (maxChars <= 0)
+ maxChars = 32767; // do them all!
+
+ // draw the drop shadow
+ if (shadow) {
+ color[0] = color[1] = color[2] = 0;
+ color[3] = setColor[3];
+ trap_R_SetColor( color );
+ s = string;
+ xx = x;
+ cnt = 0;
+ while ( *s && cnt < maxChars) {
+ if ( Q_IsColorString( s ) ) {
+ s += 2;
+ continue;
+ }
+ CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s );
+ cnt++;
+ xx += charWidth;
+ s++;
+ }
+ }
+
+ // draw the colored text
+ s = string;
+ xx = x;
+ cnt = 0;
+ trap_R_SetColor( setColor );
+ while ( *s && cnt < maxChars) {
+ if ( Q_IsColorString( s ) ) {
+ if ( !forceColor ) {
+ memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
+ color[3] = setColor[3];
+ trap_R_SetColor( color );
+ }
+ s += 2;
+ continue;
+ }
+ CG_DrawChar( xx, y, charWidth, charHeight, *s );
+ xx += charWidth;
+ cnt++;
+ s++;
+ }
+ trap_R_SetColor( NULL );
+}
+
+void CG_DrawBigString( int x, int y, const char *s, float alpha ) {
+ float color[4];
+
+ color[0] = color[1] = color[2] = 1.0;
+ color[3] = alpha;
+ CG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
+}
+
+void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {
+ CG_DrawStringExt( x, y, s, color, qtrue, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
+}
+
+void CG_DrawSmallString( int x, int y, const char *s, float alpha ) {
+ float color[4];
+
+ color[0] = color[1] = color[2] = 1.0;
+ color[3] = alpha;
+ CG_DrawStringExt( x, y, s, color, qfalse, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
+}
+
+void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ) {
+ CG_DrawStringExt( x, y, s, color, qtrue, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
+}
+
+/*
+=================
+CG_DrawStrlen
+
+Returns character count, skiping color escape codes
+=================
+*/
+int CG_DrawStrlen( const char *str ) {
+ const char *s = str;
+ int count = 0;
+
+ while ( *s ) {
+ if ( Q_IsColorString( s ) ) {
+ s += 2;
+ } else {
+ count++;
+ s++;
+ }
+ }
+
+ return count;
+}
+
+/*
+=============
+CG_TileClearBox
+
+This repeats a 64*64 tile graphic to fill the screen around a sized down
+refresh window.
+=============
+*/
+static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
+ float s1, t1, s2, t2;
+
+ s1 = x/64.0;
+ t1 = y/64.0;
+ s2 = (x+w)/64.0;
+ t2 = (y+h)/64.0;
+ trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
+}
+
+
+
+/*
+==============
+CG_TileClear
+
+Clear around a sized down screen
+==============
+*/
+void CG_TileClear( void ) {
+ int top, bottom, left, right;
+ int w, h;
+
+ w = cgs.glconfig.vidWidth;
+ h = cgs.glconfig.vidHeight;
+
+ if ( cg.refdef.x == 0 && cg.refdef.y == 0 &&
+ cg.refdef.width == w && cg.refdef.height == h ) {
+ return; // full screen rendering
+ }
+
+ top = cg.refdef.y;
+ bottom = top + cg.refdef.height-1;
+ left = cg.refdef.x;
+ right = left + cg.refdef.width-1;
+
+ // clear above view screen
+ CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
+
+ // clear below view screen
+ CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
+
+ // clear left of view screen
+ CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
+
+ // clear right of view screen
+ CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
+}
+
+
+
+/*
+================
+CG_FadeColor
+================
+*/
+float *CG_FadeColor( int startMsec, int totalMsec ) {
+ static vec4_t color;
+ int t;
+
+ if ( startMsec == 0 ) {
+ return NULL;
+ }
+
+ t = cg.time - startMsec;
+
+ if ( t >= totalMsec ) {
+ return NULL;
+ }
+
+ // fade out
+ if ( totalMsec - t < FADE_TIME ) {
+ color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
+ } else {
+ color[3] = 1.0;
+ }
+ color[0] = color[1] = color[2] = 1;
+
+ return color;
+}
+
+
+/*
+================
+CG_TeamColor
+================
+*/
+float *CG_TeamColor( int team ) {
+ static vec4_t red = {1, 0.2f, 0.2f, 1};
+ static vec4_t blue = {0.2f, 0.2f, 1, 1};
+ static vec4_t other = {1, 1, 1, 1};
+ static vec4_t spectator = {0.7f, 0.7f, 0.7f, 1};
+
+ switch ( team ) {
+ case TEAM_RED:
+ return red;
+ case TEAM_BLUE:
+ return blue;
+ case TEAM_SPECTATOR:
+ return spectator;
+ default:
+ return other;
+ }
+}
+
+
+
+/*
+=================
+CG_GetColorForHealth
+=================
+*/
+void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ) {
+ int count;
+ int max;
+
+ // calculate the total points of damage that can
+ // be sustained at the current health / armor level
+ if ( health <= 0 ) {
+ VectorClear( hcolor ); // black
+ hcolor[3] = 1;
+ return;
+ }
+ count = armor;
+ max = health * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION );
+ if ( max < count ) {
+ count = max;
+ }
+ health += count;
+
+ // set the color based on health
+ hcolor[0] = 1.0;
+ hcolor[3] = 1.0;
+ if ( health >= 100 ) {
+ hcolor[2] = 1.0;
+ } else if ( health < 66 ) {
+ hcolor[2] = 0;
+ } else {
+ hcolor[2] = ( health - 66 ) / 33.0;
+ }
+
+ if ( health > 60 ) {
+ hcolor[1] = 1.0;
+ } else if ( health < 30 ) {
+ hcolor[1] = 0;
+ } else {
+ hcolor[1] = ( health - 30 ) / 30.0;
+ }
+}
+
+/*
+=================
+CG_ColorForHealth
+=================
+*/
+void CG_ColorForHealth( vec4_t hcolor ) {
+
+ CG_GetColorForHealth( cg.snap->ps.stats[STAT_HEALTH],
+ cg.snap->ps.stats[STAT_ARMOR], hcolor );
+}
+
+
+
+
+// bk001205 - code below duplicated in q3_ui/ui-atoms.c
+// bk001205 - FIXME: does this belong in ui_shared.c?
+// bk001205 - FIXME: HARD_LINKED flags not visible here
+#ifndef Q3_STATIC // bk001205 - q_shared defines not visible here
+/*
+=================
+UI_DrawProportionalString2
+=================
+*/
+static int propMap[128][3] = {
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+{0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
+
+{0, 0, PROP_SPACE_WIDTH}, // SPACE
+{11, 122, 7}, // !
+{154, 181, 14}, // "
+{55, 122, 17}, // #
+{79, 122, 18}, // $
+{101, 122, 23}, // %
+{153, 122, 18}, // &
+{9, 93, 7}, // '
+{207, 122, 8}, // (
+{230, 122, 9}, // )
+{177, 122, 18}, // *
+{30, 152, 18}, // +
+{85, 181, 7}, // ,
+{34, 93, 11}, // -
+{110, 181, 6}, // .
+{130, 152, 14}, // /
+
+{22, 64, 17}, // 0
+{41, 64, 12}, // 1
+{58, 64, 17}, // 2
+{78, 64, 18}, // 3
+{98, 64, 19}, // 4
+{120, 64, 18}, // 5
+{141, 64, 18}, // 6
+{204, 64, 16}, // 7
+{162, 64, 17}, // 8
+{182, 64, 18}, // 9
+{59, 181, 7}, // :
+{35,181, 7}, // ;
+{203, 152, 14}, // <
+{56, 93, 14}, // =
+{228, 152, 14}, // >
+{177, 181, 18}, // ?
+
+{28, 122, 22}, // @
+{5, 4, 18}, // A
+{27, 4, 18}, // B
+{48, 4, 18}, // C
+{69, 4, 17}, // D
+{90, 4, 13}, // E
+{106, 4, 13}, // F
+{121, 4, 18}, // G
+{143, 4, 17}, // H
+{164, 4, 8}, // I
+{175, 4, 16}, // J
+{195, 4, 18}, // K
+{216, 4, 12}, // L
+{230, 4, 23}, // M
+{6, 34, 18}, // N
+{27, 34, 18}, // O
+
+{48, 34, 18}, // P
+{68, 34, 18}, // Q
+{90, 34, 17}, // R
+{110, 34, 18}, // S
+{130, 34, 14}, // T
+{146, 34, 18}, // U
+{166, 34, 19}, // V
+{185, 34, 29}, // W
+{215, 34, 18}, // X
+{234, 34, 18}, // Y
+{5, 64, 14}, // Z
+{60, 152, 7}, // [
+{106, 151, 13}, // '\'
+{83, 152, 7}, // ]
+{128, 122, 17}, // ^
+{4, 152, 21}, // _
+
+{134, 181, 5}, // '
+{5, 4, 18}, // A
+{27, 4, 18}, // B
+{48, 4, 18}, // C
+{69, 4, 17}, // D
+{90, 4, 13}, // E
+{106, 4, 13}, // F
+{121, 4, 18}, // G
+{143, 4, 17}, // H
+{164, 4, 8}, // I
+{175, 4, 16}, // J
+{195, 4, 18}, // K
+{216, 4, 12}, // L
+{230, 4, 23}, // M
+{6, 34, 18}, // N
+{27, 34, 18}, // O
+
+{48, 34, 18}, // P
+{68, 34, 18}, // Q
+{90, 34, 17}, // R
+{110, 34, 18}, // S
+{130, 34, 14}, // T
+{146, 34, 18}, // U
+{166, 34, 19}, // V
+{185, 34, 29}, // W
+{215, 34, 18}, // X
+{234, 34, 18}, // Y
+{5, 64, 14}, // Z
+{153, 152, 13}, // {
+{11, 181, 5}, // |
+{180, 152, 13}, // }
+{79, 93, 17}, // ~
+{0, 0, -1} // DEL
+};
+
+static int propMapB[26][3] = {
+{11, 12, 33},
+{49, 12, 31},
+{85, 12, 31},
+{120, 12, 30},
+{156, 12, 21},
+{183, 12, 21},
+{207, 12, 32},
+
+{13, 55, 30},
+{49, 55, 13},
+{66, 55, 29},
+{101, 55, 31},
+{135, 55, 21},
+{158, 55, 40},
+{204, 55, 32},
+
+{12, 97, 31},
+{48, 97, 31},
+{82, 97, 30},
+{118, 97, 30},
+{153, 97, 30},
+{185, 97, 25},
+{213, 97, 30},
+
+{11, 139, 32},
+{42, 139, 51},
+{93, 139, 32},
+{126, 139, 31},
+{158, 139, 25},
+};
+
+#define PROPB_GAP_WIDTH 4
+#define PROPB_SPACE_WIDTH 12
+#define PROPB_HEIGHT 36
+
+/*
+=================
+UI_DrawBannerString
+=================
+*/
+static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
+{
+ const char* s;
+ unsigned char ch; // bk001204 : array subscript
+ float ax;
+ float ay;
+ float aw;
+ float ah;
+ float frow;
+ float fcol;
+ float fwidth;
+ float fheight;
+
+ // draw the colored text
+ trap_R_SetColor( color );
+
+ ax = x * cgs.screenXScale + cgs.screenXBias;
+ ay = y * cgs.screenXScale;
+
+ s = str;
+ while ( *s )
+ {
+ ch = *s & 127;
+ if ( ch == ' ' ) {
+ ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* cgs.screenXScale;
+ }
+ else if ( ch >= 'A' && ch <= 'Z' ) {
+ ch -= 'A';
+ fcol = (float)propMapB[ch][0] / 256.0f;
+ frow = (float)propMapB[ch][1] / 256.0f;
+ fwidth = (float)propMapB[ch][2] / 256.0f;
+ fheight = (float)PROPB_HEIGHT / 256.0f;
+ aw = (float)propMapB[ch][2] * cgs.screenXScale;
+ ah = (float)PROPB_HEIGHT * cgs.screenXScale;
+ trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, cgs.media.charsetPropB );
+ ax += (aw + (float)PROPB_GAP_WIDTH * cgs.screenXScale);
+ }
+ s++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
+ const char * s;
+ int ch;
+ int width;
+ vec4_t drawcolor;
+
+ // find the width of the drawn text
+ s = str;
+ width = 0;
+ while ( *s ) {
+ ch = *s;
+ if ( ch == ' ' ) {
+ width += PROPB_SPACE_WIDTH;
+ }
+ else if ( ch >= 'A' && ch <= 'Z' ) {
+ width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
+ }
+ s++;
+ }
+ width -= PROPB_GAP_WIDTH;
+
+ switch( style & UI_FORMATMASK ) {
+ case UI_CENTER:
+ x -= width / 2;
+ break;
+
+ case UI_RIGHT:
+ x -= width;
+ break;
+
+ case UI_LEFT:
+ default:
+ break;
+ }
+
+ if ( style & UI_DROPSHADOW ) {
+ drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
+ drawcolor[3] = color[3];
+ UI_DrawBannerString2( x+2, y+2, str, drawcolor );
+ }
+
+ UI_DrawBannerString2( x, y, str, color );
+}
+
+
+int UI_ProportionalStringWidth( const char* str ) {
+ const char * s;
+ int ch;
+ int charWidth;
+ int width;
+
+ s = str;
+ width = 0;
+ while ( *s ) {
+ ch = *s & 127;
+ charWidth = propMap[ch][2];
+ if ( charWidth != -1 ) {
+ width += charWidth;
+ width += PROP_GAP_WIDTH;
+ }
+ s++;
+ }
+
+ width -= PROP_GAP_WIDTH;
+ return width;
+}
+
+static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
+{
+ const char* s;
+ unsigned char ch; // bk001204 - unsigned
+ float ax;
+ float ay;
+ float aw;
+ float ah;
+ float frow;
+ float fcol;
+ float fwidth;
+ float fheight;
+
+ // draw the colored text
+ trap_R_SetColor( color );
+
+ ax = x * cgs.screenXScale + cgs.screenXBias;
+ ay = y * cgs.screenXScale;
+
+ s = str;
+ while ( *s )
+ {
+ ch = *s & 127;
+ if ( ch == ' ' ) {
+ aw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale;
+ } else if ( propMap[ch][2] != -1 ) {
+ fcol = (float)propMap[ch][0] / 256.0f;
+ frow = (float)propMap[ch][1] / 256.0f;
+ fwidth = (float)propMap[ch][2] / 256.0f;
+ fheight = (float)PROP_HEIGHT / 256.0f;
+ aw = (float)propMap[ch][2] * cgs.screenXScale * sizeScale;
+ ah = (float)PROP_HEIGHT * cgs.screenXScale * sizeScale;
+ trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
+ } else {
+ aw = 0;
+ }
+
+ ax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale);
+ s++;
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+/*
+=================
+UI_ProportionalSizeScale
+=================
+*/
+float UI_ProportionalSizeScale( int style ) {
+ if( style & UI_SMALLFONT ) {
+ return 0.75;
+ }
+
+ return 1.00;
+}
+
+
+/*
+=================
+UI_DrawProportionalString
+=================
+*/
+void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
+ vec4_t drawcolor;
+ int width;
+ float sizeScale;
+
+ sizeScale = UI_ProportionalSizeScale( style );
+
+ switch( style & UI_FORMATMASK ) {
+ case UI_CENTER:
+ width = UI_ProportionalStringWidth( str ) * sizeScale;
+ x -= width / 2;
+ break;
+
+ case UI_RIGHT:
+ width = UI_ProportionalStringWidth( str ) * sizeScale;
+ x -= width;
+ break;
+
+ case UI_LEFT:
+ default:
+ break;
+ }
+
+ if ( style & UI_DROPSHADOW ) {
+ drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
+ drawcolor[3] = color[3];
+ UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, cgs.media.charsetProp );
+ }
+
+ if ( style & UI_INVERSE ) {
+ drawcolor[0] = color[0] * 0.8;
+ drawcolor[1] = color[1] * 0.8;
+ drawcolor[2] = color[2] * 0.8;
+ drawcolor[3] = color[3];
+ UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetProp );
+ return;
+ }
+
+ if ( style & UI_PULSE ) {
+ drawcolor[0] = color[0] * 0.8;
+ drawcolor[1] = color[1] * 0.8;
+ drawcolor[2] = color[2] * 0.8;
+ drawcolor[3] = color[3];
+ UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
+
+ drawcolor[0] = color[0];
+ drawcolor[1] = color[1];
+ drawcolor[2] = color[2];
+ drawcolor[3] = 0.5 + 0.5 * sin( cg.time / PULSE_DIVISOR );
+ UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetPropGlow );
+ return;
+ }
+
+ UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
+}
+#endif // Q3STATIC
diff --git a/code/cgame/cg_effects.c b/code/cgame/cg_effects.c
index 1ea447d..a29b856 100755
--- a/code/cgame/cg_effects.c
+++ b/code/cgame/cg_effects.c
@@ -1,718 +1,718 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_effects.c -- these functions generate localentities, usually as a result
-// of event processing
-
-#include "cg_local.h"
-
-
-/*
-==================
-CG_BubbleTrail
-
-Bullets shot underwater
-==================
-*/
-void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
- vec3_t move;
- vec3_t vec;
- float len;
- int i;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- // advance a random amount first
- i = rand() % (int)spacing;
- VectorMA( move, i, vec, move );
-
- VectorScale (vec, spacing, vec);
-
- for ( ; i < len; i += spacing ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + 1000 + random() * 250;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- re = &le->refEntity;
- re->shaderTime = cg.time / 1000.0f;
-
- re->reType = RT_SPRITE;
- re->rotation = 0;
- re->radius = 3;
- re->customShader = cgs.media.waterBubbleShader;
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- re->shaderRGBA[3] = 0xff;
-
- le->color[3] = 1.0;
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
- VectorCopy( move, le->pos.trBase );
- le->pos.trDelta[0] = crandom()*5;
- le->pos.trDelta[1] = crandom()*5;
- le->pos.trDelta[2] = crandom()*5 + 6;
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-=====================
-CG_SmokePuff
-
-Adds a smoke puff or blood trail localEntity.
-=====================
-*/
-localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
- float radius,
- float r, float g, float b, float a,
- float duration,
- int startTime,
- int fadeInTime,
- int leFlags,
- qhandle_t hShader ) {
- static int seed = 0x92;
- localEntity_t *le;
- refEntity_t *re;
-// int fadeInTime = startTime + duration / 2;
-
- le = CG_AllocLocalEntity();
- le->leFlags = leFlags;
- le->radius = radius;
-
- re = &le->refEntity;
- re->rotation = Q_random( &seed ) * 360;
- re->radius = radius;
- re->shaderTime = startTime / 1000.0f;
-
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = startTime;
- le->fadeInTime = fadeInTime;
- le->endTime = startTime + duration;
- if ( fadeInTime > startTime ) {
- le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
- }
- else {
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
- }
- le->color[0] = r;
- le->color[1] = g;
- le->color[2] = b;
- le->color[3] = a;
-
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = startTime;
- VectorCopy( vel, le->pos.trDelta );
- VectorCopy( p, le->pos.trBase );
-
- VectorCopy( p, re->origin );
- re->customShader = hShader;
-
- // rage pro can't alpha fade, so use a different shader
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
- re->customShader = cgs.media.smokePuffRageProShader;
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- re->shaderRGBA[3] = 0xff;
- } else {
- re->shaderRGBA[0] = le->color[0] * 0xff;
- re->shaderRGBA[1] = le->color[1] * 0xff;
- re->shaderRGBA[2] = le->color[2] * 0xff;
- re->shaderRGBA[3] = 0xff;
- }
-
- re->reType = RT_SPRITE;
- re->radius = le->radius;
-
- return le;
-}
-
-/*
-==================
-CG_SpawnEffect
-
-Player teleporting in or out
-==================
-*/
-void CG_SpawnEffect( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + 500;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
-#ifndef MISSIONPACK
- re->customShader = cgs.media.teleportEffectShader;
-#endif
- re->hModel = cgs.media.teleportEffectModel;
- AxisClear( re->axis );
-
- VectorCopy( org, re->origin );
-#ifdef MISSIONPACK
- re->origin[2] += 16;
-#else
- re->origin[2] -= 24;
-#endif
-}
-
-
-#ifdef MISSIONPACK
-/*
-===============
-CG_LightningBoltBeam
-===============
-*/
-void CG_LightningBoltBeam( vec3_t start, vec3_t end ) {
- localEntity_t *le;
- refEntity_t *beam;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_SHOWREFENTITY;
- le->startTime = cg.time;
- le->endTime = cg.time + 50;
-
- beam = &le->refEntity;
-
- VectorCopy( start, beam->origin );
- // this is the end point
- VectorCopy( end, beam->oldorigin );
-
- beam->reType = RT_LIGHTNING;
- beam->customShader = cgs.media.lightningShader;
-}
-
-/*
-==================
-CG_KamikazeEffect
-==================
-*/
-void CG_KamikazeEffect( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_KAMIKAZE;
- le->startTime = cg.time;
- le->endTime = cg.time + 3000;//2250;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- VectorClear(le->angles.trBase);
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.kamikazeEffectModel;
-
- VectorCopy( org, re->origin );
-
-}
-
-/*
-==================
-CG_ObeliskExplode
-==================
-*/
-void CG_ObeliskExplode( vec3_t org, int entityNum ) {
- localEntity_t *le;
- vec3_t origin;
-
- // create an explosion
- VectorCopy( org, origin );
- origin[2] += 64;
- le = CG_MakeExplosion( origin, vec3_origin,
- cgs.media.dishFlashModel,
- cgs.media.rocketExplosionShader,
- 600, qtrue );
- le->light = 300;
- le->lightColor[0] = 1;
- le->lightColor[1] = 0.75;
- le->lightColor[2] = 0.0;
-}
-
-/*
-==================
-CG_ObeliskPain
-==================
-*/
-void CG_ObeliskPain( vec3_t org ) {
- float r;
- sfxHandle_t sfx;
-
- // hit sound
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.obeliskHitSound1;
- } else if ( r == 2 ) {
- sfx = cgs.media.obeliskHitSound2;
- } else {
- sfx = cgs.media.obeliskHitSound3;
- }
- trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx );
-}
-
-
-/*
-==================
-CG_InvulnerabilityImpact
-==================
-*/
-void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) {
- localEntity_t *le;
- refEntity_t *re;
- int r;
- sfxHandle_t sfx;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_INVULIMPACT;
- le->startTime = cg.time;
- le->endTime = cg.time + 1000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.invulnerabilityImpactModel;
-
- VectorCopy( org, re->origin );
- AnglesToAxis( angles, re->axis );
-
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.invulnerabilityImpactSound1;
- } else if ( r == 2 ) {
- sfx = cgs.media.invulnerabilityImpactSound2;
- } else {
- sfx = cgs.media.invulnerabilityImpactSound3;
- }
- trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx );
-}
-
-/*
-==================
-CG_InvulnerabilityJuiced
-==================
-*/
-void CG_InvulnerabilityJuiced( vec3_t org ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t angles;
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_INVULJUICED;
- le->startTime = cg.time;
- le->endTime = cg.time + 10000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
-
- re = &le->refEntity;
-
- re->reType = RT_MODEL;
- re->shaderTime = cg.time / 1000.0f;
-
- re->hModel = cgs.media.invulnerabilityJuicedModel;
-
- VectorCopy( org, re->origin );
- VectorClear(angles);
- AnglesToAxis( angles, re->axis );
-
- trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound );
-}
-
-#endif
-
-/*
-==================
-CG_ScorePlum
-==================
-*/
-void CG_ScorePlum( int client, vec3_t org, int score ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t angles;
- static vec3_t lastPos;
-
- // only visualize for the client that scored
- if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {
- return;
- }
-
- le = CG_AllocLocalEntity();
- le->leFlags = 0;
- le->leType = LE_SCOREPLUM;
- le->startTime = cg.time;
- le->endTime = cg.time + 4000;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
-
-
- le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
- le->radius = score;
-
- VectorCopy( org, le->pos.trBase );
- if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
- le->pos.trBase[2] -= 20;
- }
-
- //CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
- VectorCopy(org, lastPos);
-
-
- re = &le->refEntity;
-
- re->reType = RT_SPRITE;
- re->radius = 16;
-
- VectorClear(angles);
- AnglesToAxis( angles, re->axis );
-}
-
-
-/*
-====================
-CG_MakeExplosion
-====================
-*/
-localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
- qhandle_t hModel, qhandle_t shader,
- int msec, qboolean isSprite ) {
- float ang;
- localEntity_t *ex;
- int offset;
- vec3_t tmpVec, newOrigin;
-
- if ( msec <= 0 ) {
- CG_Error( "CG_MakeExplosion: msec = %i", msec );
- }
-
- // skew the time a bit so they aren't all in sync
- offset = rand() & 63;
-
- ex = CG_AllocLocalEntity();
- if ( isSprite ) {
- ex->leType = LE_SPRITE_EXPLOSION;
-
- // randomly rotate sprite orientation
- ex->refEntity.rotation = rand() % 360;
- VectorScale( dir, 16, tmpVec );
- VectorAdd( tmpVec, origin, newOrigin );
- } else {
- ex->leType = LE_EXPLOSION;
- VectorCopy( origin, newOrigin );
-
- // set axis with random rotate
- if ( !dir ) {
- AxisClear( ex->refEntity.axis );
- } else {
- ang = rand() % 360;
- VectorCopy( dir, ex->refEntity.axis[0] );
- RotateAroundDirection( ex->refEntity.axis, ang );
- }
- }
-
- ex->startTime = cg.time - offset;
- ex->endTime = ex->startTime + msec;
-
- // bias the time so all shader effects start correctly
- ex->refEntity.shaderTime = ex->startTime / 1000.0f;
-
- ex->refEntity.hModel = hModel;
- ex->refEntity.customShader = shader;
-
- // set origin
- VectorCopy( newOrigin, ex->refEntity.origin );
- VectorCopy( newOrigin, ex->refEntity.oldorigin );
-
- ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
-
- return ex;
-}
-
-
-/*
-=================
-CG_Bleed
-
-This is the spurt of blood when a character gets hit
-=================
-*/
-void CG_Bleed( vec3_t origin, int entityNum ) {
- localEntity_t *ex;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- ex = CG_AllocLocalEntity();
- ex->leType = LE_EXPLOSION;
-
- ex->startTime = cg.time;
- ex->endTime = ex->startTime + 500;
-
- VectorCopy ( origin, ex->refEntity.origin);
- ex->refEntity.reType = RT_SPRITE;
- ex->refEntity.rotation = rand() % 360;
- ex->refEntity.radius = 24;
-
- ex->refEntity.customShader = cgs.media.bloodExplosionShader;
-
- // don't show player's own blood in view
- if ( entityNum == cg.snap->ps.clientNum ) {
- ex->refEntity.renderfx |= RF_THIRD_PERSON;
- }
-}
-
-
-
-/*
-==================
-CG_LaunchGib
-==================
-*/
-void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + 5000 + random() * 3000;
-
- VectorCopy( origin, re->origin );
- AxisCopy( axisDefault, re->axis );
- re->hModel = hModel;
-
- le->pos.trType = TR_GRAVITY;
- VectorCopy( origin, le->pos.trBase );
- VectorCopy( velocity, le->pos.trDelta );
- le->pos.trTime = cg.time;
-
- le->bounceFactor = 0.6f;
-
- le->leBounceSoundType = LEBS_BLOOD;
- le->leMarkType = LEMT_BLOOD;
-}
-
-/*
-===================
-CG_GibPlayer
-
-Generated a bunch of gibs launching out from the bodies location
-===================
-*/
-#define GIB_VELOCITY 250
-#define GIB_JUMP 250
-void CG_GibPlayer( vec3_t playerOrigin ) {
- vec3_t origin, velocity;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- if ( rand() & 1 ) {
- CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
- } else {
- CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
- }
-
- // allow gibs to be turned off for speed
- if ( !cg_gibs.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibArm );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibChest );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibFist );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*GIB_VELOCITY;
- velocity[1] = crandom()*GIB_VELOCITY;
- velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
- CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
-}
-
-/*
-==================
-CG_LaunchGib
-==================
-*/
-void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
- localEntity_t *le;
- refEntity_t *re;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + 10000 + random() * 6000;
-
- VectorCopy( origin, re->origin );
- AxisCopy( axisDefault, re->axis );
- re->hModel = hModel;
-
- le->pos.trType = TR_GRAVITY;
- VectorCopy( origin, le->pos.trBase );
- VectorCopy( velocity, le->pos.trDelta );
- le->pos.trTime = cg.time;
-
- le->bounceFactor = 0.1f;
-
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-#define EXP_VELOCITY 100
-#define EXP_JUMP 150
-/*
-===================
-CG_GibPlayer
-
-Generated a bunch of gibs launching out from the bodies location
-===================
-*/
-void CG_BigExplode( vec3_t playerOrigin ) {
- vec3_t origin, velocity;
-
- if ( !cg_blood.integer ) {
- return;
- }
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY;
- velocity[1] = crandom()*EXP_VELOCITY;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY;
- velocity[1] = crandom()*EXP_VELOCITY;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*1.5;
- velocity[1] = crandom()*EXP_VELOCITY*1.5;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*2.0;
- velocity[1] = crandom()*EXP_VELOCITY*2.0;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-
- VectorCopy( playerOrigin, origin );
- velocity[0] = crandom()*EXP_VELOCITY*2.5;
- velocity[1] = crandom()*EXP_VELOCITY*2.5;
- velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
- CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_effects.c -- these functions generate localentities, usually as a result
+// of event processing
+
+#include "cg_local.h"
+
+
+/*
+==================
+CG_BubbleTrail
+
+Bullets shot underwater
+==================
+*/
+void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int i;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ // advance a random amount first
+ i = rand() % (int)spacing;
+ VectorMA( move, i, vec, move );
+
+ VectorScale (vec, spacing, vec);
+
+ for ( ; i < len; i += spacing ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = LEF_PUFF_DONT_SCALE;
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 1000 + random() * 250;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ re = &le->refEntity;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->reType = RT_SPRITE;
+ re->rotation = 0;
+ re->radius = 3;
+ re->customShader = cgs.media.waterBubbleShader;
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ re->shaderRGBA[3] = 0xff;
+
+ le->color[3] = 1.0;
+
+ le->pos.trType = TR_LINEAR;
+ le->pos.trTime = cg.time;
+ VectorCopy( move, le->pos.trBase );
+ le->pos.trDelta[0] = crandom()*5;
+ le->pos.trDelta[1] = crandom()*5;
+ le->pos.trDelta[2] = crandom()*5 + 6;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+=====================
+CG_SmokePuff
+
+Adds a smoke puff or blood trail localEntity.
+=====================
+*/
+localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
+ float radius,
+ float r, float g, float b, float a,
+ float duration,
+ int startTime,
+ int fadeInTime,
+ int leFlags,
+ qhandle_t hShader ) {
+ static int seed = 0x92;
+ localEntity_t *le;
+ refEntity_t *re;
+// int fadeInTime = startTime + duration / 2;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = leFlags;
+ le->radius = radius;
+
+ re = &le->refEntity;
+ re->rotation = Q_random( &seed ) * 360;
+ re->radius = radius;
+ re->shaderTime = startTime / 1000.0f;
+
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = startTime;
+ le->fadeInTime = fadeInTime;
+ le->endTime = startTime + duration;
+ if ( fadeInTime > startTime ) {
+ le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
+ }
+ else {
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+ }
+ le->color[0] = r;
+ le->color[1] = g;
+ le->color[2] = b;
+ le->color[3] = a;
+
+
+ le->pos.trType = TR_LINEAR;
+ le->pos.trTime = startTime;
+ VectorCopy( vel, le->pos.trDelta );
+ VectorCopy( p, le->pos.trBase );
+
+ VectorCopy( p, re->origin );
+ re->customShader = hShader;
+
+ // rage pro can't alpha fade, so use a different shader
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
+ re->customShader = cgs.media.smokePuffRageProShader;
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ re->shaderRGBA[3] = 0xff;
+ } else {
+ re->shaderRGBA[0] = le->color[0] * 0xff;
+ re->shaderRGBA[1] = le->color[1] * 0xff;
+ re->shaderRGBA[2] = le->color[2] * 0xff;
+ re->shaderRGBA[3] = 0xff;
+ }
+
+ re->reType = RT_SPRITE;
+ re->radius = le->radius;
+
+ return le;
+}
+
+/*
+==================
+CG_SpawnEffect
+
+Player teleporting in or out
+==================
+*/
+void CG_SpawnEffect( vec3_t org ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_FADE_RGB;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 500;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+#ifndef MISSIONPACK
+ re->customShader = cgs.media.teleportEffectShader;
+#endif
+ re->hModel = cgs.media.teleportEffectModel;
+ AxisClear( re->axis );
+
+ VectorCopy( org, re->origin );
+#ifdef MISSIONPACK
+ re->origin[2] += 16;
+#else
+ re->origin[2] -= 24;
+#endif
+}
+
+
+#ifdef MISSIONPACK
+/*
+===============
+CG_LightningBoltBeam
+===============
+*/
+void CG_LightningBoltBeam( vec3_t start, vec3_t end ) {
+ localEntity_t *le;
+ refEntity_t *beam;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_SHOWREFENTITY;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 50;
+
+ beam = &le->refEntity;
+
+ VectorCopy( start, beam->origin );
+ // this is the end point
+ VectorCopy( end, beam->oldorigin );
+
+ beam->reType = RT_LIGHTNING;
+ beam->customShader = cgs.media.lightningShader;
+}
+
+/*
+==================
+CG_KamikazeEffect
+==================
+*/
+void CG_KamikazeEffect( vec3_t org ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_KAMIKAZE;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 3000;//2250;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ VectorClear(le->angles.trBase);
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->hModel = cgs.media.kamikazeEffectModel;
+
+ VectorCopy( org, re->origin );
+
+}
+
+/*
+==================
+CG_ObeliskExplode
+==================
+*/
+void CG_ObeliskExplode( vec3_t org, int entityNum ) {
+ localEntity_t *le;
+ vec3_t origin;
+
+ // create an explosion
+ VectorCopy( org, origin );
+ origin[2] += 64;
+ le = CG_MakeExplosion( origin, vec3_origin,
+ cgs.media.dishFlashModel,
+ cgs.media.rocketExplosionShader,
+ 600, qtrue );
+ le->light = 300;
+ le->lightColor[0] = 1;
+ le->lightColor[1] = 0.75;
+ le->lightColor[2] = 0.0;
+}
+
+/*
+==================
+CG_ObeliskPain
+==================
+*/
+void CG_ObeliskPain( vec3_t org ) {
+ float r;
+ sfxHandle_t sfx;
+
+ // hit sound
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.obeliskHitSound1;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.obeliskHitSound2;
+ } else {
+ sfx = cgs.media.obeliskHitSound3;
+ }
+ trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx );
+}
+
+
+/*
+==================
+CG_InvulnerabilityImpact
+==================
+*/
+void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ int r;
+ sfxHandle_t sfx;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_INVULIMPACT;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 1000;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->hModel = cgs.media.invulnerabilityImpactModel;
+
+ VectorCopy( org, re->origin );
+ AnglesToAxis( angles, re->axis );
+
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.invulnerabilityImpactSound1;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.invulnerabilityImpactSound2;
+ } else {
+ sfx = cgs.media.invulnerabilityImpactSound3;
+ }
+ trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx );
+}
+
+/*
+==================
+CG_InvulnerabilityJuiced
+==================
+*/
+void CG_InvulnerabilityJuiced( vec3_t org ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t angles;
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_INVULJUICED;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 10000;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+
+ re = &le->refEntity;
+
+ re->reType = RT_MODEL;
+ re->shaderTime = cg.time / 1000.0f;
+
+ re->hModel = cgs.media.invulnerabilityJuicedModel;
+
+ VectorCopy( org, re->origin );
+ VectorClear(angles);
+ AnglesToAxis( angles, re->axis );
+
+ trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound );
+}
+
+#endif
+
+/*
+==================
+CG_ScorePlum
+==================
+*/
+void CG_ScorePlum( int client, vec3_t org, int score ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t angles;
+ static vec3_t lastPos;
+
+ // only visualize for the client that scored
+ if (client != cg.predictedPlayerState.clientNum || cg_scorePlum.integer == 0) {
+ return;
+ }
+
+ le = CG_AllocLocalEntity();
+ le->leFlags = 0;
+ le->leType = LE_SCOREPLUM;
+ le->startTime = cg.time;
+ le->endTime = cg.time + 4000;
+ le->lifeRate = 1.0 / ( le->endTime - le->startTime );
+
+
+ le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
+ le->radius = score;
+
+ VectorCopy( org, le->pos.trBase );
+ if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
+ le->pos.trBase[2] -= 20;
+ }
+
+ //CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
+ VectorCopy(org, lastPos);
+
+
+ re = &le->refEntity;
+
+ re->reType = RT_SPRITE;
+ re->radius = 16;
+
+ VectorClear(angles);
+ AnglesToAxis( angles, re->axis );
+}
+
+
+/*
+====================
+CG_MakeExplosion
+====================
+*/
+localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
+ qhandle_t hModel, qhandle_t shader,
+ int msec, qboolean isSprite ) {
+ float ang;
+ localEntity_t *ex;
+ int offset;
+ vec3_t tmpVec, newOrigin;
+
+ if ( msec <= 0 ) {
+ CG_Error( "CG_MakeExplosion: msec = %i", msec );
+ }
+
+ // skew the time a bit so they aren't all in sync
+ offset = rand() & 63;
+
+ ex = CG_AllocLocalEntity();
+ if ( isSprite ) {
+ ex->leType = LE_SPRITE_EXPLOSION;
+
+ // randomly rotate sprite orientation
+ ex->refEntity.rotation = rand() % 360;
+ VectorScale( dir, 16, tmpVec );
+ VectorAdd( tmpVec, origin, newOrigin );
+ } else {
+ ex->leType = LE_EXPLOSION;
+ VectorCopy( origin, newOrigin );
+
+ // set axis with random rotate
+ if ( !dir ) {
+ AxisClear( ex->refEntity.axis );
+ } else {
+ ang = rand() % 360;
+ VectorCopy( dir, ex->refEntity.axis[0] );
+ RotateAroundDirection( ex->refEntity.axis, ang );
+ }
+ }
+
+ ex->startTime = cg.time - offset;
+ ex->endTime = ex->startTime + msec;
+
+ // bias the time so all shader effects start correctly
+ ex->refEntity.shaderTime = ex->startTime / 1000.0f;
+
+ ex->refEntity.hModel = hModel;
+ ex->refEntity.customShader = shader;
+
+ // set origin
+ VectorCopy( newOrigin, ex->refEntity.origin );
+ VectorCopy( newOrigin, ex->refEntity.oldorigin );
+
+ ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
+
+ return ex;
+}
+
+
+/*
+=================
+CG_Bleed
+
+This is the spurt of blood when a character gets hit
+=================
+*/
+void CG_Bleed( vec3_t origin, int entityNum ) {
+ localEntity_t *ex;
+
+ if ( !cg_blood.integer ) {
+ return;
+ }
+
+ ex = CG_AllocLocalEntity();
+ ex->leType = LE_EXPLOSION;
+
+ ex->startTime = cg.time;
+ ex->endTime = ex->startTime + 500;
+
+ VectorCopy ( origin, ex->refEntity.origin);
+ ex->refEntity.reType = RT_SPRITE;
+ ex->refEntity.rotation = rand() % 360;
+ ex->refEntity.radius = 24;
+
+ ex->refEntity.customShader = cgs.media.bloodExplosionShader;
+
+ // don't show player's own blood in view
+ if ( entityNum == cg.snap->ps.clientNum ) {
+ ex->refEntity.renderfx |= RF_THIRD_PERSON;
+ }
+}
+
+
+
+/*
+==================
+CG_LaunchGib
+==================
+*/
+void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + 5000 + random() * 3000;
+
+ VectorCopy( origin, re->origin );
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = hModel;
+
+ le->pos.trType = TR_GRAVITY;
+ VectorCopy( origin, le->pos.trBase );
+ VectorCopy( velocity, le->pos.trDelta );
+ le->pos.trTime = cg.time;
+
+ le->bounceFactor = 0.6f;
+
+ le->leBounceSoundType = LEBS_BLOOD;
+ le->leMarkType = LEMT_BLOOD;
+}
+
+/*
+===================
+CG_GibPlayer
+
+Generated a bunch of gibs launching out from the bodies location
+===================
+*/
+#define GIB_VELOCITY 250
+#define GIB_JUMP 250
+void CG_GibPlayer( vec3_t playerOrigin ) {
+ vec3_t origin, velocity;
+
+ if ( !cg_blood.integer ) {
+ return;
+ }
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ if ( rand() & 1 ) {
+ CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
+ } else {
+ CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
+ }
+
+ // allow gibs to be turned off for speed
+ if ( !cg_gibs.integer ) {
+ return;
+ }
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibArm );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibChest );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibFist );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*GIB_VELOCITY;
+ velocity[1] = crandom()*GIB_VELOCITY;
+ velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
+ CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
+}
+
+/*
+==================
+CG_LaunchGib
+==================
+*/
+void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
+ localEntity_t *le;
+ refEntity_t *re;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + 10000 + random() * 6000;
+
+ VectorCopy( origin, re->origin );
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = hModel;
+
+ le->pos.trType = TR_GRAVITY;
+ VectorCopy( origin, le->pos.trBase );
+ VectorCopy( velocity, le->pos.trDelta );
+ le->pos.trTime = cg.time;
+
+ le->bounceFactor = 0.1f;
+
+ le->leBounceSoundType = LEBS_BRASS;
+ le->leMarkType = LEMT_NONE;
+}
+
+#define EXP_VELOCITY 100
+#define EXP_JUMP 150
+/*
+===================
+CG_GibPlayer
+
+Generated a bunch of gibs launching out from the bodies location
+===================
+*/
+void CG_BigExplode( vec3_t playerOrigin ) {
+ vec3_t origin, velocity;
+
+ if ( !cg_blood.integer ) {
+ return;
+ }
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY;
+ velocity[1] = crandom()*EXP_VELOCITY;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY;
+ velocity[1] = crandom()*EXP_VELOCITY;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY*1.5;
+ velocity[1] = crandom()*EXP_VELOCITY*1.5;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY*2.0;
+ velocity[1] = crandom()*EXP_VELOCITY*2.0;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+
+ VectorCopy( playerOrigin, origin );
+ velocity[0] = crandom()*EXP_VELOCITY*2.5;
+ velocity[1] = crandom()*EXP_VELOCITY*2.5;
+ velocity[2] = EXP_JUMP + crandom()*EXP_VELOCITY;
+ CG_LaunchExplode( origin, velocity, cgs.media.smoke2 );
+}
+
diff --git a/code/cgame/cg_ents.c b/code/cgame/cg_ents.c
index 5855089..aa6398f 100755
--- a/code/cgame/cg_ents.c
+++ b/code/cgame/cg_ents.c
@@ -1,1037 +1,1037 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_ents.c -- present snapshot entities, happens every single frame
-
-#include "cg_local.h"
-
-
-/*
-======================
-CG_PositionEntityOnTag
-
-Modifies the entities position and axis by the given
-tag location
-======================
-*/
-void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
-
- // lerp the tag
- trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // had to cast away the const to avoid compiler problems...
- MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );
- entity->backlerp = parent->backlerp;
-}
-
-
-/*
-======================
-CG_PositionRotatedEntityOnTag
-
-Modifies the entities position and axis by the given
-tag location
-======================
-*/
-void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName ) {
- int i;
- orientation_t lerped;
- vec3_t tempAxis[3];
-
-//AxisClear( entity->axis );
- // lerp the tag
- trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
- 1.0 - parent->backlerp, tagName );
-
- // FIXME: allow origin offsets along tag?
- VectorCopy( parent->origin, entity->origin );
- for ( i = 0 ; i < 3 ; i++ ) {
- VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
- }
-
- // had to cast away the const to avoid compiler problems...
- MatrixMultiply( entity->axis, lerped.axis, tempAxis );
- MatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );
-}
-
-
-
-/*
-==========================================================================
-
-FUNCTIONS CALLED EACH FRAME
-
-==========================================================================
-*/
-
-/*
-======================
-CG_SetEntitySoundPosition
-
-Also called by event processing code
-======================
-*/
-void CG_SetEntitySoundPosition( centity_t *cent ) {
- if ( cent->currentState.solid == SOLID_BMODEL ) {
- vec3_t origin;
- float *v;
-
- v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
- VectorAdd( cent->lerpOrigin, v, origin );
- trap_S_UpdateEntityPosition( cent->currentState.number, origin );
- } else {
- trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
- }
-}
-
-/*
-==================
-CG_EntityEffects
-
-Add continuous entity effects, like local entity emission and lighting
-==================
-*/
-static void CG_EntityEffects( centity_t *cent ) {
-
- // update sound origins
- CG_SetEntitySoundPosition( cent );
-
- // add loop sound
- if ( cent->currentState.loopSound ) {
- if (cent->currentState.eType != ET_SPEAKER) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
- cgs.gameSounds[ cent->currentState.loopSound ] );
- } else {
- trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
- cgs.gameSounds[ cent->currentState.loopSound ] );
- }
- }
-
-
- // constant light glow
- if ( cent->currentState.constantLight ) {
- int cl;
- int i, r, g, b;
-
- cl = cent->currentState.constantLight;
- r = cl & 255;
- g = ( cl >> 8 ) & 255;
- b = ( cl >> 16 ) & 255;
- i = ( ( cl >> 24 ) & 255 ) * 4;
- trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b );
- }
-
-}
-
-
-/*
-==================
-CG_General
-==================
-*/
-static void CG_General( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = &cent->currentState;
-
- // if set to invisible, skip
- if (!s1->modelindex) {
- return;
- }
-
- memset (&ent, 0, sizeof(ent));
-
- // set frame
-
- ent.frame = s1->frame;
- ent.oldframe = ent.frame;
- ent.backlerp = 0;
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.hModel = cgs.gameModels[s1->modelindex];
-
- // player model
- if (s1->number == cg.snap->ps.clientNum) {
- ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors
- }
-
- // convert angles to axis
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- // add to refresh list
- trap_R_AddRefEntityToScene (&ent);
-}
-
-/*
-==================
-CG_Speaker
-
-Speaker entities can automatically play sounds
-==================
-*/
-static void CG_Speaker( centity_t *cent ) {
- if ( ! cent->currentState.clientNum ) { // FIXME: use something other than clientNum...
- return; // not auto triggering
- }
-
- if ( cg.time < cent->miscTime ) {
- return;
- }
-
- trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );
-
- // ent->s.frame = ent->wait * 10;
- // ent->s.clientNum = ent->random * 10;
- cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
-}
-
-/*
-==================
-CG_Item
-==================
-*/
-static void CG_Item( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *es;
- gitem_t *item;
- int msec;
- float frac;
- float scale;
- weaponInfo_t *wi;
-
- es = &cent->currentState;
- if ( es->modelindex >= bg_numItems ) {
- CG_Error( "Bad item index %i on entity", es->modelindex );
- }
-
- // if set to invisible, skip
- if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
- return;
- }
-
- item = &bg_itemlist[ es->modelindex ];
- if ( cg_simpleItems.integer && item->giType != IT_TEAM ) {
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_SPRITE;
- VectorCopy( cent->lerpOrigin, ent.origin );
- ent.radius = 14;
- ent.customShader = cg_items[es->modelindex].icon;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 255;
- trap_R_AddRefEntityToScene(&ent);
- return;
- }
-
- // items bob up and down continuously
- scale = 0.005 + cent->currentState.number * 0.00001;
- cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4;
-
- memset (&ent, 0, sizeof(ent));
-
- // autorotate at one of two speeds
- if ( item->giType == IT_HEALTH ) {
- VectorCopy( cg.autoAnglesFast, cent->lerpAngles );
- AxisCopy( cg.autoAxisFast, ent.axis );
- } else {
- VectorCopy( cg.autoAngles, cent->lerpAngles );
- AxisCopy( cg.autoAxis, ent.axis );
- }
-
- wi = NULL;
- // the weapons have their origin where they attatch to player
- // models, so we need to offset them or they will rotate
- // eccentricly
- if ( item->giType == IT_WEAPON ) {
- wi = &cg_weapons[item->giTag];
- cent->lerpOrigin[0] -=
- wi->weaponMidpoint[0] * ent.axis[0][0] +
- wi->weaponMidpoint[1] * ent.axis[1][0] +
- wi->weaponMidpoint[2] * ent.axis[2][0];
- cent->lerpOrigin[1] -=
- wi->weaponMidpoint[0] * ent.axis[0][1] +
- wi->weaponMidpoint[1] * ent.axis[1][1] +
- wi->weaponMidpoint[2] * ent.axis[2][1];
- cent->lerpOrigin[2] -=
- wi->weaponMidpoint[0] * ent.axis[0][2] +
- wi->weaponMidpoint[1] * ent.axis[1][2] +
- wi->weaponMidpoint[2] * ent.axis[2][2];
-
- cent->lerpOrigin[2] += 8; // an extra height boost
- }
-
- ent.hModel = cg_items[es->modelindex].models[0];
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.nonNormalizedAxes = qfalse;
-
- // if just respawned, slowly scale up
- msec = cg.time - cent->miscTime;
- if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
- frac = (float)msec / ITEM_SCALEUP_TIME;
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- } else {
- frac = 1.0;
- }
-
- // items without glow textures need to keep a minimum light value
- // so they are always visible
- if ( ( item->giType == IT_WEAPON ) ||
- ( item->giType == IT_ARMOR ) ) {
- ent.renderfx |= RF_MINLIGHT;
- }
-
- // increase the size of the weapons when they are presented as items
- if ( item->giType == IT_WEAPON ) {
- VectorScale( ent.axis[0], 1.5, ent.axis[0] );
- VectorScale( ent.axis[1], 1.5, ent.axis[1] );
- VectorScale( ent.axis[2], 1.5, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
-#ifdef MISSIONPACK
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
-#endif
- }
-
-#ifdef MISSIONPACK
- if ( item->giType == IT_HOLDABLE && item->giTag == HI_KAMIKAZE ) {
- VectorScale( ent.axis[0], 2, ent.axis[0] );
- VectorScale( ent.axis[1], 2, ent.axis[1] );
- VectorScale( ent.axis[2], 2, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- }
-#endif
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-
-#ifdef MISSIONPACK
- if ( item->giType == IT_WEAPON && wi->barrelModel ) {
- refEntity_t barrel;
-
- memset( &barrel, 0, sizeof( barrel ) );
-
- barrel.hModel = wi->barrelModel;
-
- VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = ent.shadowPlane;
- barrel.renderfx = ent.renderfx;
-
- CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
-
- AxisCopy( ent.axis, barrel.axis );
- barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
-
- trap_R_AddRefEntityToScene( &barrel );
- }
-#endif
-
- // accompanying rings / spheres for powerups
- if ( !cg_simpleItems.integer )
- {
- vec3_t spinAngles;
-
- VectorClear( spinAngles );
-
- if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )
- {
- if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )
- {
- if ( item->giType == IT_POWERUP )
- {
- ent.origin[2] += 12;
- spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;
- }
- AnglesToAxis( spinAngles, ent.axis );
-
- // scale up if respawning
- if ( frac != 1.0 ) {
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- }
- trap_R_AddRefEntityToScene( &ent );
- }
- }
- }
-}
-
-//============================================================================
-
-/*
-===============
-CG_Missile
-===============
-*/
-static void CG_Missile( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
- const weaponInfo_t *weapon;
-// int col;
-
- s1 = &cent->currentState;
- if ( s1->weapon > WP_NUM_WEAPONS ) {
- s1->weapon = 0;
- }
- weapon = &cg_weapons[s1->weapon];
-
- // calculate the axis
- VectorCopy( s1->angles, cent->lerpAngles);
-
- // add trails
- if ( weapon->missileTrailFunc )
- {
- weapon->missileTrailFunc( cent, weapon );
- }
-/*
- if ( cent->currentState.modelindex == TEAM_RED ) {
- col = 1;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- col = 2;
- }
- else {
- col = 0;
- }
-
- // add dynamic light
- if ( weapon->missileDlight ) {
- trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
- weapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] );
- }
-*/
- // add dynamic light
- if ( weapon->missileDlight ) {
- trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
- weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
- }
-
- // add missile sound
- if ( weapon->missileSound ) {
- vec3_t velocity;
-
- BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );
-
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
- }
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- if ( cent->currentState.weapon == WP_PLASMAGUN ) {
- ent.reType = RT_SPRITE;
- ent.radius = 16;
- ent.rotation = 0;
- ent.customShader = cgs.media.plasmaBallShader;
- trap_R_AddRefEntityToScene( &ent );
- return;
- }
-
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
-#ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_PROX_LAUNCHER ) {
- if (s1->generic1 == TEAM_BLUE) {
- ent.hModel = cgs.media.blueProxMine;
- }
- }
-#endif
-
- // convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
- ent.axis[0][2] = 1;
- }
-
- // spin as it moves
- if ( s1->pos.trType != TR_STATIONARY ) {
- RotateAroundDirection( ent.axis, cg.time / 4 );
- } else {
-#ifdef MISSIONPACK
- if ( s1->weapon == WP_PROX_LAUNCHER ) {
- AnglesToAxis( cent->lerpAngles, ent.axis );
- }
- else
-#endif
- {
- RotateAroundDirection( ent.axis, s1->time );
- }
- }
-
- // add to refresh list, possibly with quad glow
- CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE );
-}
-
-/*
-===============
-CG_Grapple
-
-This is called when the grapple is sitting up against the wall
-===============
-*/
-static void CG_Grapple( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
- const weaponInfo_t *weapon;
-
- s1 = &cent->currentState;
- if ( s1->weapon > WP_NUM_WEAPONS ) {
- s1->weapon = 0;
- }
- weapon = &cg_weapons[s1->weapon];
-
- // calculate the axis
- VectorCopy( s1->angles, cent->lerpAngles);
-
-#if 0 // FIXME add grapple pull sound here..?
- // add missile sound
- if ( weapon->missileSound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );
- }
-#endif
-
- // Will draw cable if needed
- CG_GrappleTrail ( cent, weapon );
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
- // convert direction of travel into axis
- if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
- ent.axis[0][2] = 1;
- }
-
- trap_R_AddRefEntityToScene( &ent );
-}
-
-/*
-===============
-CG_Mover
-===============
-*/
-static void CG_Mover( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = &cent->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- ent.renderfx = RF_NOSHADOW;
-
- // flicker between two skins (FIXME?)
- ent.skinNum = ( cg.time >> 6 ) & 1;
-
- // get the model, either as a bmodel or a modelindex
- if ( s1->solid == SOLID_BMODEL ) {
- ent.hModel = cgs.inlineDrawModel[s1->modelindex];
- } else {
- ent.hModel = cgs.gameModels[s1->modelindex];
- }
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-
- // add the secondary model
- if ( s1->modelindex2 ) {
- ent.skinNum = 0;
- ent.hModel = cgs.gameModels[s1->modelindex2];
- trap_R_AddRefEntityToScene(&ent);
- }
-
-}
-
-/*
-===============
-CG_Beam
-
-Also called as an event
-===============
-*/
-void CG_Beam( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = &cent->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( s1->pos.trBase, ent.origin );
- VectorCopy( s1->origin2, ent.oldorigin );
- AxisClear( ent.axis );
- ent.reType = RT_BEAM;
-
- ent.renderfx = RF_NOSHADOW;
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-/*
-===============
-CG_Portal
-===============
-*/
-static void CG_Portal( centity_t *cent ) {
- refEntity_t ent;
- entityState_t *s1;
-
- s1 = &cent->currentState;
-
- // create the render entity
- memset (&ent, 0, sizeof(ent));
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( s1->origin2, ent.oldorigin );
- ByteToDir( s1->eventParm, ent.axis[0] );
- PerpendicularVector( ent.axis[1], ent.axis[0] );
-
- // negating this tends to get the directions like they want
- // we really should have a camera roll value
- VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
-
- CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
- ent.reType = RT_PORTALSURFACE;
- ent.oldframe = s1->powerups;
- ent.frame = s1->frame; // rotation speed
- ent.skinNum = s1->clientNum/256.0 * 360; // roll offset
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
-/*
-=========================
-CG_AdjustPositionForMover
-
-Also called by client movement prediction code
-=========================
-*/
-void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
- centity_t *cent;
- vec3_t oldOrigin, origin, deltaOrigin;
- vec3_t oldAngles, angles, deltaAngles;
-
- if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
- VectorCopy( in, out );
- return;
- }
-
- cent = &cg_entities[ moverNum ];
- if ( cent->currentState.eType != ET_MOVER ) {
- VectorCopy( in, out );
- return;
- }
-
- BG_EvaluateTrajectory( &cent->currentState.pos, fromTime, oldOrigin );
- BG_EvaluateTrajectory( &cent->currentState.apos, fromTime, oldAngles );
-
- BG_EvaluateTrajectory( &cent->currentState.pos, toTime, origin );
- BG_EvaluateTrajectory( &cent->currentState.apos, toTime, angles );
-
- VectorSubtract( origin, oldOrigin, deltaOrigin );
- VectorSubtract( angles, oldAngles, deltaAngles );
-
- VectorAdd( in, deltaOrigin, out );
-
- // FIXME: origin change when on a rotating object
-}
-
-
-/*
-=============================
-CG_InterpolateEntityPosition
-=============================
-*/
-static void CG_InterpolateEntityPosition( centity_t *cent ) {
- vec3_t current, next;
- float f;
-
- // it would be an internal error to find an entity that interpolates without
- // a snapshot ahead of the current one
- if ( cg.nextSnap == NULL ) {
- CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
- }
-
- f = cg.frameInterpolation;
-
- // this will linearize a sine or parabolic curve, but it is important
- // to not extrapolate player positions if more recent data is available
- BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, current );
- BG_EvaluateTrajectory( &cent->nextState.pos, cg.nextSnap->serverTime, next );
-
- cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
- cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
- cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
-
- BG_EvaluateTrajectory( &cent->currentState.apos, cg.snap->serverTime, current );
- BG_EvaluateTrajectory( &cent->nextState.apos, cg.nextSnap->serverTime, next );
-
- cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
- cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
- cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
-
-}
-
-/*
-===============
-CG_CalcEntityLerpPositions
-
-===============
-*/
-static void CG_CalcEntityLerpPositions( centity_t *cent ) {
-
- // if this player does not want to see extrapolated players
- if ( !cg_smoothClients.integer ) {
- // make sure the clients use TR_INTERPOLATE
- if ( cent->currentState.number < MAX_CLIENTS ) {
- cent->currentState.pos.trType = TR_INTERPOLATE;
- cent->nextState.pos.trType = TR_INTERPOLATE;
- }
- }
-
- if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
- CG_InterpolateEntityPosition( cent );
- return;
- }
-
- // first see if we can interpolate between two snaps for
- // linear extrapolated clients
- if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
- cent->currentState.number < MAX_CLIENTS) {
- CG_InterpolateEntityPosition( cent );
- return;
- }
-
- // just use the current frame and evaluate as best we can
- BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
- BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
-
- // adjust for riding a mover if it wasn't rolled into the predicted
- // player state
- if ( cent != &cg.predictedPlayerEntity ) {
- CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum,
- cg.snap->serverTime, cg.time, cent->lerpOrigin );
- }
-}
-
-/*
-===============
-CG_TeamBase
-===============
-*/
-static void CG_TeamBase( centity_t *cent ) {
- refEntity_t model;
-#ifdef MISSIONPACK
- vec3_t angles;
- int t, h;
- float c;
-
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) {
-#else
- if ( cgs.gametype == GT_CTF) {
-#endif
- // show the flag base
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
- if ( cent->currentState.modelindex == TEAM_RED ) {
- model.hModel = cgs.media.redFlagBaseModel;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- model.hModel = cgs.media.blueFlagBaseModel;
- }
- else {
- model.hModel = cgs.media.neutralFlagBaseModel;
- }
- trap_R_AddRefEntityToScene( &model );
- }
-#ifdef MISSIONPACK
- else if ( cgs.gametype == GT_OBELISK ) {
- // show the obelisk
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
-
- model.hModel = cgs.media.overloadBaseModel;
- trap_R_AddRefEntityToScene( &model );
- // if hit
- if ( cent->currentState.frame == 1) {
- // show hit model
- // modelindex2 is the health value of the obelisk
- c = cent->currentState.modelindex2;
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = c;
- model.shaderRGBA[2] = c;
- model.shaderRGBA[3] = 0xff;
- //
- model.hModel = cgs.media.overloadEnergyModel;
- trap_R_AddRefEntityToScene( &model );
- }
- // if respawning
- if ( cent->currentState.frame == 2) {
- if ( !cent->miscTime ) {
- cent->miscTime = cg.time;
- }
- t = cg.time - cent->miscTime;
- h = (cg_obeliskRespawnDelay.integer - 5) * 1000;
- //
- if (t > h) {
- c = (float) (t - h) / h;
- if (c > 1)
- c = 1;
- }
- else {
- c = 0;
- }
- // show the lights
- AnglesToAxis( cent->currentState.angles, model.axis );
- //
- model.shaderRGBA[0] = c * 0xff;
- model.shaderRGBA[1] = c * 0xff;
- model.shaderRGBA[2] = c * 0xff;
- model.shaderRGBA[3] = c * 0xff;
-
- model.hModel = cgs.media.overloadLightsModel;
- trap_R_AddRefEntityToScene( &model );
- // show the target
- if (t > h) {
- if ( !cent->muzzleFlashTime ) {
- trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound);
- cent->muzzleFlashTime = 1;
- }
- VectorCopy(cent->currentState.angles, angles);
- angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI;
- AnglesToAxis( angles, model.axis );
-
- VectorScale( model.axis[0], c, model.axis[0]);
- VectorScale( model.axis[1], c, model.axis[1]);
- VectorScale( model.axis[2], c, model.axis[2]);
-
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = 0xff;
- model.shaderRGBA[2] = 0xff;
- model.shaderRGBA[3] = 0xff;
- //
- model.origin[2] += 56;
- model.hModel = cgs.media.overloadTargetModel;
- trap_R_AddRefEntityToScene( &model );
- }
- else {
- //FIXME: show animated smoke
- }
- }
- else {
- cent->miscTime = 0;
- cent->muzzleFlashTime = 0;
- // modelindex2 is the health value of the obelisk
- c = cent->currentState.modelindex2;
- model.shaderRGBA[0] = 0xff;
- model.shaderRGBA[1] = c;
- model.shaderRGBA[2] = c;
- model.shaderRGBA[3] = 0xff;
- // show the lights
- model.hModel = cgs.media.overloadLightsModel;
- trap_R_AddRefEntityToScene( &model );
- // show the target
- model.origin[2] += 56;
- model.hModel = cgs.media.overloadTargetModel;
- trap_R_AddRefEntityToScene( &model );
- }
- }
- else if ( cgs.gametype == GT_HARVESTER ) {
- // show harvester model
- memset(&model, 0, sizeof(model));
- model.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, model.lightingOrigin );
- VectorCopy( cent->lerpOrigin, model.origin );
- AnglesToAxis( cent->currentState.angles, model.axis );
-
- if ( cent->currentState.modelindex == TEAM_RED ) {
- model.hModel = cgs.media.harvesterModel;
- model.customSkin = cgs.media.harvesterRedSkin;
- }
- else if ( cent->currentState.modelindex == TEAM_BLUE ) {
- model.hModel = cgs.media.harvesterModel;
- model.customSkin = cgs.media.harvesterBlueSkin;
- }
- else {
- model.hModel = cgs.media.harvesterNeutralModel;
- model.customSkin = 0;
- }
- trap_R_AddRefEntityToScene( &model );
- }
-#endif
-}
-
-/*
-===============
-CG_AddCEntity
-
-===============
-*/
-static void CG_AddCEntity( centity_t *cent ) {
- // event-only entities will have been dealt with already
- if ( cent->currentState.eType >= ET_EVENTS ) {
- return;
- }
-
- // calculate the current origin
- CG_CalcEntityLerpPositions( cent );
-
- // add automatic effects
- CG_EntityEffects( cent );
-
- switch ( cent->currentState.eType ) {
- default:
- CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
- break;
- case ET_INVISIBLE:
- case ET_PUSH_TRIGGER:
- case ET_TELEPORT_TRIGGER:
- break;
- case ET_GENERAL:
- CG_General( cent );
- break;
- case ET_PLAYER:
- CG_Player( cent );
- break;
- case ET_ITEM:
- CG_Item( cent );
- break;
- case ET_MISSILE:
- CG_Missile( cent );
- break;
- case ET_MOVER:
- CG_Mover( cent );
- break;
- case ET_BEAM:
- CG_Beam( cent );
- break;
- case ET_PORTAL:
- CG_Portal( cent );
- break;
- case ET_SPEAKER:
- CG_Speaker( cent );
- break;
- case ET_GRAPPLE:
- CG_Grapple( cent );
- break;
- case ET_TEAM:
- CG_TeamBase( cent );
- break;
- }
-}
-
-/*
-===============
-CG_AddPacketEntities
-
-===============
-*/
-void CG_AddPacketEntities( void ) {
- int num;
- centity_t *cent;
- playerState_t *ps;
-
- // set cg.frameInterpolation
- if ( cg.nextSnap ) {
- int delta;
-
- delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
- if ( delta == 0 ) {
- cg.frameInterpolation = 0;
- } else {
- cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
- }
- } else {
- cg.frameInterpolation = 0; // actually, it should never be used, because
- // no entities should be marked as interpolating
- }
-
- // the auto-rotating items will all have the same axis
- cg.autoAngles[0] = 0;
- cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
- cg.autoAngles[2] = 0;
-
- cg.autoAnglesFast[0] = 0;
- cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
- cg.autoAnglesFast[2] = 0;
-
- AnglesToAxis( cg.autoAngles, cg.autoAxis );
- AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
-
- // generate and add the entity from the playerstate
- ps = &cg.predictedPlayerState;
- BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );
- CG_AddCEntity( &cg.predictedPlayerEntity );
-
- // lerp the non-predicted value for lightning gun origins
- CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
-
- // add each entity sent over by the server
- for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
- cent = &cg_entities[ cg.snap->entities[ num ].number ];
- CG_AddCEntity( cent );
- }
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_ents.c -- present snapshot entities, happens every single frame
+
+#include "cg_local.h"
+
+
+/*
+======================
+CG_PositionEntityOnTag
+
+Modifies the entities position and axis by the given
+tag location
+======================
+*/
+void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+
+ // lerp the tag
+ trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // had to cast away the const to avoid compiler problems...
+ MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );
+ entity->backlerp = parent->backlerp;
+}
+
+
+/*
+======================
+CG_PositionRotatedEntityOnTag
+
+Modifies the entities position and axis by the given
+tag location
+======================
+*/
+void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName ) {
+ int i;
+ orientation_t lerped;
+ vec3_t tempAxis[3];
+
+//AxisClear( entity->axis );
+ // lerp the tag
+ trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
+ 1.0 - parent->backlerp, tagName );
+
+ // FIXME: allow origin offsets along tag?
+ VectorCopy( parent->origin, entity->origin );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
+ }
+
+ // had to cast away the const to avoid compiler problems...
+ MatrixMultiply( entity->axis, lerped.axis, tempAxis );
+ MatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );
+}
+
+
+
+/*
+==========================================================================
+
+FUNCTIONS CALLED EACH FRAME
+
+==========================================================================
+*/
+
+/*
+======================
+CG_SetEntitySoundPosition
+
+Also called by event processing code
+======================
+*/
+void CG_SetEntitySoundPosition( centity_t *cent ) {
+ if ( cent->currentState.solid == SOLID_BMODEL ) {
+ vec3_t origin;
+ float *v;
+
+ v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
+ VectorAdd( cent->lerpOrigin, v, origin );
+ trap_S_UpdateEntityPosition( cent->currentState.number, origin );
+ } else {
+ trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
+ }
+}
+
+/*
+==================
+CG_EntityEffects
+
+Add continuous entity effects, like local entity emission and lighting
+==================
+*/
+static void CG_EntityEffects( centity_t *cent ) {
+
+ // update sound origins
+ CG_SetEntitySoundPosition( cent );
+
+ // add loop sound
+ if ( cent->currentState.loopSound ) {
+ if (cent->currentState.eType != ET_SPEAKER) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
+ cgs.gameSounds[ cent->currentState.loopSound ] );
+ } else {
+ trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
+ cgs.gameSounds[ cent->currentState.loopSound ] );
+ }
+ }
+
+
+ // constant light glow
+ if ( cent->currentState.constantLight ) {
+ int cl;
+ int i, r, g, b;
+
+ cl = cent->currentState.constantLight;
+ r = cl & 255;
+ g = ( cl >> 8 ) & 255;
+ b = ( cl >> 16 ) & 255;
+ i = ( ( cl >> 24 ) & 255 ) * 4;
+ trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b );
+ }
+
+}
+
+
+/*
+==================
+CG_General
+==================
+*/
+static void CG_General( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = &cent->currentState;
+
+ // if set to invisible, skip
+ if (!s1->modelindex) {
+ return;
+ }
+
+ memset (&ent, 0, sizeof(ent));
+
+ // set frame
+
+ ent.frame = s1->frame;
+ ent.oldframe = ent.frame;
+ ent.backlerp = 0;
+
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ ent.hModel = cgs.gameModels[s1->modelindex];
+
+ // player model
+ if (s1->number == cg.snap->ps.clientNum) {
+ ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors
+ }
+
+ // convert angles to axis
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene (&ent);
+}
+
+/*
+==================
+CG_Speaker
+
+Speaker entities can automatically play sounds
+==================
+*/
+static void CG_Speaker( centity_t *cent ) {
+ if ( ! cent->currentState.clientNum ) { // FIXME: use something other than clientNum...
+ return; // not auto triggering
+ }
+
+ if ( cg.time < cent->miscTime ) {
+ return;
+ }
+
+ trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );
+
+ // ent->s.frame = ent->wait * 10;
+ // ent->s.clientNum = ent->random * 10;
+ cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
+}
+
+/*
+==================
+CG_Item
+==================
+*/
+static void CG_Item( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *es;
+ gitem_t *item;
+ int msec;
+ float frac;
+ float scale;
+ weaponInfo_t *wi;
+
+ es = &cent->currentState;
+ if ( es->modelindex >= bg_numItems ) {
+ CG_Error( "Bad item index %i on entity", es->modelindex );
+ }
+
+ // if set to invisible, skip
+ if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
+ return;
+ }
+
+ item = &bg_itemlist[ es->modelindex ];
+ if ( cg_simpleItems.integer && item->giType != IT_TEAM ) {
+ memset( &ent, 0, sizeof( ent ) );
+ ent.reType = RT_SPRITE;
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ ent.radius = 14;
+ ent.customShader = cg_items[es->modelindex].icon;
+ ent.shaderRGBA[0] = 255;
+ ent.shaderRGBA[1] = 255;
+ ent.shaderRGBA[2] = 255;
+ ent.shaderRGBA[3] = 255;
+ trap_R_AddRefEntityToScene(&ent);
+ return;
+ }
+
+ // items bob up and down continuously
+ scale = 0.005 + cent->currentState.number * 0.00001;
+ cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) * scale ) * 4;
+
+ memset (&ent, 0, sizeof(ent));
+
+ // autorotate at one of two speeds
+ if ( item->giType == IT_HEALTH ) {
+ VectorCopy( cg.autoAnglesFast, cent->lerpAngles );
+ AxisCopy( cg.autoAxisFast, ent.axis );
+ } else {
+ VectorCopy( cg.autoAngles, cent->lerpAngles );
+ AxisCopy( cg.autoAxis, ent.axis );
+ }
+
+ wi = NULL;
+ // the weapons have their origin where they attatch to player
+ // models, so we need to offset them or they will rotate
+ // eccentricly
+ if ( item->giType == IT_WEAPON ) {
+ wi = &cg_weapons[item->giTag];
+ cent->lerpOrigin[0] -=
+ wi->weaponMidpoint[0] * ent.axis[0][0] +
+ wi->weaponMidpoint[1] * ent.axis[1][0] +
+ wi->weaponMidpoint[2] * ent.axis[2][0];
+ cent->lerpOrigin[1] -=
+ wi->weaponMidpoint[0] * ent.axis[0][1] +
+ wi->weaponMidpoint[1] * ent.axis[1][1] +
+ wi->weaponMidpoint[2] * ent.axis[2][1];
+ cent->lerpOrigin[2] -=
+ wi->weaponMidpoint[0] * ent.axis[0][2] +
+ wi->weaponMidpoint[1] * ent.axis[1][2] +
+ wi->weaponMidpoint[2] * ent.axis[2][2];
+
+ cent->lerpOrigin[2] += 8; // an extra height boost
+ }
+
+ ent.hModel = cg_items[es->modelindex].models[0];
+
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ ent.nonNormalizedAxes = qfalse;
+
+ // if just respawned, slowly scale up
+ msec = cg.time - cent->miscTime;
+ if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
+ frac = (float)msec / ITEM_SCALEUP_TIME;
+ VectorScale( ent.axis[0], frac, ent.axis[0] );
+ VectorScale( ent.axis[1], frac, ent.axis[1] );
+ VectorScale( ent.axis[2], frac, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ } else {
+ frac = 1.0;
+ }
+
+ // items without glow textures need to keep a minimum light value
+ // so they are always visible
+ if ( ( item->giType == IT_WEAPON ) ||
+ ( item->giType == IT_ARMOR ) ) {
+ ent.renderfx |= RF_MINLIGHT;
+ }
+
+ // increase the size of the weapons when they are presented as items
+ if ( item->giType == IT_WEAPON ) {
+ VectorScale( ent.axis[0], 1.5, ent.axis[0] );
+ VectorScale( ent.axis[1], 1.5, ent.axis[1] );
+ VectorScale( ent.axis[2], 1.5, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+#ifdef MISSIONPACK
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
+#endif
+ }
+
+#ifdef MISSIONPACK
+ if ( item->giType == IT_HOLDABLE && item->giTag == HI_KAMIKAZE ) {
+ VectorScale( ent.axis[0], 2, ent.axis[0] );
+ VectorScale( ent.axis[1], 2, ent.axis[1] );
+ VectorScale( ent.axis[2], 2, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ }
+#endif
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+
+#ifdef MISSIONPACK
+ if ( item->giType == IT_WEAPON && wi->barrelModel ) {
+ refEntity_t barrel;
+
+ memset( &barrel, 0, sizeof( barrel ) );
+
+ barrel.hModel = wi->barrelModel;
+
+ VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
+ barrel.shadowPlane = ent.shadowPlane;
+ barrel.renderfx = ent.renderfx;
+
+ CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
+
+ AxisCopy( ent.axis, barrel.axis );
+ barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
+
+ trap_R_AddRefEntityToScene( &barrel );
+ }
+#endif
+
+ // accompanying rings / spheres for powerups
+ if ( !cg_simpleItems.integer )
+ {
+ vec3_t spinAngles;
+
+ VectorClear( spinAngles );
+
+ if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )
+ {
+ if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )
+ {
+ if ( item->giType == IT_POWERUP )
+ {
+ ent.origin[2] += 12;
+ spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;
+ }
+ AnglesToAxis( spinAngles, ent.axis );
+
+ // scale up if respawning
+ if ( frac != 1.0 ) {
+ VectorScale( ent.axis[0], frac, ent.axis[0] );
+ VectorScale( ent.axis[1], frac, ent.axis[1] );
+ VectorScale( ent.axis[2], frac, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ }
+ trap_R_AddRefEntityToScene( &ent );
+ }
+ }
+ }
+}
+
+//============================================================================
+
+/*
+===============
+CG_Missile
+===============
+*/
+static void CG_Missile( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+ const weaponInfo_t *weapon;
+// int col;
+
+ s1 = &cent->currentState;
+ if ( s1->weapon > WP_NUM_WEAPONS ) {
+ s1->weapon = 0;
+ }
+ weapon = &cg_weapons[s1->weapon];
+
+ // calculate the axis
+ VectorCopy( s1->angles, cent->lerpAngles);
+
+ // add trails
+ if ( weapon->missileTrailFunc )
+ {
+ weapon->missileTrailFunc( cent, weapon );
+ }
+/*
+ if ( cent->currentState.modelindex == TEAM_RED ) {
+ col = 1;
+ }
+ else if ( cent->currentState.modelindex == TEAM_BLUE ) {
+ col = 2;
+ }
+ else {
+ col = 0;
+ }
+
+ // add dynamic light
+ if ( weapon->missileDlight ) {
+ trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
+ weapon->missileDlightColor[col][0], weapon->missileDlightColor[col][1], weapon->missileDlightColor[col][2] );
+ }
+*/
+ // add dynamic light
+ if ( weapon->missileDlight ) {
+ trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight,
+ weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
+ }
+
+ // add missile sound
+ if ( weapon->missileSound ) {
+ vec3_t velocity;
+
+ BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );
+
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
+ }
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ if ( cent->currentState.weapon == WP_PLASMAGUN ) {
+ ent.reType = RT_SPRITE;
+ ent.radius = 16;
+ ent.rotation = 0;
+ ent.customShader = cgs.media.plasmaBallShader;
+ trap_R_AddRefEntityToScene( &ent );
+ return;
+ }
+
+ // flicker between two skins
+ ent.skinNum = cg.clientFrame & 1;
+ ent.hModel = weapon->missileModel;
+ ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
+
+#ifdef MISSIONPACK
+ if ( cent->currentState.weapon == WP_PROX_LAUNCHER ) {
+ if (s1->generic1 == TEAM_BLUE) {
+ ent.hModel = cgs.media.blueProxMine;
+ }
+ }
+#endif
+
+ // convert direction of travel into axis
+ if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
+ ent.axis[0][2] = 1;
+ }
+
+ // spin as it moves
+ if ( s1->pos.trType != TR_STATIONARY ) {
+ RotateAroundDirection( ent.axis, cg.time / 4 );
+ } else {
+#ifdef MISSIONPACK
+ if ( s1->weapon == WP_PROX_LAUNCHER ) {
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+ }
+ else
+#endif
+ {
+ RotateAroundDirection( ent.axis, s1->time );
+ }
+ }
+
+ // add to refresh list, possibly with quad glow
+ CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE );
+}
+
+/*
+===============
+CG_Grapple
+
+This is called when the grapple is sitting up against the wall
+===============
+*/
+static void CG_Grapple( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+ const weaponInfo_t *weapon;
+
+ s1 = &cent->currentState;
+ if ( s1->weapon > WP_NUM_WEAPONS ) {
+ s1->weapon = 0;
+ }
+ weapon = &cg_weapons[s1->weapon];
+
+ // calculate the axis
+ VectorCopy( s1->angles, cent->lerpAngles);
+
+#if 0 // FIXME add grapple pull sound here..?
+ // add missile sound
+ if ( weapon->missileSound ) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );
+ }
+#endif
+
+ // Will draw cable if needed
+ CG_GrappleTrail ( cent, weapon );
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ // flicker between two skins
+ ent.skinNum = cg.clientFrame & 1;
+ ent.hModel = weapon->missileModel;
+ ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
+
+ // convert direction of travel into axis
+ if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
+ ent.axis[0][2] = 1;
+ }
+
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+/*
+===============
+CG_Mover
+===============
+*/
+static void CG_Mover( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = &cent->currentState;
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+
+ ent.renderfx = RF_NOSHADOW;
+
+ // flicker between two skins (FIXME?)
+ ent.skinNum = ( cg.time >> 6 ) & 1;
+
+ // get the model, either as a bmodel or a modelindex
+ if ( s1->solid == SOLID_BMODEL ) {
+ ent.hModel = cgs.inlineDrawModel[s1->modelindex];
+ } else {
+ ent.hModel = cgs.gameModels[s1->modelindex];
+ }
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+
+ // add the secondary model
+ if ( s1->modelindex2 ) {
+ ent.skinNum = 0;
+ ent.hModel = cgs.gameModels[s1->modelindex2];
+ trap_R_AddRefEntityToScene(&ent);
+ }
+
+}
+
+/*
+===============
+CG_Beam
+
+Also called as an event
+===============
+*/
+void CG_Beam( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = &cent->currentState;
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( s1->pos.trBase, ent.origin );
+ VectorCopy( s1->origin2, ent.oldorigin );
+ AxisClear( ent.axis );
+ ent.reType = RT_BEAM;
+
+ ent.renderfx = RF_NOSHADOW;
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+}
+
+
+/*
+===============
+CG_Portal
+===============
+*/
+static void CG_Portal( centity_t *cent ) {
+ refEntity_t ent;
+ entityState_t *s1;
+
+ s1 = &cent->currentState;
+
+ // create the render entity
+ memset (&ent, 0, sizeof(ent));
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ VectorCopy( s1->origin2, ent.oldorigin );
+ ByteToDir( s1->eventParm, ent.axis[0] );
+ PerpendicularVector( ent.axis[1], ent.axis[0] );
+
+ // negating this tends to get the directions like they want
+ // we really should have a camera roll value
+ VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
+
+ CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
+ ent.reType = RT_PORTALSURFACE;
+ ent.oldframe = s1->powerups;
+ ent.frame = s1->frame; // rotation speed
+ ent.skinNum = s1->clientNum/256.0 * 360; // roll offset
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+}
+
+
+/*
+=========================
+CG_AdjustPositionForMover
+
+Also called by client movement prediction code
+=========================
+*/
+void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
+ centity_t *cent;
+ vec3_t oldOrigin, origin, deltaOrigin;
+ vec3_t oldAngles, angles, deltaAngles;
+
+ if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
+ VectorCopy( in, out );
+ return;
+ }
+
+ cent = &cg_entities[ moverNum ];
+ if ( cent->currentState.eType != ET_MOVER ) {
+ VectorCopy( in, out );
+ return;
+ }
+
+ BG_EvaluateTrajectory( &cent->currentState.pos, fromTime, oldOrigin );
+ BG_EvaluateTrajectory( &cent->currentState.apos, fromTime, oldAngles );
+
+ BG_EvaluateTrajectory( &cent->currentState.pos, toTime, origin );
+ BG_EvaluateTrajectory( &cent->currentState.apos, toTime, angles );
+
+ VectorSubtract( origin, oldOrigin, deltaOrigin );
+ VectorSubtract( angles, oldAngles, deltaAngles );
+
+ VectorAdd( in, deltaOrigin, out );
+
+ // FIXME: origin change when on a rotating object
+}
+
+
+/*
+=============================
+CG_InterpolateEntityPosition
+=============================
+*/
+static void CG_InterpolateEntityPosition( centity_t *cent ) {
+ vec3_t current, next;
+ float f;
+
+ // it would be an internal error to find an entity that interpolates without
+ // a snapshot ahead of the current one
+ if ( cg.nextSnap == NULL ) {
+ CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
+ }
+
+ f = cg.frameInterpolation;
+
+ // this will linearize a sine or parabolic curve, but it is important
+ // to not extrapolate player positions if more recent data is available
+ BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, current );
+ BG_EvaluateTrajectory( &cent->nextState.pos, cg.nextSnap->serverTime, next );
+
+ cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
+ cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
+ cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
+
+ BG_EvaluateTrajectory( &cent->currentState.apos, cg.snap->serverTime, current );
+ BG_EvaluateTrajectory( &cent->nextState.apos, cg.nextSnap->serverTime, next );
+
+ cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
+ cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
+ cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
+
+}
+
+/*
+===============
+CG_CalcEntityLerpPositions
+
+===============
+*/
+static void CG_CalcEntityLerpPositions( centity_t *cent ) {
+
+ // if this player does not want to see extrapolated players
+ if ( !cg_smoothClients.integer ) {
+ // make sure the clients use TR_INTERPOLATE
+ if ( cent->currentState.number < MAX_CLIENTS ) {
+ cent->currentState.pos.trType = TR_INTERPOLATE;
+ cent->nextState.pos.trType = TR_INTERPOLATE;
+ }
+ }
+
+ if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
+ CG_InterpolateEntityPosition( cent );
+ return;
+ }
+
+ // first see if we can interpolate between two snaps for
+ // linear extrapolated clients
+ if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
+ cent->currentState.number < MAX_CLIENTS) {
+ CG_InterpolateEntityPosition( cent );
+ return;
+ }
+
+ // just use the current frame and evaluate as best we can
+ BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
+ BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
+
+ // adjust for riding a mover if it wasn't rolled into the predicted
+ // player state
+ if ( cent != &cg.predictedPlayerEntity ) {
+ CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum,
+ cg.snap->serverTime, cg.time, cent->lerpOrigin );
+ }
+}
+
+/*
+===============
+CG_TeamBase
+===============
+*/
+static void CG_TeamBase( centity_t *cent ) {
+ refEntity_t model;
+#ifdef MISSIONPACK
+ vec3_t angles;
+ int t, h;
+ float c;
+
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) {
+#else
+ if ( cgs.gametype == GT_CTF) {
+#endif
+ // show the flag base
+ memset(&model, 0, sizeof(model));
+ model.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, model.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, model.origin );
+ AnglesToAxis( cent->currentState.angles, model.axis );
+ if ( cent->currentState.modelindex == TEAM_RED ) {
+ model.hModel = cgs.media.redFlagBaseModel;
+ }
+ else if ( cent->currentState.modelindex == TEAM_BLUE ) {
+ model.hModel = cgs.media.blueFlagBaseModel;
+ }
+ else {
+ model.hModel = cgs.media.neutralFlagBaseModel;
+ }
+ trap_R_AddRefEntityToScene( &model );
+ }
+#ifdef MISSIONPACK
+ else if ( cgs.gametype == GT_OBELISK ) {
+ // show the obelisk
+ memset(&model, 0, sizeof(model));
+ model.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, model.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, model.origin );
+ AnglesToAxis( cent->currentState.angles, model.axis );
+
+ model.hModel = cgs.media.overloadBaseModel;
+ trap_R_AddRefEntityToScene( &model );
+ // if hit
+ if ( cent->currentState.frame == 1) {
+ // show hit model
+ // modelindex2 is the health value of the obelisk
+ c = cent->currentState.modelindex2;
+ model.shaderRGBA[0] = 0xff;
+ model.shaderRGBA[1] = c;
+ model.shaderRGBA[2] = c;
+ model.shaderRGBA[3] = 0xff;
+ //
+ model.hModel = cgs.media.overloadEnergyModel;
+ trap_R_AddRefEntityToScene( &model );
+ }
+ // if respawning
+ if ( cent->currentState.frame == 2) {
+ if ( !cent->miscTime ) {
+ cent->miscTime = cg.time;
+ }
+ t = cg.time - cent->miscTime;
+ h = (cg_obeliskRespawnDelay.integer - 5) * 1000;
+ //
+ if (t > h) {
+ c = (float) (t - h) / h;
+ if (c > 1)
+ c = 1;
+ }
+ else {
+ c = 0;
+ }
+ // show the lights
+ AnglesToAxis( cent->currentState.angles, model.axis );
+ //
+ model.shaderRGBA[0] = c * 0xff;
+ model.shaderRGBA[1] = c * 0xff;
+ model.shaderRGBA[2] = c * 0xff;
+ model.shaderRGBA[3] = c * 0xff;
+
+ model.hModel = cgs.media.overloadLightsModel;
+ trap_R_AddRefEntityToScene( &model );
+ // show the target
+ if (t > h) {
+ if ( !cent->muzzleFlashTime ) {
+ trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound);
+ cent->muzzleFlashTime = 1;
+ }
+ VectorCopy(cent->currentState.angles, angles);
+ angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI;
+ AnglesToAxis( angles, model.axis );
+
+ VectorScale( model.axis[0], c, model.axis[0]);
+ VectorScale( model.axis[1], c, model.axis[1]);
+ VectorScale( model.axis[2], c, model.axis[2]);
+
+ model.shaderRGBA[0] = 0xff;
+ model.shaderRGBA[1] = 0xff;
+ model.shaderRGBA[2] = 0xff;
+ model.shaderRGBA[3] = 0xff;
+ //
+ model.origin[2] += 56;
+ model.hModel = cgs.media.overloadTargetModel;
+ trap_R_AddRefEntityToScene( &model );
+ }
+ else {
+ //FIXME: show animated smoke
+ }
+ }
+ else {
+ cent->miscTime = 0;
+ cent->muzzleFlashTime = 0;
+ // modelindex2 is the health value of the obelisk
+ c = cent->currentState.modelindex2;
+ model.shaderRGBA[0] = 0xff;
+ model.shaderRGBA[1] = c;
+ model.shaderRGBA[2] = c;
+ model.shaderRGBA[3] = 0xff;
+ // show the lights
+ model.hModel = cgs.media.overloadLightsModel;
+ trap_R_AddRefEntityToScene( &model );
+ // show the target
+ model.origin[2] += 56;
+ model.hModel = cgs.media.overloadTargetModel;
+ trap_R_AddRefEntityToScene( &model );
+ }
+ }
+ else if ( cgs.gametype == GT_HARVESTER ) {
+ // show harvester model
+ memset(&model, 0, sizeof(model));
+ model.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, model.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, model.origin );
+ AnglesToAxis( cent->currentState.angles, model.axis );
+
+ if ( cent->currentState.modelindex == TEAM_RED ) {
+ model.hModel = cgs.media.harvesterModel;
+ model.customSkin = cgs.media.harvesterRedSkin;
+ }
+ else if ( cent->currentState.modelindex == TEAM_BLUE ) {
+ model.hModel = cgs.media.harvesterModel;
+ model.customSkin = cgs.media.harvesterBlueSkin;
+ }
+ else {
+ model.hModel = cgs.media.harvesterNeutralModel;
+ model.customSkin = 0;
+ }
+ trap_R_AddRefEntityToScene( &model );
+ }
+#endif
+}
+
+/*
+===============
+CG_AddCEntity
+
+===============
+*/
+static void CG_AddCEntity( centity_t *cent ) {
+ // event-only entities will have been dealt with already
+ if ( cent->currentState.eType >= ET_EVENTS ) {
+ return;
+ }
+
+ // calculate the current origin
+ CG_CalcEntityLerpPositions( cent );
+
+ // add automatic effects
+ CG_EntityEffects( cent );
+
+ switch ( cent->currentState.eType ) {
+ default:
+ CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
+ break;
+ case ET_INVISIBLE:
+ case ET_PUSH_TRIGGER:
+ case ET_TELEPORT_TRIGGER:
+ break;
+ case ET_GENERAL:
+ CG_General( cent );
+ break;
+ case ET_PLAYER:
+ CG_Player( cent );
+ break;
+ case ET_ITEM:
+ CG_Item( cent );
+ break;
+ case ET_MISSILE:
+ CG_Missile( cent );
+ break;
+ case ET_MOVER:
+ CG_Mover( cent );
+ break;
+ case ET_BEAM:
+ CG_Beam( cent );
+ break;
+ case ET_PORTAL:
+ CG_Portal( cent );
+ break;
+ case ET_SPEAKER:
+ CG_Speaker( cent );
+ break;
+ case ET_GRAPPLE:
+ CG_Grapple( cent );
+ break;
+ case ET_TEAM:
+ CG_TeamBase( cent );
+ break;
+ }
+}
+
+/*
+===============
+CG_AddPacketEntities
+
+===============
+*/
+void CG_AddPacketEntities( void ) {
+ int num;
+ centity_t *cent;
+ playerState_t *ps;
+
+ // set cg.frameInterpolation
+ if ( cg.nextSnap ) {
+ int delta;
+
+ delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
+ if ( delta == 0 ) {
+ cg.frameInterpolation = 0;
+ } else {
+ cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
+ }
+ } else {
+ cg.frameInterpolation = 0; // actually, it should never be used, because
+ // no entities should be marked as interpolating
+ }
+
+ // the auto-rotating items will all have the same axis
+ cg.autoAngles[0] = 0;
+ cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
+ cg.autoAngles[2] = 0;
+
+ cg.autoAnglesFast[0] = 0;
+ cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
+ cg.autoAnglesFast[2] = 0;
+
+ AnglesToAxis( cg.autoAngles, cg.autoAxis );
+ AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
+
+ // generate and add the entity from the playerstate
+ ps = &cg.predictedPlayerState;
+ BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );
+ CG_AddCEntity( &cg.predictedPlayerEntity );
+
+ // lerp the non-predicted value for lightning gun origins
+ CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
+
+ // add each entity sent over by the server
+ for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
+ cent = &cg_entities[ cg.snap->entities[ num ].number ];
+ CG_AddCEntity( cent );
+ }
+}
+
diff --git a/code/cgame/cg_event.c b/code/cgame/cg_event.c
index 86167c6..373c9a3 100755
--- a/code/cgame/cg_event.c
+++ b/code/cgame/cg_event.c
@@ -1,1205 +1,1205 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_event.c -- handle entity events at snapshot or playerstate transitions
-
-#include "cg_local.h"
-
-// for the voice chats
-#ifdef MISSIONPACK // bk001205
-#include "../../ui/menudef.h"
-#endif
-//==========================================================================
-
-/*
-===================
-CG_PlaceString
-
-Also called by scoreboard drawing
-===================
-*/
-const char *CG_PlaceString( int rank ) {
- static char str[64];
- char *s, *t;
-
- if ( rank & RANK_TIED_FLAG ) {
- rank &= ~RANK_TIED_FLAG;
- t = "Tied for ";
- } else {
- t = "";
- }
-
- if ( rank == 1 ) {
- s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue
- } else if ( rank == 2 ) {
- s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red
- } else if ( rank == 3 ) {
- s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow
- } else if ( rank == 11 ) {
- s = "11th";
- } else if ( rank == 12 ) {
- s = "12th";
- } else if ( rank == 13 ) {
- s = "13th";
- } else if ( rank % 10 == 1 ) {
- s = va("%ist", rank);
- } else if ( rank % 10 == 2 ) {
- s = va("%ind", rank);
- } else if ( rank % 10 == 3 ) {
- s = va("%ird", rank);
- } else {
- s = va("%ith", rank);
- }
-
- Com_sprintf( str, sizeof( str ), "%s%s", t, s );
- return str;
-}
-
-/*
-=============
-CG_Obituary
-=============
-*/
-static void CG_Obituary( entityState_t *ent ) {
- int mod;
- int target, attacker;
- char *message;
- char *message2;
- const char *targetInfo;
- const char *attackerInfo;
- char targetName[32];
- char attackerName[32];
- gender_t gender;
- clientInfo_t *ci;
-
- target = ent->otherEntityNum;
- attacker = ent->otherEntityNum2;
- mod = ent->eventParm;
-
- if ( target < 0 || target >= MAX_CLIENTS ) {
- CG_Error( "CG_Obituary: target out of range" );
- }
- ci = &cgs.clientinfo[target];
-
- if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
- attacker = ENTITYNUM_WORLD;
- attackerInfo = NULL;
- } else {
- attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
- }
-
- targetInfo = CG_ConfigString( CS_PLAYERS + target );
- if ( !targetInfo ) {
- return;
- }
- Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
- strcat( targetName, S_COLOR_WHITE );
-
- message2 = "";
-
- // check for single client messages
-
- 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_TARGET_LASER:
- message = "saw the light";
- break;
- case MOD_TRIGGER_HURT:
- message = "was in the wrong place";
- break;
- default:
- message = NULL;
- break;
- }
-
- if (attacker == target) {
- gender = ci->gender;
- switch (mod) {
-#ifdef MISSIONPACK
- case MOD_KAMIKAZE:
- message = "goes out with a bang";
- break;
-#endif
- case MOD_GRENADE_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "tripped on her own grenade";
- else if ( gender == GENDER_NEUTER )
- message = "tripped on its own grenade";
- else
- message = "tripped on his own grenade";
- break;
- case MOD_ROCKET_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "blew herself up";
- else if ( gender == GENDER_NEUTER )
- message = "blew itself up";
- else
- message = "blew himself up";
- break;
- case MOD_PLASMA_SPLASH:
- if ( gender == GENDER_FEMALE )
- message = "melted herself";
- else if ( gender == GENDER_NEUTER )
- message = "melted itself";
- else
- message = "melted himself";
- break;
- case MOD_BFG_SPLASH:
- message = "should have used a smaller gun";
- break;
-#ifdef MISSIONPACK
- case MOD_PROXIMITY_MINE:
- if( gender == GENDER_FEMALE ) {
- message = "found her prox mine";
- } else if ( gender == GENDER_NEUTER ) {
- message = "found it's prox mine";
- } else {
- message = "found his prox mine";
- }
- break;
-#endif
- default:
- if ( gender == GENDER_FEMALE )
- message = "killed herself";
- else if ( gender == GENDER_NEUTER )
- message = "killed itself";
- else
- message = "killed himself";
- break;
- }
- }
-
- if (message) {
- CG_Printf( "%s %s.\n", targetName, message);
- return;
- }
-
- // check for kill messages from the current clientNum
- if ( attacker == cg.snap->ps.clientNum ) {
- char *s;
-
- if ( cgs.gametype < GT_TEAM ) {
- s = va("You fragged %s\n%s place with %i", targetName,
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- cg.snap->ps.persistant[PERS_SCORE] );
- } else {
- s = va("You fragged %s", targetName );
- }
-#ifdef MISSIONPACK
- if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
- CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- }
-#else
- CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
-#endif
-
- // print the text message as well
- }
-
- // check for double client messages
- if ( !attackerInfo ) {
- attacker = ENTITYNUM_WORLD;
- strcpy( attackerName, "noname" );
- } else {
- Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
- strcat( attackerName, S_COLOR_WHITE );
- // check for kill messages about the current clientNum
- if ( target == cg.snap->ps.clientNum ) {
- Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
- }
- }
-
- if ( attacker != ENTITYNUM_WORLD ) {
- switch (mod) {
- case MOD_GRAPPLE:
- message = "was caught by";
- break;
- case MOD_GAUNTLET:
- message = "was pummeled by";
- break;
- case MOD_MACHINEGUN:
- message = "was machinegunned by";
- break;
- case MOD_SHOTGUN:
- message = "was gunned down by";
- break;
- case MOD_GRENADE:
- message = "ate";
- message2 = "'s grenade";
- break;
- case MOD_GRENADE_SPLASH:
- message = "was shredded by";
- message2 = "'s shrapnel";
- break;
- case MOD_ROCKET:
- message = "ate";
- message2 = "'s rocket";
- break;
- case MOD_ROCKET_SPLASH:
- message = "almost dodged";
- message2 = "'s rocket";
- break;
- case MOD_PLASMA:
- message = "was melted by";
- message2 = "'s plasmagun";
- break;
- case MOD_PLASMA_SPLASH:
- message = "was melted by";
- message2 = "'s plasmagun";
- break;
- case MOD_RAILGUN:
- message = "was railed by";
- break;
- case MOD_LIGHTNING:
- message = "was electrocuted by";
- break;
- case MOD_BFG:
- case MOD_BFG_SPLASH:
- message = "was blasted by";
- message2 = "'s BFG";
- break;
-#ifdef MISSIONPACK
- case MOD_NAIL:
- message = "was nailed by";
- break;
- case MOD_CHAINGUN:
- message = "got lead poisoning from";
- message2 = "'s Chaingun";
- break;
- case MOD_PROXIMITY_MINE:
- message = "was too close to";
- message2 = "'s Prox Mine";
- break;
- case MOD_KAMIKAZE:
- message = "falls to";
- message2 = "'s Kamikaze blast";
- break;
- case MOD_JUICED:
- message = "was juiced by";
- break;
-#endif
- case MOD_TELEFRAG:
- message = "tried to invade";
- message2 = "'s personal space";
- break;
- default:
- message = "was killed by";
- break;
- }
-
- if (message) {
- CG_Printf( "%s %s %s%s\n",
- targetName, message, attackerName, message2);
- return;
- }
- }
-
- // we don't know what it was
- CG_Printf( "%s died.\n", targetName );
-}
-
-//==========================================================================
-
-/*
-===============
-CG_UseItem
-===============
-*/
-static void CG_UseItem( centity_t *cent ) {
- clientInfo_t *ci;
- int itemNum, clientNum;
- gitem_t *item;
- entityState_t *es;
-
- es = &cent->currentState;
-
- itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
- if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
- itemNum = 0;
- }
-
- // print a message if the local player
- if ( es->number == cg.snap->ps.clientNum ) {
- if ( !itemNum ) {
- CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- } else {
- item = BG_FindItemForHoldable( itemNum );
- CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- }
- }
-
- switch ( itemNum ) {
- default:
- case HI_NONE:
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
- break;
-
- case HI_TELEPORTER:
- break;
-
- case HI_MEDKIT:
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- ci->medkitUsageTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
- break;
-
-#ifdef MISSIONPACK
- case HI_KAMIKAZE:
- break;
-
- case HI_PORTAL:
- break;
- case HI_INVULNERABILITY:
- trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
- break;
-#endif
- }
-
-}
-
-/*
-================
-CG_ItemPickup
-
-A new item was picked up this frame
-================
-*/
-static void CG_ItemPickup( int itemNum ) {
- cg.itemPickup = itemNum;
- cg.itemPickupTime = cg.time;
- cg.itemPickupBlendTime = cg.time;
- // see if it should be the grabbed weapon
- if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
- // select it immediately
- if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
- cg.weaponSelectTime = cg.time;
- cg.weaponSelect = bg_itemlist[itemNum].giTag;
- }
- }
-
-}
-
-
-/*
-================
-CG_PainEvent
-
-Also called by playerstate transition
-================
-*/
-void CG_PainEvent( centity_t *cent, int health ) {
- char *snd;
-
- // don't do more than two pain sounds a second
- if ( cg.time - cent->pe.painTime < 500 ) {
- return;
- }
-
- if ( health < 25 ) {
- snd = "*pain25_1.wav";
- } else if ( health < 50 ) {
- snd = "*pain50_1.wav";
- } else if ( health < 75 ) {
- snd = "*pain75_1.wav";
- } else {
- snd = "*pain100_1.wav";
- }
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE,
- CG_CustomSound( cent->currentState.number, snd ) );
-
- // save pain time for programitic twitch animation
- cent->pe.painTime = cg.time;
- cent->pe.painDirection ^= 1;
-}
-
-
-
-/*
-==============
-CG_EntityEvent
-
-An entity has an event value
-also called by CG_CheckPlayerstateEvents
-==============
-*/
-#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
-void CG_EntityEvent( centity_t *cent, vec3_t position ) {
- entityState_t *es;
- int event;
- vec3_t dir;
- const char *s;
- int clientNum;
- clientInfo_t *ci;
-
- es = &cent->currentState;
- event = es->event & ~EV_EVENT_BITS;
-
- if ( cg_debugEvents.integer ) {
- CG_Printf( "ent:%3i event:%3i ", es->number, event );
- }
-
- if ( !event ) {
- DEBUGNAME("ZEROEVENT");
- return;
- }
-
- clientNum = es->clientNum;
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- switch ( event ) {
- //
- // movement generated events
- //
- case EV_FOOTSTEP:
- DEBUGNAME("EV_FOOTSTEP");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ ci->footsteps ][rand()&3] );
- }
- break;
- case EV_FOOTSTEP_METAL:
- DEBUGNAME("EV_FOOTSTEP_METAL");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
- }
- break;
- case EV_FOOTSPLASH:
- DEBUGNAME("EV_FOOTSPLASH");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
- case EV_FOOTWADE:
- DEBUGNAME("EV_FOOTWADE");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
- case EV_SWIM:
- DEBUGNAME("EV_SWIM");
- if (cg_footsteps.integer) {
- trap_S_StartSound (NULL, es->number, CHAN_BODY,
- cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
- }
- break;
-
-
- case EV_FALL_SHORT:
- DEBUGNAME("EV_FALL_SHORT");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -8;
- cg.landTime = cg.time;
- }
- break;
- case EV_FALL_MEDIUM:
- DEBUGNAME("EV_FALL_MEDIUM");
- // use normal pain sound
- trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -16;
- cg.landTime = cg.time;
- }
- break;
- case EV_FALL_FAR:
- DEBUGNAME("EV_FALL_FAR");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
- cent->pe.painTime = cg.time; // don't play a pain sound right after this
- if ( clientNum == cg.predictedPlayerState.clientNum ) {
- // smooth landing z changes
- cg.landChange = -24;
- cg.landTime = cg.time;
- }
- break;
-
- case EV_STEP_4:
- case EV_STEP_8:
- case EV_STEP_12:
- case EV_STEP_16: // smooth out step up transitions
- DEBUGNAME("EV_STEP");
- {
- float oldStep;
- int delta;
- int step;
-
- if ( clientNum != cg.predictedPlayerState.clientNum ) {
- break;
- }
- // if we are interpolating, we don't need to smooth steps
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
- cg_nopredict.integer || cg_synchronousClients.integer ) {
- break;
- }
- // check for stepping up before a previous step is completed
- delta = cg.time - cg.stepTime;
- if (delta < STEP_TIME) {
- oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
- } else {
- oldStep = 0;
- }
-
- // add this amount
- step = 4 * (event - EV_STEP_4 + 1 );
- cg.stepChange = oldStep + step;
- if ( cg.stepChange > MAX_STEP_CHANGE ) {
- cg.stepChange = MAX_STEP_CHANGE;
- }
- cg.stepTime = cg.time;
- break;
- }
-
- case EV_JUMP_PAD:
- DEBUGNAME("EV_JUMP_PAD");
-// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
- {
- localEntity_t *smoke;
- vec3_t up = {0, 0, 1};
-
-
- smoke = CG_SmokePuff( cent->lerpOrigin, up,
- 32,
- 1, 1, 1, 0.33f,
- 1000,
- cg.time, 0,
- LEF_PUFF_DONT_SCALE,
- cgs.media.smokePuffShader );
- }
-
- // boing sound at origin, jump sound on player
- trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- break;
-
- case EV_JUMP:
- DEBUGNAME("EV_JUMP");
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
- break;
- case EV_TAUNT:
- DEBUGNAME("EV_TAUNT");
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
- break;
-#ifdef MISSIONPACK
- case EV_TAUNT_YES:
- DEBUGNAME("EV_TAUNT_YES");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
- break;
- case EV_TAUNT_NO:
- DEBUGNAME("EV_TAUNT_NO");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
- break;
- case EV_TAUNT_FOLLOWME:
- DEBUGNAME("EV_TAUNT_FOLLOWME");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
- break;
- case EV_TAUNT_GETFLAG:
- DEBUGNAME("EV_TAUNT_GETFLAG");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
- break;
- case EV_TAUNT_GUARDBASE:
- DEBUGNAME("EV_TAUNT_GUARDBASE");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
- break;
- case EV_TAUNT_PATROL:
- DEBUGNAME("EV_TAUNT_PATROL");
- CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
- break;
-#endif
- case EV_WATER_TOUCH:
- DEBUGNAME("EV_WATER_TOUCH");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
- break;
- case EV_WATER_LEAVE:
- DEBUGNAME("EV_WATER_LEAVE");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
- break;
- case EV_WATER_UNDER:
- DEBUGNAME("EV_WATER_UNDER");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
- break;
- case EV_WATER_CLEAR:
- DEBUGNAME("EV_WATER_CLEAR");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
- break;
-
- case EV_ITEM_PICKUP:
- DEBUGNAME("EV_ITEM_PICKUP");
- {
- gitem_t *item;
- int index;
-
- index = es->eventParm; // player predicted
-
- if ( index < 1 || index >= bg_numItems ) {
- break;
- }
- item = &bg_itemlist[ index ];
-
- // powerups and team items will have a separate global sound, this one
- // will be played at prediction time
- if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound );
- } else if (item->giType == IT_PERSISTANT_POWERUP) {
-#ifdef MISSIONPACK
- switch (item->giTag ) {
- case PW_SCOUT:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound );
- break;
- case PW_GUARD:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound );
- break;
- case PW_DOUBLER:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound );
- break;
- case PW_AMMOREGEN:
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound );
- break;
- }
-#endif
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
- }
-
- // show icon and name on status bar
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_ItemPickup( index );
- }
- }
- break;
-
- case EV_GLOBAL_ITEM_PICKUP:
- DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
- {
- gitem_t *item;
- int index;
-
- index = es->eventParm; // player predicted
-
- if ( index < 1 || index >= bg_numItems ) {
- break;
- }
- item = &bg_itemlist[ index ];
- // powerup pickups are global
- if( item->pickup_sound ) {
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
- }
-
- // show icon and name on status bar
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_ItemPickup( index );
- }
- }
- break;
-
- //
- // weapon events
- //
- case EV_NOAMMO:
- DEBUGNAME("EV_NOAMMO");
-// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
- if ( es->number == cg.snap->ps.clientNum ) {
- CG_OutOfAmmoChange();
- }
- break;
- case EV_CHANGE_WEAPON:
- DEBUGNAME("EV_CHANGE_WEAPON");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
- break;
- case EV_FIRE_WEAPON:
- DEBUGNAME("EV_FIRE_WEAPON");
- CG_FireWeapon( cent );
- break;
-
- case EV_USE_ITEM0:
- DEBUGNAME("EV_USE_ITEM0");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM1:
- DEBUGNAME("EV_USE_ITEM1");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM2:
- DEBUGNAME("EV_USE_ITEM2");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM3:
- DEBUGNAME("EV_USE_ITEM3");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM4:
- DEBUGNAME("EV_USE_ITEM4");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM5:
- DEBUGNAME("EV_USE_ITEM5");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM6:
- DEBUGNAME("EV_USE_ITEM6");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM7:
- DEBUGNAME("EV_USE_ITEM7");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM8:
- DEBUGNAME("EV_USE_ITEM8");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM9:
- DEBUGNAME("EV_USE_ITEM9");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM10:
- DEBUGNAME("EV_USE_ITEM10");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM11:
- DEBUGNAME("EV_USE_ITEM11");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM12:
- DEBUGNAME("EV_USE_ITEM12");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM13:
- DEBUGNAME("EV_USE_ITEM13");
- CG_UseItem( cent );
- break;
- case EV_USE_ITEM14:
- DEBUGNAME("EV_USE_ITEM14");
- CG_UseItem( cent );
- break;
-
- //=================================================================
-
- //
- // other events
- //
- case EV_PLAYER_TELEPORT_IN:
- DEBUGNAME("EV_PLAYER_TELEPORT_IN");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
- CG_SpawnEffect( position);
- break;
-
- case EV_PLAYER_TELEPORT_OUT:
- DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
- CG_SpawnEffect( position);
- break;
-
- case EV_ITEM_POP:
- DEBUGNAME("EV_ITEM_POP");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
- break;
- case EV_ITEM_RESPAWN:
- DEBUGNAME("EV_ITEM_RESPAWN");
- cent->miscTime = cg.time; // scale up from this
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
- break;
-
- case EV_GRENADE_BOUNCE:
- DEBUGNAME("EV_GRENADE_BOUNCE");
- if ( rand() & 1 ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
- }
- break;
-
-#ifdef MISSIONPACK
- case EV_PROXIMITY_MINE_STICK:
- DEBUGNAME("EV_PROXIMITY_MINE_STICK");
- if( es->eventParm & SURF_FLESH ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
- } else if( es->eventParm & SURF_METALSTEPS ) {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
- } else {
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
- }
- break;
-
- case EV_PROXIMITY_MINE_TRIGGER:
- DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
- trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
- break;
- case EV_KAMIKAZE:
- DEBUGNAME("EV_KAMIKAZE");
- CG_KamikazeEffect( cent->lerpOrigin );
- break;
- case EV_OBELISKEXPLODE:
- DEBUGNAME("EV_OBELISKEXPLODE");
- CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
- break;
- case EV_OBELISKPAIN:
- DEBUGNAME("EV_OBELISKPAIN");
- CG_ObeliskPain( cent->lerpOrigin );
- break;
- case EV_INVUL_IMPACT:
- DEBUGNAME("EV_INVUL_IMPACT");
- CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
- break;
- case EV_JUICED:
- DEBUGNAME("EV_JUICED");
- CG_InvulnerabilityJuiced( cent->lerpOrigin );
- break;
- case EV_LIGHTNINGBOLT:
- DEBUGNAME("EV_LIGHTNINGBOLT");
- CG_LightningBoltBeam(es->origin2, es->pos.trBase);
- break;
-#endif
- case EV_SCOREPLUM:
- DEBUGNAME("EV_SCOREPLUM");
- CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
- break;
-
- //
- // missile impacts
- //
- case EV_MISSILE_HIT:
- DEBUGNAME("EV_MISSILE_HIT");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
- break;
-
- case EV_MISSILE_MISS:
- DEBUGNAME("EV_MISSILE_MISS");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
- break;
-
- case EV_MISSILE_MISS_METAL:
- DEBUGNAME("EV_MISSILE_MISS_METAL");
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
- break;
-
- case EV_RAILTRAIL:
- DEBUGNAME("EV_RAILTRAIL");
- cent->currentState.weapon = WP_RAILGUN;
- // if the end was on a nomark surface, don't make an explosion
- CG_RailTrail( ci, es->origin2, es->pos.trBase );
- if ( es->eventParm != 255 ) {
- ByteToDir( es->eventParm, dir );
- CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );
- }
- break;
-
- case EV_BULLET_HIT_WALL:
- DEBUGNAME("EV_BULLET_HIT_WALL");
- ByteToDir( es->eventParm, dir );
- CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
- break;
-
- case EV_BULLET_HIT_FLESH:
- DEBUGNAME("EV_BULLET_HIT_FLESH");
- CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
- break;
-
- case EV_SHOTGUN:
- DEBUGNAME("EV_SHOTGUN");
- CG_ShotgunFire( es );
- break;
-
- case EV_GENERAL_SOUND:
- DEBUGNAME("EV_GENERAL_SOUND");
- if ( cgs.gameSounds[ es->eventParm ] ) {
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
- } else {
- s = CG_ConfigString( CS_SOUNDS + es->eventParm );
- trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
- }
- break;
-
- case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
- DEBUGNAME("EV_GLOBAL_SOUND");
- if ( cgs.gameSounds[ es->eventParm ] ) {
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
- } else {
- s = CG_ConfigString( CS_SOUNDS + es->eventParm );
- trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
- }
- break;
-
- case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
- {
- DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
- switch( es->eventParm ) {
- case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
- CG_AddBufferedSound( cgs.media.captureYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.captureOpponentSound );
- break;
- case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
- CG_AddBufferedSound( cgs.media.captureYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.captureOpponentSound );
- break;
- case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
- CG_AddBufferedSound( cgs.media.returnYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.returnOpponentSound );
- //
- CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
- break;
- case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
- if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
- CG_AddBufferedSound( cgs.media.returnYourTeamSound );
- else
- CG_AddBufferedSound( cgs.media.returnOpponentSound );
- //
- CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
- break;
-
- case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
- // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
- if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- }
- else {
- if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
- }
- else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
- }
- }
- break;
- case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
- // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
- if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- }
- else {
- if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
- }
- else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
-#ifdef MISSIONPACK
- if (cgs.gametype == GT_1FCTF)
- CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
- else
-#endif
- CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
- }
- }
- break;
- case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked
- if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
- CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
- }
- break;
- case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked
- if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
- CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
- }
- break;
-
- case GTS_REDTEAM_SCORED:
- CG_AddBufferedSound(cgs.media.redScoredSound);
- break;
- case GTS_BLUETEAM_SCORED:
- CG_AddBufferedSound(cgs.media.blueScoredSound);
- break;
- case GTS_REDTEAM_TOOK_LEAD:
- CG_AddBufferedSound(cgs.media.redLeadsSound);
- break;
- case GTS_BLUETEAM_TOOK_LEAD:
- CG_AddBufferedSound(cgs.media.blueLeadsSound);
- break;
- case GTS_TEAMS_ARE_TIED:
- CG_AddBufferedSound( cgs.media.teamsTiedSound );
- break;
-#ifdef MISSIONPACK
- case GTS_KAMIKAZE:
- trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
- break;
-#endif
- default:
- break;
- }
- break;
- }
-
- case EV_PAIN:
- // local player sounds are triggered in CG_CheckLocalSounds,
- // so ignore events on the player
- DEBUGNAME("EV_PAIN");
- if ( cent->currentState.number != cg.snap->ps.clientNum ) {
- CG_PainEvent( cent, es->eventParm );
- }
- break;
-
- case EV_DEATH1:
- case EV_DEATH2:
- case EV_DEATH3:
- DEBUGNAME("EV_DEATHx");
- trap_S_StartSound( NULL, es->number, CHAN_VOICE,
- CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
- break;
-
-
- case EV_OBITUARY:
- DEBUGNAME("EV_OBITUARY");
- CG_Obituary( es );
- break;
-
- //
- // powerup events
- //
- case EV_POWERUP_QUAD:
- DEBUGNAME("EV_POWERUP_QUAD");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_QUAD;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
- break;
- case EV_POWERUP_BATTLESUIT:
- DEBUGNAME("EV_POWERUP_BATTLESUIT");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_BATTLESUIT;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
- break;
- case EV_POWERUP_REGEN:
- DEBUGNAME("EV_POWERUP_REGEN");
- if ( es->number == cg.snap->ps.clientNum ) {
- cg.powerupActive = PW_REGEN;
- cg.powerupTime = cg.time;
- }
- trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
- break;
-
- case EV_GIB_PLAYER:
- DEBUGNAME("EV_GIB_PLAYER");
- // don't play gib sound when using the kamikaze because it interferes
- // with the kamikaze sound, downside is that the gib sound will also
- // not be played when someone is gibbed while just carrying the kamikaze
- if ( !(es->eFlags & EF_KAMIKAZE) ) {
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
- }
- CG_GibPlayer( cent->lerpOrigin );
- break;
-
- case EV_STOPLOOPINGSOUND:
- DEBUGNAME("EV_STOPLOOPINGSOUND");
- trap_S_StopLoopingSound( es->number );
- es->loopSound = 0;
- break;
-
- case EV_DEBUG_LINE:
- DEBUGNAME("EV_DEBUG_LINE");
- CG_Beam( cent );
- break;
-
- default:
- DEBUGNAME("UNKNOWN");
- CG_Error( "Unknown event: %i", event );
- break;
- }
-
-}
-
-
-/*
-==============
-CG_CheckEvents
-
-==============
-*/
-void CG_CheckEvents( centity_t *cent ) {
- // check for event-only entities
- if ( cent->currentState.eType > ET_EVENTS ) {
- if ( cent->previousEvent ) {
- return; // already fired
- }
- // if this is a player event set the entity number of the client entity number
- if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
- cent->currentState.number = cent->currentState.otherEntityNum;
- }
-
- cent->previousEvent = 1;
-
- cent->currentState.event = cent->currentState.eType - ET_EVENTS;
- } else {
- // check for events riding with another entity
- if ( cent->currentState.event == cent->previousEvent ) {
- return;
- }
- cent->previousEvent = cent->currentState.event;
- if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
- return;
- }
- }
-
- // calculate the position at exactly the frame time
- BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
- CG_SetEntitySoundPosition( cent );
-
- CG_EntityEvent( cent, cent->lerpOrigin );
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_event.c -- handle entity events at snapshot or playerstate transitions
+
+#include "cg_local.h"
+
+// for the voice chats
+#ifdef MISSIONPACK // bk001205
+#include "../../ui/menudef.h"
+#endif
+//==========================================================================
+
+/*
+===================
+CG_PlaceString
+
+Also called by scoreboard drawing
+===================
+*/
+const char *CG_PlaceString( int rank ) {
+ static char str[64];
+ char *s, *t;
+
+ if ( rank & RANK_TIED_FLAG ) {
+ rank &= ~RANK_TIED_FLAG;
+ t = "Tied for ";
+ } else {
+ t = "";
+ }
+
+ if ( rank == 1 ) {
+ s = S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue
+ } else if ( rank == 2 ) {
+ s = S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red
+ } else if ( rank == 3 ) {
+ s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow
+ } else if ( rank == 11 ) {
+ s = "11th";
+ } else if ( rank == 12 ) {
+ s = "12th";
+ } else if ( rank == 13 ) {
+ s = "13th";
+ } else if ( rank % 10 == 1 ) {
+ s = va("%ist", rank);
+ } else if ( rank % 10 == 2 ) {
+ s = va("%ind", rank);
+ } else if ( rank % 10 == 3 ) {
+ s = va("%ird", rank);
+ } else {
+ s = va("%ith", rank);
+ }
+
+ Com_sprintf( str, sizeof( str ), "%s%s", t, s );
+ return str;
+}
+
+/*
+=============
+CG_Obituary
+=============
+*/
+static void CG_Obituary( entityState_t *ent ) {
+ int mod;
+ int target, attacker;
+ char *message;
+ char *message2;
+ const char *targetInfo;
+ const char *attackerInfo;
+ char targetName[32];
+ char attackerName[32];
+ gender_t gender;
+ clientInfo_t *ci;
+
+ target = ent->otherEntityNum;
+ attacker = ent->otherEntityNum2;
+ mod = ent->eventParm;
+
+ if ( target < 0 || target >= MAX_CLIENTS ) {
+ CG_Error( "CG_Obituary: target out of range" );
+ }
+ ci = &cgs.clientinfo[target];
+
+ if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
+ attacker = ENTITYNUM_WORLD;
+ attackerInfo = NULL;
+ } else {
+ attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
+ }
+
+ targetInfo = CG_ConfigString( CS_PLAYERS + target );
+ if ( !targetInfo ) {
+ return;
+ }
+ Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
+ strcat( targetName, S_COLOR_WHITE );
+
+ message2 = "";
+
+ // check for single client messages
+
+ 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_TARGET_LASER:
+ message = "saw the light";
+ break;
+ case MOD_TRIGGER_HURT:
+ message = "was in the wrong place";
+ break;
+ default:
+ message = NULL;
+ break;
+ }
+
+ if (attacker == target) {
+ gender = ci->gender;
+ switch (mod) {
+#ifdef MISSIONPACK
+ case MOD_KAMIKAZE:
+ message = "goes out with a bang";
+ break;
+#endif
+ case MOD_GRENADE_SPLASH:
+ if ( gender == GENDER_FEMALE )
+ message = "tripped on her own grenade";
+ else if ( gender == GENDER_NEUTER )
+ message = "tripped on its own grenade";
+ else
+ message = "tripped on his own grenade";
+ break;
+ case MOD_ROCKET_SPLASH:
+ if ( gender == GENDER_FEMALE )
+ message = "blew herself up";
+ else if ( gender == GENDER_NEUTER )
+ message = "blew itself up";
+ else
+ message = "blew himself up";
+ break;
+ case MOD_PLASMA_SPLASH:
+ if ( gender == GENDER_FEMALE )
+ message = "melted herself";
+ else if ( gender == GENDER_NEUTER )
+ message = "melted itself";
+ else
+ message = "melted himself";
+ break;
+ case MOD_BFG_SPLASH:
+ message = "should have used a smaller gun";
+ break;
+#ifdef MISSIONPACK
+ case MOD_PROXIMITY_MINE:
+ if( gender == GENDER_FEMALE ) {
+ message = "found her prox mine";
+ } else if ( gender == GENDER_NEUTER ) {
+ message = "found it's prox mine";
+ } else {
+ message = "found his prox mine";
+ }
+ break;
+#endif
+ default:
+ if ( gender == GENDER_FEMALE )
+ message = "killed herself";
+ else if ( gender == GENDER_NEUTER )
+ message = "killed itself";
+ else
+ message = "killed himself";
+ break;
+ }
+ }
+
+ if (message) {
+ CG_Printf( "%s %s.\n", targetName, message);
+ return;
+ }
+
+ // check for kill messages from the current clientNum
+ if ( attacker == cg.snap->ps.clientNum ) {
+ char *s;
+
+ if ( cgs.gametype < GT_TEAM ) {
+ s = va("You fragged %s\n%s place with %i", targetName,
+ CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
+ cg.snap->ps.persistant[PERS_SCORE] );
+ } else {
+ s = va("You fragged %s", targetName );
+ }
+#ifdef MISSIONPACK
+ if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
+ CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ }
+#else
+ CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+#endif
+
+ // print the text message as well
+ }
+
+ // check for double client messages
+ if ( !attackerInfo ) {
+ attacker = ENTITYNUM_WORLD;
+ strcpy( attackerName, "noname" );
+ } else {
+ Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
+ strcat( attackerName, S_COLOR_WHITE );
+ // check for kill messages about the current clientNum
+ if ( target == cg.snap->ps.clientNum ) {
+ Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
+ }
+ }
+
+ if ( attacker != ENTITYNUM_WORLD ) {
+ switch (mod) {
+ case MOD_GRAPPLE:
+ message = "was caught by";
+ break;
+ case MOD_GAUNTLET:
+ message = "was pummeled by";
+ break;
+ case MOD_MACHINEGUN:
+ message = "was machinegunned by";
+ break;
+ case MOD_SHOTGUN:
+ message = "was gunned down by";
+ break;
+ case MOD_GRENADE:
+ message = "ate";
+ message2 = "'s grenade";
+ break;
+ case MOD_GRENADE_SPLASH:
+ message = "was shredded by";
+ message2 = "'s shrapnel";
+ break;
+ case MOD_ROCKET:
+ message = "ate";
+ message2 = "'s rocket";
+ break;
+ case MOD_ROCKET_SPLASH:
+ message = "almost dodged";
+ message2 = "'s rocket";
+ break;
+ case MOD_PLASMA:
+ message = "was melted by";
+ message2 = "'s plasmagun";
+ break;
+ case MOD_PLASMA_SPLASH:
+ message = "was melted by";
+ message2 = "'s plasmagun";
+ break;
+ case MOD_RAILGUN:
+ message = "was railed by";
+ break;
+ case MOD_LIGHTNING:
+ message = "was electrocuted by";
+ break;
+ case MOD_BFG:
+ case MOD_BFG_SPLASH:
+ message = "was blasted by";
+ message2 = "'s BFG";
+ break;
+#ifdef MISSIONPACK
+ case MOD_NAIL:
+ message = "was nailed by";
+ break;
+ case MOD_CHAINGUN:
+ message = "got lead poisoning from";
+ message2 = "'s Chaingun";
+ break;
+ case MOD_PROXIMITY_MINE:
+ message = "was too close to";
+ message2 = "'s Prox Mine";
+ break;
+ case MOD_KAMIKAZE:
+ message = "falls to";
+ message2 = "'s Kamikaze blast";
+ break;
+ case MOD_JUICED:
+ message = "was juiced by";
+ break;
+#endif
+ case MOD_TELEFRAG:
+ message = "tried to invade";
+ message2 = "'s personal space";
+ break;
+ default:
+ message = "was killed by";
+ break;
+ }
+
+ if (message) {
+ CG_Printf( "%s %s %s%s\n",
+ targetName, message, attackerName, message2);
+ return;
+ }
+ }
+
+ // we don't know what it was
+ CG_Printf( "%s died.\n", targetName );
+}
+
+//==========================================================================
+
+/*
+===============
+CG_UseItem
+===============
+*/
+static void CG_UseItem( centity_t *cent ) {
+ clientInfo_t *ci;
+ int itemNum, clientNum;
+ gitem_t *item;
+ entityState_t *es;
+
+ es = &cent->currentState;
+
+ itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
+ if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
+ itemNum = 0;
+ }
+
+ // print a message if the local player
+ if ( es->number == cg.snap->ps.clientNum ) {
+ if ( !itemNum ) {
+ CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ } else {
+ item = BG_FindItemForHoldable( itemNum );
+ CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ }
+ }
+
+ switch ( itemNum ) {
+ default:
+ case HI_NONE:
+ trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
+ break;
+
+ case HI_TELEPORTER:
+ break;
+
+ case HI_MEDKIT:
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
+ ci = &cgs.clientinfo[ clientNum ];
+ ci->medkitUsageTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
+ break;
+
+#ifdef MISSIONPACK
+ case HI_KAMIKAZE:
+ break;
+
+ case HI_PORTAL:
+ break;
+ case HI_INVULNERABILITY:
+ trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
+ break;
+#endif
+ }
+
+}
+
+/*
+================
+CG_ItemPickup
+
+A new item was picked up this frame
+================
+*/
+static void CG_ItemPickup( int itemNum ) {
+ cg.itemPickup = itemNum;
+ cg.itemPickupTime = cg.time;
+ cg.itemPickupBlendTime = cg.time;
+ // see if it should be the grabbed weapon
+ if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
+ // select it immediately
+ if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
+ cg.weaponSelectTime = cg.time;
+ cg.weaponSelect = bg_itemlist[itemNum].giTag;
+ }
+ }
+
+}
+
+
+/*
+================
+CG_PainEvent
+
+Also called by playerstate transition
+================
+*/
+void CG_PainEvent( centity_t *cent, int health ) {
+ char *snd;
+
+ // don't do more than two pain sounds a second
+ if ( cg.time - cent->pe.painTime < 500 ) {
+ return;
+ }
+
+ if ( health < 25 ) {
+ snd = "*pain25_1.wav";
+ } else if ( health < 50 ) {
+ snd = "*pain50_1.wav";
+ } else if ( health < 75 ) {
+ snd = "*pain75_1.wav";
+ } else {
+ snd = "*pain100_1.wav";
+ }
+ trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE,
+ CG_CustomSound( cent->currentState.number, snd ) );
+
+ // save pain time for programitic twitch animation
+ cent->pe.painTime = cg.time;
+ cent->pe.painDirection ^= 1;
+}
+
+
+
+/*
+==============
+CG_EntityEvent
+
+An entity has an event value
+also called by CG_CheckPlayerstateEvents
+==============
+*/
+#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
+void CG_EntityEvent( centity_t *cent, vec3_t position ) {
+ entityState_t *es;
+ int event;
+ vec3_t dir;
+ const char *s;
+ int clientNum;
+ clientInfo_t *ci;
+
+ es = &cent->currentState;
+ event = es->event & ~EV_EVENT_BITS;
+
+ if ( cg_debugEvents.integer ) {
+ CG_Printf( "ent:%3i event:%3i ", es->number, event );
+ }
+
+ if ( !event ) {
+ DEBUGNAME("ZEROEVENT");
+ return;
+ }
+
+ clientNum = es->clientNum;
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ switch ( event ) {
+ //
+ // movement generated events
+ //
+ case EV_FOOTSTEP:
+ DEBUGNAME("EV_FOOTSTEP");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ ci->footsteps ][rand()&3] );
+ }
+ break;
+ case EV_FOOTSTEP_METAL:
+ DEBUGNAME("EV_FOOTSTEP_METAL");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
+ }
+ break;
+ case EV_FOOTSPLASH:
+ DEBUGNAME("EV_FOOTSPLASH");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
+ }
+ break;
+ case EV_FOOTWADE:
+ DEBUGNAME("EV_FOOTWADE");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
+ }
+ break;
+ case EV_SWIM:
+ DEBUGNAME("EV_SWIM");
+ if (cg_footsteps.integer) {
+ trap_S_StartSound (NULL, es->number, CHAN_BODY,
+ cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
+ }
+ break;
+
+
+ case EV_FALL_SHORT:
+ DEBUGNAME("EV_FALL_SHORT");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
+ if ( clientNum == cg.predictedPlayerState.clientNum ) {
+ // smooth landing z changes
+ cg.landChange = -8;
+ cg.landTime = cg.time;
+ }
+ break;
+ case EV_FALL_MEDIUM:
+ DEBUGNAME("EV_FALL_MEDIUM");
+ // use normal pain sound
+ trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
+ if ( clientNum == cg.predictedPlayerState.clientNum ) {
+ // smooth landing z changes
+ cg.landChange = -16;
+ cg.landTime = cg.time;
+ }
+ break;
+ case EV_FALL_FAR:
+ DEBUGNAME("EV_FALL_FAR");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
+ cent->pe.painTime = cg.time; // don't play a pain sound right after this
+ if ( clientNum == cg.predictedPlayerState.clientNum ) {
+ // smooth landing z changes
+ cg.landChange = -24;
+ cg.landTime = cg.time;
+ }
+ break;
+
+ case EV_STEP_4:
+ case EV_STEP_8:
+ case EV_STEP_12:
+ case EV_STEP_16: // smooth out step up transitions
+ DEBUGNAME("EV_STEP");
+ {
+ float oldStep;
+ int delta;
+ int step;
+
+ if ( clientNum != cg.predictedPlayerState.clientNum ) {
+ break;
+ }
+ // if we are interpolating, we don't need to smooth steps
+ if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
+ cg_nopredict.integer || cg_synchronousClients.integer ) {
+ break;
+ }
+ // check for stepping up before a previous step is completed
+ delta = cg.time - cg.stepTime;
+ if (delta < STEP_TIME) {
+ oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
+ } else {
+ oldStep = 0;
+ }
+
+ // add this amount
+ step = 4 * (event - EV_STEP_4 + 1 );
+ cg.stepChange = oldStep + step;
+ if ( cg.stepChange > MAX_STEP_CHANGE ) {
+ cg.stepChange = MAX_STEP_CHANGE;
+ }
+ cg.stepTime = cg.time;
+ break;
+ }
+
+ case EV_JUMP_PAD:
+ DEBUGNAME("EV_JUMP_PAD");
+// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
+ {
+ localEntity_t *smoke;
+ vec3_t up = {0, 0, 1};
+
+
+ smoke = CG_SmokePuff( cent->lerpOrigin, up,
+ 32,
+ 1, 1, 1, 0.33f,
+ 1000,
+ cg.time, 0,
+ LEF_PUFF_DONT_SCALE,
+ cgs.media.smokePuffShader );
+ }
+
+ // boing sound at origin, jump sound on player
+ trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
+ break;
+
+ case EV_JUMP:
+ DEBUGNAME("EV_JUMP");
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
+ break;
+ case EV_TAUNT:
+ DEBUGNAME("EV_TAUNT");
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
+ break;
+#ifdef MISSIONPACK
+ case EV_TAUNT_YES:
+ DEBUGNAME("EV_TAUNT_YES");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
+ break;
+ case EV_TAUNT_NO:
+ DEBUGNAME("EV_TAUNT_NO");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
+ break;
+ case EV_TAUNT_FOLLOWME:
+ DEBUGNAME("EV_TAUNT_FOLLOWME");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
+ break;
+ case EV_TAUNT_GETFLAG:
+ DEBUGNAME("EV_TAUNT_GETFLAG");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
+ break;
+ case EV_TAUNT_GUARDBASE:
+ DEBUGNAME("EV_TAUNT_GUARDBASE");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
+ break;
+ case EV_TAUNT_PATROL:
+ DEBUGNAME("EV_TAUNT_PATROL");
+ CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
+ break;
+#endif
+ case EV_WATER_TOUCH:
+ DEBUGNAME("EV_WATER_TOUCH");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
+ break;
+ case EV_WATER_LEAVE:
+ DEBUGNAME("EV_WATER_LEAVE");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
+ break;
+ case EV_WATER_UNDER:
+ DEBUGNAME("EV_WATER_UNDER");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
+ break;
+ case EV_WATER_CLEAR:
+ DEBUGNAME("EV_WATER_CLEAR");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
+ break;
+
+ case EV_ITEM_PICKUP:
+ DEBUGNAME("EV_ITEM_PICKUP");
+ {
+ gitem_t *item;
+ int index;
+
+ index = es->eventParm; // player predicted
+
+ if ( index < 1 || index >= bg_numItems ) {
+ break;
+ }
+ item = &bg_itemlist[ index ];
+
+ // powerups and team items will have a separate global sound, this one
+ // will be played at prediction time
+ if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound );
+ } else if (item->giType == IT_PERSISTANT_POWERUP) {
+#ifdef MISSIONPACK
+ switch (item->giTag ) {
+ case PW_SCOUT:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound );
+ break;
+ case PW_GUARD:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound );
+ break;
+ case PW_DOUBLER:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound );
+ break;
+ case PW_AMMOREGEN:
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound );
+ break;
+ }
+#endif
+ } else {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
+ }
+
+ // show icon and name on status bar
+ if ( es->number == cg.snap->ps.clientNum ) {
+ CG_ItemPickup( index );
+ }
+ }
+ break;
+
+ case EV_GLOBAL_ITEM_PICKUP:
+ DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
+ {
+ gitem_t *item;
+ int index;
+
+ index = es->eventParm; // player predicted
+
+ if ( index < 1 || index >= bg_numItems ) {
+ break;
+ }
+ item = &bg_itemlist[ index ];
+ // powerup pickups are global
+ if( item->pickup_sound ) {
+ trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
+ }
+
+ // show icon and name on status bar
+ if ( es->number == cg.snap->ps.clientNum ) {
+ CG_ItemPickup( index );
+ }
+ }
+ break;
+
+ //
+ // weapon events
+ //
+ case EV_NOAMMO:
+ DEBUGNAME("EV_NOAMMO");
+// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
+ if ( es->number == cg.snap->ps.clientNum ) {
+ CG_OutOfAmmoChange();
+ }
+ break;
+ case EV_CHANGE_WEAPON:
+ DEBUGNAME("EV_CHANGE_WEAPON");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
+ break;
+ case EV_FIRE_WEAPON:
+ DEBUGNAME("EV_FIRE_WEAPON");
+ CG_FireWeapon( cent );
+ break;
+
+ case EV_USE_ITEM0:
+ DEBUGNAME("EV_USE_ITEM0");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM1:
+ DEBUGNAME("EV_USE_ITEM1");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM2:
+ DEBUGNAME("EV_USE_ITEM2");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM3:
+ DEBUGNAME("EV_USE_ITEM3");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM4:
+ DEBUGNAME("EV_USE_ITEM4");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM5:
+ DEBUGNAME("EV_USE_ITEM5");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM6:
+ DEBUGNAME("EV_USE_ITEM6");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM7:
+ DEBUGNAME("EV_USE_ITEM7");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM8:
+ DEBUGNAME("EV_USE_ITEM8");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM9:
+ DEBUGNAME("EV_USE_ITEM9");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM10:
+ DEBUGNAME("EV_USE_ITEM10");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM11:
+ DEBUGNAME("EV_USE_ITEM11");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM12:
+ DEBUGNAME("EV_USE_ITEM12");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM13:
+ DEBUGNAME("EV_USE_ITEM13");
+ CG_UseItem( cent );
+ break;
+ case EV_USE_ITEM14:
+ DEBUGNAME("EV_USE_ITEM14");
+ CG_UseItem( cent );
+ break;
+
+ //=================================================================
+
+ //
+ // other events
+ //
+ case EV_PLAYER_TELEPORT_IN:
+ DEBUGNAME("EV_PLAYER_TELEPORT_IN");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
+ CG_SpawnEffect( position);
+ break;
+
+ case EV_PLAYER_TELEPORT_OUT:
+ DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
+ CG_SpawnEffect( position);
+ break;
+
+ case EV_ITEM_POP:
+ DEBUGNAME("EV_ITEM_POP");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
+ break;
+ case EV_ITEM_RESPAWN:
+ DEBUGNAME("EV_ITEM_RESPAWN");
+ cent->miscTime = cg.time; // scale up from this
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
+ break;
+
+ case EV_GRENADE_BOUNCE:
+ DEBUGNAME("EV_GRENADE_BOUNCE");
+ if ( rand() & 1 ) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
+ } else {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
+ }
+ break;
+
+#ifdef MISSIONPACK
+ case EV_PROXIMITY_MINE_STICK:
+ DEBUGNAME("EV_PROXIMITY_MINE_STICK");
+ if( es->eventParm & SURF_FLESH ) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
+ } else if( es->eventParm & SURF_METALSTEPS ) {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
+ } else {
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
+ }
+ break;
+
+ case EV_PROXIMITY_MINE_TRIGGER:
+ DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
+ trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
+ break;
+ case EV_KAMIKAZE:
+ DEBUGNAME("EV_KAMIKAZE");
+ CG_KamikazeEffect( cent->lerpOrigin );
+ break;
+ case EV_OBELISKEXPLODE:
+ DEBUGNAME("EV_OBELISKEXPLODE");
+ CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
+ break;
+ case EV_OBELISKPAIN:
+ DEBUGNAME("EV_OBELISKPAIN");
+ CG_ObeliskPain( cent->lerpOrigin );
+ break;
+ case EV_INVUL_IMPACT:
+ DEBUGNAME("EV_INVUL_IMPACT");
+ CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
+ break;
+ case EV_JUICED:
+ DEBUGNAME("EV_JUICED");
+ CG_InvulnerabilityJuiced( cent->lerpOrigin );
+ break;
+ case EV_LIGHTNINGBOLT:
+ DEBUGNAME("EV_LIGHTNINGBOLT");
+ CG_LightningBoltBeam(es->origin2, es->pos.trBase);
+ break;
+#endif
+ case EV_SCOREPLUM:
+ DEBUGNAME("EV_SCOREPLUM");
+ CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
+ break;
+
+ //
+ // missile impacts
+ //
+ case EV_MISSILE_HIT:
+ DEBUGNAME("EV_MISSILE_HIT");
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
+ break;
+
+ case EV_MISSILE_MISS:
+ DEBUGNAME("EV_MISSILE_MISS");
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
+ break;
+
+ case EV_MISSILE_MISS_METAL:
+ DEBUGNAME("EV_MISSILE_MISS_METAL");
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
+ break;
+
+ case EV_RAILTRAIL:
+ DEBUGNAME("EV_RAILTRAIL");
+ cent->currentState.weapon = WP_RAILGUN;
+ // if the end was on a nomark surface, don't make an explosion
+ CG_RailTrail( ci, es->origin2, es->pos.trBase );
+ if ( es->eventParm != 255 ) {
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );
+ }
+ break;
+
+ case EV_BULLET_HIT_WALL:
+ DEBUGNAME("EV_BULLET_HIT_WALL");
+ ByteToDir( es->eventParm, dir );
+ CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
+ break;
+
+ case EV_BULLET_HIT_FLESH:
+ DEBUGNAME("EV_BULLET_HIT_FLESH");
+ CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
+ break;
+
+ case EV_SHOTGUN:
+ DEBUGNAME("EV_SHOTGUN");
+ CG_ShotgunFire( es );
+ break;
+
+ case EV_GENERAL_SOUND:
+ DEBUGNAME("EV_GENERAL_SOUND");
+ if ( cgs.gameSounds[ es->eventParm ] ) {
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
+ } else {
+ s = CG_ConfigString( CS_SOUNDS + es->eventParm );
+ trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
+ }
+ break;
+
+ case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
+ DEBUGNAME("EV_GLOBAL_SOUND");
+ if ( cgs.gameSounds[ es->eventParm ] ) {
+ trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
+ } else {
+ s = CG_ConfigString( CS_SOUNDS + es->eventParm );
+ trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
+ }
+ break;
+
+ case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
+ {
+ DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
+ switch( es->eventParm ) {
+ case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
+ CG_AddBufferedSound( cgs.media.captureYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.captureOpponentSound );
+ break;
+ case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
+ CG_AddBufferedSound( cgs.media.captureYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.captureOpponentSound );
+ break;
+ case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
+ CG_AddBufferedSound( cgs.media.returnYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.returnOpponentSound );
+ //
+ CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
+ break;
+ case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
+ if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
+ CG_AddBufferedSound( cgs.media.returnYourTeamSound );
+ else
+ CG_AddBufferedSound( cgs.media.returnOpponentSound );
+ //
+ CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
+ break;
+
+ case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
+ // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
+ if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
+ }
+ else {
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
+#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
+ else
+#endif
+ CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
+ }
+ else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
+#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
+ else
+#endif
+ CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
+ }
+ }
+ break;
+ case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
+ // if this player picked up the flag then a sound is played in CG_CheckLocalSounds
+ if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
+ }
+ else {
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
+#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
+ else
+#endif
+ CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
+ }
+ else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
+#ifdef MISSIONPACK
+ if (cgs.gametype == GT_1FCTF)
+ CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
+ else
+#endif
+ CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
+ }
+ }
+ break;
+ case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
+ CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
+ }
+ break;
+ case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked
+ if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
+ CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
+ }
+ break;
+
+ case GTS_REDTEAM_SCORED:
+ CG_AddBufferedSound(cgs.media.redScoredSound);
+ break;
+ case GTS_BLUETEAM_SCORED:
+ CG_AddBufferedSound(cgs.media.blueScoredSound);
+ break;
+ case GTS_REDTEAM_TOOK_LEAD:
+ CG_AddBufferedSound(cgs.media.redLeadsSound);
+ break;
+ case GTS_BLUETEAM_TOOK_LEAD:
+ CG_AddBufferedSound(cgs.media.blueLeadsSound);
+ break;
+ case GTS_TEAMS_ARE_TIED:
+ CG_AddBufferedSound( cgs.media.teamsTiedSound );
+ break;
+#ifdef MISSIONPACK
+ case GTS_KAMIKAZE:
+ trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
+ break;
+#endif
+ default:
+ break;
+ }
+ break;
+ }
+
+ case EV_PAIN:
+ // local player sounds are triggered in CG_CheckLocalSounds,
+ // so ignore events on the player
+ DEBUGNAME("EV_PAIN");
+ if ( cent->currentState.number != cg.snap->ps.clientNum ) {
+ CG_PainEvent( cent, es->eventParm );
+ }
+ break;
+
+ case EV_DEATH1:
+ case EV_DEATH2:
+ case EV_DEATH3:
+ DEBUGNAME("EV_DEATHx");
+ trap_S_StartSound( NULL, es->number, CHAN_VOICE,
+ CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
+ break;
+
+
+ case EV_OBITUARY:
+ DEBUGNAME("EV_OBITUARY");
+ CG_Obituary( es );
+ break;
+
+ //
+ // powerup events
+ //
+ case EV_POWERUP_QUAD:
+ DEBUGNAME("EV_POWERUP_QUAD");
+ if ( es->number == cg.snap->ps.clientNum ) {
+ cg.powerupActive = PW_QUAD;
+ cg.powerupTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
+ break;
+ case EV_POWERUP_BATTLESUIT:
+ DEBUGNAME("EV_POWERUP_BATTLESUIT");
+ if ( es->number == cg.snap->ps.clientNum ) {
+ cg.powerupActive = PW_BATTLESUIT;
+ cg.powerupTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
+ break;
+ case EV_POWERUP_REGEN:
+ DEBUGNAME("EV_POWERUP_REGEN");
+ if ( es->number == cg.snap->ps.clientNum ) {
+ cg.powerupActive = PW_REGEN;
+ cg.powerupTime = cg.time;
+ }
+ trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
+ break;
+
+ case EV_GIB_PLAYER:
+ DEBUGNAME("EV_GIB_PLAYER");
+ // don't play gib sound when using the kamikaze because it interferes
+ // with the kamikaze sound, downside is that the gib sound will also
+ // not be played when someone is gibbed while just carrying the kamikaze
+ if ( !(es->eFlags & EF_KAMIKAZE) ) {
+ trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
+ }
+ CG_GibPlayer( cent->lerpOrigin );
+ break;
+
+ case EV_STOPLOOPINGSOUND:
+ DEBUGNAME("EV_STOPLOOPINGSOUND");
+ trap_S_StopLoopingSound( es->number );
+ es->loopSound = 0;
+ break;
+
+ case EV_DEBUG_LINE:
+ DEBUGNAME("EV_DEBUG_LINE");
+ CG_Beam( cent );
+ break;
+
+ default:
+ DEBUGNAME("UNKNOWN");
+ CG_Error( "Unknown event: %i", event );
+ break;
+ }
+
+}
+
+
+/*
+==============
+CG_CheckEvents
+
+==============
+*/
+void CG_CheckEvents( centity_t *cent ) {
+ // check for event-only entities
+ if ( cent->currentState.eType > ET_EVENTS ) {
+ if ( cent->previousEvent ) {
+ return; // already fired
+ }
+ // if this is a player event set the entity number of the client entity number
+ if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
+ cent->currentState.number = cent->currentState.otherEntityNum;
+ }
+
+ cent->previousEvent = 1;
+
+ cent->currentState.event = cent->currentState.eType - ET_EVENTS;
+ } else {
+ // check for events riding with another entity
+ if ( cent->currentState.event == cent->previousEvent ) {
+ return;
+ }
+ cent->previousEvent = cent->currentState.event;
+ if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
+ return;
+ }
+ }
+
+ // calculate the position at exactly the frame time
+ BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
+ CG_SetEntitySoundPosition( cent );
+
+ CG_EntityEvent( cent, cent->lerpOrigin );
+}
+
diff --git a/code/cgame/cg_info.c b/code/cgame/cg_info.c
index 04124d1..53f0b05 100755
--- a/code/cgame/cg_info.c
+++ b/code/cgame/cg_info.c
@@ -1,297 +1,297 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_info.c -- display information while data is being loading
-
-#include "cg_local.h"
-
-#define MAX_LOADING_PLAYER_ICONS 16
-#define MAX_LOADING_ITEM_ICONS 26
-
-static int loadingPlayerIconCount;
-static int loadingItemIconCount;
-static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS];
-static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS];
-
-
-/*
-===================
-CG_DrawLoadingIcons
-===================
-*/
-static void CG_DrawLoadingIcons( void ) {
- int n;
- int x, y;
-
- for( n = 0; n < loadingPlayerIconCount; n++ ) {
- x = 16 + n * 78;
- y = 324-40;
- CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] );
- }
-
- for( n = 0; n < loadingItemIconCount; n++ ) {
- y = 400-40;
- if( n >= 13 ) {
- y += 40;
- }
- x = 16 + n % 13 * 48;
- CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] );
- }
-}
-
-
-/*
-======================
-CG_LoadingString
-
-======================
-*/
-void CG_LoadingString( const char *s ) {
- Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
-
- trap_UpdateScreen();
-}
-
-/*
-===================
-CG_LoadingItem
-===================
-*/
-void CG_LoadingItem( int itemNum ) {
- gitem_t *item;
-
- item = &bg_itemlist[itemNum];
-
- if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) {
- loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon );
- }
-
- CG_LoadingString( item->pickup_name );
-}
-
-/*
-===================
-CG_LoadingClient
-===================
-*/
-void CG_LoadingClient( int clientNum ) {
- const char *info;
- char *skin;
- char personality[MAX_QPATH];
- char model[MAX_QPATH];
- char iconName[MAX_QPATH];
-
- info = CG_ConfigString( CS_PLAYERS + clientNum );
-
- if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) {
- Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) );
- skin = Q_strrchr( model, '/' );
- if ( skin ) {
- *skin++ = '\0';
- } else {
- skin = "default";
- }
-
- Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", model, skin );
-
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
- Com_sprintf( iconName, MAX_QPATH, "models/players/characters/%s/icon_%s.tga", model, skin );
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- }
- if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
- Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", DEFAULT_MODEL, "default" );
- loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
- }
- if ( loadingPlayerIcons[loadingPlayerIconCount] ) {
- loadingPlayerIconCount++;
- }
- }
-
- Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) );
- Q_CleanStr( personality );
-
- if( cgs.gametype == GT_SINGLE_PLAYER ) {
- trap_S_RegisterSound( va( "sound/player/announce/%s.wav", personality ), qtrue );
- }
-
- CG_LoadingString( personality );
-}
-
-
-/*
-====================
-CG_DrawInformation
-
-Draw all the status / pacifier stuff during level loading
-====================
-*/
-void CG_DrawInformation( void ) {
- const char *s;
- const char *info;
- const char *sysInfo;
- int y;
- int value;
- qhandle_t levelshot;
- qhandle_t detail;
- char buf[1024];
-
- info = CG_ConfigString( CS_SERVERINFO );
- sysInfo = CG_ConfigString( CS_SYSTEMINFO );
-
- s = Info_ValueForKey( info, "mapname" );
- levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
- if ( !levelshot ) {
- levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
- }
- trap_R_SetColor( NULL );
- CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot );
-
- // blend a detail texture over it
- detail = trap_R_RegisterShader( "levelShotDetail" );
- trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail );
-
- // draw the icons of things as they are loaded
- CG_DrawLoadingIcons();
-
- // the first 150 rows are reserved for the client connection
- // screen to write into
- if ( cg.infoScreenText[0] ) {
- UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- } else {
- UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- }
-
- // draw info string information
-
- y = 180-32;
-
- // don't print server lines if playing a local game
- trap_Cvar_VariableStringBuffer( "sv_running", buf, sizeof( buf ) );
- if ( !atoi( buf ) ) {
- // server hostname
- Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024);
- Q_CleanStr(buf);
- UI_DrawProportionalString( 320, y, buf,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
-
- // pure server
- s = Info_ValueForKey( sysInfo, "sv_pure" );
- if ( s[0] == '1' ) {
- UI_DrawProportionalString( 320, y, "Pure Server",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // server-specific message of the day
- s = CG_ConfigString( CS_MOTD );
- if ( s[0] ) {
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // some extra space after hostname and motd
- y += 10;
- }
-
- // map-specific message (long map name)
- s = CG_ConfigString( CS_MESSAGE );
- if ( s[0] ) {
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // cheats warning
- s = Info_ValueForKey( sysInfo, "sv_cheats" );
- if ( s[0] == '1' ) {
- UI_DrawProportionalString( 320, y, "CHEATS ARE ENABLED",
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- // game type
- switch ( cgs.gametype ) {
- case GT_FFA:
- s = "Free For All";
- break;
- case GT_SINGLE_PLAYER:
- s = "Single Player";
- break;
- case GT_TOURNAMENT:
- s = "Tournament";
- break;
- case GT_TEAM:
- s = "Team Deathmatch";
- break;
- case GT_CTF:
- s = "Capture The Flag";
- break;
-#ifdef MISSIONPACK
- case GT_1FCTF:
- s = "One Flag CTF";
- break;
- case GT_OBELISK:
- s = "Overload";
- break;
- case GT_HARVESTER:
- s = "Harvester";
- break;
-#endif
- default:
- s = "Unknown Gametype";
- break;
- }
- UI_DrawProportionalString( 320, y, s,
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
-
- value = atoi( Info_ValueForKey( info, "timelimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "timelimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
-
- if (cgs.gametype < GT_CTF ) {
- value = atoi( Info_ValueForKey( info, "fraglimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "fraglimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
- }
-
- if (cgs.gametype >= GT_CTF) {
- value = atoi( Info_ValueForKey( info, "capturelimit" ) );
- if ( value ) {
- UI_DrawProportionalString( 320, y, va( "capturelimit %i", value ),
- UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
- y += PROP_HEIGHT;
- }
- }
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_info.c -- display information while data is being loading
+
+#include "cg_local.h"
+
+#define MAX_LOADING_PLAYER_ICONS 16
+#define MAX_LOADING_ITEM_ICONS 26
+
+static int loadingPlayerIconCount;
+static int loadingItemIconCount;
+static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS];
+static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS];
+
+
+/*
+===================
+CG_DrawLoadingIcons
+===================
+*/
+static void CG_DrawLoadingIcons( void ) {
+ int n;
+ int x, y;
+
+ for( n = 0; n < loadingPlayerIconCount; n++ ) {
+ x = 16 + n * 78;
+ y = 324-40;
+ CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] );
+ }
+
+ for( n = 0; n < loadingItemIconCount; n++ ) {
+ y = 400-40;
+ if( n >= 13 ) {
+ y += 40;
+ }
+ x = 16 + n % 13 * 48;
+ CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] );
+ }
+}
+
+
+/*
+======================
+CG_LoadingString
+
+======================
+*/
+void CG_LoadingString( const char *s ) {
+ Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
+
+ trap_UpdateScreen();
+}
+
+/*
+===================
+CG_LoadingItem
+===================
+*/
+void CG_LoadingItem( int itemNum ) {
+ gitem_t *item;
+
+ item = &bg_itemlist[itemNum];
+
+ if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) {
+ loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon );
+ }
+
+ CG_LoadingString( item->pickup_name );
+}
+
+/*
+===================
+CG_LoadingClient
+===================
+*/
+void CG_LoadingClient( int clientNum ) {
+ const char *info;
+ char *skin;
+ char personality[MAX_QPATH];
+ char model[MAX_QPATH];
+ char iconName[MAX_QPATH];
+
+ info = CG_ConfigString( CS_PLAYERS + clientNum );
+
+ if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) {
+ Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) );
+ skin = Q_strrchr( model, '/' );
+ if ( skin ) {
+ *skin++ = '\0';
+ } else {
+ skin = "default";
+ }
+
+ Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", model, skin );
+
+ loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
+ if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
+ Com_sprintf( iconName, MAX_QPATH, "models/players/characters/%s/icon_%s.tga", model, skin );
+ loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
+ }
+ if ( !loadingPlayerIcons[loadingPlayerIconCount] ) {
+ Com_sprintf( iconName, MAX_QPATH, "models/players/%s/icon_%s.tga", DEFAULT_MODEL, "default" );
+ loadingPlayerIcons[loadingPlayerIconCount] = trap_R_RegisterShaderNoMip( iconName );
+ }
+ if ( loadingPlayerIcons[loadingPlayerIconCount] ) {
+ loadingPlayerIconCount++;
+ }
+ }
+
+ Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) );
+ Q_CleanStr( personality );
+
+ if( cgs.gametype == GT_SINGLE_PLAYER ) {
+ trap_S_RegisterSound( va( "sound/player/announce/%s.wav", personality ), qtrue );
+ }
+
+ CG_LoadingString( personality );
+}
+
+
+/*
+====================
+CG_DrawInformation
+
+Draw all the status / pacifier stuff during level loading
+====================
+*/
+void CG_DrawInformation( void ) {
+ const char *s;
+ const char *info;
+ const char *sysInfo;
+ int y;
+ int value;
+ qhandle_t levelshot;
+ qhandle_t detail;
+ char buf[1024];
+
+ info = CG_ConfigString( CS_SERVERINFO );
+ sysInfo = CG_ConfigString( CS_SYSTEMINFO );
+
+ s = Info_ValueForKey( info, "mapname" );
+ levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
+ if ( !levelshot ) {
+ levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
+ }
+ trap_R_SetColor( NULL );
+ CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot );
+
+ // blend a detail texture over it
+ detail = trap_R_RegisterShader( "levelShotDetail" );
+ trap_R_DrawStretchPic( 0, 0, cgs.glconfig.vidWidth, cgs.glconfig.vidHeight, 0, 0, 2.5, 2, detail );
+
+ // draw the icons of things as they are loaded
+ CG_DrawLoadingIcons();
+
+ // the first 150 rows are reserved for the client connection
+ // screen to write into
+ if ( cg.infoScreenText[0] ) {
+ UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ } else {
+ UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...",
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ }
+
+ // draw info string information
+
+ y = 180-32;
+
+ // don't print server lines if playing a local game
+ trap_Cvar_VariableStringBuffer( "sv_running", buf, sizeof( buf ) );
+ if ( !atoi( buf ) ) {
+ // server hostname
+ Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024);
+ Q_CleanStr(buf);
+ UI_DrawProportionalString( 320, y, buf,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+
+ // pure server
+ s = Info_ValueForKey( sysInfo, "sv_pure" );
+ if ( s[0] == '1' ) {
+ UI_DrawProportionalString( 320, y, "Pure Server",
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // server-specific message of the day
+ s = CG_ConfigString( CS_MOTD );
+ if ( s[0] ) {
+ UI_DrawProportionalString( 320, y, s,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // some extra space after hostname and motd
+ y += 10;
+ }
+
+ // map-specific message (long map name)
+ s = CG_ConfigString( CS_MESSAGE );
+ if ( s[0] ) {
+ UI_DrawProportionalString( 320, y, s,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // cheats warning
+ s = Info_ValueForKey( sysInfo, "sv_cheats" );
+ if ( s[0] == '1' ) {
+ UI_DrawProportionalString( 320, y, "CHEATS ARE ENABLED",
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ // game type
+ switch ( cgs.gametype ) {
+ case GT_FFA:
+ s = "Free For All";
+ break;
+ case GT_SINGLE_PLAYER:
+ s = "Single Player";
+ break;
+ case GT_TOURNAMENT:
+ s = "Tournament";
+ break;
+ case GT_TEAM:
+ s = "Team Deathmatch";
+ break;
+ case GT_CTF:
+ s = "Capture The Flag";
+ break;
+#ifdef MISSIONPACK
+ case GT_1FCTF:
+ s = "One Flag CTF";
+ break;
+ case GT_OBELISK:
+ s = "Overload";
+ break;
+ case GT_HARVESTER:
+ s = "Harvester";
+ break;
+#endif
+ default:
+ s = "Unknown Gametype";
+ break;
+ }
+ UI_DrawProportionalString( 320, y, s,
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+
+ value = atoi( Info_ValueForKey( info, "timelimit" ) );
+ if ( value ) {
+ UI_DrawProportionalString( 320, y, va( "timelimit %i", value ),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+
+ if (cgs.gametype < GT_CTF ) {
+ value = atoi( Info_ValueForKey( info, "fraglimit" ) );
+ if ( value ) {
+ UI_DrawProportionalString( 320, y, va( "fraglimit %i", value ),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+ }
+
+ if (cgs.gametype >= GT_CTF) {
+ value = atoi( Info_ValueForKey( info, "capturelimit" ) );
+ if ( value ) {
+ UI_DrawProportionalString( 320, y, va( "capturelimit %i", value ),
+ UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite );
+ y += PROP_HEIGHT;
+ }
+ }
+}
+
diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h
index 4dd5c9d..a23f715 100755
--- a/code/cgame/cg_local.h
+++ b/code/cgame/cg_local.h
@@ -1,1669 +1,1669 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#include "../game/q_shared.h"
-#include "tr_types.h"
-#include "../game/bg_public.h"
-#include "cg_public.h"
-
-
-// The entire cgame module is unloaded and reloaded on each level change,
-// so there is NO persistant data between levels on the client side.
-// If you absolutely need something stored, it can either be kept
-// by the server in the server stored userinfos, or stashed in a cvar.
-
-#ifdef MISSIONPACK
-#define CG_FONT_THRESHOLD 0.1
-#endif
-
-#define POWERUP_BLINKS 5
-
-#define POWERUP_BLINK_TIME 1000
-#define FADE_TIME 200
-#define PULSE_TIME 200
-#define DAMAGE_DEFLECT_TIME 100
-#define DAMAGE_RETURN_TIME 400
-#define DAMAGE_TIME 500
-#define LAND_DEFLECT_TIME 150
-#define LAND_RETURN_TIME 300
-#define STEP_TIME 200
-#define DUCK_TIME 100
-#define PAIN_TWITCH_TIME 200
-#define WEAPON_SELECT_TIME 1400
-#define ITEM_SCALEUP_TIME 1000
-#define ZOOM_TIME 150
-#define ITEM_BLOB_TIME 200
-#define MUZZLE_FLASH_TIME 20
-#define SINK_TIME 1000 // time for fragments to sink into ground before going away
-#define ATTACKER_HEAD_TIME 10000
-#define REWARD_TIME 3000
-
-#define PULSE_SCALE 1.5 // amount to scale up the icons when activating
-
-#define MAX_STEP_CHANGE 32
-
-#define MAX_VERTS_ON_POLY 10
-#define MAX_MARK_POLYS 256
-
-#define STAT_MINUS 10 // num frame for '-' stats digit
-
-#define ICON_SIZE 48
-#define CHAR_WIDTH 32
-#define CHAR_HEIGHT 48
-#define TEXT_ICON_SPACE 4
-
-#define TEAMCHAT_WIDTH 80
-#define TEAMCHAT_HEIGHT 8
-
-// very large characters
-#define GIANT_WIDTH 32
-#define GIANT_HEIGHT 48
-
-#define NUM_CROSSHAIRS 10
-
-#define TEAM_OVERLAY_MAXNAME_WIDTH 12
-#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
-
-#define DEFAULT_MODEL "sarge"
-#ifdef MISSIONPACK
-#define DEFAULT_TEAM_MODEL "james"
-#define DEFAULT_TEAM_HEAD "*james"
-#else
-#define DEFAULT_TEAM_MODEL "sarge"
-#define DEFAULT_TEAM_HEAD "sarge"
-#endif
-
-#define DEFAULT_REDTEAM_NAME "Stroggs"
-#define DEFAULT_BLUETEAM_NAME "Pagans"
-
-typedef enum {
- FOOTSTEP_NORMAL,
- FOOTSTEP_BOOT,
- FOOTSTEP_FLESH,
- FOOTSTEP_MECH,
- FOOTSTEP_ENERGY,
- FOOTSTEP_METAL,
- FOOTSTEP_SPLASH,
-
- FOOTSTEP_TOTAL
-} footstep_t;
-
-typedef enum {
- IMPACTSOUND_DEFAULT,
- IMPACTSOUND_METAL,
- IMPACTSOUND_FLESH
-} impactSound_t;
-
-//=================================================
-
-// player entities need to track more information
-// than any other type of entity.
-
-// note that not every player entity is a client entity,
-// because corpses after respawn are outside the normal
-// client numbering range
-
-// when changing animation, set animationTime to frameTime + lerping time
-// The current lerp will finish out, then it will lerp to the new animation
-typedef struct {
- int oldFrame;
- int oldFrameTime; // time when ->oldFrame was exactly on
-
- int frame;
- int frameTime; // time when ->frame will be exactly on
-
- float backlerp;
-
- float yawAngle;
- qboolean yawing;
- float pitchAngle;
- qboolean pitching;
-
- int animationNumber; // may include ANIM_TOGGLEBIT
- animation_t *animation;
- int animationTime; // time when the first frame of the animation will be exact
-} lerpFrame_t;
-
-
-typedef struct {
- lerpFrame_t legs, torso, flag;
- int painTime;
- int painDirection; // flip from 0 to 1
- int lightningFiring;
-
- // railgun trail spawning
- vec3_t railgunImpact;
- qboolean railgunFlash;
-
- // machinegun spinning
- float barrelAngle;
- int barrelTime;
- qboolean barrelSpinning;
-} playerEntity_t;
-
-//=================================================
-
-
-
-// centity_t have a direct corespondence with gentity_t in the game, but
-// only the entityState_t is directly communicated to the cgame
-typedef struct centity_s {
- entityState_t currentState; // from cg.frame
- entityState_t nextState; // from cg.nextFrame, if available
- qboolean interpolate; // true if next is valid to interpolate to
- qboolean currentValid; // true if cg.frame holds this entity
-
- int muzzleFlashTime; // move to playerEntity?
- int previousEvent;
- int teleportFlag;
-
- int trailTime; // so missile trails can handle dropped initial packets
- int dustTrailTime;
- int miscTime;
-
- int snapShotTime; // last time this entity was found in a snapshot
-
- playerEntity_t pe;
-
- int errorTime; // decay the error from this time
- vec3_t errorOrigin;
- vec3_t errorAngles;
-
- qboolean extrapolated; // false if origin / angles is an interpolation
- vec3_t rawOrigin;
- vec3_t rawAngles;
-
- vec3_t beamEnd;
-
- // exact interpolated position of entity on this frame
- vec3_t lerpOrigin;
- vec3_t lerpAngles;
-} centity_t;
-
-
-//======================================================================
-
-// local entities are created as a result of events or predicted actions,
-// and live independantly from all server transmitted entities
-
-typedef struct markPoly_s {
- struct markPoly_s *prevMark, *nextMark;
- int time;
- qhandle_t markShader;
- qboolean alphaFade; // fade alpha instead of rgb
- float color[4];
- poly_t poly;
- polyVert_t verts[MAX_VERTS_ON_POLY];
-} markPoly_t;
-
-
-typedef enum {
- LE_MARK,
- LE_EXPLOSION,
- LE_SPRITE_EXPLOSION,
- LE_FRAGMENT,
- LE_MOVE_SCALE_FADE,
- LE_FALL_SCALE_FADE,
- LE_FADE_RGB,
- LE_SCALE_FADE,
- LE_SCOREPLUM,
-#ifdef MISSIONPACK
- LE_KAMIKAZE,
- LE_INVULIMPACT,
- LE_INVULJUICED,
- LE_SHOWREFENTITY
-#endif
-} leType_t;
-
-typedef enum {
- LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time
- LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells
- LEF_SOUND1 = 0x0004, // sound 1 for kamikaze
- LEF_SOUND2 = 0x0008 // sound 2 for kamikaze
-} leFlag_t;
-
-typedef enum {
- LEMT_NONE,
- LEMT_BURN,
- LEMT_BLOOD
-} leMarkType_t; // fragment local entities can leave marks on walls
-
-typedef enum {
- LEBS_NONE,
- LEBS_BLOOD,
- LEBS_BRASS
-} leBounceSoundType_t; // fragment local entities can make sounds on impacts
-
-typedef struct localEntity_s {
- struct localEntity_s *prev, *next;
- leType_t leType;
- int leFlags;
-
- int startTime;
- int endTime;
- int fadeInTime;
-
- float lifeRate; // 1.0 / (endTime - startTime)
-
- trajectory_t pos;
- trajectory_t angles;
-
- float bounceFactor; // 0.0 = no bounce, 1.0 = perfect
-
- float color[4];
-
- float radius;
-
- float light;
- vec3_t lightColor;
-
- leMarkType_t leMarkType; // mark to leave on fragment impact
- leBounceSoundType_t leBounceSoundType;
-
- refEntity_t refEntity;
-} localEntity_t;
-
-//======================================================================
-
-
-typedef struct {
- int client;
- int score;
- int ping;
- int time;
- int scoreFlags;
- int powerUps;
- int accuracy;
- int impressiveCount;
- int excellentCount;
- int guantletCount;
- int defendCount;
- int assistCount;
- int captures;
- qboolean perfect;
- int team;
-} score_t;
-
-// each client has an associated clientInfo_t
-// that contains media references necessary to present the
-// client model and other color coded effects
-// this is regenerated each time a client's configstring changes,
-// usually as a result of a userinfo (name, model, etc) change
-#define MAX_CUSTOM_SOUNDS 32
-
-typedef struct {
- qboolean infoValid;
-
- char name[MAX_QPATH];
- team_t team;
-
- int botSkill; // 0 = not bot, 1-5 = bot
-
- vec3_t color1;
- vec3_t color2;
-
- int score; // updated by score servercmds
- int location; // location index for team mode
- int health; // you only get this info about your teammates
- int armor;
- int curWeapon;
-
- int handicap;
- int wins, losses; // in tourney mode
-
- int teamTask; // task in teamplay (offence/defence)
- qboolean teamLeader; // true when this is a team leader
-
- int powerups; // so can display quad/flag status
-
- int medkitUsageTime;
- int invulnerabilityStartTime;
- int invulnerabilityStopTime;
-
- int breathPuffTime;
-
- // when clientinfo is changed, the loading of models/skins/sounds
- // can be deferred until you are dead, to prevent hitches in
- // gameplay
- char modelName[MAX_QPATH];
- char skinName[MAX_QPATH];
- char headModelName[MAX_QPATH];
- char headSkinName[MAX_QPATH];
- char redTeam[MAX_TEAMNAME];
- char blueTeam[MAX_TEAMNAME];
- qboolean deferred;
-
- qboolean newAnims; // true if using the new mission pack animations
- qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
- qboolean fixedtorso; // true if torso never changes yaw
-
- vec3_t headOffset; // move head in icon views
- footstep_t footsteps;
- gender_t gender; // from model
-
- qhandle_t legsModel;
- qhandle_t legsSkin;
-
- qhandle_t torsoModel;
- qhandle_t torsoSkin;
-
- qhandle_t headModel;
- qhandle_t headSkin;
-
- qhandle_t modelIcon;
-
- animation_t animations[MAX_TOTALANIMATIONS];
-
- sfxHandle_t sounds[MAX_CUSTOM_SOUNDS];
-} clientInfo_t;
-
-
-// each WP_* weapon enum has an associated weaponInfo_t
-// that contains media references necessary to present the
-// weapon and its effects
-typedef struct weaponInfo_s {
- qboolean registered;
- gitem_t *item;
-
- qhandle_t handsModel; // the hands don't actually draw, they just position the weapon
- qhandle_t weaponModel;
- qhandle_t barrelModel;
- qhandle_t flashModel;
-
- vec3_t weaponMidpoint; // so it will rotate centered instead of by tag
-
- float flashDlight;
- vec3_t flashDlightColor;
- sfxHandle_t flashSound[4]; // fast firing weapons randomly choose
-
- qhandle_t weaponIcon;
- qhandle_t ammoIcon;
-
- qhandle_t ammoModel;
-
- qhandle_t missileModel;
- sfxHandle_t missileSound;
- void (*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi );
- float missileDlight;
- vec3_t missileDlightColor;
- int missileRenderfx;
-
- void (*ejectBrassFunc)( centity_t * );
-
- float trailRadius;
- float wiTrailTime;
-
- sfxHandle_t readySound;
- sfxHandle_t firingSound;
- qboolean loopFireSound;
-} weaponInfo_t;
-
-
-// each IT_* item has an associated itemInfo_t
-// that constains media references necessary to present the
-// item and its effects
-typedef struct {
- qboolean registered;
- qhandle_t models[MAX_ITEM_MODELS];
- qhandle_t icon;
-} itemInfo_t;
-
-
-typedef struct {
- int itemNum;
-} powerupInfo_t;
-
-
-#define MAX_SKULLTRAIL 10
-
-typedef struct {
- vec3_t positions[MAX_SKULLTRAIL];
- int numpositions;
-} skulltrail_t;
-
-
-#define MAX_REWARDSTACK 10
-#define MAX_SOUNDBUFFER 20
-
-//======================================================================
-
-// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action
-// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after
-
-#define MAX_PREDICTED_EVENTS 16
-
-typedef struct {
- int clientFrame; // incremented each frame
-
- int clientNum;
-
- qboolean demoPlayback;
- qboolean levelShot; // taking a level menu screenshot
- int deferredPlayerLoading;
- qboolean loading; // don't defer players at initial startup
- qboolean intermissionStarted; // don't play voice rewards, because game will end shortly
-
- // there are only one or two snapshot_t that are relevent at a time
- int latestSnapshotNum; // the number of snapshots the client system has received
- int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet
-
- snapshot_t *snap; // cg.snap->serverTime <= cg.time
- snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL
- snapshot_t activeSnapshots[2];
-
- float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime)
-
- qboolean thisFrameTeleport;
- qboolean nextFrameTeleport;
-
- int frametime; // cg.time - cg.oldTime
-
- int time; // this is the time value that the client
- // is rendering at.
- int oldTime; // time at last frame, used for missile trails and prediction checking
-
- int physicsTime; // either cg.snap->time or cg.nextSnap->time
-
- int timelimitWarnings; // 5 min, 1 min, overtime
- int fraglimitWarnings;
-
- qboolean mapRestart; // set on a map restart to set back the weapon
-
- qboolean renderingThirdPerson; // during deaths, chasecams, etc
-
- // prediction state
- qboolean hyperspace; // true if prediction has hit a trigger_teleport
- playerState_t predictedPlayerState;
- centity_t predictedPlayerEntity;
- qboolean validPPS; // clear until the first call to CG_PredictPlayerState
- int predictedErrorTime;
- vec3_t predictedError;
-
- int eventSequence;
- int predictableEvents[MAX_PREDICTED_EVENTS];
-
- float stepChange; // for stair up smoothing
- int stepTime;
-
- float duckChange; // for duck viewheight smoothing
- int duckTime;
-
- float landChange; // for landing hard
- int landTime;
-
- // input state sent to server
- int weaponSelect;
-
- // auto rotating items
- vec3_t autoAngles;
- vec3_t autoAxis[3];
- vec3_t autoAnglesFast;
- vec3_t autoAxisFast[3];
-
- // view rendering
- refdef_t refdef;
- vec3_t refdefViewAngles; // will be converted to refdef.viewaxis
-
- // zoom key
- qboolean zoomed;
- int zoomTime;
- float zoomSensitivity;
-
- // information screen text during loading
- char infoScreenText[MAX_STRING_CHARS];
-
- // scoreboard
- int scoresRequestTime;
- int numScores;
- int selectedScore;
- int teamScores[2];
- score_t scores[MAX_CLIENTS];
- qboolean showScores;
- qboolean scoreBoardShowing;
- int scoreFadeTime;
- char killerName[MAX_NAME_LENGTH];
- char spectatorList[MAX_STRING_CHARS]; // list of names
- int spectatorLen; // length of list
- float spectatorWidth; // width in device units
- int spectatorTime; // next time to offset
- int spectatorPaintX; // current paint x
- int spectatorPaintX2; // current paint x
- int spectatorOffset; // current offset from start
- int spectatorPaintLen; // current offset from start
-
- // skull trails
- skulltrail_t skulltrails[MAX_CLIENTS];
-
- // centerprinting
- int centerPrintTime;
- int centerPrintCharWidth;
- int centerPrintY;
- char centerPrint[1024];
- int centerPrintLines;
-
- // low ammo warning state
- int lowAmmoWarning; // 1 = low, 2 = empty
-
- // kill timers for carnage reward
- int lastKillTime;
-
- // crosshair client ID
- int crosshairClientNum;
- int crosshairClientTime;
-
- // powerup active flashing
- int powerupActive;
- int powerupTime;
-
- // attacking player
- int attackerTime;
- int voiceTime;
-
- // reward medals
- int rewardStack;
- int rewardTime;
- int rewardCount[MAX_REWARDSTACK];
- qhandle_t rewardShader[MAX_REWARDSTACK];
- qhandle_t rewardSound[MAX_REWARDSTACK];
-
- // sound buffer mainly for announcer sounds
- int soundBufferIn;
- int soundBufferOut;
- int soundTime;
- qhandle_t soundBuffer[MAX_SOUNDBUFFER];
-
- // for voice chat buffer
- int voiceChatTime;
- int voiceChatBufferIn;
- int voiceChatBufferOut;
-
- // warmup countdown
- int warmup;
- int warmupCount;
-
- //==========================
-
- int itemPickup;
- int itemPickupTime;
- int itemPickupBlendTime; // the pulse around the crosshair is timed seperately
-
- int weaponSelectTime;
- int weaponAnimation;
- int weaponAnimationTime;
-
- // blend blobs
- float damageTime;
- float damageX, damageY, damageValue;
-
- // status bar head
- float headYaw;
- float headEndPitch;
- float headEndYaw;
- int headEndTime;
- float headStartPitch;
- float headStartYaw;
- int headStartTime;
-
- // view movement
- float v_dmg_time;
- float v_dmg_pitch;
- float v_dmg_roll;
-
- vec3_t kick_angles; // weapon kicks
- vec3_t kick_origin;
-
- // temp working variables for player view
- float bobfracsin;
- int bobcycle;
- float xyspeed;
- int nextOrbitTime;
-
- //qboolean cameraMode; // if rendering from a loaded camera
-
-
- // development tool
- refEntity_t testModelEntity;
- char testModelName[MAX_QPATH];
- qboolean testGun;
-
-} cg_t;
-
-
-// all of the model, shader, and sound references that are
-// loaded at gamestate time are stored in cgMedia_t
-// Other media that can be tied to clients, weapons, or items are
-// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
-typedef struct {
- qhandle_t charsetShader;
- qhandle_t charsetProp;
- qhandle_t charsetPropGlow;
- qhandle_t charsetPropB;
- qhandle_t whiteShader;
-
- qhandle_t redCubeModel;
- qhandle_t blueCubeModel;
- qhandle_t redCubeIcon;
- qhandle_t blueCubeIcon;
- qhandle_t redFlagModel;
- qhandle_t blueFlagModel;
- qhandle_t neutralFlagModel;
- qhandle_t redFlagShader[3];
- qhandle_t blueFlagShader[3];
- qhandle_t flagShader[4];
-
- qhandle_t flagPoleModel;
- qhandle_t flagFlapModel;
-
- qhandle_t redFlagFlapSkin;
- qhandle_t blueFlagFlapSkin;
- qhandle_t neutralFlagFlapSkin;
-
- qhandle_t redFlagBaseModel;
- qhandle_t blueFlagBaseModel;
- qhandle_t neutralFlagBaseModel;
-
-#ifdef MISSIONPACK
- qhandle_t overloadBaseModel;
- qhandle_t overloadTargetModel;
- qhandle_t overloadLightsModel;
- qhandle_t overloadEnergyModel;
-
- qhandle_t harvesterModel;
- qhandle_t harvesterRedSkin;
- qhandle_t harvesterBlueSkin;
- qhandle_t harvesterNeutralModel;
-#endif
-
- qhandle_t armorModel;
- qhandle_t armorIcon;
-
- qhandle_t teamStatusBar;
-
- qhandle_t deferShader;
-
- // gib explosions
- qhandle_t gibAbdomen;
- qhandle_t gibArm;
- qhandle_t gibChest;
- qhandle_t gibFist;
- qhandle_t gibFoot;
- qhandle_t gibForearm;
- qhandle_t gibIntestine;
- qhandle_t gibLeg;
- qhandle_t gibSkull;
- qhandle_t gibBrain;
-
- qhandle_t smoke2;
-
- qhandle_t machinegunBrassModel;
- qhandle_t shotgunBrassModel;
-
- qhandle_t railRingsShader;
- qhandle_t railCoreShader;
-
- qhandle_t lightningShader;
-
- qhandle_t friendShader;
-
- qhandle_t balloonShader;
- qhandle_t connectionShader;
-
- qhandle_t selectShader;
- qhandle_t viewBloodShader;
- qhandle_t tracerShader;
- qhandle_t crosshairShader[NUM_CROSSHAIRS];
- qhandle_t lagometerShader;
- qhandle_t backTileShader;
- qhandle_t noammoShader;
-
- qhandle_t smokePuffShader;
- qhandle_t smokePuffRageProShader;
- qhandle_t shotgunSmokePuffShader;
- qhandle_t plasmaBallShader;
- qhandle_t waterBubbleShader;
- qhandle_t bloodTrailShader;
-#ifdef MISSIONPACK
- qhandle_t nailPuffShader;
- qhandle_t blueProxMine;
-#endif
-
- qhandle_t numberShaders[11];
-
- qhandle_t shadowMarkShader;
-
- qhandle_t botSkillShaders[5];
-
- // wall mark shaders
- qhandle_t wakeMarkShader;
- qhandle_t bloodMarkShader;
- qhandle_t bulletMarkShader;
- qhandle_t burnMarkShader;
- qhandle_t holeMarkShader;
- qhandle_t energyMarkShader;
-
- // powerup shaders
- qhandle_t quadShader;
- qhandle_t redQuadShader;
- qhandle_t quadWeaponShader;
- qhandle_t invisShader;
- qhandle_t regenShader;
- qhandle_t battleSuitShader;
- qhandle_t battleWeaponShader;
- qhandle_t hastePuffShader;
- qhandle_t redKamikazeShader;
- qhandle_t blueKamikazeShader;
-
- // weapon effect models
- qhandle_t bulletFlashModel;
- qhandle_t ringFlashModel;
- qhandle_t dishFlashModel;
- qhandle_t lightningExplosionModel;
-
- // weapon effect shaders
- qhandle_t railExplosionShader;
- qhandle_t plasmaExplosionShader;
- qhandle_t bulletExplosionShader;
- qhandle_t rocketExplosionShader;
- qhandle_t grenadeExplosionShader;
- qhandle_t bfgExplosionShader;
- qhandle_t bloodExplosionShader;
-
- // special effects models
- qhandle_t teleportEffectModel;
- qhandle_t teleportEffectShader;
-#ifdef MISSIONPACK
- qhandle_t kamikazeEffectModel;
- qhandle_t kamikazeShockWave;
- qhandle_t kamikazeHeadModel;
- qhandle_t kamikazeHeadTrail;
- qhandle_t guardPowerupModel;
- qhandle_t scoutPowerupModel;
- qhandle_t doublerPowerupModel;
- qhandle_t ammoRegenPowerupModel;
- qhandle_t invulnerabilityImpactModel;
- qhandle_t invulnerabilityJuicedModel;
- qhandle_t medkitUsageModel;
- qhandle_t dustPuffShader;
- qhandle_t heartShader;
-#endif
- qhandle_t invulnerabilityPowerupModel;
-
- // scoreboard headers
- qhandle_t scoreboardName;
- qhandle_t scoreboardPing;
- qhandle_t scoreboardScore;
- qhandle_t scoreboardTime;
-
- // medals shown during gameplay
- qhandle_t medalImpressive;
- qhandle_t medalExcellent;
- qhandle_t medalGauntlet;
- qhandle_t medalDefend;
- qhandle_t medalAssist;
- qhandle_t medalCapture;
-
- // sounds
- sfxHandle_t quadSound;
- sfxHandle_t tracerSound;
- sfxHandle_t selectSound;
- sfxHandle_t useNothingSound;
- sfxHandle_t wearOffSound;
- sfxHandle_t footsteps[FOOTSTEP_TOTAL][4];
- sfxHandle_t sfx_lghit1;
- sfxHandle_t sfx_lghit2;
- sfxHandle_t sfx_lghit3;
- sfxHandle_t sfx_ric1;
- sfxHandle_t sfx_ric2;
- sfxHandle_t sfx_ric3;
- sfxHandle_t sfx_railg;
- sfxHandle_t sfx_rockexp;
- sfxHandle_t sfx_plasmaexp;
-#ifdef MISSIONPACK
- sfxHandle_t sfx_proxexp;
- sfxHandle_t sfx_nghit;
- sfxHandle_t sfx_nghitflesh;
- sfxHandle_t sfx_nghitmetal;
- sfxHandle_t sfx_chghit;
- sfxHandle_t sfx_chghitflesh;
- sfxHandle_t sfx_chghitmetal;
- sfxHandle_t kamikazeExplodeSound;
- sfxHandle_t kamikazeImplodeSound;
- sfxHandle_t kamikazeFarSound;
- sfxHandle_t useInvulnerabilitySound;
- sfxHandle_t invulnerabilityImpactSound1;
- sfxHandle_t invulnerabilityImpactSound2;
- sfxHandle_t invulnerabilityImpactSound3;
- sfxHandle_t invulnerabilityJuicedSound;
- sfxHandle_t obeliskHitSound1;
- sfxHandle_t obeliskHitSound2;
- sfxHandle_t obeliskHitSound3;
- sfxHandle_t obeliskRespawnSound;
- sfxHandle_t winnerSound;
- sfxHandle_t loserSound;
- sfxHandle_t youSuckSound;
-#endif
- sfxHandle_t gibSound;
- sfxHandle_t gibBounce1Sound;
- sfxHandle_t gibBounce2Sound;
- sfxHandle_t gibBounce3Sound;
- sfxHandle_t teleInSound;
- sfxHandle_t teleOutSound;
- sfxHandle_t noAmmoSound;
- sfxHandle_t respawnSound;
- sfxHandle_t talkSound;
- sfxHandle_t landSound;
- sfxHandle_t fallSound;
- sfxHandle_t jumpPadSound;
-
- sfxHandle_t oneMinuteSound;
- sfxHandle_t fiveMinuteSound;
- sfxHandle_t suddenDeathSound;
-
- sfxHandle_t threeFragSound;
- sfxHandle_t twoFragSound;
- sfxHandle_t oneFragSound;
-
- sfxHandle_t hitSound;
- sfxHandle_t hitSoundHighArmor;
- sfxHandle_t hitSoundLowArmor;
- sfxHandle_t hitTeamSound;
- sfxHandle_t impressiveSound;
- sfxHandle_t excellentSound;
- sfxHandle_t deniedSound;
- sfxHandle_t humiliationSound;
- sfxHandle_t assistSound;
- sfxHandle_t defendSound;
- sfxHandle_t firstImpressiveSound;
- sfxHandle_t firstExcellentSound;
- sfxHandle_t firstHumiliationSound;
-
- sfxHandle_t takenLeadSound;
- sfxHandle_t tiedLeadSound;
- sfxHandle_t lostLeadSound;
-
- sfxHandle_t voteNow;
- sfxHandle_t votePassed;
- sfxHandle_t voteFailed;
-
- sfxHandle_t watrInSound;
- sfxHandle_t watrOutSound;
- sfxHandle_t watrUnSound;
-
- sfxHandle_t flightSound;
- sfxHandle_t medkitSound;
-
- sfxHandle_t weaponHoverSound;
-
- // teamplay sounds
- sfxHandle_t captureAwardSound;
- sfxHandle_t redScoredSound;
- sfxHandle_t blueScoredSound;
- sfxHandle_t redLeadsSound;
- sfxHandle_t blueLeadsSound;
- sfxHandle_t teamsTiedSound;
-
- sfxHandle_t captureYourTeamSound;
- sfxHandle_t captureOpponentSound;
- sfxHandle_t returnYourTeamSound;
- sfxHandle_t returnOpponentSound;
- sfxHandle_t takenYourTeamSound;
- sfxHandle_t takenOpponentSound;
-
- sfxHandle_t redFlagReturnedSound;
- sfxHandle_t blueFlagReturnedSound;
- sfxHandle_t neutralFlagReturnedSound;
- sfxHandle_t enemyTookYourFlagSound;
- sfxHandle_t enemyTookTheFlagSound;
- sfxHandle_t yourTeamTookEnemyFlagSound;
- sfxHandle_t yourTeamTookTheFlagSound;
- sfxHandle_t youHaveFlagSound;
- sfxHandle_t yourBaseIsUnderAttackSound;
- sfxHandle_t holyShitSound;
-
- // tournament sounds
- sfxHandle_t count3Sound;
- sfxHandle_t count2Sound;
- sfxHandle_t count1Sound;
- sfxHandle_t countFightSound;
- sfxHandle_t countPrepareSound;
-
-#ifdef MISSIONPACK
- // new stuff
- qhandle_t patrolShader;
- qhandle_t assaultShader;
- qhandle_t campShader;
- qhandle_t followShader;
- qhandle_t defendShader;
- qhandle_t teamLeaderShader;
- qhandle_t retrieveShader;
- qhandle_t escortShader;
- qhandle_t flagShaders[3];
- sfxHandle_t countPrepareTeamSound;
-
- sfxHandle_t ammoregenSound;
- sfxHandle_t doublerSound;
- sfxHandle_t guardSound;
- sfxHandle_t scoutSound;
-#endif
- qhandle_t cursor;
- qhandle_t selectCursor;
- qhandle_t sizeCursor;
-
- sfxHandle_t regenSound;
- sfxHandle_t protectSound;
- sfxHandle_t n_healthSound;
- sfxHandle_t hgrenb1aSound;
- sfxHandle_t hgrenb2aSound;
- sfxHandle_t wstbimplSound;
- sfxHandle_t wstbimpmSound;
- sfxHandle_t wstbimpdSound;
- sfxHandle_t wstbactvSound;
-
-} cgMedia_t;
-
-
-// The client game static (cgs) structure hold everything
-// loaded or calculated from the gamestate. It will NOT
-// be cleared when a tournement restart is done, allowing
-// all clients to begin playing instantly
-typedef struct {
- gameState_t gameState; // gamestate from server
- glconfig_t glconfig; // rendering configuration
- float screenXScale; // derived from glconfig
- float screenYScale;
- float screenXBias;
-
- int serverCommandSequence; // reliable command stream counter
- int processedSnapshotNum;// the number of snapshots cgame has requested
-
- qboolean localServer; // detected on startup by checking sv_running
-
- // parsed from serverinfo
- gametype_t gametype;
- int dmflags;
- int teamflags;
- int fraglimit;
- int capturelimit;
- int timelimit;
- int maxclients;
- char mapname[MAX_QPATH];
- char redTeam[MAX_QPATH];
- char blueTeam[MAX_QPATH];
-
- int voteTime;
- int voteYes;
- int voteNo;
- qboolean voteModified; // beep whenever changed
- char voteString[MAX_STRING_TOKENS];
-
- int teamVoteTime[2];
- int teamVoteYes[2];
- int teamVoteNo[2];
- qboolean teamVoteModified[2]; // beep whenever changed
- char teamVoteString[2][MAX_STRING_TOKENS];
-
- int levelStartTime;
-
- int scores1, scores2; // from configstrings
- int redflag, blueflag; // flag status from configstrings
- int flagStatus;
-
- qboolean newHud;
-
- //
- // locally derived information from gamestate
- //
- qhandle_t gameModels[MAX_MODELS];
- sfxHandle_t gameSounds[MAX_SOUNDS];
-
- int numInlineModels;
- qhandle_t inlineDrawModel[MAX_MODELS];
- vec3_t inlineModelMidpoints[MAX_MODELS];
-
- clientInfo_t clientinfo[MAX_CLIENTS];
-
- // teamchat width is *3 because of embedded color codes
- char teamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH*3+1];
- int teamChatMsgTimes[TEAMCHAT_HEIGHT];
- int teamChatPos;
- int teamLastChatPos;
-
- int cursorX;
- int cursorY;
- qboolean eventHandling;
- qboolean mouseCaptured;
- qboolean sizingHud;
- void *capturedItem;
- qhandle_t activeCursor;
-
- // orders
- int currentOrder;
- qboolean orderPending;
- int orderTime;
- int currentVoiceClient;
- int acceptOrderTime;
- int acceptTask;
- int acceptLeader;
- char acceptVoice[MAX_NAME_LENGTH];
-
- // media
- cgMedia_t media;
-
-} cgs_t;
-
-//==============================================================================
-
-extern cgs_t cgs;
-extern cg_t cg;
-extern centity_t cg_entities[MAX_GENTITIES];
-extern weaponInfo_t cg_weapons[MAX_WEAPONS];
-extern itemInfo_t cg_items[MAX_ITEMS];
-extern markPoly_t cg_markPolys[MAX_MARK_POLYS];
-
-extern vmCvar_t cg_centertime;
-extern vmCvar_t cg_runpitch;
-extern vmCvar_t cg_runroll;
-extern vmCvar_t cg_bobup;
-extern vmCvar_t cg_bobpitch;
-extern vmCvar_t cg_bobroll;
-extern vmCvar_t cg_swingSpeed;
-extern vmCvar_t cg_shadows;
-extern vmCvar_t cg_gibs;
-extern vmCvar_t cg_drawTimer;
-extern vmCvar_t cg_drawFPS;
-extern vmCvar_t cg_drawSnapshot;
-extern vmCvar_t cg_draw3dIcons;
-extern vmCvar_t cg_drawIcons;
-extern vmCvar_t cg_drawAmmoWarning;
-extern vmCvar_t cg_drawCrosshair;
-extern vmCvar_t cg_drawCrosshairNames;
-extern vmCvar_t cg_drawRewards;
-extern vmCvar_t cg_drawTeamOverlay;
-extern vmCvar_t cg_teamOverlayUserinfo;
-extern vmCvar_t cg_crosshairX;
-extern vmCvar_t cg_crosshairY;
-extern vmCvar_t cg_crosshairSize;
-extern vmCvar_t cg_crosshairHealth;
-extern vmCvar_t cg_drawStatus;
-extern vmCvar_t cg_draw2D;
-extern vmCvar_t cg_animSpeed;
-extern vmCvar_t cg_debugAnim;
-extern vmCvar_t cg_debugPosition;
-extern vmCvar_t cg_debugEvents;
-extern vmCvar_t cg_railTrailTime;
-extern vmCvar_t cg_errorDecay;
-extern vmCvar_t cg_nopredict;
-extern vmCvar_t cg_noPlayerAnims;
-extern vmCvar_t cg_showmiss;
-extern vmCvar_t cg_footsteps;
-extern vmCvar_t cg_addMarks;
-extern vmCvar_t cg_brassTime;
-extern vmCvar_t cg_gun_frame;
-extern vmCvar_t cg_gun_x;
-extern vmCvar_t cg_gun_y;
-extern vmCvar_t cg_gun_z;
-extern vmCvar_t cg_drawGun;
-extern vmCvar_t cg_viewsize;
-extern vmCvar_t cg_tracerChance;
-extern vmCvar_t cg_tracerWidth;
-extern vmCvar_t cg_tracerLength;
-extern vmCvar_t cg_autoswitch;
-extern vmCvar_t cg_ignore;
-extern vmCvar_t cg_simpleItems;
-extern vmCvar_t cg_fov;
-extern vmCvar_t cg_zoomFov;
-extern vmCvar_t cg_thirdPersonRange;
-extern vmCvar_t cg_thirdPersonAngle;
-extern vmCvar_t cg_thirdPerson;
-extern vmCvar_t cg_stereoSeparation;
-extern vmCvar_t cg_lagometer;
-extern vmCvar_t cg_drawAttacker;
-extern vmCvar_t cg_synchronousClients;
-extern vmCvar_t cg_teamChatTime;
-extern vmCvar_t cg_teamChatHeight;
-extern vmCvar_t cg_stats;
-extern vmCvar_t cg_forceModel;
-extern vmCvar_t cg_buildScript;
-extern vmCvar_t cg_paused;
-extern vmCvar_t cg_blood;
-extern vmCvar_t cg_predictItems;
-extern vmCvar_t cg_deferPlayers;
-extern vmCvar_t cg_drawFriend;
-extern vmCvar_t cg_teamChatsOnly;
-extern vmCvar_t cg_noVoiceChats;
-extern vmCvar_t cg_noVoiceText;
-extern vmCvar_t cg_scorePlum;
-extern vmCvar_t cg_smoothClients;
-extern vmCvar_t pmove_fixed;
-extern vmCvar_t pmove_msec;
-//extern vmCvar_t cg_pmove_fixed;
-extern vmCvar_t cg_cameraOrbit;
-extern vmCvar_t cg_cameraOrbitDelay;
-extern vmCvar_t cg_timescaleFadeEnd;
-extern vmCvar_t cg_timescaleFadeSpeed;
-extern vmCvar_t cg_timescale;
-extern vmCvar_t cg_cameraMode;
-extern vmCvar_t cg_smallFont;
-extern vmCvar_t cg_bigFont;
-extern vmCvar_t cg_noTaunt;
-extern vmCvar_t cg_noProjectileTrail;
-extern vmCvar_t cg_oldRail;
-extern vmCvar_t cg_oldRocket;
-extern vmCvar_t cg_oldPlasma;
-extern vmCvar_t cg_trueLightning;
-#ifdef MISSIONPACK
-extern vmCvar_t cg_redTeamName;
-extern vmCvar_t cg_blueTeamName;
-extern vmCvar_t cg_currentSelectedPlayer;
-extern vmCvar_t cg_currentSelectedPlayerName;
-extern vmCvar_t cg_singlePlayer;
-extern vmCvar_t cg_enableDust;
-extern vmCvar_t cg_enableBreath;
-extern vmCvar_t cg_singlePlayerActive;
-extern vmCvar_t cg_recordSPDemo;
-extern vmCvar_t cg_recordSPDemoName;
-extern vmCvar_t cg_obeliskRespawnDelay;
-#endif
-
-//
-// cg_main.c
-//
-const char *CG_ConfigString( int index );
-const char *CG_Argv( int arg );
-
-void QDECL CG_Printf( const char *msg, ... );
-void QDECL CG_Error( const char *msg, ... );
-
-void CG_StartMusic( void );
-
-void CG_UpdateCvars( void );
-
-int CG_CrosshairPlayer( void );
-int CG_LastAttacker( void );
-void CG_LoadMenus(const char *menuFile);
-void CG_KeyEvent(int key, qboolean down);
-void CG_MouseEvent(int x, int y);
-void CG_EventHandling(int type);
-void CG_RankRunFrame( void );
-void CG_SetScoreSelection(void *menu);
-score_t *CG_GetSelectedScore();
-void CG_BuildSpectatorString();
-
-
-//
-// cg_view.c
-//
-void CG_TestModel_f (void);
-void CG_TestGun_f (void);
-void CG_TestModelNextFrame_f (void);
-void CG_TestModelPrevFrame_f (void);
-void CG_TestModelNextSkin_f (void);
-void CG_TestModelPrevSkin_f (void);
-void CG_ZoomDown_f( void );
-void CG_ZoomUp_f( void );
-void CG_AddBufferedSound( sfxHandle_t sfx);
-
-void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
-
-
-//
-// cg_drawtools.c
-//
-void CG_AdjustFrom640( float *x, float *y, float *w, float *h );
-void CG_FillRect( float x, float y, float width, float height, const float *color );
-void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
-void CG_DrawString( float x, float y, const char *string,
- float charWidth, float charHeight, const float *modulate );
-
-
-void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
- qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars );
-void CG_DrawBigString( int x, int y, const char *s, float alpha );
-void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color );
-void CG_DrawSmallString( int x, int y, const char *s, float alpha );
-void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color );
-
-int CG_DrawStrlen( const char *str );
-
-float *CG_FadeColor( int startMsec, int totalMsec );
-float *CG_TeamColor( int team );
-void CG_TileClear( void );
-void CG_ColorForHealth( vec4_t hcolor );
-void CG_GetColorForHealth( int health, int armor, vec4_t hcolor );
-
-void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
-void CG_DrawRect( float x, float y, float width, float height, float size, const float *color );
-void CG_DrawSides(float x, float y, float w, float h, float size);
-void CG_DrawTopBottom(float x, float y, float w, float h, float size);
-
-
-//
-// cg_draw.c, cg_newDraw.c
-//
-extern int sortedTeamPlayers[TEAM_MAXOVERLAY];
-extern int numSortedTeamPlayers;
-extern int drawTeamOverlayModificationCount;
-extern char systemChat[256];
-extern char teamChat1[256];
-extern char teamChat2[256];
-
-void CG_AddLagometerFrameInfo( void );
-void CG_AddLagometerSnapshotInfo( snapshot_t *snap );
-void CG_CenterPrint( const char *str, int y, int charWidth );
-void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles );
-void CG_DrawActive( stereoFrame_t stereoView );
-void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D );
-void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team );
-void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
-void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);
-int CG_Text_Width(const char *text, float scale, int limit);
-int CG_Text_Height(const char *text, float scale, int limit);
-void CG_SelectPrevPlayer();
-void CG_SelectNextPlayer();
-float CG_GetValue(int ownerDraw);
-qboolean CG_OwnerDrawVisible(int flags);
-void CG_RunMenuScript(char **args);
-void CG_ShowResponseHead();
-void CG_SetPrintString(int type, const char *p);
-void CG_InitTeamChat();
-void CG_GetTeamColor(vec4_t *color);
-const char *CG_GetGameStatusText();
-const char *CG_GetKillerText();
-void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles );
-void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader);
-void CG_CheckOrderPending();
-const char *CG_GameTypeString();
-qboolean CG_YourTeamHasFlag();
-qboolean CG_OtherTeamHasFlag();
-qhandle_t CG_StatusHandle(int task);
-
-
-
-//
-// cg_player.c
-//
-void CG_Player( centity_t *cent );
-void CG_ResetPlayerEntity( centity_t *cent );
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team );
-void CG_NewClientInfo( int clientNum );
-sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
-
-//
-// cg_predict.c
-//
-void CG_BuildSolidList( void );
-int CG_PointContents( const vec3_t point, int passEntityNum );
-void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask );
-void CG_PredictPlayerState( void );
-void CG_LoadDeferredPlayers( void );
-
-
-//
-// cg_events.c
-//
-void CG_CheckEvents( centity_t *cent );
-const char *CG_PlaceString( int rank );
-void CG_EntityEvent( centity_t *cent, vec3_t position );
-void CG_PainEvent( centity_t *cent, int health );
-
-
-//
-// cg_ents.c
-//
-void CG_SetEntitySoundPosition( centity_t *cent );
-void CG_AddPacketEntities( void );
-void CG_Beam( centity_t *cent );
-void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out );
-
-void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName );
-void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
- qhandle_t parentModel, char *tagName );
-
-
-
-//
-// cg_weapons.c
-//
-void CG_NextWeapon_f( void );
-void CG_PrevWeapon_f( void );
-void CG_Weapon_f( void );
-
-void CG_RegisterWeapon( int weaponNum );
-void CG_RegisterItemVisuals( int itemNum );
-
-void CG_FireWeapon( centity_t *cent );
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType );
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum );
-void CG_ShotgunFire( entityState_t *es );
-void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
-
-void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );
-void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );
-void CG_AddViewWeapon (playerState_t *ps);
-void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );
-void CG_DrawWeaponSelect( void );
-
-void CG_OutOfAmmoChange( void ); // should this be in pmove?
-
-//
-// cg_marks.c
-//
-void CG_InitMarkPolys( void );
-void CG_AddMarks( void );
-void CG_ImpactMark( qhandle_t markShader,
- const vec3_t origin, const vec3_t dir,
- float orientation,
- float r, float g, float b, float a,
- qboolean alphaFade,
- float radius, qboolean temporary );
-
-//
-// cg_localents.c
-//
-void CG_InitLocalEntities( void );
-localEntity_t *CG_AllocLocalEntity( void );
-void CG_AddLocalEntities( void );
-
-//
-// cg_effects.c
-//
-localEntity_t *CG_SmokePuff( const vec3_t p,
- const vec3_t vel,
- float radius,
- float r, float g, float b, float a,
- float duration,
- int startTime,
- int fadeInTime,
- int leFlags,
- qhandle_t hShader );
-void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing );
-void CG_SpawnEffect( vec3_t org );
-#ifdef MISSIONPACK
-void CG_KamikazeEffect( vec3_t org );
-void CG_ObeliskExplode( vec3_t org, int entityNum );
-void CG_ObeliskPain( vec3_t org );
-void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles );
-void CG_InvulnerabilityJuiced( vec3_t org );
-void CG_LightningBoltBeam( vec3_t start, vec3_t end );
-#endif
-void CG_ScorePlum( int client, vec3_t org, int score );
-
-void CG_GibPlayer( vec3_t playerOrigin );
-void CG_BigExplode( vec3_t playerOrigin );
-
-void CG_Bleed( vec3_t origin, int entityNum );
-
-localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
- qhandle_t hModel, qhandle_t shader, int msec,
- qboolean isSprite );
-
-//
-// cg_snapshot.c
-//
-void CG_ProcessSnapshots( void );
-
-//
-// cg_info.c
-//
-void CG_LoadingString( const char *s );
-void CG_LoadingItem( int itemNum );
-void CG_LoadingClient( int clientNum );
-void CG_DrawInformation( void );
-
-//
-// cg_scoreboard.c
-//
-qboolean CG_DrawOldScoreboard( void );
-void CG_DrawOldTourneyScoreboard( void );
-
-//
-// cg_consolecmds.c
-//
-qboolean CG_ConsoleCommand( void );
-void CG_InitConsoleCommands( void );
-
-//
-// cg_servercmds.c
-//
-void CG_ExecuteNewServerCommands( int latestSequence );
-void CG_ParseServerinfo( void );
-void CG_SetConfigValues( void );
-void CG_LoadVoiceChats( void );
-void CG_ShaderStateChanged(void);
-void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd );
-void CG_PlayBufferedVoiceChats( void );
-
-//
-// cg_playerstate.c
-//
-void CG_Respawn( void );
-void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
-void CG_CheckChangedPredictableEvents( playerState_t *ps );
-
-
-//===============================================
-
-//
-// system traps
-// These functions are how the cgame communicates with the main game system
-//
-
-// print message on the local console
-void trap_Print( const char *fmt );
-
-// abort the game
-void trap_Error( const char *fmt );
-
-// milliseconds should only be used for performance tuning, never
-// for anything game related. Get time from the CG_DrawActiveFrame parameter
-int trap_Milliseconds( void );
-
-// console variable interaction
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
-void trap_Cvar_Update( vmCvar_t *vmCvar );
-void trap_Cvar_Set( const char *var_name, const char *value );
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
-
-// ServerCommand and ConsoleCommand parameter access
-int trap_Argc( void );
-void trap_Argv( int n, char *buffer, int bufferLength );
-void trap_Args( char *buffer, int bufferLength );
-
-// filesystem access
-// returns length of file
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
-void trap_FS_Read( void *buffer, int len, fileHandle_t f );
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
-void trap_FS_FCloseFile( fileHandle_t f );
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
-
-// add commands to the local console as if they were typed in
-// for map changing, etc. The command is not executed immediately,
-// but will be executed in order the next time console commands
-// are processed
-void trap_SendConsoleCommand( const char *text );
-
-// register a command name so the console can perform command completion.
-// FIXME: replace this with a normal console command "defineCommand"?
-void trap_AddCommand( const char *cmdName );
-
-// send a string to the server over the network
-void trap_SendClientCommand( const char *s );
-
-// force a screen update, only used during gamestate load
-void trap_UpdateScreen( void );
-
-// model collision
-void trap_CM_LoadMap( const char *mapname );
-int trap_CM_NumInlineModels( void );
-clipHandle_t trap_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels
-clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );
-int trap_CM_PointContents( const vec3_t p, clipHandle_t model );
-int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
-void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask );
-void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles );
-
-// Returns the projection of a polygon onto the solid brushes in the world
-int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
- const vec3_t projection,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer );
-
-// normal sounds will have their volume dynamically changed as their entity
-// moves and the listener moves
-void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
-void trap_S_StopLoopingSound(int entnum);
-
-// a local sound is always played full volume
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
-void trap_S_ClearLoopingSounds( qboolean killall );
-void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
-void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
-
-// respatialize recalculates the volumes of sound as they should be heard by the
-// given entityNum and position
-void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music
-void trap_S_StopBackgroundTrack( void );
-
-
-void trap_R_LoadWorldMap( const char *mapname );
-
-// all media should be registered during level startup to prevent
-// hitches during gameplay
-qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
-qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
-qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found
-
-// a scene is built up by calls to R_ClearScene and the various R_Add functions.
-// Nothing is drawn until R_RenderScene is called.
-void trap_R_ClearScene( void );
-void trap_R_AddRefEntityToScene( const refEntity_t *re );
-
-// polys are intended for simple wall marks, not really for doing
-// significant construction
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
-void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
-void trap_R_RenderScene( const refdef_t *fd );
-void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1
-void trap_R_DrawStretchPic( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader );
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
-int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
- float frac, const char *tagName );
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
-
-// The glconfig_t will not change during the life of a cgame.
-// If it needs to change, the entire cgame will be restarted, because
-// all the qhandle_t are then invalid.
-void trap_GetGlconfig( glconfig_t *glconfig );
-
-// the gamestate should be grabbed at startup, and whenever a
-// configstring changes
-void trap_GetGameState( gameState_t *gamestate );
-
-// cgame will poll each frame to see if a newer snapshot has arrived
-// that it is interested in. The time is returned seperately so that
-// snapshot latency can be calculated.
-void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );
-
-// a snapshot get can fail if the snapshot (or the entties it holds) is so
-// old that it has fallen out of the client system queue
-qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot );
-
-// retrieve a text command from the server stream
-// the current snapshot will hold the number of the most recent command
-// qfalse can be returned if the client system handled the command
-// argc() / argv() can be used to examine the parameters of the command
-qboolean trap_GetServerCommand( int serverCommandNumber );
-
-// returns the most recent command number that can be passed to GetUserCmd
-// this will always be at least one higher than the number in the current
-// snapshot, and it may be quite a few higher if it is a fast computer on
-// a lagged connection
-int trap_GetCurrentCmdNumber( void );
-
-qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd );
-
-// used for the weapon select and zoom
-void trap_SetUserCmdValue( int stateValue, float sensitivityScale );
-
-// aids for VM testing
-void testPrintInt( char *string, int i );
-void testPrintFloat( char *string, float f );
-
-int trap_MemoryRemaining( void );
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
-qboolean trap_Key_IsDown( int keynum );
-int trap_Key_GetCatcher( void );
-void trap_Key_SetCatcher( int catcher );
-int trap_Key_GetKey( const char *binding );
-
-
-typedef enum {
- SYSTEM_PRINT,
- CHAT_PRINT,
- TEAMCHAT_PRINT
-} q3print_t; // bk001201 - warning: useless keyword or type name in empty declaration
-
-
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
-e_status trap_CIN_StopCinematic(int handle);
-e_status trap_CIN_RunCinematic (int handle);
-void trap_CIN_DrawCinematic (int handle);
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
-
-void trap_SnapVector( float *v );
-
-qboolean trap_loadCamera(const char *name);
-void trap_startCamera(int time);
-qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize );
-
-void CG_ClearParticles (void);
-void CG_AddParticles (void);
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum);
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent);
-void CG_AddParticleShrapnel (localEntity_t *le);
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent);
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration);
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir);
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha);
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd);
-extern qboolean initparticles;
-int CG_NewParticleArea ( int num );
-
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "../game/q_shared.h"
+#include "tr_types.h"
+#include "../game/bg_public.h"
+#include "cg_public.h"
+
+
+// The entire cgame module is unloaded and reloaded on each level change,
+// so there is NO persistant data between levels on the client side.
+// If you absolutely need something stored, it can either be kept
+// by the server in the server stored userinfos, or stashed in a cvar.
+
+#ifdef MISSIONPACK
+#define CG_FONT_THRESHOLD 0.1
+#endif
+
+#define POWERUP_BLINKS 5
+
+#define POWERUP_BLINK_TIME 1000
+#define FADE_TIME 200
+#define PULSE_TIME 200
+#define DAMAGE_DEFLECT_TIME 100
+#define DAMAGE_RETURN_TIME 400
+#define DAMAGE_TIME 500
+#define LAND_DEFLECT_TIME 150
+#define LAND_RETURN_TIME 300
+#define STEP_TIME 200
+#define DUCK_TIME 100
+#define PAIN_TWITCH_TIME 200
+#define WEAPON_SELECT_TIME 1400
+#define ITEM_SCALEUP_TIME 1000
+#define ZOOM_TIME 150
+#define ITEM_BLOB_TIME 200
+#define MUZZLE_FLASH_TIME 20
+#define SINK_TIME 1000 // time for fragments to sink into ground before going away
+#define ATTACKER_HEAD_TIME 10000
+#define REWARD_TIME 3000
+
+#define PULSE_SCALE 1.5 // amount to scale up the icons when activating
+
+#define MAX_STEP_CHANGE 32
+
+#define MAX_VERTS_ON_POLY 10
+#define MAX_MARK_POLYS 256
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+
+#define ICON_SIZE 48
+#define CHAR_WIDTH 32
+#define CHAR_HEIGHT 48
+#define TEXT_ICON_SPACE 4
+
+#define TEAMCHAT_WIDTH 80
+#define TEAMCHAT_HEIGHT 8
+
+// very large characters
+#define GIANT_WIDTH 32
+#define GIANT_HEIGHT 48
+
+#define NUM_CROSSHAIRS 10
+
+#define TEAM_OVERLAY_MAXNAME_WIDTH 12
+#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
+
+#define DEFAULT_MODEL "sarge"
+#ifdef MISSIONPACK
+#define DEFAULT_TEAM_MODEL "james"
+#define DEFAULT_TEAM_HEAD "*james"
+#else
+#define DEFAULT_TEAM_MODEL "sarge"
+#define DEFAULT_TEAM_HEAD "sarge"
+#endif
+
+#define DEFAULT_REDTEAM_NAME "Stroggs"
+#define DEFAULT_BLUETEAM_NAME "Pagans"
+
+typedef enum {
+ FOOTSTEP_NORMAL,
+ FOOTSTEP_BOOT,
+ FOOTSTEP_FLESH,
+ FOOTSTEP_MECH,
+ FOOTSTEP_ENERGY,
+ FOOTSTEP_METAL,
+ FOOTSTEP_SPLASH,
+
+ FOOTSTEP_TOTAL
+} footstep_t;
+
+typedef enum {
+ IMPACTSOUND_DEFAULT,
+ IMPACTSOUND_METAL,
+ IMPACTSOUND_FLESH
+} impactSound_t;
+
+//=================================================
+
+// player entities need to track more information
+// than any other type of entity.
+
+// note that not every player entity is a client entity,
+// because corpses after respawn are outside the normal
+// client numbering range
+
+// when changing animation, set animationTime to frameTime + lerping time
+// The current lerp will finish out, then it will lerp to the new animation
+typedef struct {
+ int oldFrame;
+ int oldFrameTime; // time when ->oldFrame was exactly on
+
+ int frame;
+ int frameTime; // time when ->frame will be exactly on
+
+ float backlerp;
+
+ float yawAngle;
+ qboolean yawing;
+ float pitchAngle;
+ qboolean pitching;
+
+ int animationNumber; // may include ANIM_TOGGLEBIT
+ animation_t *animation;
+ int animationTime; // time when the first frame of the animation will be exact
+} lerpFrame_t;
+
+
+typedef struct {
+ lerpFrame_t legs, torso, flag;
+ int painTime;
+ int painDirection; // flip from 0 to 1
+ int lightningFiring;
+
+ // railgun trail spawning
+ vec3_t railgunImpact;
+ qboolean railgunFlash;
+
+ // machinegun spinning
+ float barrelAngle;
+ int barrelTime;
+ qboolean barrelSpinning;
+} playerEntity_t;
+
+//=================================================
+
+
+
+// centity_t have a direct corespondence with gentity_t in the game, but
+// only the entityState_t is directly communicated to the cgame
+typedef struct centity_s {
+ entityState_t currentState; // from cg.frame
+ entityState_t nextState; // from cg.nextFrame, if available
+ qboolean interpolate; // true if next is valid to interpolate to
+ qboolean currentValid; // true if cg.frame holds this entity
+
+ int muzzleFlashTime; // move to playerEntity?
+ int previousEvent;
+ int teleportFlag;
+
+ int trailTime; // so missile trails can handle dropped initial packets
+ int dustTrailTime;
+ int miscTime;
+
+ int snapShotTime; // last time this entity was found in a snapshot
+
+ playerEntity_t pe;
+
+ int errorTime; // decay the error from this time
+ vec3_t errorOrigin;
+ vec3_t errorAngles;
+
+ qboolean extrapolated; // false if origin / angles is an interpolation
+ vec3_t rawOrigin;
+ vec3_t rawAngles;
+
+ vec3_t beamEnd;
+
+ // exact interpolated position of entity on this frame
+ vec3_t lerpOrigin;
+ vec3_t lerpAngles;
+} centity_t;
+
+
+//======================================================================
+
+// local entities are created as a result of events or predicted actions,
+// and live independantly from all server transmitted entities
+
+typedef struct markPoly_s {
+ struct markPoly_s *prevMark, *nextMark;
+ int time;
+ qhandle_t markShader;
+ qboolean alphaFade; // fade alpha instead of rgb
+ float color[4];
+ poly_t poly;
+ polyVert_t verts[MAX_VERTS_ON_POLY];
+} markPoly_t;
+
+
+typedef enum {
+ LE_MARK,
+ LE_EXPLOSION,
+ LE_SPRITE_EXPLOSION,
+ LE_FRAGMENT,
+ LE_MOVE_SCALE_FADE,
+ LE_FALL_SCALE_FADE,
+ LE_FADE_RGB,
+ LE_SCALE_FADE,
+ LE_SCOREPLUM,
+#ifdef MISSIONPACK
+ LE_KAMIKAZE,
+ LE_INVULIMPACT,
+ LE_INVULJUICED,
+ LE_SHOWREFENTITY
+#endif
+} leType_t;
+
+typedef enum {
+ LEF_PUFF_DONT_SCALE = 0x0001, // do not scale size over time
+ LEF_TUMBLE = 0x0002, // tumble over time, used for ejecting shells
+ LEF_SOUND1 = 0x0004, // sound 1 for kamikaze
+ LEF_SOUND2 = 0x0008 // sound 2 for kamikaze
+} leFlag_t;
+
+typedef enum {
+ LEMT_NONE,
+ LEMT_BURN,
+ LEMT_BLOOD
+} leMarkType_t; // fragment local entities can leave marks on walls
+
+typedef enum {
+ LEBS_NONE,
+ LEBS_BLOOD,
+ LEBS_BRASS
+} leBounceSoundType_t; // fragment local entities can make sounds on impacts
+
+typedef struct localEntity_s {
+ struct localEntity_s *prev, *next;
+ leType_t leType;
+ int leFlags;
+
+ int startTime;
+ int endTime;
+ int fadeInTime;
+
+ float lifeRate; // 1.0 / (endTime - startTime)
+
+ trajectory_t pos;
+ trajectory_t angles;
+
+ float bounceFactor; // 0.0 = no bounce, 1.0 = perfect
+
+ float color[4];
+
+ float radius;
+
+ float light;
+ vec3_t lightColor;
+
+ leMarkType_t leMarkType; // mark to leave on fragment impact
+ leBounceSoundType_t leBounceSoundType;
+
+ refEntity_t refEntity;
+} localEntity_t;
+
+//======================================================================
+
+
+typedef struct {
+ int client;
+ int score;
+ int ping;
+ int time;
+ int scoreFlags;
+ int powerUps;
+ int accuracy;
+ int impressiveCount;
+ int excellentCount;
+ int guantletCount;
+ int defendCount;
+ int assistCount;
+ int captures;
+ qboolean perfect;
+ int team;
+} score_t;
+
+// each client has an associated clientInfo_t
+// that contains media references necessary to present the
+// client model and other color coded effects
+// this is regenerated each time a client's configstring changes,
+// usually as a result of a userinfo (name, model, etc) change
+#define MAX_CUSTOM_SOUNDS 32
+
+typedef struct {
+ qboolean infoValid;
+
+ char name[MAX_QPATH];
+ team_t team;
+
+ int botSkill; // 0 = not bot, 1-5 = bot
+
+ vec3_t color1;
+ vec3_t color2;
+
+ int score; // updated by score servercmds
+ int location; // location index for team mode
+ int health; // you only get this info about your teammates
+ int armor;
+ int curWeapon;
+
+ int handicap;
+ int wins, losses; // in tourney mode
+
+ int teamTask; // task in teamplay (offence/defence)
+ qboolean teamLeader; // true when this is a team leader
+
+ int powerups; // so can display quad/flag status
+
+ int medkitUsageTime;
+ int invulnerabilityStartTime;
+ int invulnerabilityStopTime;
+
+ int breathPuffTime;
+
+ // when clientinfo is changed, the loading of models/skins/sounds
+ // can be deferred until you are dead, to prevent hitches in
+ // gameplay
+ char modelName[MAX_QPATH];
+ char skinName[MAX_QPATH];
+ char headModelName[MAX_QPATH];
+ char headSkinName[MAX_QPATH];
+ char redTeam[MAX_TEAMNAME];
+ char blueTeam[MAX_TEAMNAME];
+ qboolean deferred;
+
+ qboolean newAnims; // true if using the new mission pack animations
+ qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
+ qboolean fixedtorso; // true if torso never changes yaw
+
+ vec3_t headOffset; // move head in icon views
+ footstep_t footsteps;
+ gender_t gender; // from model
+
+ qhandle_t legsModel;
+ qhandle_t legsSkin;
+
+ qhandle_t torsoModel;
+ qhandle_t torsoSkin;
+
+ qhandle_t headModel;
+ qhandle_t headSkin;
+
+ qhandle_t modelIcon;
+
+ animation_t animations[MAX_TOTALANIMATIONS];
+
+ sfxHandle_t sounds[MAX_CUSTOM_SOUNDS];
+} clientInfo_t;
+
+
+// each WP_* weapon enum has an associated weaponInfo_t
+// that contains media references necessary to present the
+// weapon and its effects
+typedef struct weaponInfo_s {
+ qboolean registered;
+ gitem_t *item;
+
+ qhandle_t handsModel; // the hands don't actually draw, they just position the weapon
+ qhandle_t weaponModel;
+ qhandle_t barrelModel;
+ qhandle_t flashModel;
+
+ vec3_t weaponMidpoint; // so it will rotate centered instead of by tag
+
+ float flashDlight;
+ vec3_t flashDlightColor;
+ sfxHandle_t flashSound[4]; // fast firing weapons randomly choose
+
+ qhandle_t weaponIcon;
+ qhandle_t ammoIcon;
+
+ qhandle_t ammoModel;
+
+ qhandle_t missileModel;
+ sfxHandle_t missileSound;
+ void (*missileTrailFunc)( centity_t *, const struct weaponInfo_s *wi );
+ float missileDlight;
+ vec3_t missileDlightColor;
+ int missileRenderfx;
+
+ void (*ejectBrassFunc)( centity_t * );
+
+ float trailRadius;
+ float wiTrailTime;
+
+ sfxHandle_t readySound;
+ sfxHandle_t firingSound;
+ qboolean loopFireSound;
+} weaponInfo_t;
+
+
+// each IT_* item has an associated itemInfo_t
+// that constains media references necessary to present the
+// item and its effects
+typedef struct {
+ qboolean registered;
+ qhandle_t models[MAX_ITEM_MODELS];
+ qhandle_t icon;
+} itemInfo_t;
+
+
+typedef struct {
+ int itemNum;
+} powerupInfo_t;
+
+
+#define MAX_SKULLTRAIL 10
+
+typedef struct {
+ vec3_t positions[MAX_SKULLTRAIL];
+ int numpositions;
+} skulltrail_t;
+
+
+#define MAX_REWARDSTACK 10
+#define MAX_SOUNDBUFFER 20
+
+//======================================================================
+
+// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action
+// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after
+
+#define MAX_PREDICTED_EVENTS 16
+
+typedef struct {
+ int clientFrame; // incremented each frame
+
+ int clientNum;
+
+ qboolean demoPlayback;
+ qboolean levelShot; // taking a level menu screenshot
+ int deferredPlayerLoading;
+ qboolean loading; // don't defer players at initial startup
+ qboolean intermissionStarted; // don't play voice rewards, because game will end shortly
+
+ // there are only one or two snapshot_t that are relevent at a time
+ int latestSnapshotNum; // the number of snapshots the client system has received
+ int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet
+
+ snapshot_t *snap; // cg.snap->serverTime <= cg.time
+ snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL
+ snapshot_t activeSnapshots[2];
+
+ float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime)
+
+ qboolean thisFrameTeleport;
+ qboolean nextFrameTeleport;
+
+ int frametime; // cg.time - cg.oldTime
+
+ int time; // this is the time value that the client
+ // is rendering at.
+ int oldTime; // time at last frame, used for missile trails and prediction checking
+
+ int physicsTime; // either cg.snap->time or cg.nextSnap->time
+
+ int timelimitWarnings; // 5 min, 1 min, overtime
+ int fraglimitWarnings;
+
+ qboolean mapRestart; // set on a map restart to set back the weapon
+
+ qboolean renderingThirdPerson; // during deaths, chasecams, etc
+
+ // prediction state
+ qboolean hyperspace; // true if prediction has hit a trigger_teleport
+ playerState_t predictedPlayerState;
+ centity_t predictedPlayerEntity;
+ qboolean validPPS; // clear until the first call to CG_PredictPlayerState
+ int predictedErrorTime;
+ vec3_t predictedError;
+
+ int eventSequence;
+ int predictableEvents[MAX_PREDICTED_EVENTS];
+
+ float stepChange; // for stair up smoothing
+ int stepTime;
+
+ float duckChange; // for duck viewheight smoothing
+ int duckTime;
+
+ float landChange; // for landing hard
+ int landTime;
+
+ // input state sent to server
+ int weaponSelect;
+
+ // auto rotating items
+ vec3_t autoAngles;
+ vec3_t autoAxis[3];
+ vec3_t autoAnglesFast;
+ vec3_t autoAxisFast[3];
+
+ // view rendering
+ refdef_t refdef;
+ vec3_t refdefViewAngles; // will be converted to refdef.viewaxis
+
+ // zoom key
+ qboolean zoomed;
+ int zoomTime;
+ float zoomSensitivity;
+
+ // information screen text during loading
+ char infoScreenText[MAX_STRING_CHARS];
+
+ // scoreboard
+ int scoresRequestTime;
+ int numScores;
+ int selectedScore;
+ int teamScores[2];
+ score_t scores[MAX_CLIENTS];
+ qboolean showScores;
+ qboolean scoreBoardShowing;
+ int scoreFadeTime;
+ char killerName[MAX_NAME_LENGTH];
+ char spectatorList[MAX_STRING_CHARS]; // list of names
+ int spectatorLen; // length of list
+ float spectatorWidth; // width in device units
+ int spectatorTime; // next time to offset
+ int spectatorPaintX; // current paint x
+ int spectatorPaintX2; // current paint x
+ int spectatorOffset; // current offset from start
+ int spectatorPaintLen; // current offset from start
+
+ // skull trails
+ skulltrail_t skulltrails[MAX_CLIENTS];
+
+ // centerprinting
+ int centerPrintTime;
+ int centerPrintCharWidth;
+ int centerPrintY;
+ char centerPrint[1024];
+ int centerPrintLines;
+
+ // low ammo warning state
+ int lowAmmoWarning; // 1 = low, 2 = empty
+
+ // kill timers for carnage reward
+ int lastKillTime;
+
+ // crosshair client ID
+ int crosshairClientNum;
+ int crosshairClientTime;
+
+ // powerup active flashing
+ int powerupActive;
+ int powerupTime;
+
+ // attacking player
+ int attackerTime;
+ int voiceTime;
+
+ // reward medals
+ int rewardStack;
+ int rewardTime;
+ int rewardCount[MAX_REWARDSTACK];
+ qhandle_t rewardShader[MAX_REWARDSTACK];
+ qhandle_t rewardSound[MAX_REWARDSTACK];
+
+ // sound buffer mainly for announcer sounds
+ int soundBufferIn;
+ int soundBufferOut;
+ int soundTime;
+ qhandle_t soundBuffer[MAX_SOUNDBUFFER];
+
+ // for voice chat buffer
+ int voiceChatTime;
+ int voiceChatBufferIn;
+ int voiceChatBufferOut;
+
+ // warmup countdown
+ int warmup;
+ int warmupCount;
+
+ //==========================
+
+ int itemPickup;
+ int itemPickupTime;
+ int itemPickupBlendTime; // the pulse around the crosshair is timed seperately
+
+ int weaponSelectTime;
+ int weaponAnimation;
+ int weaponAnimationTime;
+
+ // blend blobs
+ float damageTime;
+ float damageX, damageY, damageValue;
+
+ // status bar head
+ float headYaw;
+ float headEndPitch;
+ float headEndYaw;
+ int headEndTime;
+ float headStartPitch;
+ float headStartYaw;
+ int headStartTime;
+
+ // view movement
+ float v_dmg_time;
+ float v_dmg_pitch;
+ float v_dmg_roll;
+
+ vec3_t kick_angles; // weapon kicks
+ vec3_t kick_origin;
+
+ // temp working variables for player view
+ float bobfracsin;
+ int bobcycle;
+ float xyspeed;
+ int nextOrbitTime;
+
+ //qboolean cameraMode; // if rendering from a loaded camera
+
+
+ // development tool
+ refEntity_t testModelEntity;
+ char testModelName[MAX_QPATH];
+ qboolean testGun;
+
+} cg_t;
+
+
+// all of the model, shader, and sound references that are
+// loaded at gamestate time are stored in cgMedia_t
+// Other media that can be tied to clients, weapons, or items are
+// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t
+typedef struct {
+ qhandle_t charsetShader;
+ qhandle_t charsetProp;
+ qhandle_t charsetPropGlow;
+ qhandle_t charsetPropB;
+ qhandle_t whiteShader;
+
+ qhandle_t redCubeModel;
+ qhandle_t blueCubeModel;
+ qhandle_t redCubeIcon;
+ qhandle_t blueCubeIcon;
+ qhandle_t redFlagModel;
+ qhandle_t blueFlagModel;
+ qhandle_t neutralFlagModel;
+ qhandle_t redFlagShader[3];
+ qhandle_t blueFlagShader[3];
+ qhandle_t flagShader[4];
+
+ qhandle_t flagPoleModel;
+ qhandle_t flagFlapModel;
+
+ qhandle_t redFlagFlapSkin;
+ qhandle_t blueFlagFlapSkin;
+ qhandle_t neutralFlagFlapSkin;
+
+ qhandle_t redFlagBaseModel;
+ qhandle_t blueFlagBaseModel;
+ qhandle_t neutralFlagBaseModel;
+
+#ifdef MISSIONPACK
+ qhandle_t overloadBaseModel;
+ qhandle_t overloadTargetModel;
+ qhandle_t overloadLightsModel;
+ qhandle_t overloadEnergyModel;
+
+ qhandle_t harvesterModel;
+ qhandle_t harvesterRedSkin;
+ qhandle_t harvesterBlueSkin;
+ qhandle_t harvesterNeutralModel;
+#endif
+
+ qhandle_t armorModel;
+ qhandle_t armorIcon;
+
+ qhandle_t teamStatusBar;
+
+ qhandle_t deferShader;
+
+ // gib explosions
+ qhandle_t gibAbdomen;
+ qhandle_t gibArm;
+ qhandle_t gibChest;
+ qhandle_t gibFist;
+ qhandle_t gibFoot;
+ qhandle_t gibForearm;
+ qhandle_t gibIntestine;
+ qhandle_t gibLeg;
+ qhandle_t gibSkull;
+ qhandle_t gibBrain;
+
+ qhandle_t smoke2;
+
+ qhandle_t machinegunBrassModel;
+ qhandle_t shotgunBrassModel;
+
+ qhandle_t railRingsShader;
+ qhandle_t railCoreShader;
+
+ qhandle_t lightningShader;
+
+ qhandle_t friendShader;
+
+ qhandle_t balloonShader;
+ qhandle_t connectionShader;
+
+ qhandle_t selectShader;
+ qhandle_t viewBloodShader;
+ qhandle_t tracerShader;
+ qhandle_t crosshairShader[NUM_CROSSHAIRS];
+ qhandle_t lagometerShader;
+ qhandle_t backTileShader;
+ qhandle_t noammoShader;
+
+ qhandle_t smokePuffShader;
+ qhandle_t smokePuffRageProShader;
+ qhandle_t shotgunSmokePuffShader;
+ qhandle_t plasmaBallShader;
+ qhandle_t waterBubbleShader;
+ qhandle_t bloodTrailShader;
+#ifdef MISSIONPACK
+ qhandle_t nailPuffShader;
+ qhandle_t blueProxMine;
+#endif
+
+ qhandle_t numberShaders[11];
+
+ qhandle_t shadowMarkShader;
+
+ qhandle_t botSkillShaders[5];
+
+ // wall mark shaders
+ qhandle_t wakeMarkShader;
+ qhandle_t bloodMarkShader;
+ qhandle_t bulletMarkShader;
+ qhandle_t burnMarkShader;
+ qhandle_t holeMarkShader;
+ qhandle_t energyMarkShader;
+
+ // powerup shaders
+ qhandle_t quadShader;
+ qhandle_t redQuadShader;
+ qhandle_t quadWeaponShader;
+ qhandle_t invisShader;
+ qhandle_t regenShader;
+ qhandle_t battleSuitShader;
+ qhandle_t battleWeaponShader;
+ qhandle_t hastePuffShader;
+ qhandle_t redKamikazeShader;
+ qhandle_t blueKamikazeShader;
+
+ // weapon effect models
+ qhandle_t bulletFlashModel;
+ qhandle_t ringFlashModel;
+ qhandle_t dishFlashModel;
+ qhandle_t lightningExplosionModel;
+
+ // weapon effect shaders
+ qhandle_t railExplosionShader;
+ qhandle_t plasmaExplosionShader;
+ qhandle_t bulletExplosionShader;
+ qhandle_t rocketExplosionShader;
+ qhandle_t grenadeExplosionShader;
+ qhandle_t bfgExplosionShader;
+ qhandle_t bloodExplosionShader;
+
+ // special effects models
+ qhandle_t teleportEffectModel;
+ qhandle_t teleportEffectShader;
+#ifdef MISSIONPACK
+ qhandle_t kamikazeEffectModel;
+ qhandle_t kamikazeShockWave;
+ qhandle_t kamikazeHeadModel;
+ qhandle_t kamikazeHeadTrail;
+ qhandle_t guardPowerupModel;
+ qhandle_t scoutPowerupModel;
+ qhandle_t doublerPowerupModel;
+ qhandle_t ammoRegenPowerupModel;
+ qhandle_t invulnerabilityImpactModel;
+ qhandle_t invulnerabilityJuicedModel;
+ qhandle_t medkitUsageModel;
+ qhandle_t dustPuffShader;
+ qhandle_t heartShader;
+#endif
+ qhandle_t invulnerabilityPowerupModel;
+
+ // scoreboard headers
+ qhandle_t scoreboardName;
+ qhandle_t scoreboardPing;
+ qhandle_t scoreboardScore;
+ qhandle_t scoreboardTime;
+
+ // medals shown during gameplay
+ qhandle_t medalImpressive;
+ qhandle_t medalExcellent;
+ qhandle_t medalGauntlet;
+ qhandle_t medalDefend;
+ qhandle_t medalAssist;
+ qhandle_t medalCapture;
+
+ // sounds
+ sfxHandle_t quadSound;
+ sfxHandle_t tracerSound;
+ sfxHandle_t selectSound;
+ sfxHandle_t useNothingSound;
+ sfxHandle_t wearOffSound;
+ sfxHandle_t footsteps[FOOTSTEP_TOTAL][4];
+ sfxHandle_t sfx_lghit1;
+ sfxHandle_t sfx_lghit2;
+ sfxHandle_t sfx_lghit3;
+ sfxHandle_t sfx_ric1;
+ sfxHandle_t sfx_ric2;
+ sfxHandle_t sfx_ric3;
+ sfxHandle_t sfx_railg;
+ sfxHandle_t sfx_rockexp;
+ sfxHandle_t sfx_plasmaexp;
+#ifdef MISSIONPACK
+ sfxHandle_t sfx_proxexp;
+ sfxHandle_t sfx_nghit;
+ sfxHandle_t sfx_nghitflesh;
+ sfxHandle_t sfx_nghitmetal;
+ sfxHandle_t sfx_chghit;
+ sfxHandle_t sfx_chghitflesh;
+ sfxHandle_t sfx_chghitmetal;
+ sfxHandle_t kamikazeExplodeSound;
+ sfxHandle_t kamikazeImplodeSound;
+ sfxHandle_t kamikazeFarSound;
+ sfxHandle_t useInvulnerabilitySound;
+ sfxHandle_t invulnerabilityImpactSound1;
+ sfxHandle_t invulnerabilityImpactSound2;
+ sfxHandle_t invulnerabilityImpactSound3;
+ sfxHandle_t invulnerabilityJuicedSound;
+ sfxHandle_t obeliskHitSound1;
+ sfxHandle_t obeliskHitSound2;
+ sfxHandle_t obeliskHitSound3;
+ sfxHandle_t obeliskRespawnSound;
+ sfxHandle_t winnerSound;
+ sfxHandle_t loserSound;
+ sfxHandle_t youSuckSound;
+#endif
+ sfxHandle_t gibSound;
+ sfxHandle_t gibBounce1Sound;
+ sfxHandle_t gibBounce2Sound;
+ sfxHandle_t gibBounce3Sound;
+ sfxHandle_t teleInSound;
+ sfxHandle_t teleOutSound;
+ sfxHandle_t noAmmoSound;
+ sfxHandle_t respawnSound;
+ sfxHandle_t talkSound;
+ sfxHandle_t landSound;
+ sfxHandle_t fallSound;
+ sfxHandle_t jumpPadSound;
+
+ sfxHandle_t oneMinuteSound;
+ sfxHandle_t fiveMinuteSound;
+ sfxHandle_t suddenDeathSound;
+
+ sfxHandle_t threeFragSound;
+ sfxHandle_t twoFragSound;
+ sfxHandle_t oneFragSound;
+
+ sfxHandle_t hitSound;
+ sfxHandle_t hitSoundHighArmor;
+ sfxHandle_t hitSoundLowArmor;
+ sfxHandle_t hitTeamSound;
+ sfxHandle_t impressiveSound;
+ sfxHandle_t excellentSound;
+ sfxHandle_t deniedSound;
+ sfxHandle_t humiliationSound;
+ sfxHandle_t assistSound;
+ sfxHandle_t defendSound;
+ sfxHandle_t firstImpressiveSound;
+ sfxHandle_t firstExcellentSound;
+ sfxHandle_t firstHumiliationSound;
+
+ sfxHandle_t takenLeadSound;
+ sfxHandle_t tiedLeadSound;
+ sfxHandle_t lostLeadSound;
+
+ sfxHandle_t voteNow;
+ sfxHandle_t votePassed;
+ sfxHandle_t voteFailed;
+
+ sfxHandle_t watrInSound;
+ sfxHandle_t watrOutSound;
+ sfxHandle_t watrUnSound;
+
+ sfxHandle_t flightSound;
+ sfxHandle_t medkitSound;
+
+ sfxHandle_t weaponHoverSound;
+
+ // teamplay sounds
+ sfxHandle_t captureAwardSound;
+ sfxHandle_t redScoredSound;
+ sfxHandle_t blueScoredSound;
+ sfxHandle_t redLeadsSound;
+ sfxHandle_t blueLeadsSound;
+ sfxHandle_t teamsTiedSound;
+
+ sfxHandle_t captureYourTeamSound;
+ sfxHandle_t captureOpponentSound;
+ sfxHandle_t returnYourTeamSound;
+ sfxHandle_t returnOpponentSound;
+ sfxHandle_t takenYourTeamSound;
+ sfxHandle_t takenOpponentSound;
+
+ sfxHandle_t redFlagReturnedSound;
+ sfxHandle_t blueFlagReturnedSound;
+ sfxHandle_t neutralFlagReturnedSound;
+ sfxHandle_t enemyTookYourFlagSound;
+ sfxHandle_t enemyTookTheFlagSound;
+ sfxHandle_t yourTeamTookEnemyFlagSound;
+ sfxHandle_t yourTeamTookTheFlagSound;
+ sfxHandle_t youHaveFlagSound;
+ sfxHandle_t yourBaseIsUnderAttackSound;
+ sfxHandle_t holyShitSound;
+
+ // tournament sounds
+ sfxHandle_t count3Sound;
+ sfxHandle_t count2Sound;
+ sfxHandle_t count1Sound;
+ sfxHandle_t countFightSound;
+ sfxHandle_t countPrepareSound;
+
+#ifdef MISSIONPACK
+ // new stuff
+ qhandle_t patrolShader;
+ qhandle_t assaultShader;
+ qhandle_t campShader;
+ qhandle_t followShader;
+ qhandle_t defendShader;
+ qhandle_t teamLeaderShader;
+ qhandle_t retrieveShader;
+ qhandle_t escortShader;
+ qhandle_t flagShaders[3];
+ sfxHandle_t countPrepareTeamSound;
+
+ sfxHandle_t ammoregenSound;
+ sfxHandle_t doublerSound;
+ sfxHandle_t guardSound;
+ sfxHandle_t scoutSound;
+#endif
+ qhandle_t cursor;
+ qhandle_t selectCursor;
+ qhandle_t sizeCursor;
+
+ sfxHandle_t regenSound;
+ sfxHandle_t protectSound;
+ sfxHandle_t n_healthSound;
+ sfxHandle_t hgrenb1aSound;
+ sfxHandle_t hgrenb2aSound;
+ sfxHandle_t wstbimplSound;
+ sfxHandle_t wstbimpmSound;
+ sfxHandle_t wstbimpdSound;
+ sfxHandle_t wstbactvSound;
+
+} cgMedia_t;
+
+
+// The client game static (cgs) structure hold everything
+// loaded or calculated from the gamestate. It will NOT
+// be cleared when a tournement restart is done, allowing
+// all clients to begin playing instantly
+typedef struct {
+ gameState_t gameState; // gamestate from server
+ glconfig_t glconfig; // rendering configuration
+ float screenXScale; // derived from glconfig
+ float screenYScale;
+ float screenXBias;
+
+ int serverCommandSequence; // reliable command stream counter
+ int processedSnapshotNum;// the number of snapshots cgame has requested
+
+ qboolean localServer; // detected on startup by checking sv_running
+
+ // parsed from serverinfo
+ gametype_t gametype;
+ int dmflags;
+ int teamflags;
+ int fraglimit;
+ int capturelimit;
+ int timelimit;
+ int maxclients;
+ char mapname[MAX_QPATH];
+ char redTeam[MAX_QPATH];
+ char blueTeam[MAX_QPATH];
+
+ int voteTime;
+ int voteYes;
+ int voteNo;
+ qboolean voteModified; // beep whenever changed
+ char voteString[MAX_STRING_TOKENS];
+
+ int teamVoteTime[2];
+ int teamVoteYes[2];
+ int teamVoteNo[2];
+ qboolean teamVoteModified[2]; // beep whenever changed
+ char teamVoteString[2][MAX_STRING_TOKENS];
+
+ int levelStartTime;
+
+ int scores1, scores2; // from configstrings
+ int redflag, blueflag; // flag status from configstrings
+ int flagStatus;
+
+ qboolean newHud;
+
+ //
+ // locally derived information from gamestate
+ //
+ qhandle_t gameModels[MAX_MODELS];
+ sfxHandle_t gameSounds[MAX_SOUNDS];
+
+ int numInlineModels;
+ qhandle_t inlineDrawModel[MAX_MODELS];
+ vec3_t inlineModelMidpoints[MAX_MODELS];
+
+ clientInfo_t clientinfo[MAX_CLIENTS];
+
+ // teamchat width is *3 because of embedded color codes
+ char teamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH*3+1];
+ int teamChatMsgTimes[TEAMCHAT_HEIGHT];
+ int teamChatPos;
+ int teamLastChatPos;
+
+ int cursorX;
+ int cursorY;
+ qboolean eventHandling;
+ qboolean mouseCaptured;
+ qboolean sizingHud;
+ void *capturedItem;
+ qhandle_t activeCursor;
+
+ // orders
+ int currentOrder;
+ qboolean orderPending;
+ int orderTime;
+ int currentVoiceClient;
+ int acceptOrderTime;
+ int acceptTask;
+ int acceptLeader;
+ char acceptVoice[MAX_NAME_LENGTH];
+
+ // media
+ cgMedia_t media;
+
+} cgs_t;
+
+//==============================================================================
+
+extern cgs_t cgs;
+extern cg_t cg;
+extern centity_t cg_entities[MAX_GENTITIES];
+extern weaponInfo_t cg_weapons[MAX_WEAPONS];
+extern itemInfo_t cg_items[MAX_ITEMS];
+extern markPoly_t cg_markPolys[MAX_MARK_POLYS];
+
+extern vmCvar_t cg_centertime;
+extern vmCvar_t cg_runpitch;
+extern vmCvar_t cg_runroll;
+extern vmCvar_t cg_bobup;
+extern vmCvar_t cg_bobpitch;
+extern vmCvar_t cg_bobroll;
+extern vmCvar_t cg_swingSpeed;
+extern vmCvar_t cg_shadows;
+extern vmCvar_t cg_gibs;
+extern vmCvar_t cg_drawTimer;
+extern vmCvar_t cg_drawFPS;
+extern vmCvar_t cg_drawSnapshot;
+extern vmCvar_t cg_draw3dIcons;
+extern vmCvar_t cg_drawIcons;
+extern vmCvar_t cg_drawAmmoWarning;
+extern vmCvar_t cg_drawCrosshair;
+extern vmCvar_t cg_drawCrosshairNames;
+extern vmCvar_t cg_drawRewards;
+extern vmCvar_t cg_drawTeamOverlay;
+extern vmCvar_t cg_teamOverlayUserinfo;
+extern vmCvar_t cg_crosshairX;
+extern vmCvar_t cg_crosshairY;
+extern vmCvar_t cg_crosshairSize;
+extern vmCvar_t cg_crosshairHealth;
+extern vmCvar_t cg_drawStatus;
+extern vmCvar_t cg_draw2D;
+extern vmCvar_t cg_animSpeed;
+extern vmCvar_t cg_debugAnim;
+extern vmCvar_t cg_debugPosition;
+extern vmCvar_t cg_debugEvents;
+extern vmCvar_t cg_railTrailTime;
+extern vmCvar_t cg_errorDecay;
+extern vmCvar_t cg_nopredict;
+extern vmCvar_t cg_noPlayerAnims;
+extern vmCvar_t cg_showmiss;
+extern vmCvar_t cg_footsteps;
+extern vmCvar_t cg_addMarks;
+extern vmCvar_t cg_brassTime;
+extern vmCvar_t cg_gun_frame;
+extern vmCvar_t cg_gun_x;
+extern vmCvar_t cg_gun_y;
+extern vmCvar_t cg_gun_z;
+extern vmCvar_t cg_drawGun;
+extern vmCvar_t cg_viewsize;
+extern vmCvar_t cg_tracerChance;
+extern vmCvar_t cg_tracerWidth;
+extern vmCvar_t cg_tracerLength;
+extern vmCvar_t cg_autoswitch;
+extern vmCvar_t cg_ignore;
+extern vmCvar_t cg_simpleItems;
+extern vmCvar_t cg_fov;
+extern vmCvar_t cg_zoomFov;
+extern vmCvar_t cg_thirdPersonRange;
+extern vmCvar_t cg_thirdPersonAngle;
+extern vmCvar_t cg_thirdPerson;
+extern vmCvar_t cg_stereoSeparation;
+extern vmCvar_t cg_lagometer;
+extern vmCvar_t cg_drawAttacker;
+extern vmCvar_t cg_synchronousClients;
+extern vmCvar_t cg_teamChatTime;
+extern vmCvar_t cg_teamChatHeight;
+extern vmCvar_t cg_stats;
+extern vmCvar_t cg_forceModel;
+extern vmCvar_t cg_buildScript;
+extern vmCvar_t cg_paused;
+extern vmCvar_t cg_blood;
+extern vmCvar_t cg_predictItems;
+extern vmCvar_t cg_deferPlayers;
+extern vmCvar_t cg_drawFriend;
+extern vmCvar_t cg_teamChatsOnly;
+extern vmCvar_t cg_noVoiceChats;
+extern vmCvar_t cg_noVoiceText;
+extern vmCvar_t cg_scorePlum;
+extern vmCvar_t cg_smoothClients;
+extern vmCvar_t pmove_fixed;
+extern vmCvar_t pmove_msec;
+//extern vmCvar_t cg_pmove_fixed;
+extern vmCvar_t cg_cameraOrbit;
+extern vmCvar_t cg_cameraOrbitDelay;
+extern vmCvar_t cg_timescaleFadeEnd;
+extern vmCvar_t cg_timescaleFadeSpeed;
+extern vmCvar_t cg_timescale;
+extern vmCvar_t cg_cameraMode;
+extern vmCvar_t cg_smallFont;
+extern vmCvar_t cg_bigFont;
+extern vmCvar_t cg_noTaunt;
+extern vmCvar_t cg_noProjectileTrail;
+extern vmCvar_t cg_oldRail;
+extern vmCvar_t cg_oldRocket;
+extern vmCvar_t cg_oldPlasma;
+extern vmCvar_t cg_trueLightning;
+#ifdef MISSIONPACK
+extern vmCvar_t cg_redTeamName;
+extern vmCvar_t cg_blueTeamName;
+extern vmCvar_t cg_currentSelectedPlayer;
+extern vmCvar_t cg_currentSelectedPlayerName;
+extern vmCvar_t cg_singlePlayer;
+extern vmCvar_t cg_enableDust;
+extern vmCvar_t cg_enableBreath;
+extern vmCvar_t cg_singlePlayerActive;
+extern vmCvar_t cg_recordSPDemo;
+extern vmCvar_t cg_recordSPDemoName;
+extern vmCvar_t cg_obeliskRespawnDelay;
+#endif
+
+//
+// cg_main.c
+//
+const char *CG_ConfigString( int index );
+const char *CG_Argv( int arg );
+
+void QDECL CG_Printf( const char *msg, ... );
+void QDECL CG_Error( const char *msg, ... );
+
+void CG_StartMusic( void );
+
+void CG_UpdateCvars( void );
+
+int CG_CrosshairPlayer( void );
+int CG_LastAttacker( void );
+void CG_LoadMenus(const char *menuFile);
+void CG_KeyEvent(int key, qboolean down);
+void CG_MouseEvent(int x, int y);
+void CG_EventHandling(int type);
+void CG_RankRunFrame( void );
+void CG_SetScoreSelection(void *menu);
+score_t *CG_GetSelectedScore();
+void CG_BuildSpectatorString();
+
+
+//
+// cg_view.c
+//
+void CG_TestModel_f (void);
+void CG_TestGun_f (void);
+void CG_TestModelNextFrame_f (void);
+void CG_TestModelPrevFrame_f (void);
+void CG_TestModelNextSkin_f (void);
+void CG_TestModelPrevSkin_f (void);
+void CG_ZoomDown_f( void );
+void CG_ZoomUp_f( void );
+void CG_AddBufferedSound( sfxHandle_t sfx);
+
+void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
+
+
+//
+// cg_drawtools.c
+//
+void CG_AdjustFrom640( float *x, float *y, float *w, float *h );
+void CG_FillRect( float x, float y, float width, float height, const float *color );
+void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader );
+void CG_DrawString( float x, float y, const char *string,
+ float charWidth, float charHeight, const float *modulate );
+
+
+void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
+ qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars );
+void CG_DrawBigString( int x, int y, const char *s, float alpha );
+void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color );
+void CG_DrawSmallString( int x, int y, const char *s, float alpha );
+void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color );
+
+int CG_DrawStrlen( const char *str );
+
+float *CG_FadeColor( int startMsec, int totalMsec );
+float *CG_TeamColor( int team );
+void CG_TileClear( void );
+void CG_ColorForHealth( vec4_t hcolor );
+void CG_GetColorForHealth( int health, int armor, vec4_t hcolor );
+
+void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color );
+void CG_DrawRect( float x, float y, float width, float height, float size, const float *color );
+void CG_DrawSides(float x, float y, float w, float h, float size);
+void CG_DrawTopBottom(float x, float y, float w, float h, float size);
+
+
+//
+// cg_draw.c, cg_newDraw.c
+//
+extern int sortedTeamPlayers[TEAM_MAXOVERLAY];
+extern int numSortedTeamPlayers;
+extern int drawTeamOverlayModificationCount;
+extern char systemChat[256];
+extern char teamChat1[256];
+extern char teamChat2[256];
+
+void CG_AddLagometerFrameInfo( void );
+void CG_AddLagometerSnapshotInfo( snapshot_t *snap );
+void CG_CenterPrint( const char *str, int y, int charWidth );
+void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles );
+void CG_DrawActive( stereoFrame_t stereoView );
+void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D );
+void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team );
+void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle);
+void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style);
+int CG_Text_Width(const char *text, float scale, int limit);
+int CG_Text_Height(const char *text, float scale, int limit);
+void CG_SelectPrevPlayer();
+void CG_SelectNextPlayer();
+float CG_GetValue(int ownerDraw);
+qboolean CG_OwnerDrawVisible(int flags);
+void CG_RunMenuScript(char **args);
+void CG_ShowResponseHead();
+void CG_SetPrintString(int type, const char *p);
+void CG_InitTeamChat();
+void CG_GetTeamColor(vec4_t *color);
+const char *CG_GetGameStatusText();
+const char *CG_GetKillerText();
+void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles );
+void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader);
+void CG_CheckOrderPending();
+const char *CG_GameTypeString();
+qboolean CG_YourTeamHasFlag();
+qboolean CG_OtherTeamHasFlag();
+qhandle_t CG_StatusHandle(int task);
+
+
+
+//
+// cg_player.c
+//
+void CG_Player( centity_t *cent );
+void CG_ResetPlayerEntity( centity_t *cent );
+void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team );
+void CG_NewClientInfo( int clientNum );
+sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
+
+//
+// cg_predict.c
+//
+void CG_BuildSolidList( void );
+int CG_PointContents( const vec3_t point, int passEntityNum );
+void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int skipNumber, int mask );
+void CG_PredictPlayerState( void );
+void CG_LoadDeferredPlayers( void );
+
+
+//
+// cg_events.c
+//
+void CG_CheckEvents( centity_t *cent );
+const char *CG_PlaceString( int rank );
+void CG_EntityEvent( centity_t *cent, vec3_t position );
+void CG_PainEvent( centity_t *cent, int health );
+
+
+//
+// cg_ents.c
+//
+void CG_SetEntitySoundPosition( centity_t *cent );
+void CG_AddPacketEntities( void );
+void CG_Beam( centity_t *cent );
+void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out );
+
+void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName );
+void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent,
+ qhandle_t parentModel, char *tagName );
+
+
+
+//
+// cg_weapons.c
+//
+void CG_NextWeapon_f( void );
+void CG_PrevWeapon_f( void );
+void CG_Weapon_f( void );
+
+void CG_RegisterWeapon( int weaponNum );
+void CG_RegisterItemVisuals( int itemNum );
+
+void CG_FireWeapon( centity_t *cent );
+void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType );
+void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum );
+void CG_ShotgunFire( entityState_t *es );
+void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
+
+void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );
+void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );
+void CG_AddViewWeapon (playerState_t *ps);
+void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );
+void CG_DrawWeaponSelect( void );
+
+void CG_OutOfAmmoChange( void ); // should this be in pmove?
+
+//
+// cg_marks.c
+//
+void CG_InitMarkPolys( void );
+void CG_AddMarks( void );
+void CG_ImpactMark( qhandle_t markShader,
+ const vec3_t origin, const vec3_t dir,
+ float orientation,
+ float r, float g, float b, float a,
+ qboolean alphaFade,
+ float radius, qboolean temporary );
+
+//
+// cg_localents.c
+//
+void CG_InitLocalEntities( void );
+localEntity_t *CG_AllocLocalEntity( void );
+void CG_AddLocalEntities( void );
+
+//
+// cg_effects.c
+//
+localEntity_t *CG_SmokePuff( const vec3_t p,
+ const vec3_t vel,
+ float radius,
+ float r, float g, float b, float a,
+ float duration,
+ int startTime,
+ int fadeInTime,
+ int leFlags,
+ qhandle_t hShader );
+void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing );
+void CG_SpawnEffect( vec3_t org );
+#ifdef MISSIONPACK
+void CG_KamikazeEffect( vec3_t org );
+void CG_ObeliskExplode( vec3_t org, int entityNum );
+void CG_ObeliskPain( vec3_t org );
+void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles );
+void CG_InvulnerabilityJuiced( vec3_t org );
+void CG_LightningBoltBeam( vec3_t start, vec3_t end );
+#endif
+void CG_ScorePlum( int client, vec3_t org, int score );
+
+void CG_GibPlayer( vec3_t playerOrigin );
+void CG_BigExplode( vec3_t playerOrigin );
+
+void CG_Bleed( vec3_t origin, int entityNum );
+
+localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
+ qhandle_t hModel, qhandle_t shader, int msec,
+ qboolean isSprite );
+
+//
+// cg_snapshot.c
+//
+void CG_ProcessSnapshots( void );
+
+//
+// cg_info.c
+//
+void CG_LoadingString( const char *s );
+void CG_LoadingItem( int itemNum );
+void CG_LoadingClient( int clientNum );
+void CG_DrawInformation( void );
+
+//
+// cg_scoreboard.c
+//
+qboolean CG_DrawOldScoreboard( void );
+void CG_DrawOldTourneyScoreboard( void );
+
+//
+// cg_consolecmds.c
+//
+qboolean CG_ConsoleCommand( void );
+void CG_InitConsoleCommands( void );
+
+//
+// cg_servercmds.c
+//
+void CG_ExecuteNewServerCommands( int latestSequence );
+void CG_ParseServerinfo( void );
+void CG_SetConfigValues( void );
+void CG_LoadVoiceChats( void );
+void CG_ShaderStateChanged(void);
+void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd );
+void CG_PlayBufferedVoiceChats( void );
+
+//
+// cg_playerstate.c
+//
+void CG_Respawn( void );
+void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
+void CG_CheckChangedPredictableEvents( playerState_t *ps );
+
+
+//===============================================
+
+//
+// system traps
+// These functions are how the cgame communicates with the main game system
+//
+
+// print message on the local console
+void trap_Print( const char *fmt );
+
+// abort the game
+void trap_Error( const char *fmt );
+
+// milliseconds should only be used for performance tuning, never
+// for anything game related. Get time from the CG_DrawActiveFrame parameter
+int trap_Milliseconds( void );
+
+// console variable interaction
+void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
+void trap_Cvar_Update( vmCvar_t *vmCvar );
+void trap_Cvar_Set( const char *var_name, const char *value );
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+
+// ServerCommand and ConsoleCommand parameter access
+int trap_Argc( void );
+void trap_Argv( int n, char *buffer, int bufferLength );
+void trap_Args( char *buffer, int bufferLength );
+
+// filesystem access
+// returns length of file
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
+void trap_FS_Read( void *buffer, int len, fileHandle_t f );
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
+void trap_FS_FCloseFile( fileHandle_t f );
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
+
+// add commands to the local console as if they were typed in
+// for map changing, etc. The command is not executed immediately,
+// but will be executed in order the next time console commands
+// are processed
+void trap_SendConsoleCommand( const char *text );
+
+// register a command name so the console can perform command completion.
+// FIXME: replace this with a normal console command "defineCommand"?
+void trap_AddCommand( const char *cmdName );
+
+// send a string to the server over the network
+void trap_SendClientCommand( const char *s );
+
+// force a screen update, only used during gamestate load
+void trap_UpdateScreen( void );
+
+// model collision
+void trap_CM_LoadMap( const char *mapname );
+int trap_CM_NumInlineModels( void );
+clipHandle_t trap_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels
+clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs );
+int trap_CM_PointContents( const vec3_t p, clipHandle_t model );
+int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
+void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask );
+void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles );
+
+// Returns the projection of a polygon onto the solid brushes in the world
+int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
+ const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer,
+ int maxFragments, markFragment_t *fragmentBuffer );
+
+// normal sounds will have their volume dynamically changed as their entity
+// moves and the listener moves
+void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
+void trap_S_StopLoopingSound(int entnum);
+
+// a local sound is always played full volume
+void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum );
+void trap_S_ClearLoopingSounds( qboolean killall );
+void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin );
+
+// respatialize recalculates the volumes of sound as they should be heard by the
+// given entityNum and position
+void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found
+void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music
+void trap_S_StopBackgroundTrack( void );
+
+
+void trap_R_LoadWorldMap( const char *mapname );
+
+// all media should be registered during level startup to prevent
+// hitches during gameplay
+qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found
+qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found
+qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found
+qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found
+
+// a scene is built up by calls to R_ClearScene and the various R_Add functions.
+// Nothing is drawn until R_RenderScene is called.
+void trap_R_ClearScene( void );
+void trap_R_AddRefEntityToScene( const refEntity_t *re );
+
+// polys are intended for simple wall marks, not really for doing
+// significant construction
+void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts );
+void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys );
+void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
+void trap_R_RenderScene( const refdef_t *fd );
+void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1
+void trap_R_DrawStretchPic( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader );
+void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs );
+int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
+ float frac, const char *tagName );
+void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset );
+
+// The glconfig_t will not change during the life of a cgame.
+// If it needs to change, the entire cgame will be restarted, because
+// all the qhandle_t are then invalid.
+void trap_GetGlconfig( glconfig_t *glconfig );
+
+// the gamestate should be grabbed at startup, and whenever a
+// configstring changes
+void trap_GetGameState( gameState_t *gamestate );
+
+// cgame will poll each frame to see if a newer snapshot has arrived
+// that it is interested in. The time is returned seperately so that
+// snapshot latency can be calculated.
+void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );
+
+// a snapshot get can fail if the snapshot (or the entties it holds) is so
+// old that it has fallen out of the client system queue
+qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot );
+
+// retrieve a text command from the server stream
+// the current snapshot will hold the number of the most recent command
+// qfalse can be returned if the client system handled the command
+// argc() / argv() can be used to examine the parameters of the command
+qboolean trap_GetServerCommand( int serverCommandNumber );
+
+// returns the most recent command number that can be passed to GetUserCmd
+// this will always be at least one higher than the number in the current
+// snapshot, and it may be quite a few higher if it is a fast computer on
+// a lagged connection
+int trap_GetCurrentCmdNumber( void );
+
+qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd );
+
+// used for the weapon select and zoom
+void trap_SetUserCmdValue( int stateValue, float sensitivityScale );
+
+// aids for VM testing
+void testPrintInt( char *string, int i );
+void testPrintFloat( char *string, float f );
+
+int trap_MemoryRemaining( void );
+void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
+qboolean trap_Key_IsDown( int keynum );
+int trap_Key_GetCatcher( void );
+void trap_Key_SetCatcher( int catcher );
+int trap_Key_GetKey( const char *binding );
+
+
+typedef enum {
+ SYSTEM_PRINT,
+ CHAT_PRINT,
+ TEAMCHAT_PRINT
+} q3print_t; // bk001201 - warning: useless keyword or type name in empty declaration
+
+
+int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits);
+e_status trap_CIN_StopCinematic(int handle);
+e_status trap_CIN_RunCinematic (int handle);
+void trap_CIN_DrawCinematic (int handle);
+void trap_CIN_SetExtents (int handle, int x, int y, int w, int h);
+
+void trap_SnapVector( float *v );
+
+qboolean trap_loadCamera(const char *name);
+void trap_startCamera(int time);
+qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
+
+qboolean trap_GetEntityToken( char *buffer, int bufferSize );
+
+void CG_ClearParticles (void);
+void CG_AddParticles (void);
+void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum);
+void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent);
+void CG_AddParticleShrapnel (localEntity_t *le);
+void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent);
+void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration);
+void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed);
+void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir);
+void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha);
+void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd);
+extern qboolean initparticles;
+int CG_NewParticleArea ( int num );
+
+
diff --git a/code/cgame/cg_localents.c b/code/cgame/cg_localents.c
index 534b147..b14df64 100755
--- a/code/cgame/cg_localents.c
+++ b/code/cgame/cg_localents.c
@@ -1,886 +1,886 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-// cg_localents.c -- every frame, generate renderer commands for locally
-// processed entities, like smoke puffs, gibs, shells, etc.
-
-#include "cg_local.h"
-
-#define MAX_LOCAL_ENTITIES 512
-localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
-localEntity_t cg_activeLocalEntities; // double linked list
-localEntity_t *cg_freeLocalEntities; // single linked list
-
-/*
-===================
-CG_InitLocalEntities
-
-This is called at startup and for tournement restarts
-===================
-*/
-void CG_InitLocalEntities( void ) {
- int i;
-
- memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
- cg_activeLocalEntities.next = &cg_activeLocalEntities;
- cg_activeLocalEntities.prev = &cg_activeLocalEntities;
- cg_freeLocalEntities = cg_localEntities;
- for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
- cg_localEntities[i].next = &cg_localEntities[i+1];
- }
-}
-
-
-/*
-==================
-CG_FreeLocalEntity
-==================
-*/
-void CG_FreeLocalEntity( localEntity_t *le ) {
- if ( !le->prev ) {
- CG_Error( "CG_FreeLocalEntity: not active" );
- }
-
- // remove from the doubly linked active list
- le->prev->next = le->next;
- le->next->prev = le->prev;
-
- // the free list is only singly linked
- le->next = cg_freeLocalEntities;
- cg_freeLocalEntities = le;
-}
-
-/*
-===================
-CG_AllocLocalEntity
-
-Will allways succeed, even if it requires freeing an old active entity
-===================
-*/
-localEntity_t *CG_AllocLocalEntity( void ) {
- localEntity_t *le;
-
- if ( !cg_freeLocalEntities ) {
- // no free entities, so free the one at the end of the chain
- // remove the oldest active entity
- CG_FreeLocalEntity( cg_activeLocalEntities.prev );
- }
-
- le = cg_freeLocalEntities;
- cg_freeLocalEntities = cg_freeLocalEntities->next;
-
- memset( le, 0, sizeof( *le ) );
-
- // link into the active list
- le->next = cg_activeLocalEntities.next;
- le->prev = &cg_activeLocalEntities;
- cg_activeLocalEntities.next->prev = le;
- cg_activeLocalEntities.next = le;
- return le;
-}
-
-
-/*
-====================================================================================
-
-FRAGMENT PROCESSING
-
-A fragment localentity interacts with the environment in some way (hitting walls),
-or generates more localentities along a trail.
-
-====================================================================================
-*/
-
-/*
-================
-CG_BloodTrail
-
-Leave expanding blood puffs behind gibs
-================
-*/
-void CG_BloodTrail( localEntity_t *le ) {
- int t;
- int t2;
- int step;
- vec3_t newOrigin;
- localEntity_t *blood;
-
- step = 150;
- t = step * ( (cg.time - cg.frametime + step ) / step );
- t2 = step * ( cg.time / step );
-
- for ( ; t <= t2; t += step ) {
- BG_EvaluateTrajectory( &le->pos, t, newOrigin );
-
- blood = CG_SmokePuff( newOrigin, vec3_origin,
- 20, // radius
- 1, 1, 1, 1, // color
- 2000, // trailTime
- t, // startTime
- 0, // fadeInTime
- 0, // flags
- cgs.media.bloodTrailShader );
- // use the optimized version
- blood->leType = LE_FALL_SCALE_FADE;
- // drop a total of 40 units over its lifetime
- blood->pos.trDelta[2] = 40;
- }
-}
-
-
-/*
-================
-CG_FragmentBounceMark
-================
-*/
-void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
- int radius;
-
- if ( le->leMarkType == LEMT_BLOOD ) {
-
- radius = 16 + (rand()&31);
- CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
- } else if ( le->leMarkType == LEMT_BURN ) {
-
- radius = 8 + (rand()&15);
- CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
- 1,1,1,1, qtrue, radius, qfalse );
- }
-
-
- // don't allow a fragment to make multiple marks, or they
- // pile up while settling
- le->leMarkType = LEMT_NONE;
-}
-
-/*
-================
-CG_FragmentBounceSound
-================
-*/
-void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- // half the gibs will make splat sounds
- if ( rand() & 1 ) {
- int r = rand()&3;
- sfxHandle_t s;
-
- if ( r == 0 ) {
- s = cgs.media.gibBounce1Sound;
- } else if ( r == 1 ) {
- s = cgs.media.gibBounce2Sound;
- } else {
- s = cgs.media.gibBounce3Sound;
- }
- trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
- }
- } else if ( le->leBounceSoundType == LEBS_BRASS ) {
-
- }
-
- // don't allow a fragment to make multiple bounce sounds,
- // or it gets too noisy as they settle
- le->leBounceSoundType = LEBS_NONE;
-}
-
-
-/*
-================
-CG_ReflectVelocity
-================
-*/
-void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
- vec3_t velocity;
- float dot;
- int hitTime;
-
- // reflect the velocity on the trace plane
- hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
- BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
- dot = DotProduct( velocity, trace->plane.normal );
- VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
-
- VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
-
- VectorCopy( trace->endpos, le->pos.trBase );
- le->pos.trTime = cg.time;
-
-
- // check for stop, making sure that even on low FPS systems it doesn't bobble
- if ( trace->allsolid ||
- ( trace->plane.normal[2] > 0 &&
- ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
- le->pos.trType = TR_STATIONARY;
- } else {
-
- }
-}
-
-/*
-================
-CG_AddFragment
-================
-*/
-void CG_AddFragment( localEntity_t *le ) {
- vec3_t newOrigin;
- trace_t trace;
-
- if ( le->pos.trType == TR_STATIONARY ) {
- // sink into the ground if near the removal time
- int t;
- float oldZ;
-
- t = le->endTime - cg.time;
- if ( t < SINK_TIME ) {
- // we must use an explicit lighting origin, otherwise the
- // lighting would be lost as soon as the origin went
- // into the ground
- VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
- le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
- oldZ = le->refEntity.origin[2];
- le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
- trap_R_AddRefEntityToScene( &le->refEntity );
- le->refEntity.origin[2] = oldZ;
- } else {
- trap_R_AddRefEntityToScene( &le->refEntity );
- }
-
- return;
- }
-
- // calculate new position
- BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
-
- // trace a line from previous position to new position
- CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
- if ( trace.fraction == 1.0 ) {
- // still in free fall
- VectorCopy( newOrigin, le->refEntity.origin );
-
- if ( le->leFlags & LEF_TUMBLE ) {
- vec3_t angles;
-
- BG_EvaluateTrajectory( &le->angles, cg.time, angles );
- AnglesToAxis( angles, le->refEntity.axis );
- }
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-
- // add a blood trail
- if ( le->leBounceSoundType == LEBS_BLOOD ) {
- CG_BloodTrail( le );
- }
-
- return;
- }
-
- // if it is in a nodrop zone, remove it
- // this keeps gibs from waiting at the bottom of pits of death
- // and floating levels
- if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- // leave a mark
- CG_FragmentBounceMark( le, &trace );
-
- // do a bouncy sound
- CG_FragmentBounceSound( le, &trace );
-
- // reflect the velocity on the trace plane
- CG_ReflectVelocity( le, &trace );
-
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-/*
-=====================================================================
-
-TRIVIAL LOCAL ENTITIES
-
-These only do simple scaling or modulation before passing to the renderer
-=====================================================================
-*/
-
-/*
-====================
-CG_AddFadeRGB
-====================
-*/
-void CG_AddFadeRGB( localEntity_t *le ) {
- refEntity_t *re;
- float c;
-
- re = &le->refEntity;
-
- c = ( le->endTime - cg.time ) * le->lifeRate;
- c *= 0xff;
-
- re->shaderRGBA[0] = le->color[0] * c;
- re->shaderRGBA[1] = le->color[1] * c;
- re->shaderRGBA[2] = le->color[2] * c;
- re->shaderRGBA[3] = le->color[3] * c;
-
- trap_R_AddRefEntityToScene( re );
-}
-
-/*
-==================
-CG_AddMoveScaleFade
-==================
-*/
-static void CG_AddMoveScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
- // fade / grow time
- c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
- }
- else {
- // fade / grow time
- c = ( le->endTime - cg.time ) * le->lifeRate;
- }
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
-
- if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
- re->radius = le->radius * ( 1.0 - c ) + 8;
- }
-
- BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-/*
-===================
-CG_AddScaleFade
-
-For rocket smokes that hang in place, fade out, and are
-removed if the view passes through them.
-There are often many of these, so it needs to be simple.
-===================
-*/
-static void CG_AddScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- // fade / grow time
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
- re->radius = le->radius * ( 1.0 - c ) + 8;
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-/*
-=================
-CG_AddFallScaleFade
-
-This is just an optimized CG_AddMoveScaleFade
-For blood mists that drift down, fade out, and are
-removed if the view passes through them.
-There are often 100+ of these, so it needs to be simple.
-=================
-*/
-static void CG_AddFallScaleFade( localEntity_t *le ) {
- refEntity_t *re;
- float c;
- vec3_t delta;
- float len;
-
- re = &le->refEntity;
-
- // fade time
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- re->shaderRGBA[3] = 0xff * c * le->color[3];
-
- re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];
-
- re->radius = le->radius * ( 1.0 - c ) + 16;
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( re->origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < le->radius ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- trap_R_AddRefEntityToScene( re );
-}
-
-
-
-/*
-================
-CG_AddExplosion
-================
-*/
-static void CG_AddExplosion( localEntity_t *ex ) {
- refEntity_t *ent;
-
- ent = &ex->refEntity;
-
- // add the entity
- trap_R_AddRefEntityToScene(ent);
-
- // add the dlight
- if ( ex->light ) {
- float light;
-
- light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
- if ( light < 0.5 ) {
- light = 1.0;
- } else {
- light = 1.0 - ( light - 0.5 ) * 2;
- }
- light = ex->light * light;
- trap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
- }
-}
-
-/*
-================
-CG_AddSpriteExplosion
-================
-*/
-static void CG_AddSpriteExplosion( localEntity_t *le ) {
- refEntity_t re;
- float c;
-
- re = le->refEntity;
-
- c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
- if ( c > 1 ) {
- c = 1.0; // can happen during connection problems
- }
-
- re.shaderRGBA[0] = 0xff;
- re.shaderRGBA[1] = 0xff;
- re.shaderRGBA[2] = 0xff;
- re.shaderRGBA[3] = 0xff * c * 0.33;
-
- re.reType = RT_SPRITE;
- re.radius = 42 * ( 1.0 - c ) + 30;
-
- trap_R_AddRefEntityToScene( &re );
-
- // add the dlight
- if ( le->light ) {
- float light;
-
- light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
- if ( light < 0.5 ) {
- light = 1.0;
- } else {
- light = 1.0 - ( light - 0.5 ) * 2;
- }
- light = le->light * light;
- trap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
- }
-}
-
-
-#ifdef MISSIONPACK
-/*
-====================
-CG_AddKamikaze
-====================
-*/
-void CG_AddKamikaze( localEntity_t *le ) {
- refEntity_t *re;
- refEntity_t shockwave;
- float c;
- vec3_t test, axis[3];
- int t;
-
- re = &le->refEntity;
-
- t = cg.time - le->startTime;
- VectorClear( test );
- AnglesToAxis( test, axis );
-
- if (t > KAMI_SHOCKWAVE_STARTTIME && t < KAMI_SHOCKWAVE_ENDTIME) {
-
- if (!(le->leFlags & LEF_SOUND1)) {
-// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeExplodeSound );
- trap_S_StartLocalSound(cgs.media.kamikazeExplodeSound, CHAN_AUTO);
- le->leFlags |= LEF_SOUND1;
- }
- // 1st kamikaze shockwave
- memset(&shockwave, 0, sizeof(shockwave));
- shockwave.hModel = cgs.media.kamikazeShockWave;
- shockwave.reType = RT_MODEL;
- shockwave.shaderTime = re->shaderTime;
- VectorCopy(re->origin, shockwave.origin);
-
- c = (float)(t - KAMI_SHOCKWAVE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME);
- VectorScale( axis[0], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
- VectorScale( axis[1], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
- VectorScale( axis[2], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
- shockwave.nonNormalizedAxes = qtrue;
-
- if (t > KAMI_SHOCKWAVEFADE_STARTTIME) {
- c = (float)(t - KAMI_SHOCKWAVEFADE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVEFADE_STARTTIME);
- }
- else {
- c = 0;
- }
- c *= 0xff;
- shockwave.shaderRGBA[0] = 0xff - c;
- shockwave.shaderRGBA[1] = 0xff - c;
- shockwave.shaderRGBA[2] = 0xff - c;
- shockwave.shaderRGBA[3] = 0xff - c;
-
- trap_R_AddRefEntityToScene( &shockwave );
- }
-
- if (t > KAMI_EXPLODE_STARTTIME && t < KAMI_IMPLODE_ENDTIME) {
- // explosion and implosion
- c = ( le->endTime - cg.time ) * le->lifeRate;
- c *= 0xff;
- re->shaderRGBA[0] = le->color[0] * c;
- re->shaderRGBA[1] = le->color[1] * c;
- re->shaderRGBA[2] = le->color[2] * c;
- re->shaderRGBA[3] = le->color[3] * c;
-
- if( t < KAMI_IMPLODE_STARTTIME ) {
- c = (float)(t - KAMI_EXPLODE_STARTTIME) / (float)(KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME);
- }
- else {
- if (!(le->leFlags & LEF_SOUND2)) {
-// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeImplodeSound );
- trap_S_StartLocalSound(cgs.media.kamikazeImplodeSound, CHAN_AUTO);
- le->leFlags |= LEF_SOUND2;
- }
- c = (float)(KAMI_IMPLODE_ENDTIME - t) / (float) (KAMI_IMPLODE_ENDTIME - KAMI_IMPLODE_STARTTIME);
- }
- VectorScale( axis[0], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[0] );
- VectorScale( axis[1], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[1] );
- VectorScale( axis[2], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[2] );
- re->nonNormalizedAxes = qtrue;
-
- trap_R_AddRefEntityToScene( re );
- // add the dlight
- trap_R_AddLightToScene( re->origin, c * 1000.0, 1.0, 1.0, c );
- }
-
- if (t > KAMI_SHOCKWAVE2_STARTTIME && t < KAMI_SHOCKWAVE2_ENDTIME) {
- // 2nd kamikaze shockwave
- if (le->angles.trBase[0] == 0 &&
- le->angles.trBase[1] == 0 &&
- le->angles.trBase[2] == 0) {
- le->angles.trBase[0] = random() * 360;
- le->angles.trBase[1] = random() * 360;
- le->angles.trBase[2] = random() * 360;
- }
- else {
- c = 0;
- }
- memset(&shockwave, 0, sizeof(shockwave));
- shockwave.hModel = cgs.media.kamikazeShockWave;
- shockwave.reType = RT_MODEL;
- shockwave.shaderTime = re->shaderTime;
- VectorCopy(re->origin, shockwave.origin);
-
- test[0] = le->angles.trBase[0];
- test[1] = le->angles.trBase[1];
- test[2] = le->angles.trBase[2];
- AnglesToAxis( test, axis );
-
- c = (float)(t - KAMI_SHOCKWAVE2_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2_STARTTIME);
- VectorScale( axis[0], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
- VectorScale( axis[1], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
- VectorScale( axis[2], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
- shockwave.nonNormalizedAxes = qtrue;
-
- if (t > KAMI_SHOCKWAVE2FADE_STARTTIME) {
- c = (float)(t - KAMI_SHOCKWAVE2FADE_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2FADE_STARTTIME);
- }
- else {
- c = 0;
- }
- c *= 0xff;
- shockwave.shaderRGBA[0] = 0xff - c;
- shockwave.shaderRGBA[1] = 0xff - c;
- shockwave.shaderRGBA[2] = 0xff - c;
- shockwave.shaderRGBA[3] = 0xff - c;
-
- trap_R_AddRefEntityToScene( &shockwave );
- }
-}
-
-/*
-===================
-CG_AddInvulnerabilityImpact
-===================
-*/
-void CG_AddInvulnerabilityImpact( localEntity_t *le ) {
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-/*
-===================
-CG_AddInvulnerabilityJuiced
-===================
-*/
-void CG_AddInvulnerabilityJuiced( localEntity_t *le ) {
- int t;
-
- t = cg.time - le->startTime;
- if ( t > 3000 ) {
- le->refEntity.axis[0][0] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
- le->refEntity.axis[1][1] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
- le->refEntity.axis[2][2] = (float) 0.7 + 0.3 * (2000 - (t - 3000)) / 2000;
- }
- if ( t > 5000 ) {
- le->endTime = 0;
- CG_GibPlayer( le->refEntity.origin );
- }
- else {
- trap_R_AddRefEntityToScene( &le->refEntity );
- }
-}
-
-/*
-===================
-CG_AddRefEntity
-===================
-*/
-void CG_AddRefEntity( localEntity_t *le ) {
- if (le->endTime < cg.time) {
- CG_FreeLocalEntity( le );
- return;
- }
- trap_R_AddRefEntityToScene( &le->refEntity );
-}
-
-#endif
-/*
-===================
-CG_AddScorePlum
-===================
-*/
-#define NUMBER_SIZE 8
-
-void CG_AddScorePlum( localEntity_t *le ) {
- refEntity_t *re;
- vec3_t origin, delta, dir, vec, up = {0, 0, 1};
- float c, len;
- int i, score, digits[10], numdigits, negative;
-
- re = &le->refEntity;
-
- c = ( le->endTime - cg.time ) * le->lifeRate;
-
- score = le->radius;
- if (score < 0) {
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0x11;
- re->shaderRGBA[2] = 0x11;
- }
- else {
- re->shaderRGBA[0] = 0xff;
- re->shaderRGBA[1] = 0xff;
- re->shaderRGBA[2] = 0xff;
- if (score >= 50) {
- re->shaderRGBA[1] = 0;
- } else if (score >= 20) {
- re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
- } else if (score >= 10) {
- re->shaderRGBA[2] = 0;
- } else if (score >= 2) {
- re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
- }
-
- }
- if (c < 0.25)
- re->shaderRGBA[3] = 0xff * 4 * c;
- else
- re->shaderRGBA[3] = 0xff;
-
- re->radius = NUMBER_SIZE / 2;
-
- VectorCopy(le->pos.trBase, origin);
- origin[2] += 110 - c * 100;
-
- VectorSubtract(cg.refdef.vieworg, origin, dir);
- CrossProduct(dir, up, vec);
- VectorNormalize(vec);
-
- VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
-
- // if the view would be "inside" the sprite, kill the sprite
- // so it doesn't add too much overdraw
- VectorSubtract( origin, cg.refdef.vieworg, delta );
- len = VectorLength( delta );
- if ( len < 20 ) {
- CG_FreeLocalEntity( le );
- return;
- }
-
- negative = qfalse;
- if (score < 0) {
- negative = qtrue;
- score = -score;
- }
-
- for (numdigits = 0; !(numdigits && !score); numdigits++) {
- digits[numdigits] = score % 10;
- score = score / 10;
- }
-
- if (negative) {
- digits[numdigits] = 10;
- numdigits++;
- }
-
- for (i = 0; i < numdigits; i++) {
- VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
- re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
- trap_R_AddRefEntityToScene( re );
- }
-}
-
-
-
-
-//==============================================================================
-
-/*
-===================
-CG_AddLocalEntities
-
-===================
-*/
-void CG_AddLocalEntities( void ) {
- localEntity_t *le, *next;
-
- // walk the list backwards, so any new local entities generated
- // (trails, marks, etc) will be present this frame
- le = cg_activeLocalEntities.prev;
- for ( ; le != &cg_activeLocalEntities ; le = next ) {
- // grab next now, so if the local entity is freed we
- // still have it
- next = le->prev;
-
- if ( cg.time >= le->endTime ) {
- CG_FreeLocalEntity( le );
- continue;
- }
- switch ( le->leType ) {
- default:
- CG_Error( "Bad leType: %i", le->leType );
- break;
-
- case LE_MARK:
- break;
-
- case LE_SPRITE_EXPLOSION:
- CG_AddSpriteExplosion( le );
- break;
-
- case LE_EXPLOSION:
- CG_AddExplosion( le );
- break;
-
- case LE_FRAGMENT: // gibs and brass
- CG_AddFragment( le );
- break;
-
- case LE_MOVE_SCALE_FADE: // water bubbles
- CG_AddMoveScaleFade( le );
- break;
-
- case LE_FADE_RGB: // teleporters, railtrails
- CG_AddFadeRGB( le );
- break;
-
- case LE_FALL_SCALE_FADE: // gib blood trails
- CG_AddFallScaleFade( le );
- break;
-
- case LE_SCALE_FADE: // rocket trails
- CG_AddScaleFade( le );
- break;
-
- case LE_SCOREPLUM:
- CG_AddScorePlum( le );
- break;
-
-#ifdef MISSIONPACK
- case LE_KAMIKAZE:
- CG_AddKamikaze( le );
- break;
- case LE_INVULIMPACT:
- CG_AddInvulnerabilityImpact( le );
- break;
- case LE_INVULJUICED:
- CG_AddInvulnerabilityJuiced( le );
- break;
- case LE_SHOWREFENTITY:
- CG_AddRefEntity( le );
- break;
-#endif
- }
- }
-}
-
-
-
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+// cg_localents.c -- every frame, generate renderer commands for locally
+// processed entities, like smoke puffs, gibs, shells, etc.
+
+#include "cg_local.h"
+
+#define MAX_LOCAL_ENTITIES 512
+localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
+localEntity_t cg_activeLocalEntities; // double linked list
+localEntity_t *cg_freeLocalEntities; // single linked list
+
+/*
+===================
+CG_InitLocalEntities
+
+This is called at startup and for tournement restarts
+===================
+*/
+void CG_InitLocalEntities( void ) {
+ int i;
+
+ memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
+ cg_activeLocalEntities.next = &cg_activeLocalEntities;
+ cg_activeLocalEntities.prev = &cg_activeLocalEntities;
+ cg_freeLocalEntities = cg_localEntities;
+ for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
+ cg_localEntities[i].next = &cg_localEntities[i+1];
+ }
+}
+
+
+/*
+==================
+CG_FreeLocalEntity
+==================
+*/
+void CG_FreeLocalEntity( localEntity_t *le ) {
+ if ( !le->prev ) {
+ CG_Error( "CG_FreeLocalEntity: not active" );
+ }
+
+ // remove from the doubly linked active list
+ le->prev->next = le->next;
+ le->next->prev = le->prev;
+
+ // the free list is only singly linked
+ le->next = cg_freeLocalEntities;
+ cg_freeLocalEntities = le;
+}
+
+/*
+===================
+CG_AllocLocalEntity
+
+Will allways succeed, even if it requires freeing an old active entity
+===================
+*/
+localEntity_t *CG_AllocLocalEntity( void ) {
+ localEntity_t *le;
+
+ if ( !cg_freeLocalEntities ) {
+ // no free entities, so free the one at the end of the chain
+ // remove the oldest active entity
+ CG_FreeLocalEntity( cg_activeLocalEntities.prev );
+ }
+
+ le = cg_freeLocalEntities;
+ cg_freeLocalEntities = cg_freeLocalEntities->next;
+
+ memset( le, 0, sizeof( *le ) );
+
+ // link into the active list
+ le->next = cg_activeLocalEntities.next;
+ le->prev = &cg_activeLocalEntities;
+ cg_activeLocalEntities.next->prev = le;
+ cg_activeLocalEntities.next = le;
+ return le;
+}
+
+
+/*
+====================================================================================
+
+FRAGMENT PROCESSING
+
+A fragment localentity interacts with the environment in some way (hitting walls),
+or generates more localentities along a trail.
+
+====================================================================================
+*/
+
+/*
+================
+CG_BloodTrail
+
+Leave expanding blood puffs behind gibs
+================
+*/
+void CG_BloodTrail( localEntity_t *le ) {
+ int t;
+ int t2;
+ int step;
+ vec3_t newOrigin;
+ localEntity_t *blood;
+
+ step = 150;
+ t = step * ( (cg.time - cg.frametime + step ) / step );
+ t2 = step * ( cg.time / step );
+
+ for ( ; t <= t2; t += step ) {
+ BG_EvaluateTrajectory( &le->pos, t, newOrigin );
+
+ blood = CG_SmokePuff( newOrigin, vec3_origin,
+ 20, // radius
+ 1, 1, 1, 1, // color
+ 2000, // trailTime
+ t, // startTime
+ 0, // fadeInTime
+ 0, // flags
+ cgs.media.bloodTrailShader );
+ // use the optimized version
+ blood->leType = LE_FALL_SCALE_FADE;
+ // drop a total of 40 units over its lifetime
+ blood->pos.trDelta[2] = 40;
+ }
+}
+
+
+/*
+================
+CG_FragmentBounceMark
+================
+*/
+void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
+ int radius;
+
+ if ( le->leMarkType == LEMT_BLOOD ) {
+
+ radius = 16 + (rand()&31);
+ CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
+ 1,1,1,1, qtrue, radius, qfalse );
+ } else if ( le->leMarkType == LEMT_BURN ) {
+
+ radius = 8 + (rand()&15);
+ CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
+ 1,1,1,1, qtrue, radius, qfalse );
+ }
+
+
+ // don't allow a fragment to make multiple marks, or they
+ // pile up while settling
+ le->leMarkType = LEMT_NONE;
+}
+
+/*
+================
+CG_FragmentBounceSound
+================
+*/
+void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
+ if ( le->leBounceSoundType == LEBS_BLOOD ) {
+ // half the gibs will make splat sounds
+ if ( rand() & 1 ) {
+ int r = rand()&3;
+ sfxHandle_t s;
+
+ if ( r == 0 ) {
+ s = cgs.media.gibBounce1Sound;
+ } else if ( r == 1 ) {
+ s = cgs.media.gibBounce2Sound;
+ } else {
+ s = cgs.media.gibBounce3Sound;
+ }
+ trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s );
+ }
+ } else if ( le->leBounceSoundType == LEBS_BRASS ) {
+
+ }
+
+ // don't allow a fragment to make multiple bounce sounds,
+ // or it gets too noisy as they settle
+ le->leBounceSoundType = LEBS_NONE;
+}
+
+
+/*
+================
+CG_ReflectVelocity
+================
+*/
+void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
+ vec3_t velocity;
+ float dot;
+ int hitTime;
+
+ // reflect the velocity on the trace plane
+ hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
+ BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
+ dot = DotProduct( velocity, trace->plane.normal );
+ VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
+
+ VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
+
+ VectorCopy( trace->endpos, le->pos.trBase );
+ le->pos.trTime = cg.time;
+
+
+ // check for stop, making sure that even on low FPS systems it doesn't bobble
+ if ( trace->allsolid ||
+ ( trace->plane.normal[2] > 0 &&
+ ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
+ le->pos.trType = TR_STATIONARY;
+ } else {
+
+ }
+}
+
+/*
+================
+CG_AddFragment
+================
+*/
+void CG_AddFragment( localEntity_t *le ) {
+ vec3_t newOrigin;
+ trace_t trace;
+
+ if ( le->pos.trType == TR_STATIONARY ) {
+ // sink into the ground if near the removal time
+ int t;
+ float oldZ;
+
+ t = le->endTime - cg.time;
+ if ( t < SINK_TIME ) {
+ // we must use an explicit lighting origin, otherwise the
+ // lighting would be lost as soon as the origin went
+ // into the ground
+ VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
+ le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
+ oldZ = le->refEntity.origin[2];
+ le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
+ trap_R_AddRefEntityToScene( &le->refEntity );
+ le->refEntity.origin[2] = oldZ;
+ } else {
+ trap_R_AddRefEntityToScene( &le->refEntity );
+ }
+
+ return;
+ }
+
+ // calculate new position
+ BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
+
+ // trace a line from previous position to new position
+ CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
+ if ( trace.fraction == 1.0 ) {
+ // still in free fall
+ VectorCopy( newOrigin, le->refEntity.origin );
+
+ if ( le->leFlags & LEF_TUMBLE ) {
+ vec3_t angles;
+
+ BG_EvaluateTrajectory( &le->angles, cg.time, angles );
+ AnglesToAxis( angles, le->refEntity.axis );
+ }
+
+ trap_R_AddRefEntityToScene( &le->refEntity );
+
+ // add a blood trail
+ if ( le->leBounceSoundType == LEBS_BLOOD ) {
+ CG_BloodTrail( le );
+ }
+
+ return;
+ }
+
+ // if it is in a nodrop zone, remove it
+ // this keeps gibs from waiting at the bottom of pits of death
+ // and floating levels
+ if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ // leave a mark
+ CG_FragmentBounceMark( le, &trace );
+
+ // do a bouncy sound
+ CG_FragmentBounceSound( le, &trace );
+
+ // reflect the velocity on the trace plane
+ CG_ReflectVelocity( le, &trace );
+
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+/*
+=====================================================================
+
+TRIVIAL LOCAL ENTITIES
+
+These only do simple scaling or modulation before passing to the renderer
+=====================================================================
+*/
+
+/*
+====================
+CG_AddFadeRGB
+====================
+*/
+void CG_AddFadeRGB( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+
+ re = &le->refEntity;
+
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+ c *= 0xff;
+
+ re->shaderRGBA[0] = le->color[0] * c;
+ re->shaderRGBA[1] = le->color[1] * c;
+ re->shaderRGBA[2] = le->color[2] * c;
+ re->shaderRGBA[3] = le->color[3] * c;
+
+ trap_R_AddRefEntityToScene( re );
+}
+
+/*
+==================
+CG_AddMoveScaleFade
+==================
+*/
+static void CG_AddMoveScaleFade( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+ vec3_t delta;
+ float len;
+
+ re = &le->refEntity;
+
+ if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
+ // fade / grow time
+ c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
+ }
+ else {
+ // fade / grow time
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+ }
+
+ re->shaderRGBA[3] = 0xff * c * le->color[3];
+
+ if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
+ re->radius = le->radius * ( 1.0 - c ) + 8;
+ }
+
+ BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( re->origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ if ( len < le->radius ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ trap_R_AddRefEntityToScene( re );
+}
+
+
+/*
+===================
+CG_AddScaleFade
+
+For rocket smokes that hang in place, fade out, and are
+removed if the view passes through them.
+There are often many of these, so it needs to be simple.
+===================
+*/
+static void CG_AddScaleFade( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+ vec3_t delta;
+ float len;
+
+ re = &le->refEntity;
+
+ // fade / grow time
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+
+ re->shaderRGBA[3] = 0xff * c * le->color[3];
+ re->radius = le->radius * ( 1.0 - c ) + 8;
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( re->origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ if ( len < le->radius ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ trap_R_AddRefEntityToScene( re );
+}
+
+
+/*
+=================
+CG_AddFallScaleFade
+
+This is just an optimized CG_AddMoveScaleFade
+For blood mists that drift down, fade out, and are
+removed if the view passes through them.
+There are often 100+ of these, so it needs to be simple.
+=================
+*/
+static void CG_AddFallScaleFade( localEntity_t *le ) {
+ refEntity_t *re;
+ float c;
+ vec3_t delta;
+ float len;
+
+ re = &le->refEntity;
+
+ // fade time
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+
+ re->shaderRGBA[3] = 0xff * c * le->color[3];
+
+ re->origin[2] = le->pos.trBase[2] - ( 1.0 - c ) * le->pos.trDelta[2];
+
+ re->radius = le->radius * ( 1.0 - c ) + 16;
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( re->origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ if ( len < le->radius ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ trap_R_AddRefEntityToScene( re );
+}
+
+
+
+/*
+================
+CG_AddExplosion
+================
+*/
+static void CG_AddExplosion( localEntity_t *ex ) {
+ refEntity_t *ent;
+
+ ent = &ex->refEntity;
+
+ // add the entity
+ trap_R_AddRefEntityToScene(ent);
+
+ // add the dlight
+ if ( ex->light ) {
+ float light;
+
+ light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
+ if ( light < 0.5 ) {
+ light = 1.0;
+ } else {
+ light = 1.0 - ( light - 0.5 ) * 2;
+ }
+ light = ex->light * light;
+ trap_R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
+ }
+}
+
+/*
+================
+CG_AddSpriteExplosion
+================
+*/
+static void CG_AddSpriteExplosion( localEntity_t *le ) {
+ refEntity_t re;
+ float c;
+
+ re = le->refEntity;
+
+ c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
+ if ( c > 1 ) {
+ c = 1.0; // can happen during connection problems
+ }
+
+ re.shaderRGBA[0] = 0xff;
+ re.shaderRGBA[1] = 0xff;
+ re.shaderRGBA[2] = 0xff;
+ re.shaderRGBA[3] = 0xff * c * 0.33;
+
+ re.reType = RT_SPRITE;
+ re.radius = 42 * ( 1.0 - c ) + 30;
+
+ trap_R_AddRefEntityToScene( &re );
+
+ // add the dlight
+ if ( le->light ) {
+ float light;
+
+ light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
+ if ( light < 0.5 ) {
+ light = 1.0;
+ } else {
+ light = 1.0 - ( light - 0.5 ) * 2;
+ }
+ light = le->light * light;
+ trap_R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
+ }
+}
+
+
+#ifdef MISSIONPACK
+/*
+====================
+CG_AddKamikaze
+====================
+*/
+void CG_AddKamikaze( localEntity_t *le ) {
+ refEntity_t *re;
+ refEntity_t shockwave;
+ float c;
+ vec3_t test, axis[3];
+ int t;
+
+ re = &le->refEntity;
+
+ t = cg.time - le->startTime;
+ VectorClear( test );
+ AnglesToAxis( test, axis );
+
+ if (t > KAMI_SHOCKWAVE_STARTTIME && t < KAMI_SHOCKWAVE_ENDTIME) {
+
+ if (!(le->leFlags & LEF_SOUND1)) {
+// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeExplodeSound );
+ trap_S_StartLocalSound(cgs.media.kamikazeExplodeSound, CHAN_AUTO);
+ le->leFlags |= LEF_SOUND1;
+ }
+ // 1st kamikaze shockwave
+ memset(&shockwave, 0, sizeof(shockwave));
+ shockwave.hModel = cgs.media.kamikazeShockWave;
+ shockwave.reType = RT_MODEL;
+ shockwave.shaderTime = re->shaderTime;
+ VectorCopy(re->origin, shockwave.origin);
+
+ c = (float)(t - KAMI_SHOCKWAVE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME);
+ VectorScale( axis[0], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
+ VectorScale( axis[1], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
+ VectorScale( axis[2], c * KAMI_SHOCKWAVE_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
+ shockwave.nonNormalizedAxes = qtrue;
+
+ if (t > KAMI_SHOCKWAVEFADE_STARTTIME) {
+ c = (float)(t - KAMI_SHOCKWAVEFADE_STARTTIME) / (float)(KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVEFADE_STARTTIME);
+ }
+ else {
+ c = 0;
+ }
+ c *= 0xff;
+ shockwave.shaderRGBA[0] = 0xff - c;
+ shockwave.shaderRGBA[1] = 0xff - c;
+ shockwave.shaderRGBA[2] = 0xff - c;
+ shockwave.shaderRGBA[3] = 0xff - c;
+
+ trap_R_AddRefEntityToScene( &shockwave );
+ }
+
+ if (t > KAMI_EXPLODE_STARTTIME && t < KAMI_IMPLODE_ENDTIME) {
+ // explosion and implosion
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+ c *= 0xff;
+ re->shaderRGBA[0] = le->color[0] * c;
+ re->shaderRGBA[1] = le->color[1] * c;
+ re->shaderRGBA[2] = le->color[2] * c;
+ re->shaderRGBA[3] = le->color[3] * c;
+
+ if( t < KAMI_IMPLODE_STARTTIME ) {
+ c = (float)(t - KAMI_EXPLODE_STARTTIME) / (float)(KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME);
+ }
+ else {
+ if (!(le->leFlags & LEF_SOUND2)) {
+// trap_S_StartSound (re->origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.kamikazeImplodeSound );
+ trap_S_StartLocalSound(cgs.media.kamikazeImplodeSound, CHAN_AUTO);
+ le->leFlags |= LEF_SOUND2;
+ }
+ c = (float)(KAMI_IMPLODE_ENDTIME - t) / (float) (KAMI_IMPLODE_ENDTIME - KAMI_IMPLODE_STARTTIME);
+ }
+ VectorScale( axis[0], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[0] );
+ VectorScale( axis[1], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[1] );
+ VectorScale( axis[2], c * KAMI_BOOMSPHERE_MAXRADIUS / KAMI_BOOMSPHEREMODEL_RADIUS, re->axis[2] );
+ re->nonNormalizedAxes = qtrue;
+
+ trap_R_AddRefEntityToScene( re );
+ // add the dlight
+ trap_R_AddLightToScene( re->origin, c * 1000.0, 1.0, 1.0, c );
+ }
+
+ if (t > KAMI_SHOCKWAVE2_STARTTIME && t < KAMI_SHOCKWAVE2_ENDTIME) {
+ // 2nd kamikaze shockwave
+ if (le->angles.trBase[0] == 0 &&
+ le->angles.trBase[1] == 0 &&
+ le->angles.trBase[2] == 0) {
+ le->angles.trBase[0] = random() * 360;
+ le->angles.trBase[1] = random() * 360;
+ le->angles.trBase[2] = random() * 360;
+ }
+ else {
+ c = 0;
+ }
+ memset(&shockwave, 0, sizeof(shockwave));
+ shockwave.hModel = cgs.media.kamikazeShockWave;
+ shockwave.reType = RT_MODEL;
+ shockwave.shaderTime = re->shaderTime;
+ VectorCopy(re->origin, shockwave.origin);
+
+ test[0] = le->angles.trBase[0];
+ test[1] = le->angles.trBase[1];
+ test[2] = le->angles.trBase[2];
+ AnglesToAxis( test, axis );
+
+ c = (float)(t - KAMI_SHOCKWAVE2_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2_STARTTIME);
+ VectorScale( axis[0], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[0] );
+ VectorScale( axis[1], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[1] );
+ VectorScale( axis[2], c * KAMI_SHOCKWAVE2_MAXRADIUS / KAMI_SHOCKWAVEMODEL_RADIUS, shockwave.axis[2] );
+ shockwave.nonNormalizedAxes = qtrue;
+
+ if (t > KAMI_SHOCKWAVE2FADE_STARTTIME) {
+ c = (float)(t - KAMI_SHOCKWAVE2FADE_STARTTIME) / (float)(KAMI_SHOCKWAVE2_ENDTIME - KAMI_SHOCKWAVE2FADE_STARTTIME);
+ }
+ else {
+ c = 0;
+ }
+ c *= 0xff;
+ shockwave.shaderRGBA[0] = 0xff - c;
+ shockwave.shaderRGBA[1] = 0xff - c;
+ shockwave.shaderRGBA[2] = 0xff - c;
+ shockwave.shaderRGBA[3] = 0xff - c;
+
+ trap_R_AddRefEntityToScene( &shockwave );
+ }
+}
+
+/*
+===================
+CG_AddInvulnerabilityImpact
+===================
+*/
+void CG_AddInvulnerabilityImpact( localEntity_t *le ) {
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+/*
+===================
+CG_AddInvulnerabilityJuiced
+===================
+*/
+void CG_AddInvulnerabilityJuiced( localEntity_t *le ) {
+ int t;
+
+ t = cg.time - le->startTime;
+ if ( t > 3000 ) {
+ le->refEntity.axis[0][0] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
+ le->refEntity.axis[1][1] = (float) 1.0 + 0.3 * (t - 3000) / 2000;
+ le->refEntity.axis[2][2] = (float) 0.7 + 0.3 * (2000 - (t - 3000)) / 2000;
+ }
+ if ( t > 5000 ) {
+ le->endTime = 0;
+ CG_GibPlayer( le->refEntity.origin );
+ }
+ else {
+ trap_R_AddRefEntityToScene( &le->refEntity );
+ }
+}
+
+/*
+===================
+CG_AddRefEntity
+===================
+*/
+void CG_AddRefEntity( localEntity_t *le ) {
+ if (le->endTime < cg.time) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+ trap_R_AddRefEntityToScene( &le->refEntity );
+}
+
+#endif
+/*
+===================
+CG_AddScorePlum
+===================
+*/
+#define NUMBER_SIZE 8
+
+void CG_AddScorePlum( localEntity_t *le ) {
+ refEntity_t *re;
+ vec3_t origin, delta, dir, vec, up = {0, 0, 1};
+ float c, len;
+ int i, score, digits[10], numdigits, negative;
+
+ re = &le->refEntity;
+
+ c = ( le->endTime - cg.time ) * le->lifeRate;
+
+ score = le->radius;
+ if (score < 0) {
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0x11;
+ re->shaderRGBA[2] = 0x11;
+ }
+ else {
+ re->shaderRGBA[0] = 0xff;
+ re->shaderRGBA[1] = 0xff;
+ re->shaderRGBA[2] = 0xff;
+ if (score >= 50) {
+ re->shaderRGBA[1] = 0;
+ } else if (score >= 20) {
+ re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
+ } else if (score >= 10) {
+ re->shaderRGBA[2] = 0;
+ } else if (score >= 2) {
+ re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
+ }
+
+ }
+ if (c < 0.25)
+ re->shaderRGBA[3] = 0xff * 4 * c;
+ else
+ re->shaderRGBA[3] = 0xff;
+
+ re->radius = NUMBER_SIZE / 2;
+
+ VectorCopy(le->pos.trBase, origin);
+ origin[2] += 110 - c * 100;
+
+ VectorSubtract(cg.refdef.vieworg, origin, dir);
+ CrossProduct(dir, up, vec);
+ VectorNormalize(vec);
+
+ VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
+
+ // if the view would be "inside" the sprite, kill the sprite
+ // so it doesn't add too much overdraw
+ VectorSubtract( origin, cg.refdef.vieworg, delta );
+ len = VectorLength( delta );
+ if ( len < 20 ) {
+ CG_FreeLocalEntity( le );
+ return;
+ }
+
+ negative = qfalse;
+ if (score < 0) {
+ negative = qtrue;
+ score = -score;
+ }
+
+ for (numdigits = 0; !(numdigits && !score); numdigits++) {
+ digits[numdigits] = score % 10;
+ score = score / 10;
+ }
+
+ if (negative) {
+ digits[numdigits] = 10;
+ numdigits++;
+ }
+
+ for (i = 0; i < numdigits; i++) {
+ VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
+ re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
+ trap_R_AddRefEntityToScene( re );
+ }
+}
+
+
+
+
+//==============================================================================
+
+/*
+===================
+CG_AddLocalEntities
+
+===================
+*/
+void CG_AddLocalEntities( void ) {
+ localEntity_t *le, *next;
+
+ // walk the list backwards, so any new local entities generated
+ // (trails, marks, etc) will be present this frame
+ le = cg_activeLocalEntities.prev;
+ for ( ; le != &cg_activeLocalEntities ; le = next ) {
+ // grab next now, so if the local entity is freed we
+ // still have it
+ next = le->prev;
+
+ if ( cg.time >= le->endTime ) {
+ CG_FreeLocalEntity( le );
+ continue;
+ }
+ switch ( le->leType ) {
+ default:
+ CG_Error( "Bad leType: %i", le->leType );
+ break;
+
+ case LE_MARK:
+ break;
+
+ case LE_SPRITE_EXPLOSION:
+ CG_AddSpriteExplosion( le );
+ break;
+
+ case LE_EXPLOSION:
+ CG_AddExplosion( le );
+ break;
+
+ case LE_FRAGMENT: // gibs and brass
+ CG_AddFragment( le );
+ break;
+
+ case LE_MOVE_SCALE_FADE: // water bubbles
+ CG_AddMoveScaleFade( le );
+ break;
+
+ case LE_FADE_RGB: // teleporters, railtrails
+ CG_AddFadeRGB( le );
+ break;
+
+ case LE_FALL_SCALE_FADE: // gib blood trails
+ CG_AddFallScaleFade( le );
+ break;
+
+ case LE_SCALE_FADE: // rocket trails
+ CG_AddScaleFade( le );
+ break;
+
+ case LE_SCOREPLUM:
+ CG_AddScorePlum( le );
+ break;
+
+#ifdef MISSIONPACK
+ case LE_KAMIKAZE:
+ CG_AddKamikaze( le );
+ break;
+ case LE_INVULIMPACT:
+ CG_AddInvulnerabilityImpact( le );
+ break;
+ case LE_INVULJUICED:
+ CG_AddInvulnerabilityJuiced( le );
+ break;
+ case LE_SHOWREFENTITY:
+ CG_AddRefEntity( le );
+ break;
+#endif
+ }
+ }
+}
+
+
+
+
diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c
index aa9ec27..7212996 100755
--- a/code/cgame/cg_main.c
+++ b/code/cgame/cg_main.c
@@ -1,1997 +1,1997 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_main.c -- initialization and primary entry point for cgame
-#include "cg_local.h"
-
-#ifdef MISSIONPACK
-#include "../ui/ui_shared.h"
-// display context for new ui stuff
-displayContextDef_t cgDC;
-#endif
-
-int forceModelModificationCount = -1;
-
-void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
-void CG_Shutdown( void );
-
-
-/*
-================
-vmMain
-
-This is the only way control passes into the module.
-This must be the very first function compiled into the .q3vm file
-================
-*/
-int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
-
- switch ( command ) {
- case CG_INIT:
- CG_Init( arg0, arg1, arg2 );
- return 0;
- case CG_SHUTDOWN:
- CG_Shutdown();
- return 0;
- case CG_CONSOLE_COMMAND:
- return CG_ConsoleCommand();
- case CG_DRAW_ACTIVE_FRAME:
- CG_DrawActiveFrame( arg0, arg1, arg2 );
- return 0;
- case CG_CROSSHAIR_PLAYER:
- return CG_CrosshairPlayer();
- case CG_LAST_ATTACKER:
- return CG_LastAttacker();
- case CG_KEY_EVENT:
- CG_KeyEvent(arg0, arg1);
- return 0;
- case CG_MOUSE_EVENT:
-#ifdef MISSIONPACK
- cgDC.cursorx = cgs.cursorX;
- cgDC.cursory = cgs.cursorY;
-#endif
- CG_MouseEvent(arg0, arg1);
- return 0;
- case CG_EVENT_HANDLING:
- CG_EventHandling(arg0);
- return 0;
- default:
- CG_Error( "vmMain: unknown command %i", command );
- break;
- }
- return -1;
-}
-
-
-cg_t cg;
-cgs_t cgs;
-centity_t cg_entities[MAX_GENTITIES];
-weaponInfo_t cg_weapons[MAX_WEAPONS];
-itemInfo_t cg_items[MAX_ITEMS];
-
-
-vmCvar_t cg_railTrailTime;
-vmCvar_t cg_centertime;
-vmCvar_t cg_runpitch;
-vmCvar_t cg_runroll;
-vmCvar_t cg_bobup;
-vmCvar_t cg_bobpitch;
-vmCvar_t cg_bobroll;
-vmCvar_t cg_swingSpeed;
-vmCvar_t cg_shadows;
-vmCvar_t cg_gibs;
-vmCvar_t cg_drawTimer;
-vmCvar_t cg_drawFPS;
-vmCvar_t cg_drawSnapshot;
-vmCvar_t cg_draw3dIcons;
-vmCvar_t cg_drawIcons;
-vmCvar_t cg_drawAmmoWarning;
-vmCvar_t cg_drawCrosshair;
-vmCvar_t cg_drawCrosshairNames;
-vmCvar_t cg_drawRewards;
-vmCvar_t cg_crosshairSize;
-vmCvar_t cg_crosshairX;
-vmCvar_t cg_crosshairY;
-vmCvar_t cg_crosshairHealth;
-vmCvar_t cg_draw2D;
-vmCvar_t cg_drawStatus;
-vmCvar_t cg_animSpeed;
-vmCvar_t cg_debugAnim;
-vmCvar_t cg_debugPosition;
-vmCvar_t cg_debugEvents;
-vmCvar_t cg_errorDecay;
-vmCvar_t cg_nopredict;
-vmCvar_t cg_noPlayerAnims;
-vmCvar_t cg_showmiss;
-vmCvar_t cg_footsteps;
-vmCvar_t cg_addMarks;
-vmCvar_t cg_brassTime;
-vmCvar_t cg_viewsize;
-vmCvar_t cg_drawGun;
-vmCvar_t cg_gun_frame;
-vmCvar_t cg_gun_x;
-vmCvar_t cg_gun_y;
-vmCvar_t cg_gun_z;
-vmCvar_t cg_tracerChance;
-vmCvar_t cg_tracerWidth;
-vmCvar_t cg_tracerLength;
-vmCvar_t cg_autoswitch;
-vmCvar_t cg_ignore;
-vmCvar_t cg_simpleItems;
-vmCvar_t cg_fov;
-vmCvar_t cg_zoomFov;
-vmCvar_t cg_thirdPerson;
-vmCvar_t cg_thirdPersonRange;
-vmCvar_t cg_thirdPersonAngle;
-vmCvar_t cg_stereoSeparation;
-vmCvar_t cg_lagometer;
-vmCvar_t cg_drawAttacker;
-vmCvar_t cg_synchronousClients;
-vmCvar_t cg_teamChatTime;
-vmCvar_t cg_teamChatHeight;
-vmCvar_t cg_stats;
-vmCvar_t cg_buildScript;
-vmCvar_t cg_forceModel;
-vmCvar_t cg_paused;
-vmCvar_t cg_blood;
-vmCvar_t cg_predictItems;
-vmCvar_t cg_deferPlayers;
-vmCvar_t cg_drawTeamOverlay;
-vmCvar_t cg_teamOverlayUserinfo;
-vmCvar_t cg_drawFriend;
-vmCvar_t cg_teamChatsOnly;
-vmCvar_t cg_noVoiceChats;
-vmCvar_t cg_noVoiceText;
-vmCvar_t cg_hudFiles;
-vmCvar_t cg_scorePlum;
-vmCvar_t cg_smoothClients;
-vmCvar_t pmove_fixed;
-//vmCvar_t cg_pmove_fixed;
-vmCvar_t pmove_msec;
-vmCvar_t cg_pmove_msec;
-vmCvar_t cg_cameraMode;
-vmCvar_t cg_cameraOrbit;
-vmCvar_t cg_cameraOrbitDelay;
-vmCvar_t cg_timescaleFadeEnd;
-vmCvar_t cg_timescaleFadeSpeed;
-vmCvar_t cg_timescale;
-vmCvar_t cg_smallFont;
-vmCvar_t cg_bigFont;
-vmCvar_t cg_noTaunt;
-vmCvar_t cg_noProjectileTrail;
-vmCvar_t cg_oldRail;
-vmCvar_t cg_oldRocket;
-vmCvar_t cg_oldPlasma;
-vmCvar_t cg_trueLightning;
-
-#ifdef MISSIONPACK
-vmCvar_t cg_redTeamName;
-vmCvar_t cg_blueTeamName;
-vmCvar_t cg_currentSelectedPlayer;
-vmCvar_t cg_currentSelectedPlayerName;
-vmCvar_t cg_singlePlayer;
-vmCvar_t cg_enableDust;
-vmCvar_t cg_enableBreath;
-vmCvar_t cg_singlePlayerActive;
-vmCvar_t cg_recordSPDemo;
-vmCvar_t cg_recordSPDemoName;
-vmCvar_t cg_obeliskRespawnDelay;
-#endif
-
-typedef struct {
- vmCvar_t *vmCvar;
- char *cvarName;
- char *defaultString;
- int cvarFlags;
-} cvarTable_t;
-
-static cvarTable_t cvarTable[] = { // bk001129
- { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging
- { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
- { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
- { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE },
- { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE },
- { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
- { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE },
- { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
- { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE },
- { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
- { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
- { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE },
- { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
- { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
- { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
- { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
- { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
- { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE },
- { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
- { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
- { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE },
- { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
- { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE },
- { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
- { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
- { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
- { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
- { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
- { &cg_lagometer, "cg_lagometer", "1", CVAR_ARCHIVE },
- { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE },
- { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
- { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
- { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
- { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
- { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
- { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
- { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
- { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
- { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
- { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
- { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
- { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
- { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
- { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
- { &cg_errorDecay, "cg_errordecay", "100", 0 },
- { &cg_nopredict, "cg_nopredict", "0", 0 },
- { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
- { &cg_showmiss, "cg_showmiss", "0", 0 },
- { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
- { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT },
- { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT },
- { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT },
- { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT },
- { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
- { &cg_thirdPerson, "cg_thirdPerson", "0", 0 },
- { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE },
- { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE },
- { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
- { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
-#ifdef MISSIONPACK
- { &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE },
-#else
- { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
-#endif
- { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE },
- { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO },
- { &cg_stats, "cg_stats", "0", 0 },
- { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
- { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
- { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE },
- { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
- // the following variables are created in other parts of the system,
- // but we also reference them here
- { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
- { &cg_paused, "cl_paused", "0", CVAR_ROM },
- { &cg_blood, "com_blood", "1", CVAR_ARCHIVE },
- { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo
-#ifdef MISSIONPACK
- { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
- { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
- { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
- { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
- { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO},
- { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO},
- { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO},
- { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO},
- { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
- { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE},
- { &cg_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO},
- { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
-#endif
- { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
- { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
- { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0},
- { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0},
- { &cg_timescale, "timescale", "1", 0},
- { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE},
- { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
- { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
-
- { &pmove_fixed, "pmove_fixed", "0", 0},
- { &pmove_msec, "pmove_msec", "8", 0},
- { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
- { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
- { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
- { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
- { &cg_oldRail, "cg_oldRail", "1", CVAR_ARCHIVE},
- { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE},
- { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE},
- { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}
-// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE }
-};
-
-static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
-
-/*
-=================
-CG_RegisterCvars
-=================
-*/
-void CG_RegisterCvars( void ) {
- int i;
- cvarTable_t *cv;
- char var[MAX_TOKEN_CHARS];
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Register( cv->vmCvar, cv->cvarName,
- cv->defaultString, cv->cvarFlags );
- }
-
- // see if we are also running the server on this machine
- trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
- cgs.localServer = atoi( var );
-
- forceModelModificationCount = cg_forceModel.modificationCount;
-
- trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
- trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
-}
-
-/*
-===================
-CG_ForceModelChange
-===================
-*/
-static void CG_ForceModelChange( void ) {
- int i;
-
- for (i=0 ; i<MAX_CLIENTS ; i++) {
- const char *clientInfo;
-
- clientInfo = CG_ConfigString( CS_PLAYERS+i );
- if ( !clientInfo[0] ) {
- continue;
- }
- CG_NewClientInfo( i );
- }
-}
-
-/*
-=================
-CG_UpdateCvars
-=================
-*/
-void CG_UpdateCvars( void ) {
- int i;
- cvarTable_t *cv;
-
- for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
- trap_Cvar_Update( cv->vmCvar );
- }
-
- // check for modications here
-
- // If team overlay is on, ask for updates from the server. If its off,
- // let the server know so we don't receive it
- if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) {
- drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount;
-
- if ( cg_drawTeamOverlay.integer > 0 ) {
- trap_Cvar_Set( "teamoverlay", "1" );
- } else {
- trap_Cvar_Set( "teamoverlay", "0" );
- }
- // FIXME E3 HACK
- trap_Cvar_Set( "teamoverlay", "1" );
- }
-
- // if force model changed
- if ( forceModelModificationCount != cg_forceModel.modificationCount ) {
- forceModelModificationCount = cg_forceModel.modificationCount;
- CG_ForceModelChange();
- }
-}
-
-int CG_CrosshairPlayer( void ) {
- if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) {
- return -1;
- }
- return cg.crosshairClientNum;
-}
-
-int CG_LastAttacker( void ) {
- if ( !cg.attackerTime ) {
- return -1;
- }
- return cg.snap->ps.persistant[PERS_ATTACKER];
-}
-
-void QDECL CG_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- vsprintf (text, msg, argptr);
- va_end (argptr);
-
- trap_Print( text );
-}
-
-void QDECL CG_Error( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- vsprintf (text, msg, argptr);
- va_end (argptr);
-
- trap_Error( text );
-}
-
-#ifndef CGAME_HARD_LINKED
-// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME)
-
-void QDECL Com_Error( int level, const char *error, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- vsprintf (text, error, argptr);
- va_end (argptr);
-
- CG_Error( "%s", text);
-}
-
-void QDECL Com_Printf( const char *msg, ... ) {
- va_list argptr;
- char text[1024];
-
- va_start (argptr, msg);
- vsprintf (text, msg, argptr);
- va_end (argptr);
-
- CG_Printf ("%s", text);
-}
-
-#endif
-
-/*
-================
-CG_Argv
-================
-*/
-const char *CG_Argv( int arg ) {
- static char buffer[MAX_STRING_CHARS];
-
- trap_Argv( arg, buffer, sizeof( buffer ) );
-
- return buffer;
-}
-
-
-//========================================================================
-
-/*
-=================
-CG_RegisterItemSounds
-
-The server says this item is used on this level
-=================
-*/
-static void CG_RegisterItemSounds( int itemNum ) {
- gitem_t *item;
- char data[MAX_QPATH];
- char *s, *start;
- int len;
-
- item = &bg_itemlist[ itemNum ];
-
- if( item->pickup_sound ) {
- trap_S_RegisterSound( item->pickup_sound, qfalse );
- }
-
- // parse the space seperated precache string for other media
- s = item->sounds;
- if (!s || !s[0])
- return;
-
- while (*s) {
- start = s;
- while (*s && *s != ' ') {
- s++;
- }
-
- len = s-start;
- if (len >= MAX_QPATH || len < 5) {
- CG_Error( "PrecacheItem: %s has bad precache string",
- item->classname);
- return;
- }
- memcpy (data, start, len);
- data[len] = 0;
- if ( *s ) {
- s++;
- }
-
- if ( !strcmp(data+len-3, "wav" )) {
- trap_S_RegisterSound( data, qfalse );
- }
- }
-}
-
-
-/*
-=================
-CG_RegisterSounds
-
-called during a precache command
-=================
-*/
-static void CG_RegisterSounds( void ) {
- int i;
- char items[MAX_ITEMS+1];
- char name[MAX_QPATH];
- const char *soundName;
-
- // voice commands
-#ifdef MISSIONPACK
- CG_LoadVoiceChats();
-#endif
-
- cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qtrue );
- cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qtrue );
- cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qtrue );
- cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qtrue );
- cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qtrue );
- cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qtrue );
- cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qtrue );
- cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qtrue );
- cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qtrue );
- cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qtrue );
- cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue );
-#ifdef MISSIONPACK
- cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue );
-#endif
-
- if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {
-
- cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
- cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qtrue );
- cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qtrue );
- cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qtrue );
- cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qtrue );
-
- cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qtrue );
- cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qtrue );
-
- cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
- cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qtrue );
-
- cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qtrue );
- cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
-
- cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qtrue );
- cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qtrue );
-
- if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
- cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qtrue );
- cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qtrue );
- cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qtrue );
- cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qtrue );
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
- // FIXME: get a replacement for this sound ?
- cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
- cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
- cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
- }
-
- if ( cgs.gametype == GT_1FCTF || cgs.gametype == GT_CTF || cg_buildScript.integer ) {
- cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
- cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
- }
-
- if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
- cgs.media.yourBaseIsUnderAttackSound = trap_S_RegisterSound( "sound/teamplay/voc_base_attack.wav", qtrue );
- }
-#else
- cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
- cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
- cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
- cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
- cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
-#endif
- }
-
- cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse );
- cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
- cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav", qfalse );
- cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav", qfalse );
- cgs.media.gibSound = trap_S_RegisterSound( "sound/player/gibsplt1.wav", qfalse );
- cgs.media.gibBounce1Sound = trap_S_RegisterSound( "sound/player/gibimp1.wav", qfalse );
- cgs.media.gibBounce2Sound = trap_S_RegisterSound( "sound/player/gibimp2.wav", qfalse );
- cgs.media.gibBounce3Sound = trap_S_RegisterSound( "sound/player/gibimp3.wav", qfalse );
-
-#ifdef MISSIONPACK
- cgs.media.useInvulnerabilitySound = trap_S_RegisterSound( "sound/items/invul_activate.wav", qfalse );
- cgs.media.invulnerabilityImpactSound1 = trap_S_RegisterSound( "sound/items/invul_impact_01.wav", qfalse );
- cgs.media.invulnerabilityImpactSound2 = trap_S_RegisterSound( "sound/items/invul_impact_02.wav", qfalse );
- cgs.media.invulnerabilityImpactSound3 = trap_S_RegisterSound( "sound/items/invul_impact_03.wav", qfalse );
- cgs.media.invulnerabilityJuicedSound = trap_S_RegisterSound( "sound/items/invul_juiced.wav", qfalse );
- cgs.media.obeliskHitSound1 = trap_S_RegisterSound( "sound/items/obelisk_hit_01.wav", qfalse );
- cgs.media.obeliskHitSound2 = trap_S_RegisterSound( "sound/items/obelisk_hit_02.wav", qfalse );
- cgs.media.obeliskHitSound3 = trap_S_RegisterSound( "sound/items/obelisk_hit_03.wav", qfalse );
- cgs.media.obeliskRespawnSound = trap_S_RegisterSound( "sound/items/obelisk_respawn.wav", qfalse );
-
- cgs.media.ammoregenSound = trap_S_RegisterSound("sound/items/cl_ammoregen.wav", qfalse);
- cgs.media.doublerSound = trap_S_RegisterSound("sound/items/cl_doubler.wav", qfalse);
- cgs.media.guardSound = trap_S_RegisterSound("sound/items/cl_guard.wav", qfalse);
- cgs.media.scoutSound = trap_S_RegisterSound("sound/items/cl_scout.wav", qfalse);
-#endif
-
- cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/telein.wav", qfalse );
- cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/teleout.wav", qfalse );
- cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav", qfalse );
-
- cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav", qfalse );
-
- cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav", qfalse );
- cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav", qfalse);
-
- cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav", qfalse );
-#ifdef MISSIONPACK
- cgs.media.hitSoundHighArmor = trap_S_RegisterSound( "sound/feedback/hithi.wav", qfalse );
- cgs.media.hitSoundLowArmor = trap_S_RegisterSound( "sound/feedback/hitlo.wav", qfalse );
-#endif
-
- cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav", qtrue );
- cgs.media.excellentSound = trap_S_RegisterSound( "sound/feedback/excellent.wav", qtrue );
- cgs.media.deniedSound = trap_S_RegisterSound( "sound/feedback/denied.wav", qtrue );
- cgs.media.humiliationSound = trap_S_RegisterSound( "sound/feedback/humiliation.wav", qtrue );
- cgs.media.assistSound = trap_S_RegisterSound( "sound/feedback/assist.wav", qtrue );
- cgs.media.defendSound = trap_S_RegisterSound( "sound/feedback/defense.wav", qtrue );
-#ifdef MISSIONPACK
- cgs.media.firstImpressiveSound = trap_S_RegisterSound( "sound/feedback/first_impressive.wav", qtrue );
- cgs.media.firstExcellentSound = trap_S_RegisterSound( "sound/feedback/first_excellent.wav", qtrue );
- cgs.media.firstHumiliationSound = trap_S_RegisterSound( "sound/feedback/first_gauntlet.wav", qtrue );
-#endif
-
- cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/feedback/takenlead.wav", qtrue);
- cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/feedback/tiedlead.wav", qtrue);
- cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/feedback/lostlead.wav", qtrue);
-
-#ifdef MISSIONPACK
- cgs.media.voteNow = trap_S_RegisterSound( "sound/feedback/vote_now.wav", qtrue);
- cgs.media.votePassed = trap_S_RegisterSound( "sound/feedback/vote_passed.wav", qtrue);
- cgs.media.voteFailed = trap_S_RegisterSound( "sound/feedback/vote_failed.wav", qtrue);
-#endif
-
- cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav", qfalse);
- cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav", qfalse);
- cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav", qfalse);
-
- cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/world/jumppad.wav", qfalse );
-
- for (i=0 ; i<4 ; i++) {
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_NORMAL][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_BOOT][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/flesh%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_FLESH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/mech%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_MECH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/energy%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_ENERGY][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/splash%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_SPLASH][i] = trap_S_RegisterSound (name, qfalse);
-
- Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1);
- cgs.media.footsteps[FOOTSTEP_METAL][i] = trap_S_RegisterSound (name, qfalse);
- }
-
- // only register the items that the server says we need
- strcpy( items, CG_ConfigString( CS_ITEMS ) );
-
- for ( i = 1 ; i < bg_numItems ; i++ ) {
-// if ( items[ i ] == '1' || cg_buildScript.integer ) {
- CG_RegisterItemSounds( i );
-// }
- }
-
- for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
- soundName = CG_ConfigString( CS_SOUNDS+i );
- if ( !soundName[0] ) {
- break;
- }
- if ( soundName[0] == '*' ) {
- continue; // custom sound
- }
- cgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );
- }
-
- // FIXME: only needed with item
- cgs.media.flightSound = trap_S_RegisterSound( "sound/items/flight.wav", qfalse );
- cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_medkit.wav", qfalse);
- cgs.media.quadSound = trap_S_RegisterSound("sound/items/damage3.wav", qfalse);
- cgs.media.sfx_ric1 = trap_S_RegisterSound ("sound/weapons/machinegun/ric1.wav", qfalse);
- cgs.media.sfx_ric2 = trap_S_RegisterSound ("sound/weapons/machinegun/ric2.wav", qfalse);
- cgs.media.sfx_ric3 = trap_S_RegisterSound ("sound/weapons/machinegun/ric3.wav", qfalse);
- cgs.media.sfx_railg = trap_S_RegisterSound ("sound/weapons/railgun/railgf1a.wav", qfalse);
- cgs.media.sfx_rockexp = trap_S_RegisterSound ("sound/weapons/rocket/rocklx1a.wav", qfalse);
- cgs.media.sfx_plasmaexp = trap_S_RegisterSound ("sound/weapons/plasma/plasmx1a.wav", qfalse);
-#ifdef MISSIONPACK
- cgs.media.sfx_proxexp = trap_S_RegisterSound( "sound/weapons/proxmine/wstbexpl.wav" , qfalse);
- cgs.media.sfx_nghit = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpd.wav" , qfalse);
- cgs.media.sfx_nghitflesh = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpl.wav" , qfalse);
- cgs.media.sfx_nghitmetal = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpm.wav", qfalse );
- cgs.media.sfx_chghit = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpd.wav", qfalse );
- cgs.media.sfx_chghitflesh = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpl.wav", qfalse );
- cgs.media.sfx_chghitmetal = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpm.wav", qfalse );
- cgs.media.weaponHoverSound = trap_S_RegisterSound( "sound/weapons/weapon_hover.wav", qfalse );
- cgs.media.kamikazeExplodeSound = trap_S_RegisterSound( "sound/items/kam_explode.wav", qfalse );
- cgs.media.kamikazeImplodeSound = trap_S_RegisterSound( "sound/items/kam_implode.wav", qfalse );
- cgs.media.kamikazeFarSound = trap_S_RegisterSound( "sound/items/kam_explode_far.wav", qfalse );
- cgs.media.winnerSound = trap_S_RegisterSound( "sound/feedback/voc_youwin.wav", qfalse );
- cgs.media.loserSound = trap_S_RegisterSound( "sound/feedback/voc_youlose.wav", qfalse );
- cgs.media.youSuckSound = trap_S_RegisterSound( "sound/misc/yousuck.wav", qfalse );
-
- cgs.media.wstbimplSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpl.wav", qfalse);
- cgs.media.wstbimpmSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpm.wav", qfalse);
- cgs.media.wstbimpdSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpd.wav", qfalse);
- cgs.media.wstbactvSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbactv.wav", qfalse);
-#endif
-
- cgs.media.regenSound = trap_S_RegisterSound("sound/items/regen.wav", qfalse);
- cgs.media.protectSound = trap_S_RegisterSound("sound/items/protect3.wav", qfalse);
- cgs.media.n_healthSound = trap_S_RegisterSound("sound/items/n_health.wav", qfalse );
- cgs.media.hgrenb1aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb1a.wav", qfalse);
- cgs.media.hgrenb2aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb2a.wav", qfalse);
-
-#ifdef MISSIONPACK
- trap_S_RegisterSound("sound/player/james/death1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/death2.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/death3.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/jump1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/pain25_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/pain75_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/pain100_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/falling1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/gasp.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/drown.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/fall1.wav", qfalse );
- trap_S_RegisterSound("sound/player/james/taunt.wav", qfalse );
-
- trap_S_RegisterSound("sound/player/janet/death1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/death2.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/death3.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/jump1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/pain25_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/pain75_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/pain100_1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/falling1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/gasp.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/drown.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/fall1.wav", qfalse );
- trap_S_RegisterSound("sound/player/janet/taunt.wav", qfalse );
-#endif
-
-}
-
-
-//===================================================================================
-
-
-/*
-=================
-CG_RegisterGraphics
-
-This function may execute for a couple of minutes with a slow disk.
-=================
-*/
-static void CG_RegisterGraphics( void ) {
- int i;
- char items[MAX_ITEMS+1];
- static char *sb_nums[11] = {
- "gfx/2d/numbers/zero_32b",
- "gfx/2d/numbers/one_32b",
- "gfx/2d/numbers/two_32b",
- "gfx/2d/numbers/three_32b",
- "gfx/2d/numbers/four_32b",
- "gfx/2d/numbers/five_32b",
- "gfx/2d/numbers/six_32b",
- "gfx/2d/numbers/seven_32b",
- "gfx/2d/numbers/eight_32b",
- "gfx/2d/numbers/nine_32b",
- "gfx/2d/numbers/minus_32b",
- };
-
- // clear any references to old media
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
- trap_R_ClearScene();
-
- CG_LoadingString( cgs.mapname );
-
- trap_R_LoadWorldMap( cgs.mapname );
-
- // precache status bar pics
- CG_LoadingString( "game media" );
-
- for ( i=0 ; i<11 ; i++) {
- cgs.media.numberShaders[i] = trap_R_RegisterShader( sb_nums[i] );
- }
-
- cgs.media.botSkillShaders[0] = trap_R_RegisterShader( "menu/art/skill1.tga" );
- cgs.media.botSkillShaders[1] = trap_R_RegisterShader( "menu/art/skill2.tga" );
- cgs.media.botSkillShaders[2] = trap_R_RegisterShader( "menu/art/skill3.tga" );
- cgs.media.botSkillShaders[3] = trap_R_RegisterShader( "menu/art/skill4.tga" );
- cgs.media.botSkillShaders[4] = trap_R_RegisterShader( "menu/art/skill5.tga" );
-
- cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" );
-
- cgs.media.deferShader = trap_R_RegisterShaderNoMip( "gfx/2d/defer.tga" );
-
- cgs.media.scoreboardName = trap_R_RegisterShaderNoMip( "menu/tab/name.tga" );
- cgs.media.scoreboardPing = trap_R_RegisterShaderNoMip( "menu/tab/ping.tga" );
- cgs.media.scoreboardScore = trap_R_RegisterShaderNoMip( "menu/tab/score.tga" );
- cgs.media.scoreboardTime = trap_R_RegisterShaderNoMip( "menu/tab/time.tga" );
-
- cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" );
- cgs.media.smokePuffRageProShader = trap_R_RegisterShader( "smokePuffRagePro" );
- cgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( "shotgunSmokePuff" );
-#ifdef MISSIONPACK
- cgs.media.nailPuffShader = trap_R_RegisterShader( "nailtrail" );
- cgs.media.blueProxMine = trap_R_RegisterModel( "models/weaphits/proxmineb.md3" );
-#endif
- cgs.media.plasmaBallShader = trap_R_RegisterShader( "sprites/plasma1" );
- cgs.media.bloodTrailShader = trap_R_RegisterShader( "bloodTrail" );
- cgs.media.lagometerShader = trap_R_RegisterShader("lagometer" );
- cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" );
-
- cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" );
-
- cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" );
- cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" );
-
- for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) {
- cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%c", 'a'+i) );
- }
-
- cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" );
- cgs.media.noammoShader = trap_R_RegisterShader( "icons/noammo" );
-
- // powerup shaders
- cgs.media.quadShader = trap_R_RegisterShader("powerups/quad" );
- cgs.media.quadWeaponShader = trap_R_RegisterShader("powerups/quadWeapon" );
- cgs.media.battleSuitShader = trap_R_RegisterShader("powerups/battleSuit" );
- cgs.media.battleWeaponShader = trap_R_RegisterShader("powerups/battleWeapon" );
- cgs.media.invisShader = trap_R_RegisterShader("powerups/invisibility" );
- cgs.media.regenShader = trap_R_RegisterShader("powerups/regen" );
- cgs.media.hastePuffShader = trap_R_RegisterShader("hasteSmokePuff" );
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
-#else
- if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
-#endif
- cgs.media.redCubeModel = trap_R_RegisterModel( "models/powerups/orb/r_orb.md3" );
- cgs.media.blueCubeModel = trap_R_RegisterModel( "models/powerups/orb/b_orb.md3" );
- cgs.media.redCubeIcon = trap_R_RegisterShader( "icons/skull_red" );
- cgs.media.blueCubeIcon = trap_R_RegisterShader( "icons/skull_blue" );
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
-#else
- if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
-#endif
- cgs.media.redFlagModel = trap_R_RegisterModel( "models/flags/r_flag.md3" );
- cgs.media.blueFlagModel = trap_R_RegisterModel( "models/flags/b_flag.md3" );
- cgs.media.redFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_red1" );
- cgs.media.redFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
- cgs.media.redFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_red3" );
- cgs.media.blueFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_blu1" );
- cgs.media.blueFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
- cgs.media.blueFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu3" );
-#ifdef MISSIONPACK
- cgs.media.flagPoleModel = trap_R_RegisterModel( "models/flag2/flagpole.md3" );
- cgs.media.flagFlapModel = trap_R_RegisterModel( "models/flag2/flagflap3.md3" );
-
- cgs.media.redFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/red.skin" );
- cgs.media.blueFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/blue.skin" );
- cgs.media.neutralFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/white.skin" );
-
- cgs.media.redFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/red_base.md3" );
- cgs.media.blueFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/blue_base.md3" );
- cgs.media.neutralFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/ntrl_base.md3" );
-#endif
- }
-
-#ifdef MISSIONPACK
- if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
- cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
- cgs.media.flagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral1" );
- cgs.media.flagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
- cgs.media.flagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
- cgs.media.flagShader[3] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral3" );
- }
-
- if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
- cgs.media.overloadBaseModel = trap_R_RegisterModel( "models/powerups/overload_base.md3" );
- cgs.media.overloadTargetModel = trap_R_RegisterModel( "models/powerups/overload_target.md3" );
- cgs.media.overloadLightsModel = trap_R_RegisterModel( "models/powerups/overload_lights.md3" );
- cgs.media.overloadEnergyModel = trap_R_RegisterModel( "models/powerups/overload_energy.md3" );
- }
-
- if ( cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
- cgs.media.harvesterModel = trap_R_RegisterModel( "models/powerups/harvester/harvester.md3" );
- cgs.media.harvesterRedSkin = trap_R_RegisterSkin( "models/powerups/harvester/red.skin" );
- cgs.media.harvesterBlueSkin = trap_R_RegisterSkin( "models/powerups/harvester/blue.skin" );
- cgs.media.harvesterNeutralModel = trap_R_RegisterModel( "models/powerups/obelisk/obelisk.md3" );
- }
-
- cgs.media.redKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikred" );
- cgs.media.dustPuffShader = trap_R_RegisterShader("hasteSmokePuff" );
-#endif
-
- if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {
- cgs.media.friendShader = trap_R_RegisterShader( "sprites/foe" );
- cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" );
- cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" );
-#ifdef MISSIONPACK
- cgs.media.blueKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikblu" );
-#endif
- }
-
- cgs.media.armorModel = trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" );
- cgs.media.armorIcon = trap_R_RegisterShaderNoMip( "icons/iconr_yellow" );
-
- cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" );
- cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
-
- cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" );
- cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" );
- cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" );
- cgs.media.gibFist = trap_R_RegisterModel( "models/gibs/fist.md3" );
- cgs.media.gibFoot = trap_R_RegisterModel( "models/gibs/foot.md3" );
- cgs.media.gibForearm = trap_R_RegisterModel( "models/gibs/forearm.md3" );
- cgs.media.gibIntestine = trap_R_RegisterModel( "models/gibs/intestine.md3" );
- cgs.media.gibLeg = trap_R_RegisterModel( "models/gibs/leg.md3" );
- cgs.media.gibSkull = trap_R_RegisterModel( "models/gibs/skull.md3" );
- cgs.media.gibBrain = trap_R_RegisterModel( "models/gibs/brain.md3" );
-
- cgs.media.smoke2 = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
-
- cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" );
-
- cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" );
-
- cgs.media.bulletFlashModel = trap_R_RegisterModel("models/weaphits/bullet.md3");
- cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3");
- cgs.media.dishFlashModel = trap_R_RegisterModel("models/weaphits/boom01.md3");
-#ifdef MISSIONPACK
- cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/powerups/pop.md3" );
-#else
- cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" );
- cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" );
-#endif
-#ifdef MISSIONPACK
- cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" );
- cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" );
- cgs.media.kamikazeHeadModel = trap_R_RegisterModel( "models/powerups/kamikazi.md3" );
- cgs.media.kamikazeHeadTrail = trap_R_RegisterModel( "models/powerups/trailtest.md3" );
- cgs.media.guardPowerupModel = trap_R_RegisterModel( "models/powerups/guard_player.md3" );
- cgs.media.scoutPowerupModel = trap_R_RegisterModel( "models/powerups/scout_player.md3" );
- cgs.media.doublerPowerupModel = trap_R_RegisterModel( "models/powerups/doubler_player.md3" );
- cgs.media.ammoRegenPowerupModel = trap_R_RegisterModel( "models/powerups/ammo_player.md3" );
- cgs.media.invulnerabilityImpactModel = trap_R_RegisterModel( "models/powerups/shield/impact.md3" );
- cgs.media.invulnerabilityJuicedModel = trap_R_RegisterModel( "models/powerups/shield/juicer.md3" );
- cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" );
- cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" );
-
-#endif
-
- cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" );
- cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" );
- cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" );
- cgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( "medal_gauntlet" );
- cgs.media.medalDefend = trap_R_RegisterShaderNoMip( "medal_defend" );
- cgs.media.medalAssist = trap_R_RegisterShaderNoMip( "medal_assist" );
- cgs.media.medalCapture = trap_R_RegisterShaderNoMip( "medal_capture" );
-
-
- memset( cg_items, 0, sizeof( cg_items ) );
- memset( cg_weapons, 0, sizeof( cg_weapons ) );
-
- // only register the items that the server says we need
- strcpy( items, CG_ConfigString( CS_ITEMS) );
-
- for ( i = 1 ; i < bg_numItems ; i++ ) {
- if ( items[ i ] == '1' || cg_buildScript.integer ) {
- CG_LoadingItem( i );
- CG_RegisterItemVisuals( i );
- }
- }
-
- // wall marks
- cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" );
- cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" );
- cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" );
- cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" );
- cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" );
- cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" );
- cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" );
-
- // register the inline models
- cgs.numInlineModels = trap_CM_NumInlineModels();
- for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
- char name[10];
- vec3_t mins, maxs;
- int j;
-
- Com_sprintf( name, sizeof(name), "*%i", i );
- cgs.inlineDrawModel[i] = trap_R_RegisterModel( name );
- trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
- for ( j = 0 ; j < 3 ; j++ ) {
- cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
- }
- }
-
- // register all the server specified models
- for (i=1 ; i<MAX_MODELS ; i++) {
- const char *modelName;
-
- modelName = CG_ConfigString( CS_MODELS+i );
- if ( !modelName[0] ) {
- break;
- }
- cgs.gameModels[i] = trap_R_RegisterModel( modelName );
- }
-
-#ifdef MISSIONPACK
- // new stuff
- cgs.media.patrolShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/patrol.tga");
- cgs.media.assaultShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/assault.tga");
- cgs.media.campShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/camp.tga");
- cgs.media.followShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/follow.tga");
- cgs.media.defendShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/defend.tga");
- cgs.media.teamLeaderShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/team_leader.tga");
- cgs.media.retrieveShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/retrieve.tga");
- cgs.media.escortShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/escort.tga");
- cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- cgs.media.sizeCursor = trap_R_RegisterShaderNoMip( "ui/assets/sizecursor.tga" );
- cgs.media.selectCursor = trap_R_RegisterShaderNoMip( "ui/assets/selectcursor.tga" );
- cgs.media.flagShaders[0] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_in_base.tga");
- cgs.media.flagShaders[1] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_capture.tga");
- cgs.media.flagShaders[2] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_missing.tga");
-
- trap_R_RegisterModel( "models/players/james/lower.md3" );
- trap_R_RegisterModel( "models/players/james/upper.md3" );
- trap_R_RegisterModel( "models/players/heads/james/james.md3" );
-
- trap_R_RegisterModel( "models/players/janet/lower.md3" );
- trap_R_RegisterModel( "models/players/janet/upper.md3" );
- trap_R_RegisterModel( "models/players/heads/janet/janet.md3" );
-
-#endif
- CG_ClearParticles ();
-/*
- for (i=1; i<MAX_PARTICLES_AREAS; i++)
- {
- {
- int rval;
-
- rval = CG_NewParticleArea ( CS_PARTICLES + i);
- if (!rval)
- break;
- }
- }
-*/
-}
-
-
-
-/*
-=======================
-CG_BuildSpectatorString
-
-=======================
-*/
-void CG_BuildSpectatorString() {
- int i;
- cg.spectatorList[0] = 0;
- for (i = 0; i < MAX_CLIENTS; i++) {
- if (cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_SPECTATOR ) {
- Q_strcat(cg.spectatorList, sizeof(cg.spectatorList), va("%s ", cgs.clientinfo[i].name));
- }
- }
- i = strlen(cg.spectatorList);
- if (i != cg.spectatorLen) {
- cg.spectatorLen = i;
- cg.spectatorWidth = -1;
- }
-}
-
-
-/*
-===================
-CG_RegisterClients
-===================
-*/
-static void CG_RegisterClients( void ) {
- int i;
-
- CG_LoadingClient(cg.clientNum);
- CG_NewClientInfo(cg.clientNum);
-
- for (i=0 ; i<MAX_CLIENTS ; i++) {
- const char *clientInfo;
-
- if (cg.clientNum == i) {
- continue;
- }
-
- clientInfo = CG_ConfigString( CS_PLAYERS+i );
- if ( !clientInfo[0]) {
- continue;
- }
- CG_LoadingClient( i );
- CG_NewClientInfo( i );
- }
- CG_BuildSpectatorString();
-}
-
-//===========================================================================
-
-/*
-=================
-CG_ConfigString
-=================
-*/
-const char *CG_ConfigString( int index ) {
- if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
- CG_Error( "CG_ConfigString: bad index: %i", index );
- }
- return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
-}
-
-//==================================================================
-
-/*
-======================
-CG_StartMusic
-
-======================
-*/
-void CG_StartMusic( void ) {
- char *s;
- char parm1[MAX_QPATH], parm2[MAX_QPATH];
-
- // start the background music
- s = (char *)CG_ConfigString( CS_MUSIC );
- Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
- Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
-
- trap_S_StartBackgroundTrack( parm1, parm2 );
-}
-#ifdef MISSIONPACK
-char *CG_GetMenuBuffer(const char *filename) {
- int len;
- fileHandle_t f;
- static char buf[MAX_MENUFILE];
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
- return NULL;
- }
- if ( len >= MAX_MENUFILE ) {
- trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
- trap_FS_FCloseFile( f );
- return NULL;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- return buf;
-}
-
-//
-// ==============================
-// new hud stuff ( mission pack )
-// ==============================
-//
-qboolean CG_Asset_Parse(int handle) {
- pc_token_t token;
- const char *tempStr;
-
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
- if (Q_stricmp(token.string, "{") != 0) {
- return qfalse;
- }
-
- while ( 1 ) {
- if (!trap_PC_ReadToken(handle, &token))
- return qfalse;
-
- if (Q_stricmp(token.string, "}") == 0) {
- return qtrue;
- }
-
- // font
- if (Q_stricmp(token.string, "font") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont);
- continue;
- }
-
- // smallFont
- if (Q_stricmp(token.string, "smallFont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont);
- continue;
- }
-
- // font
- if (Q_stricmp(token.string, "bigfont") == 0) {
- int pointSize;
- if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
- return qfalse;
- }
- cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont);
- continue;
- }
-
- // gradientbar
- if (Q_stricmp(token.string, "gradientbar") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
- continue;
- }
-
- // enterMenuSound
- if (Q_stricmp(token.string, "menuEnterSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // exitMenuSound
- if (Q_stricmp(token.string, "menuExitSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // itemFocusSound
- if (Q_stricmp(token.string, "itemFocusSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- // menuBuzzSound
- if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
- if (!PC_String_Parse(handle, &tempStr)) {
- return qfalse;
- }
- cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
- continue;
- }
-
- if (Q_stricmp(token.string, "cursor") == 0) {
- if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) {
- return qfalse;
- }
- cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeClamp") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeCycle") == 0) {
- if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "fadeAmount") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowX") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowY") == 0) {
- if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) {
- return qfalse;
- }
- continue;
- }
-
- if (Q_stricmp(token.string, "shadowColor") == 0) {
- if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) {
- return qfalse;
- }
- cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
- continue;
- }
- }
- return qfalse; // bk001204 - why not?
-}
-
-void CG_ParseMenu(const char *menuFile) {
- pc_token_t token;
- int handle;
-
- handle = trap_PC_LoadSource(menuFile);
- if (!handle)
- handle = trap_PC_LoadSource("ui/testhud.menu");
- if (!handle)
- return;
-
- while ( 1 ) {
- if (!trap_PC_ReadToken( handle, &token )) {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( token.string[0] == '}' ) {
- break;
- }
-
- if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
- if (CG_Asset_Parse(handle)) {
- continue;
- } else {
- break;
- }
- }
-
-
- if (Q_stricmp(token.string, "menudef") == 0) {
- // start a new menu
- Menu_New(handle);
- }
- }
- trap_PC_FreeSource(handle);
-}
-
-qboolean CG_Load_Menu(char **p) {
- char *token;
-
- token = COM_ParseExt(p, qtrue);
-
- if (token[0] != '{') {
- return qfalse;
- }
-
- while ( 1 ) {
-
- token = COM_ParseExt(p, qtrue);
-
- if (Q_stricmp(token, "}") == 0) {
- return qtrue;
- }
-
- if ( !token || token[0] == 0 ) {
- return qfalse;
- }
-
- CG_ParseMenu(token);
- }
- return qfalse;
-}
-
-
-
-void CG_LoadMenus(const char *menuFile) {
- char *token;
- char *p;
- int len, start;
- fileHandle_t f;
- static char buf[MAX_MENUDEFFILE];
-
- start = trap_Milliseconds();
-
- len = trap_FS_FOpenFile( menuFile, &f, FS_READ );
- if ( !f ) {
- trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
- len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ );
- if (!f) {
- trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n", menuFile ) );
- }
- }
-
- if ( len >= MAX_MENUDEFFILE ) {
- trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", menuFile, len, MAX_MENUDEFFILE ) );
- trap_FS_FCloseFile( f );
- return;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- COM_Compress(buf);
-
- Menu_Reset();
-
- p = buf;
-
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if( !token || token[0] == 0 || token[0] == '}') {
- break;
- }
-
- //if ( Q_stricmp( token, "{" ) ) {
- // Com_Printf( "Missing { in menu file\n" );
- // break;
- //}
-
- //if ( menuCount == MAX_MENUS ) {
- // Com_Printf( "Too many menus!\n" );
- // break;
- //}
-
- if ( Q_stricmp( token, "}" ) == 0 ) {
- break;
- }
-
- if (Q_stricmp(token, "loadmenu") == 0) {
- if (CG_Load_Menu(&p)) {
- continue;
- } else {
- break;
- }
- }
- }
-
- Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
-
-}
-
-
-
-static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
- return qfalse;
-}
-
-
-static int CG_FeederCount(float feederID) {
- int i, count;
- count = 0;
- if (feederID == FEEDER_REDTEAM_LIST) {
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_RED) {
- count++;
- }
- }
- } else if (feederID == FEEDER_BLUETEAM_LIST) {
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_BLUE) {
- count++;
- }
- }
- } else if (feederID == FEEDER_SCOREBOARD) {
- return cg.numScores;
- }
- return count;
-}
-
-
-void CG_SetScoreSelection(void *p) {
- menuDef_t *menu = (menuDef_t*)p;
- playerState_t *ps = &cg.snap->ps;
- int i, red, blue;
- red = blue = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == TEAM_RED) {
- red++;
- } else if (cg.scores[i].team == TEAM_BLUE) {
- blue++;
- }
- if (ps->clientNum == cg.scores[i].client) {
- cg.selectedScore = i;
- }
- }
-
- if (menu == NULL) {
- // just interested in setting the selected score
- return;
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
- int feeder = FEEDER_REDTEAM_LIST;
- i = red;
- if (cg.scores[cg.selectedScore].team == TEAM_BLUE) {
- feeder = FEEDER_BLUETEAM_LIST;
- i = blue;
- }
- Menu_SetFeederSelection(menu, feeder, i, NULL);
- } else {
- Menu_SetFeederSelection(menu, FEEDER_SCOREBOARD, cg.selectedScore, NULL);
- }
-}
-
-// FIXME: might need to cache this info
-static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex) {
- int i, count;
- if ( cgs.gametype >= GT_TEAM ) {
- count = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == team) {
- if (count == index) {
- *scoreIndex = i;
- return &cgs.clientinfo[cg.scores[i].client];
- }
- count++;
- }
- }
- }
- *scoreIndex = index;
- return &cgs.clientinfo[ cg.scores[index].client ];
-}
-
-static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
- gitem_t *item;
- int scoreIndex = 0;
- clientInfo_t *info = NULL;
- int team = -1;
- score_t *sp = NULL;
-
- *handle = -1;
-
- if (feederID == FEEDER_REDTEAM_LIST) {
- team = TEAM_RED;
- } else if (feederID == FEEDER_BLUETEAM_LIST) {
- team = TEAM_BLUE;
- }
-
- info = CG_InfoFromScoreIndex(index, team, &scoreIndex);
- sp = &cg.scores[scoreIndex];
-
- if (info && info->infoValid) {
- switch (column) {
- case 0:
- if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) {
- item = BG_FindItemForPowerup( PW_REDFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) {
- item = BG_FindItemForPowerup( PW_BLUEFLAG );
- *handle = cg_items[ ITEM_INDEX(item) ].icon;
- } else {
- if ( info->botSkill > 0 && info->botSkill <= 5 ) {
- *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ];
- } else if ( info->handicap < 100 ) {
- return va("%i", info->handicap );
- }
- }
- break;
- case 1:
- if (team == -1) {
- return "";
- } else {
- *handle = CG_StatusHandle(info->teamTask);
- }
- break;
- case 2:
- if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << sp->client ) ) {
- return "Ready";
- }
- if (team == -1) {
- if (cgs.gametype == GT_TOURNAMENT) {
- return va("%i/%i", info->wins, info->losses);
- } else if (info->infoValid && info->team == TEAM_SPECTATOR ) {
- return "Spectator";
- } else {
- return "";
- }
- } else {
- if (info->teamLeader) {
- return "Leader";
- }
- }
- break;
- case 3:
- return info->name;
- break;
- case 4:
- return va("%i", info->score);
- break;
- case 5:
- return va("%4i", sp->time);
- break;
- case 6:
- if ( sp->ping == -1 ) {
- return "connecting";
- }
- return va("%4i", sp->ping);
- break;
- }
- }
-
- return "";
-}
-
-static qhandle_t CG_FeederItemImage(float feederID, int index) {
- return 0;
-}
-
-static void CG_FeederSelection(float feederID, int index) {
- if ( cgs.gametype >= GT_TEAM ) {
- int i, count;
- int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE;
- count = 0;
- for (i = 0; i < cg.numScores; i++) {
- if (cg.scores[i].team == team) {
- if (index == count) {
- cg.selectedScore = i;
- }
- count++;
- }
- }
- } else {
- cg.selectedScore = index;
- }
-}
-#endif
-
-#ifdef MISSIONPACK // bk001204 - only needed there
-static float CG_Cvar_Get(const char *cvar) {
- char buff[128];
- memset(buff, 0, sizeof(buff));
- trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff));
- return atof(buff);
-}
-#endif
-
-#ifdef MISSIONPACK
-void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
- CG_Text_Paint(x, y, scale, color, text, 0, limit, style);
-}
-
-static int CG_OwnerDrawWidth(int ownerDraw, float scale) {
- switch (ownerDraw) {
- case CG_GAME_TYPE:
- return CG_Text_Width(CG_GameTypeString(), scale, 0);
- case CG_GAME_STATUS:
- return CG_Text_Width(CG_GetGameStatusText(), scale, 0);
- break;
- case CG_KILLER:
- return CG_Text_Width(CG_GetKillerText(), scale, 0);
- break;
- case CG_RED_NAME:
- return CG_Text_Width(cg_redTeamName.string, scale, 0);
- break;
- case CG_BLUE_NAME:
- return CG_Text_Width(cg_blueTeamName.string, scale, 0);
- break;
-
-
- }
- return 0;
-}
-
-static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
- return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
-}
-
-static void CG_StopCinematic(int handle) {
- trap_CIN_StopCinematic(handle);
-}
-
-static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
- trap_CIN_SetExtents(handle, x, y, w, h);
- trap_CIN_DrawCinematic(handle);
-}
-
-static void CG_RunCinematicFrame(int handle) {
- trap_CIN_RunCinematic(handle);
-}
-
-/*
-=================
-CG_LoadHudMenu();
-
-=================
-*/
-void CG_LoadHudMenu() {
- char buff[1024];
- const char *hudSet;
-
- cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
- cgDC.setColor = &trap_R_SetColor;
- cgDC.drawHandlePic = &CG_DrawPic;
- cgDC.drawStretchPic = &trap_R_DrawStretchPic;
- cgDC.drawText = &CG_Text_Paint;
- cgDC.textWidth = &CG_Text_Width;
- cgDC.textHeight = &CG_Text_Height;
- cgDC.registerModel = &trap_R_RegisterModel;
- cgDC.modelBounds = &trap_R_ModelBounds;
- cgDC.fillRect = &CG_FillRect;
- cgDC.drawRect = &CG_DrawRect;
- cgDC.drawSides = &CG_DrawSides;
- cgDC.drawTopBottom = &CG_DrawTopBottom;
- cgDC.clearScene = &trap_R_ClearScene;
- cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
- cgDC.renderScene = &trap_R_RenderScene;
- cgDC.registerFont = &trap_R_RegisterFont;
- cgDC.ownerDrawItem = &CG_OwnerDraw;
- cgDC.getValue = &CG_GetValue;
- cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
- cgDC.runScript = &CG_RunMenuScript;
- cgDC.getTeamColor = &CG_GetTeamColor;
- cgDC.setCVar = trap_Cvar_Set;
- cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
- cgDC.getCVarValue = CG_Cvar_Get;
- cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
- //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
- //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
- cgDC.startLocalSound = &trap_S_StartLocalSound;
- cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
- cgDC.feederCount = &CG_FeederCount;
- cgDC.feederItemImage = &CG_FeederItemImage;
- cgDC.feederItemText = &CG_FeederItemText;
- cgDC.feederSelection = &CG_FeederSelection;
- //cgDC.setBinding = &trap_Key_SetBinding;
- //cgDC.getBindingBuf = &trap_Key_GetBindingBuf;
- //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
- //cgDC.executeText = &trap_Cmd_ExecuteText;
- cgDC.Error = &Com_Error;
- cgDC.Print = &Com_Printf;
- cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
- //cgDC.Pause = &CG_Pause;
- cgDC.registerSound = &trap_S_RegisterSound;
- cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
- cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
- cgDC.playCinematic = &CG_PlayCinematic;
- cgDC.stopCinematic = &CG_StopCinematic;
- cgDC.drawCinematic = &CG_DrawCinematic;
- cgDC.runCinematicFrame = &CG_RunCinematicFrame;
-
- Init_Display(&cgDC);
-
- Menu_Reset();
-
- trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
- hudSet = buff;
- if (hudSet[0] == '\0') {
- hudSet = "ui/hud.txt";
- }
-
- CG_LoadMenus(hudSet);
-}
-
-void CG_AssetCache() {
- //if (Assets.textFont == NULL) {
- // trap_R_RegisterFont("fonts/arial.ttf", 72, &Assets.textFont);
- //}
- //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
- //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
- cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
- cgDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
- cgDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
- cgDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
- cgDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
- cgDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
- cgDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
- cgDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
- cgDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
- cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
- cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
- cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
- cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
- cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
- cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
- cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
- cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
-}
-#endif
-/*
-=================
-CG_Init
-
-Called after every level change or subsystem restart
-Will perform callbacks to make the loading info screen update.
-=================
-*/
-void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {
- const char *s;
-
- // clear everything
- memset( &cgs, 0, sizeof( cgs ) );
- memset( &cg, 0, sizeof( cg ) );
- memset( cg_entities, 0, sizeof(cg_entities) );
- memset( cg_weapons, 0, sizeof(cg_weapons) );
- memset( cg_items, 0, sizeof(cg_items) );
-
- cg.clientNum = clientNum;
-
- cgs.processedSnapshotNum = serverMessageNum;
- cgs.serverCommandSequence = serverCommandSequence;
-
- // load a few needed things before we do any screen updates
- cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" );
- cgs.media.whiteShader = trap_R_RegisterShader( "white" );
- cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
- cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
- cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
-
- CG_RegisterCvars();
-
- CG_InitConsoleCommands();
-
- cg.weaponSelect = WP_MACHINEGUN;
-
- cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for
- cgs.flagStatus = -1;
- // old servers
-
- // get the rendering configuration from the client system
- trap_GetGlconfig( &cgs.glconfig );
- cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
- cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
-
- // get the gamestate from the client system
- trap_GetGameState( &cgs.gameState );
-
- // check version
- s = CG_ConfigString( CS_GAME_VERSION );
- if ( strcmp( s, GAME_VERSION ) ) {
- CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
- }
-
- s = CG_ConfigString( CS_LEVEL_START_TIME );
- cgs.levelStartTime = atoi( s );
-
- CG_ParseServerinfo();
-
- // load the new map
- CG_LoadingString( "collision map" );
-
- trap_CM_LoadMap( cgs.mapname );
-
-#ifdef MISSIONPACK
- String_Init();
-#endif
-
- cg.loading = qtrue; // force players to load instead of defer
-
- CG_LoadingString( "sounds" );
-
- CG_RegisterSounds();
-
- CG_LoadingString( "graphics" );
-
- CG_RegisterGraphics();
-
- CG_LoadingString( "clients" );
-
- CG_RegisterClients(); // if low on memory, some clients will be deferred
-
-#ifdef MISSIONPACK
- CG_AssetCache();
- CG_LoadHudMenu(); // load new hud stuff
-#endif
-
- cg.loading = qfalse; // future players will be deferred
-
- CG_InitLocalEntities();
-
- CG_InitMarkPolys();
-
- // remove the last loading update
- cg.infoScreenText[0] = 0;
-
- // Make sure we have update values (scores)
- CG_SetConfigValues();
-
- CG_StartMusic();
-
- CG_LoadingString( "" );
-
-#ifdef MISSIONPACK
- CG_InitTeamChat();
-#endif
-
- CG_ShaderStateChanged();
-
- trap_S_ClearLoopingSounds( qtrue );
-}
-
-/*
-=================
-CG_Shutdown
-
-Called before every level change or subsystem restart
-=================
-*/
-void CG_Shutdown( void ) {
- // some mods may need to do cleanup work here,
- // like closing files or archiving session data
-}
-
-
-/*
-==================
-CG_EventHandling
-==================
- type 0 - no event handling
- 1 - team menu
- 2 - hud editor
-
-*/
-#ifndef MISSIONPACK
-void CG_EventHandling(int type) {
-}
-
-
-
-void CG_KeyEvent(int key, qboolean down) {
-}
-
-void CG_MouseEvent(int x, int y) {
-}
-#endif
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_main.c -- initialization and primary entry point for cgame
+#include "cg_local.h"
+
+#ifdef MISSIONPACK
+#include "../ui/ui_shared.h"
+// display context for new ui stuff
+displayContextDef_t cgDC;
+#endif
+
+int forceModelModificationCount = -1;
+
+void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
+void CG_Shutdown( void );
+
+
+/*
+================
+vmMain
+
+This is the only way control passes into the module.
+This must be the very first function compiled into the .q3vm file
+================
+*/
+int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
+
+ switch ( command ) {
+ case CG_INIT:
+ CG_Init( arg0, arg1, arg2 );
+ return 0;
+ case CG_SHUTDOWN:
+ CG_Shutdown();
+ return 0;
+ case CG_CONSOLE_COMMAND:
+ return CG_ConsoleCommand();
+ case CG_DRAW_ACTIVE_FRAME:
+ CG_DrawActiveFrame( arg0, arg1, arg2 );
+ return 0;
+ case CG_CROSSHAIR_PLAYER:
+ return CG_CrosshairPlayer();
+ case CG_LAST_ATTACKER:
+ return CG_LastAttacker();
+ case CG_KEY_EVENT:
+ CG_KeyEvent(arg0, arg1);
+ return 0;
+ case CG_MOUSE_EVENT:
+#ifdef MISSIONPACK
+ cgDC.cursorx = cgs.cursorX;
+ cgDC.cursory = cgs.cursorY;
+#endif
+ CG_MouseEvent(arg0, arg1);
+ return 0;
+ case CG_EVENT_HANDLING:
+ CG_EventHandling(arg0);
+ return 0;
+ default:
+ CG_Error( "vmMain: unknown command %i", command );
+ break;
+ }
+ return -1;
+}
+
+
+cg_t cg;
+cgs_t cgs;
+centity_t cg_entities[MAX_GENTITIES];
+weaponInfo_t cg_weapons[MAX_WEAPONS];
+itemInfo_t cg_items[MAX_ITEMS];
+
+
+vmCvar_t cg_railTrailTime;
+vmCvar_t cg_centertime;
+vmCvar_t cg_runpitch;
+vmCvar_t cg_runroll;
+vmCvar_t cg_bobup;
+vmCvar_t cg_bobpitch;
+vmCvar_t cg_bobroll;
+vmCvar_t cg_swingSpeed;
+vmCvar_t cg_shadows;
+vmCvar_t cg_gibs;
+vmCvar_t cg_drawTimer;
+vmCvar_t cg_drawFPS;
+vmCvar_t cg_drawSnapshot;
+vmCvar_t cg_draw3dIcons;
+vmCvar_t cg_drawIcons;
+vmCvar_t cg_drawAmmoWarning;
+vmCvar_t cg_drawCrosshair;
+vmCvar_t cg_drawCrosshairNames;
+vmCvar_t cg_drawRewards;
+vmCvar_t cg_crosshairSize;
+vmCvar_t cg_crosshairX;
+vmCvar_t cg_crosshairY;
+vmCvar_t cg_crosshairHealth;
+vmCvar_t cg_draw2D;
+vmCvar_t cg_drawStatus;
+vmCvar_t cg_animSpeed;
+vmCvar_t cg_debugAnim;
+vmCvar_t cg_debugPosition;
+vmCvar_t cg_debugEvents;
+vmCvar_t cg_errorDecay;
+vmCvar_t cg_nopredict;
+vmCvar_t cg_noPlayerAnims;
+vmCvar_t cg_showmiss;
+vmCvar_t cg_footsteps;
+vmCvar_t cg_addMarks;
+vmCvar_t cg_brassTime;
+vmCvar_t cg_viewsize;
+vmCvar_t cg_drawGun;
+vmCvar_t cg_gun_frame;
+vmCvar_t cg_gun_x;
+vmCvar_t cg_gun_y;
+vmCvar_t cg_gun_z;
+vmCvar_t cg_tracerChance;
+vmCvar_t cg_tracerWidth;
+vmCvar_t cg_tracerLength;
+vmCvar_t cg_autoswitch;
+vmCvar_t cg_ignore;
+vmCvar_t cg_simpleItems;
+vmCvar_t cg_fov;
+vmCvar_t cg_zoomFov;
+vmCvar_t cg_thirdPerson;
+vmCvar_t cg_thirdPersonRange;
+vmCvar_t cg_thirdPersonAngle;
+vmCvar_t cg_stereoSeparation;
+vmCvar_t cg_lagometer;
+vmCvar_t cg_drawAttacker;
+vmCvar_t cg_synchronousClients;
+vmCvar_t cg_teamChatTime;
+vmCvar_t cg_teamChatHeight;
+vmCvar_t cg_stats;
+vmCvar_t cg_buildScript;
+vmCvar_t cg_forceModel;
+vmCvar_t cg_paused;
+vmCvar_t cg_blood;
+vmCvar_t cg_predictItems;
+vmCvar_t cg_deferPlayers;
+vmCvar_t cg_drawTeamOverlay;
+vmCvar_t cg_teamOverlayUserinfo;
+vmCvar_t cg_drawFriend;
+vmCvar_t cg_teamChatsOnly;
+vmCvar_t cg_noVoiceChats;
+vmCvar_t cg_noVoiceText;
+vmCvar_t cg_hudFiles;
+vmCvar_t cg_scorePlum;
+vmCvar_t cg_smoothClients;
+vmCvar_t pmove_fixed;
+//vmCvar_t cg_pmove_fixed;
+vmCvar_t pmove_msec;
+vmCvar_t cg_pmove_msec;
+vmCvar_t cg_cameraMode;
+vmCvar_t cg_cameraOrbit;
+vmCvar_t cg_cameraOrbitDelay;
+vmCvar_t cg_timescaleFadeEnd;
+vmCvar_t cg_timescaleFadeSpeed;
+vmCvar_t cg_timescale;
+vmCvar_t cg_smallFont;
+vmCvar_t cg_bigFont;
+vmCvar_t cg_noTaunt;
+vmCvar_t cg_noProjectileTrail;
+vmCvar_t cg_oldRail;
+vmCvar_t cg_oldRocket;
+vmCvar_t cg_oldPlasma;
+vmCvar_t cg_trueLightning;
+
+#ifdef MISSIONPACK
+vmCvar_t cg_redTeamName;
+vmCvar_t cg_blueTeamName;
+vmCvar_t cg_currentSelectedPlayer;
+vmCvar_t cg_currentSelectedPlayerName;
+vmCvar_t cg_singlePlayer;
+vmCvar_t cg_enableDust;
+vmCvar_t cg_enableBreath;
+vmCvar_t cg_singlePlayerActive;
+vmCvar_t cg_recordSPDemo;
+vmCvar_t cg_recordSPDemoName;
+vmCvar_t cg_obeliskRespawnDelay;
+#endif
+
+typedef struct {
+ vmCvar_t *vmCvar;
+ char *cvarName;
+ char *defaultString;
+ int cvarFlags;
+} cvarTable_t;
+
+static cvarTable_t cvarTable[] = { // bk001129
+ { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging
+ { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
+ { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
+ { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE },
+ { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE },
+ { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
+ { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE },
+ { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
+ { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE },
+ { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
+ { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
+ { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE },
+ { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
+ { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
+ { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
+ { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
+ { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
+ { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE },
+ { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
+ { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
+ { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE },
+ { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
+ { &cg_crosshairHealth, "cg_crosshairHealth", "1", CVAR_ARCHIVE },
+ { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
+ { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
+ { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
+ { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
+ { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
+ { &cg_lagometer, "cg_lagometer", "1", CVAR_ARCHIVE },
+ { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE },
+ { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
+ { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
+ { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
+ { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
+ { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
+ { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
+ { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
+ { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
+ { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
+ { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
+ { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
+ { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
+ { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
+ { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
+ { &cg_errorDecay, "cg_errordecay", "100", 0 },
+ { &cg_nopredict, "cg_nopredict", "0", 0 },
+ { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
+ { &cg_showmiss, "cg_showmiss", "0", 0 },
+ { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
+ { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT },
+ { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT },
+ { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT },
+ { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT },
+ { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT },
+ { &cg_thirdPerson, "cg_thirdPerson", "0", 0 },
+ { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE },
+ { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE },
+ { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
+ { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
+#ifdef MISSIONPACK
+ { &cg_deferPlayers, "cg_deferPlayers", "0", CVAR_ARCHIVE },
+#else
+ { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
+#endif
+ { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE },
+ { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO },
+ { &cg_stats, "cg_stats", "0", 0 },
+ { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
+ { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
+ { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE },
+ { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
+ // the following variables are created in other parts of the system,
+ // but we also reference them here
+ { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
+ { &cg_paused, "cl_paused", "0", CVAR_ROM },
+ { &cg_blood, "com_blood", "1", CVAR_ARCHIVE },
+ { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo
+#ifdef MISSIONPACK
+ { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
+ { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
+ { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
+ { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
+ { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO},
+ { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO},
+ { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO},
+ { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO},
+ { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
+ { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE},
+ { &cg_obeliskRespawnDelay, "g_obeliskRespawnDelay", "10", CVAR_SERVERINFO},
+ { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
+#endif
+ { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
+ { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
+ { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0},
+ { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0},
+ { &cg_timescale, "timescale", "1", 0},
+ { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE},
+ { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
+ { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
+
+ { &pmove_fixed, "pmove_fixed", "0", 0},
+ { &pmove_msec, "pmove_msec", "8", 0},
+ { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE},
+ { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
+ { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
+ { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
+ { &cg_oldRail, "cg_oldRail", "1", CVAR_ARCHIVE},
+ { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE},
+ { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE},
+ { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}
+// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE }
+};
+
+static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
+
+/*
+=================
+CG_RegisterCvars
+=================
+*/
+void CG_RegisterCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+ char var[MAX_TOKEN_CHARS];
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Register( cv->vmCvar, cv->cvarName,
+ cv->defaultString, cv->cvarFlags );
+ }
+
+ // see if we are also running the server on this machine
+ trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
+ cgs.localServer = atoi( var );
+
+ forceModelModificationCount = cg_forceModel.modificationCount;
+
+ trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
+ trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
+ trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
+ trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
+}
+
+/*
+===================
+CG_ForceModelChange
+===================
+*/
+static void CG_ForceModelChange( void ) {
+ int i;
+
+ for (i=0 ; i<MAX_CLIENTS ; i++) {
+ const char *clientInfo;
+
+ clientInfo = CG_ConfigString( CS_PLAYERS+i );
+ if ( !clientInfo[0] ) {
+ continue;
+ }
+ CG_NewClientInfo( i );
+ }
+}
+
+/*
+=================
+CG_UpdateCvars
+=================
+*/
+void CG_UpdateCvars( void ) {
+ int i;
+ cvarTable_t *cv;
+
+ for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
+ trap_Cvar_Update( cv->vmCvar );
+ }
+
+ // check for modications here
+
+ // If team overlay is on, ask for updates from the server. If its off,
+ // let the server know so we don't receive it
+ if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) {
+ drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount;
+
+ if ( cg_drawTeamOverlay.integer > 0 ) {
+ trap_Cvar_Set( "teamoverlay", "1" );
+ } else {
+ trap_Cvar_Set( "teamoverlay", "0" );
+ }
+ // FIXME E3 HACK
+ trap_Cvar_Set( "teamoverlay", "1" );
+ }
+
+ // if force model changed
+ if ( forceModelModificationCount != cg_forceModel.modificationCount ) {
+ forceModelModificationCount = cg_forceModel.modificationCount;
+ CG_ForceModelChange();
+ }
+}
+
+int CG_CrosshairPlayer( void ) {
+ if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) {
+ return -1;
+ }
+ return cg.crosshairClientNum;
+}
+
+int CG_LastAttacker( void ) {
+ if ( !cg.attackerTime ) {
+ return -1;
+ }
+ return cg.snap->ps.persistant[PERS_ATTACKER];
+}
+
+void QDECL CG_Printf( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ vsprintf (text, msg, argptr);
+ va_end (argptr);
+
+ trap_Print( text );
+}
+
+void QDECL CG_Error( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ vsprintf (text, msg, argptr);
+ va_end (argptr);
+
+ trap_Error( text );
+}
+
+#ifndef CGAME_HARD_LINKED
+// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME)
+
+void QDECL Com_Error( int level, const char *error, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, error);
+ vsprintf (text, error, argptr);
+ va_end (argptr);
+
+ CG_Error( "%s", text);
+}
+
+void QDECL Com_Printf( const char *msg, ... ) {
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, msg);
+ vsprintf (text, msg, argptr);
+ va_end (argptr);
+
+ CG_Printf ("%s", text);
+}
+
+#endif
+
+/*
+================
+CG_Argv
+================
+*/
+const char *CG_Argv( int arg ) {
+ static char buffer[MAX_STRING_CHARS];
+
+ trap_Argv( arg, buffer, sizeof( buffer ) );
+
+ return buffer;
+}
+
+
+//========================================================================
+
+/*
+=================
+CG_RegisterItemSounds
+
+The server says this item is used on this level
+=================
+*/
+static void CG_RegisterItemSounds( int itemNum ) {
+ gitem_t *item;
+ char data[MAX_QPATH];
+ char *s, *start;
+ int len;
+
+ item = &bg_itemlist[ itemNum ];
+
+ if( item->pickup_sound ) {
+ trap_S_RegisterSound( item->pickup_sound, qfalse );
+ }
+
+ // parse the space seperated precache string for other media
+ s = item->sounds;
+ if (!s || !s[0])
+ return;
+
+ while (*s) {
+ start = s;
+ while (*s && *s != ' ') {
+ s++;
+ }
+
+ len = s-start;
+ if (len >= MAX_QPATH || len < 5) {
+ CG_Error( "PrecacheItem: %s has bad precache string",
+ item->classname);
+ return;
+ }
+ memcpy (data, start, len);
+ data[len] = 0;
+ if ( *s ) {
+ s++;
+ }
+
+ if ( !strcmp(data+len-3, "wav" )) {
+ trap_S_RegisterSound( data, qfalse );
+ }
+ }
+}
+
+
+/*
+=================
+CG_RegisterSounds
+
+called during a precache command
+=================
+*/
+static void CG_RegisterSounds( void ) {
+ int i;
+ char items[MAX_ITEMS+1];
+ char name[MAX_QPATH];
+ const char *soundName;
+
+ // voice commands
+#ifdef MISSIONPACK
+ CG_LoadVoiceChats();
+#endif
+
+ cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qtrue );
+ cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qtrue );
+ cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qtrue );
+ cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qtrue );
+ cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qtrue );
+ cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qtrue );
+ cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qtrue );
+ cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qtrue );
+ cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qtrue );
+ cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qtrue );
+ cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue );
+#ifdef MISSIONPACK
+ cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue );
+#endif
+
+ if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {
+
+ cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
+ cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qtrue );
+ cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qtrue );
+ cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qtrue );
+ cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qtrue );
+
+ cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qtrue );
+ cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qtrue );
+
+ cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qtrue );
+ cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qtrue );
+
+ cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qtrue );
+ cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
+
+ cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qtrue );
+ cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qtrue );
+
+ if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
+ cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qtrue );
+ cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qtrue );
+ cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qtrue );
+ cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qtrue );
+ }
+
+#ifdef MISSIONPACK
+ if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
+ // FIXME: get a replacement for this sound ?
+ cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
+ cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
+ cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
+ }
+
+ if ( cgs.gametype == GT_1FCTF || cgs.gametype == GT_CTF || cg_buildScript.integer ) {
+ cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
+ cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
+ }
+
+ if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
+ cgs.media.yourBaseIsUnderAttackSound = trap_S_RegisterSound( "sound/teamplay/voc_base_attack.wav", qtrue );
+ }
+#else
+ cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qtrue );
+ cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qtrue);
+ cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qtrue );
+ cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
+ cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
+#endif
+ }
+
+ cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse );
+ cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
+ cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav", qfalse );
+ cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav", qfalse );
+ cgs.media.gibSound = trap_S_RegisterSound( "sound/player/gibsplt1.wav", qfalse );
+ cgs.media.gibBounce1Sound = trap_S_RegisterSound( "sound/player/gibimp1.wav", qfalse );
+ cgs.media.gibBounce2Sound = trap_S_RegisterSound( "sound/player/gibimp2.wav", qfalse );
+ cgs.media.gibBounce3Sound = trap_S_RegisterSound( "sound/player/gibimp3.wav", qfalse );
+
+#ifdef MISSIONPACK
+ cgs.media.useInvulnerabilitySound = trap_S_RegisterSound( "sound/items/invul_activate.wav", qfalse );
+ cgs.media.invulnerabilityImpactSound1 = trap_S_RegisterSound( "sound/items/invul_impact_01.wav", qfalse );
+ cgs.media.invulnerabilityImpactSound2 = trap_S_RegisterSound( "sound/items/invul_impact_02.wav", qfalse );
+ cgs.media.invulnerabilityImpactSound3 = trap_S_RegisterSound( "sound/items/invul_impact_03.wav", qfalse );
+ cgs.media.invulnerabilityJuicedSound = trap_S_RegisterSound( "sound/items/invul_juiced.wav", qfalse );
+ cgs.media.obeliskHitSound1 = trap_S_RegisterSound( "sound/items/obelisk_hit_01.wav", qfalse );
+ cgs.media.obeliskHitSound2 = trap_S_RegisterSound( "sound/items/obelisk_hit_02.wav", qfalse );
+ cgs.media.obeliskHitSound3 = trap_S_RegisterSound( "sound/items/obelisk_hit_03.wav", qfalse );
+ cgs.media.obeliskRespawnSound = trap_S_RegisterSound( "sound/items/obelisk_respawn.wav", qfalse );
+
+ cgs.media.ammoregenSound = trap_S_RegisterSound("sound/items/cl_ammoregen.wav", qfalse);
+ cgs.media.doublerSound = trap_S_RegisterSound("sound/items/cl_doubler.wav", qfalse);
+ cgs.media.guardSound = trap_S_RegisterSound("sound/items/cl_guard.wav", qfalse);
+ cgs.media.scoutSound = trap_S_RegisterSound("sound/items/cl_scout.wav", qfalse);
+#endif
+
+ cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/telein.wav", qfalse );
+ cgs.media.teleOutSound = trap_S_RegisterSound( "sound/world/teleout.wav", qfalse );
+ cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav", qfalse );
+
+ cgs.media.noAmmoSound = trap_S_RegisterSound( "sound/weapons/noammo.wav", qfalse );
+
+ cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav", qfalse );
+ cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav", qfalse);
+
+ cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav", qfalse );
+#ifdef MISSIONPACK
+ cgs.media.hitSoundHighArmor = trap_S_RegisterSound( "sound/feedback/hithi.wav", qfalse );
+ cgs.media.hitSoundLowArmor = trap_S_RegisterSound( "sound/feedback/hitlo.wav", qfalse );
+#endif
+
+ cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav", qtrue );
+ cgs.media.excellentSound = trap_S_RegisterSound( "sound/feedback/excellent.wav", qtrue );
+ cgs.media.deniedSound = trap_S_RegisterSound( "sound/feedback/denied.wav", qtrue );
+ cgs.media.humiliationSound = trap_S_RegisterSound( "sound/feedback/humiliation.wav", qtrue );
+ cgs.media.assistSound = trap_S_RegisterSound( "sound/feedback/assist.wav", qtrue );
+ cgs.media.defendSound = trap_S_RegisterSound( "sound/feedback/defense.wav", qtrue );
+#ifdef MISSIONPACK
+ cgs.media.firstImpressiveSound = trap_S_RegisterSound( "sound/feedback/first_impressive.wav", qtrue );
+ cgs.media.firstExcellentSound = trap_S_RegisterSound( "sound/feedback/first_excellent.wav", qtrue );
+ cgs.media.firstHumiliationSound = trap_S_RegisterSound( "sound/feedback/first_gauntlet.wav", qtrue );
+#endif
+
+ cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/feedback/takenlead.wav", qtrue);
+ cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/feedback/tiedlead.wav", qtrue);
+ cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/feedback/lostlead.wav", qtrue);
+
+#ifdef MISSIONPACK
+ cgs.media.voteNow = trap_S_RegisterSound( "sound/feedback/vote_now.wav", qtrue);
+ cgs.media.votePassed = trap_S_RegisterSound( "sound/feedback/vote_passed.wav", qtrue);
+ cgs.media.voteFailed = trap_S_RegisterSound( "sound/feedback/vote_failed.wav", qtrue);
+#endif
+
+ cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav", qfalse);
+ cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav", qfalse);
+ cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav", qfalse);
+
+ cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/world/jumppad.wav", qfalse );
+
+ for (i=0 ; i<4 ; i++) {
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_NORMAL][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_BOOT][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/flesh%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_FLESH][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/mech%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_MECH][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/energy%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_ENERGY][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/splash%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_SPLASH][i] = trap_S_RegisterSound (name, qfalse);
+
+ Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1);
+ cgs.media.footsteps[FOOTSTEP_METAL][i] = trap_S_RegisterSound (name, qfalse);
+ }
+
+ // only register the items that the server says we need
+ strcpy( items, CG_ConfigString( CS_ITEMS ) );
+
+ for ( i = 1 ; i < bg_numItems ; i++ ) {
+// if ( items[ i ] == '1' || cg_buildScript.integer ) {
+ CG_RegisterItemSounds( i );
+// }
+ }
+
+ for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
+ soundName = CG_ConfigString( CS_SOUNDS+i );
+ if ( !soundName[0] ) {
+ break;
+ }
+ if ( soundName[0] == '*' ) {
+ continue; // custom sound
+ }
+ cgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );
+ }
+
+ // FIXME: only needed with item
+ cgs.media.flightSound = trap_S_RegisterSound( "sound/items/flight.wav", qfalse );
+ cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_medkit.wav", qfalse);
+ cgs.media.quadSound = trap_S_RegisterSound("sound/items/damage3.wav", qfalse);
+ cgs.media.sfx_ric1 = trap_S_RegisterSound ("sound/weapons/machinegun/ric1.wav", qfalse);
+ cgs.media.sfx_ric2 = trap_S_RegisterSound ("sound/weapons/machinegun/ric2.wav", qfalse);
+ cgs.media.sfx_ric3 = trap_S_RegisterSound ("sound/weapons/machinegun/ric3.wav", qfalse);
+ cgs.media.sfx_railg = trap_S_RegisterSound ("sound/weapons/railgun/railgf1a.wav", qfalse);
+ cgs.media.sfx_rockexp = trap_S_RegisterSound ("sound/weapons/rocket/rocklx1a.wav", qfalse);
+ cgs.media.sfx_plasmaexp = trap_S_RegisterSound ("sound/weapons/plasma/plasmx1a.wav", qfalse);
+#ifdef MISSIONPACK
+ cgs.media.sfx_proxexp = trap_S_RegisterSound( "sound/weapons/proxmine/wstbexpl.wav" , qfalse);
+ cgs.media.sfx_nghit = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpd.wav" , qfalse);
+ cgs.media.sfx_nghitflesh = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpl.wav" , qfalse);
+ cgs.media.sfx_nghitmetal = trap_S_RegisterSound( "sound/weapons/nailgun/wnalimpm.wav", qfalse );
+ cgs.media.sfx_chghit = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpd.wav", qfalse );
+ cgs.media.sfx_chghitflesh = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpl.wav", qfalse );
+ cgs.media.sfx_chghitmetal = trap_S_RegisterSound( "sound/weapons/vulcan/wvulimpm.wav", qfalse );
+ cgs.media.weaponHoverSound = trap_S_RegisterSound( "sound/weapons/weapon_hover.wav", qfalse );
+ cgs.media.kamikazeExplodeSound = trap_S_RegisterSound( "sound/items/kam_explode.wav", qfalse );
+ cgs.media.kamikazeImplodeSound = trap_S_RegisterSound( "sound/items/kam_implode.wav", qfalse );
+ cgs.media.kamikazeFarSound = trap_S_RegisterSound( "sound/items/kam_explode_far.wav", qfalse );
+ cgs.media.winnerSound = trap_S_RegisterSound( "sound/feedback/voc_youwin.wav", qfalse );
+ cgs.media.loserSound = trap_S_RegisterSound( "sound/feedback/voc_youlose.wav", qfalse );
+ cgs.media.youSuckSound = trap_S_RegisterSound( "sound/misc/yousuck.wav", qfalse );
+
+ cgs.media.wstbimplSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpl.wav", qfalse);
+ cgs.media.wstbimpmSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpm.wav", qfalse);
+ cgs.media.wstbimpdSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbimpd.wav", qfalse);
+ cgs.media.wstbactvSound = trap_S_RegisterSound("sound/weapons/proxmine/wstbactv.wav", qfalse);
+#endif
+
+ cgs.media.regenSound = trap_S_RegisterSound("sound/items/regen.wav", qfalse);
+ cgs.media.protectSound = trap_S_RegisterSound("sound/items/protect3.wav", qfalse);
+ cgs.media.n_healthSound = trap_S_RegisterSound("sound/items/n_health.wav", qfalse );
+ cgs.media.hgrenb1aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb1a.wav", qfalse);
+ cgs.media.hgrenb2aSound = trap_S_RegisterSound("sound/weapons/grenade/hgrenb2a.wav", qfalse);
+
+#ifdef MISSIONPACK
+ trap_S_RegisterSound("sound/player/james/death1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/death2.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/death3.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/jump1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/pain25_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/pain75_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/pain100_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/falling1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/gasp.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/drown.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/fall1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/james/taunt.wav", qfalse );
+
+ trap_S_RegisterSound("sound/player/janet/death1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/death2.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/death3.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/jump1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/pain25_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/pain75_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/pain100_1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/falling1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/gasp.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/drown.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/fall1.wav", qfalse );
+ trap_S_RegisterSound("sound/player/janet/taunt.wav", qfalse );
+#endif
+
+}
+
+
+//===================================================================================
+
+
+/*
+=================
+CG_RegisterGraphics
+
+This function may execute for a couple of minutes with a slow disk.
+=================
+*/
+static void CG_RegisterGraphics( void ) {
+ int i;
+ char items[MAX_ITEMS+1];
+ static char *sb_nums[11] = {
+ "gfx/2d/numbers/zero_32b",
+ "gfx/2d/numbers/one_32b",
+ "gfx/2d/numbers/two_32b",
+ "gfx/2d/numbers/three_32b",
+ "gfx/2d/numbers/four_32b",
+ "gfx/2d/numbers/five_32b",
+ "gfx/2d/numbers/six_32b",
+ "gfx/2d/numbers/seven_32b",
+ "gfx/2d/numbers/eight_32b",
+ "gfx/2d/numbers/nine_32b",
+ "gfx/2d/numbers/minus_32b",
+ };
+
+ // clear any references to old media
+ memset( &cg.refdef, 0, sizeof( cg.refdef ) );
+ trap_R_ClearScene();
+
+ CG_LoadingString( cgs.mapname );
+
+ trap_R_LoadWorldMap( cgs.mapname );
+
+ // precache status bar pics
+ CG_LoadingString( "game media" );
+
+ for ( i=0 ; i<11 ; i++) {
+ cgs.media.numberShaders[i] = trap_R_RegisterShader( sb_nums[i] );
+ }
+
+ cgs.media.botSkillShaders[0] = trap_R_RegisterShader( "menu/art/skill1.tga" );
+ cgs.media.botSkillShaders[1] = trap_R_RegisterShader( "menu/art/skill2.tga" );
+ cgs.media.botSkillShaders[2] = trap_R_RegisterShader( "menu/art/skill3.tga" );
+ cgs.media.botSkillShaders[3] = trap_R_RegisterShader( "menu/art/skill4.tga" );
+ cgs.media.botSkillShaders[4] = trap_R_RegisterShader( "menu/art/skill5.tga" );
+
+ cgs.media.viewBloodShader = trap_R_RegisterShader( "viewBloodBlend" );
+
+ cgs.media.deferShader = trap_R_RegisterShaderNoMip( "gfx/2d/defer.tga" );
+
+ cgs.media.scoreboardName = trap_R_RegisterShaderNoMip( "menu/tab/name.tga" );
+ cgs.media.scoreboardPing = trap_R_RegisterShaderNoMip( "menu/tab/ping.tga" );
+ cgs.media.scoreboardScore = trap_R_RegisterShaderNoMip( "menu/tab/score.tga" );
+ cgs.media.scoreboardTime = trap_R_RegisterShaderNoMip( "menu/tab/time.tga" );
+
+ cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" );
+ cgs.media.smokePuffRageProShader = trap_R_RegisterShader( "smokePuffRagePro" );
+ cgs.media.shotgunSmokePuffShader = trap_R_RegisterShader( "shotgunSmokePuff" );
+#ifdef MISSIONPACK
+ cgs.media.nailPuffShader = trap_R_RegisterShader( "nailtrail" );
+ cgs.media.blueProxMine = trap_R_RegisterModel( "models/weaphits/proxmineb.md3" );
+#endif
+ cgs.media.plasmaBallShader = trap_R_RegisterShader( "sprites/plasma1" );
+ cgs.media.bloodTrailShader = trap_R_RegisterShader( "bloodTrail" );
+ cgs.media.lagometerShader = trap_R_RegisterShader("lagometer" );
+ cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" );
+
+ cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" );
+
+ cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" );
+ cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" );
+
+ for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) {
+ cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/2d/crosshair%c", 'a'+i) );
+ }
+
+ cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" );
+ cgs.media.noammoShader = trap_R_RegisterShader( "icons/noammo" );
+
+ // powerup shaders
+ cgs.media.quadShader = trap_R_RegisterShader("powerups/quad" );
+ cgs.media.quadWeaponShader = trap_R_RegisterShader("powerups/quadWeapon" );
+ cgs.media.battleSuitShader = trap_R_RegisterShader("powerups/battleSuit" );
+ cgs.media.battleWeaponShader = trap_R_RegisterShader("powerups/battleWeapon" );
+ cgs.media.invisShader = trap_R_RegisterShader("powerups/invisibility" );
+ cgs.media.regenShader = trap_R_RegisterShader("powerups/regen" );
+ cgs.media.hastePuffShader = trap_R_RegisterShader("hasteSmokePuff" );
+
+#ifdef MISSIONPACK
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
+#else
+ if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
+#endif
+ cgs.media.redCubeModel = trap_R_RegisterModel( "models/powerups/orb/r_orb.md3" );
+ cgs.media.blueCubeModel = trap_R_RegisterModel( "models/powerups/orb/b_orb.md3" );
+ cgs.media.redCubeIcon = trap_R_RegisterShader( "icons/skull_red" );
+ cgs.media.blueCubeIcon = trap_R_RegisterShader( "icons/skull_blue" );
+ }
+
+#ifdef MISSIONPACK
+ if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF || cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
+#else
+ if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) {
+#endif
+ cgs.media.redFlagModel = trap_R_RegisterModel( "models/flags/r_flag.md3" );
+ cgs.media.blueFlagModel = trap_R_RegisterModel( "models/flags/b_flag.md3" );
+ cgs.media.redFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_red1" );
+ cgs.media.redFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
+ cgs.media.redFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_red3" );
+ cgs.media.blueFlagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_blu1" );
+ cgs.media.blueFlagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
+ cgs.media.blueFlagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu3" );
+#ifdef MISSIONPACK
+ cgs.media.flagPoleModel = trap_R_RegisterModel( "models/flag2/flagpole.md3" );
+ cgs.media.flagFlapModel = trap_R_RegisterModel( "models/flag2/flagflap3.md3" );
+
+ cgs.media.redFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/red.skin" );
+ cgs.media.blueFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/blue.skin" );
+ cgs.media.neutralFlagFlapSkin = trap_R_RegisterSkin( "models/flag2/white.skin" );
+
+ cgs.media.redFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/red_base.md3" );
+ cgs.media.blueFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/blue_base.md3" );
+ cgs.media.neutralFlagBaseModel = trap_R_RegisterModel( "models/mapobjects/flagbase/ntrl_base.md3" );
+#endif
+ }
+
+#ifdef MISSIONPACK
+ if ( cgs.gametype == GT_1FCTF || cg_buildScript.integer ) {
+ cgs.media.neutralFlagModel = trap_R_RegisterModel( "models/flags/n_flag.md3" );
+ cgs.media.flagShader[0] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral1" );
+ cgs.media.flagShader[1] = trap_R_RegisterShaderNoMip( "icons/iconf_red2" );
+ cgs.media.flagShader[2] = trap_R_RegisterShaderNoMip( "icons/iconf_blu2" );
+ cgs.media.flagShader[3] = trap_R_RegisterShaderNoMip( "icons/iconf_neutral3" );
+ }
+
+ if ( cgs.gametype == GT_OBELISK || cg_buildScript.integer ) {
+ cgs.media.overloadBaseModel = trap_R_RegisterModel( "models/powerups/overload_base.md3" );
+ cgs.media.overloadTargetModel = trap_R_RegisterModel( "models/powerups/overload_target.md3" );
+ cgs.media.overloadLightsModel = trap_R_RegisterModel( "models/powerups/overload_lights.md3" );
+ cgs.media.overloadEnergyModel = trap_R_RegisterModel( "models/powerups/overload_energy.md3" );
+ }
+
+ if ( cgs.gametype == GT_HARVESTER || cg_buildScript.integer ) {
+ cgs.media.harvesterModel = trap_R_RegisterModel( "models/powerups/harvester/harvester.md3" );
+ cgs.media.harvesterRedSkin = trap_R_RegisterSkin( "models/powerups/harvester/red.skin" );
+ cgs.media.harvesterBlueSkin = trap_R_RegisterSkin( "models/powerups/harvester/blue.skin" );
+ cgs.media.harvesterNeutralModel = trap_R_RegisterModel( "models/powerups/obelisk/obelisk.md3" );
+ }
+
+ cgs.media.redKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikred" );
+ cgs.media.dustPuffShader = trap_R_RegisterShader("hasteSmokePuff" );
+#endif
+
+ if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {
+ cgs.media.friendShader = trap_R_RegisterShader( "sprites/foe" );
+ cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" );
+ cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" );
+#ifdef MISSIONPACK
+ cgs.media.blueKamikazeShader = trap_R_RegisterShader( "models/weaphits/kamikblu" );
+#endif
+ }
+
+ cgs.media.armorModel = trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" );
+ cgs.media.armorIcon = trap_R_RegisterShaderNoMip( "icons/iconr_yellow" );
+
+ cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" );
+ cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
+
+ cgs.media.gibAbdomen = trap_R_RegisterModel( "models/gibs/abdomen.md3" );
+ cgs.media.gibArm = trap_R_RegisterModel( "models/gibs/arm.md3" );
+ cgs.media.gibChest = trap_R_RegisterModel( "models/gibs/chest.md3" );
+ cgs.media.gibFist = trap_R_RegisterModel( "models/gibs/fist.md3" );
+ cgs.media.gibFoot = trap_R_RegisterModel( "models/gibs/foot.md3" );
+ cgs.media.gibForearm = trap_R_RegisterModel( "models/gibs/forearm.md3" );
+ cgs.media.gibIntestine = trap_R_RegisterModel( "models/gibs/intestine.md3" );
+ cgs.media.gibLeg = trap_R_RegisterModel( "models/gibs/leg.md3" );
+ cgs.media.gibSkull = trap_R_RegisterModel( "models/gibs/skull.md3" );
+ cgs.media.gibBrain = trap_R_RegisterModel( "models/gibs/brain.md3" );
+
+ cgs.media.smoke2 = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
+
+ cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" );
+
+ cgs.media.bloodExplosionShader = trap_R_RegisterShader( "bloodExplosion" );
+
+ cgs.media.bulletFlashModel = trap_R_RegisterModel("models/weaphits/bullet.md3");
+ cgs.media.ringFlashModel = trap_R_RegisterModel("models/weaphits/ring02.md3");
+ cgs.media.dishFlashModel = trap_R_RegisterModel("models/weaphits/boom01.md3");
+#ifdef MISSIONPACK
+ cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/powerups/pop.md3" );
+#else
+ cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" );
+ cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" );
+#endif
+#ifdef MISSIONPACK
+ cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" );
+ cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" );
+ cgs.media.kamikazeHeadModel = trap_R_RegisterModel( "models/powerups/kamikazi.md3" );
+ cgs.media.kamikazeHeadTrail = trap_R_RegisterModel( "models/powerups/trailtest.md3" );
+ cgs.media.guardPowerupModel = trap_R_RegisterModel( "models/powerups/guard_player.md3" );
+ cgs.media.scoutPowerupModel = trap_R_RegisterModel( "models/powerups/scout_player.md3" );
+ cgs.media.doublerPowerupModel = trap_R_RegisterModel( "models/powerups/doubler_player.md3" );
+ cgs.media.ammoRegenPowerupModel = trap_R_RegisterModel( "models/powerups/ammo_player.md3" );
+ cgs.media.invulnerabilityImpactModel = trap_R_RegisterModel( "models/powerups/shield/impact.md3" );
+ cgs.media.invulnerabilityJuicedModel = trap_R_RegisterModel( "models/powerups/shield/juicer.md3" );
+ cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" );
+ cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" );
+
+#endif
+
+ cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" );
+ cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" );
+ cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" );
+ cgs.media.medalGauntlet = trap_R_RegisterShaderNoMip( "medal_gauntlet" );
+ cgs.media.medalDefend = trap_R_RegisterShaderNoMip( "medal_defend" );
+ cgs.media.medalAssist = trap_R_RegisterShaderNoMip( "medal_assist" );
+ cgs.media.medalCapture = trap_R_RegisterShaderNoMip( "medal_capture" );
+
+
+ memset( cg_items, 0, sizeof( cg_items ) );
+ memset( cg_weapons, 0, sizeof( cg_weapons ) );
+
+ // only register the items that the server says we need
+ strcpy( items, CG_ConfigString( CS_ITEMS) );
+
+ for ( i = 1 ; i < bg_numItems ; i++ ) {
+ if ( items[ i ] == '1' || cg_buildScript.integer ) {
+ CG_LoadingItem( i );
+ CG_RegisterItemVisuals( i );
+ }
+ }
+
+ // wall marks
+ cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" );
+ cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" );
+ cgs.media.holeMarkShader = trap_R_RegisterShader( "gfx/damage/hole_lg_mrk" );
+ cgs.media.energyMarkShader = trap_R_RegisterShader( "gfx/damage/plasma_mrk" );
+ cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" );
+ cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" );
+ cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" );
+
+ // register the inline models
+ cgs.numInlineModels = trap_CM_NumInlineModels();
+ for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
+ char name[10];
+ vec3_t mins, maxs;
+ int j;
+
+ Com_sprintf( name, sizeof(name), "*%i", i );
+ cgs.inlineDrawModel[i] = trap_R_RegisterModel( name );
+ trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
+ for ( j = 0 ; j < 3 ; j++ ) {
+ cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
+ }
+ }
+
+ // register all the server specified models
+ for (i=1 ; i<MAX_MODELS ; i++) {
+ const char *modelName;
+
+ modelName = CG_ConfigString( CS_MODELS+i );
+ if ( !modelName[0] ) {
+ break;
+ }
+ cgs.gameModels[i] = trap_R_RegisterModel( modelName );
+ }
+
+#ifdef MISSIONPACK
+ // new stuff
+ cgs.media.patrolShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/patrol.tga");
+ cgs.media.assaultShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/assault.tga");
+ cgs.media.campShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/camp.tga");
+ cgs.media.followShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/follow.tga");
+ cgs.media.defendShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/defend.tga");
+ cgs.media.teamLeaderShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/team_leader.tga");
+ cgs.media.retrieveShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/retrieve.tga");
+ cgs.media.escortShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/escort.tga");
+ cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
+ cgs.media.sizeCursor = trap_R_RegisterShaderNoMip( "ui/assets/sizecursor.tga" );
+ cgs.media.selectCursor = trap_R_RegisterShaderNoMip( "ui/assets/selectcursor.tga" );
+ cgs.media.flagShaders[0] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_in_base.tga");
+ cgs.media.flagShaders[1] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_capture.tga");
+ cgs.media.flagShaders[2] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_missing.tga");
+
+ trap_R_RegisterModel( "models/players/james/lower.md3" );
+ trap_R_RegisterModel( "models/players/james/upper.md3" );
+ trap_R_RegisterModel( "models/players/heads/james/james.md3" );
+
+ trap_R_RegisterModel( "models/players/janet/lower.md3" );
+ trap_R_RegisterModel( "models/players/janet/upper.md3" );
+ trap_R_RegisterModel( "models/players/heads/janet/janet.md3" );
+
+#endif
+ CG_ClearParticles ();
+/*
+ for (i=1; i<MAX_PARTICLES_AREAS; i++)
+ {
+ {
+ int rval;
+
+ rval = CG_NewParticleArea ( CS_PARTICLES + i);
+ if (!rval)
+ break;
+ }
+ }
+*/
+}
+
+
+
+/*
+=======================
+CG_BuildSpectatorString
+
+=======================
+*/
+void CG_BuildSpectatorString() {
+ int i;
+ cg.spectatorList[0] = 0;
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_SPECTATOR ) {
+ Q_strcat(cg.spectatorList, sizeof(cg.spectatorList), va("%s ", cgs.clientinfo[i].name));
+ }
+ }
+ i = strlen(cg.spectatorList);
+ if (i != cg.spectatorLen) {
+ cg.spectatorLen = i;
+ cg.spectatorWidth = -1;
+ }
+}
+
+
+/*
+===================
+CG_RegisterClients
+===================
+*/
+static void CG_RegisterClients( void ) {
+ int i;
+
+ CG_LoadingClient(cg.clientNum);
+ CG_NewClientInfo(cg.clientNum);
+
+ for (i=0 ; i<MAX_CLIENTS ; i++) {
+ const char *clientInfo;
+
+ if (cg.clientNum == i) {
+ continue;
+ }
+
+ clientInfo = CG_ConfigString( CS_PLAYERS+i );
+ if ( !clientInfo[0]) {
+ continue;
+ }
+ CG_LoadingClient( i );
+ CG_NewClientInfo( i );
+ }
+ CG_BuildSpectatorString();
+}
+
+//===========================================================================
+
+/*
+=================
+CG_ConfigString
+=================
+*/
+const char *CG_ConfigString( int index ) {
+ if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
+ CG_Error( "CG_ConfigString: bad index: %i", index );
+ }
+ return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
+}
+
+//==================================================================
+
+/*
+======================
+CG_StartMusic
+
+======================
+*/
+void CG_StartMusic( void ) {
+ char *s;
+ char parm1[MAX_QPATH], parm2[MAX_QPATH];
+
+ // start the background music
+ s = (char *)CG_ConfigString( CS_MUSIC );
+ Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
+ Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
+
+ trap_S_StartBackgroundTrack( parm1, parm2 );
+}
+#ifdef MISSIONPACK
+char *CG_GetMenuBuffer(const char *filename) {
+ int len;
+ fileHandle_t f;
+ static char buf[MAX_MENUFILE];
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
+ return NULL;
+ }
+ if ( len >= MAX_MENUFILE ) {
+ trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
+ trap_FS_FCloseFile( f );
+ return NULL;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ return buf;
+}
+
+//
+// ==============================
+// new hud stuff ( mission pack )
+// ==============================
+//
+qboolean CG_Asset_Parse(int handle) {
+ pc_token_t token;
+ const char *tempStr;
+
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+ if (Q_stricmp(token.string, "{") != 0) {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken(handle, &token))
+ return qfalse;
+
+ if (Q_stricmp(token.string, "}") == 0) {
+ return qtrue;
+ }
+
+ // font
+ if (Q_stricmp(token.string, "font") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
+ return qfalse;
+ }
+ cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont);
+ continue;
+ }
+
+ // smallFont
+ if (Q_stricmp(token.string, "smallFont") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
+ return qfalse;
+ }
+ cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont);
+ continue;
+ }
+
+ // font
+ if (Q_stricmp(token.string, "bigfont") == 0) {
+ int pointSize;
+ if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle, &pointSize)) {
+ return qfalse;
+ }
+ cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont);
+ continue;
+ }
+
+ // gradientbar
+ if (Q_stricmp(token.string, "gradientbar") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
+ continue;
+ }
+
+ // enterMenuSound
+ if (Q_stricmp(token.string, "menuEnterSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // exitMenuSound
+ if (Q_stricmp(token.string, "menuExitSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // itemFocusSound
+ if (Q_stricmp(token.string, "itemFocusSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ // menuBuzzSound
+ if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
+ if (!PC_String_Parse(handle, &tempStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "cursor") == 0) {
+ if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) {
+ return qfalse;
+ }
+ cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeClamp") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeCycle") == 0) {
+ if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "fadeAmount") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowX") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowY") == 0) {
+ if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) {
+ return qfalse;
+ }
+ continue;
+ }
+
+ if (Q_stricmp(token.string, "shadowColor") == 0) {
+ if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) {
+ return qfalse;
+ }
+ cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
+ continue;
+ }
+ }
+ return qfalse; // bk001204 - why not?
+}
+
+void CG_ParseMenu(const char *menuFile) {
+ pc_token_t token;
+ int handle;
+
+ handle = trap_PC_LoadSource(menuFile);
+ if (!handle)
+ handle = trap_PC_LoadSource("ui/testhud.menu");
+ if (!handle)
+ return;
+
+ while ( 1 ) {
+ if (!trap_PC_ReadToken( handle, &token )) {
+ break;
+ }
+
+ //if ( Q_stricmp( token, "{" ) ) {
+ // Com_Printf( "Missing { in menu file\n" );
+ // break;
+ //}
+
+ //if ( menuCount == MAX_MENUS ) {
+ // Com_Printf( "Too many menus!\n" );
+ // break;
+ //}
+
+ if ( token.string[0] == '}' ) {
+ break;
+ }
+
+ if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
+ if (CG_Asset_Parse(handle)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+
+ if (Q_stricmp(token.string, "menudef") == 0) {
+ // start a new menu
+ Menu_New(handle);
+ }
+ }
+ trap_PC_FreeSource(handle);
+}
+
+qboolean CG_Load_Menu(char **p) {
+ char *token;
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (token[0] != '{') {
+ return qfalse;
+ }
+
+ while ( 1 ) {
+
+ token = COM_ParseExt(p, qtrue);
+
+ if (Q_stricmp(token, "}") == 0) {
+ return qtrue;
+ }
+
+ if ( !token || token[0] == 0 ) {
+ return qfalse;
+ }
+
+ CG_ParseMenu(token);
+ }
+ return qfalse;
+}
+
+
+
+void CG_LoadMenus(const char *menuFile) {
+ char *token;
+ char *p;
+ int len, start;
+ fileHandle_t f;
+ static char buf[MAX_MENUDEFFILE];
+
+ start = trap_Milliseconds();
+
+ len = trap_FS_FOpenFile( menuFile, &f, FS_READ );
+ if ( !f ) {
+ trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
+ len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ );
+ if (!f) {
+ trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n", menuFile ) );
+ }
+ }
+
+ if ( len >= MAX_MENUDEFFILE ) {
+ trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", menuFile, len, MAX_MENUDEFFILE ) );
+ trap_FS_FCloseFile( f );
+ return;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ COM_Compress(buf);
+
+ Menu_Reset();
+
+ p = buf;
+
+ while ( 1 ) {
+ token = COM_ParseExt( &p, qtrue );
+ if( !token || token[0] == 0 || token[0] == '}') {
+ break;
+ }
+
+ //if ( Q_stricmp( token, "{" ) ) {
+ // Com_Printf( "Missing { in menu file\n" );
+ // break;
+ //}
+
+ //if ( menuCount == MAX_MENUS ) {
+ // Com_Printf( "Too many menus!\n" );
+ // break;
+ //}
+
+ if ( Q_stricmp( token, "}" ) == 0 ) {
+ break;
+ }
+
+ if (Q_stricmp(token, "loadmenu") == 0) {
+ if (CG_Load_Menu(&p)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
+
+}
+
+
+
+static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
+ return qfalse;
+}
+
+
+static int CG_FeederCount(float feederID) {
+ int i, count;
+ count = 0;
+ if (feederID == FEEDER_REDTEAM_LIST) {
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == TEAM_RED) {
+ count++;
+ }
+ }
+ } else if (feederID == FEEDER_BLUETEAM_LIST) {
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == TEAM_BLUE) {
+ count++;
+ }
+ }
+ } else if (feederID == FEEDER_SCOREBOARD) {
+ return cg.numScores;
+ }
+ return count;
+}
+
+
+void CG_SetScoreSelection(void *p) {
+ menuDef_t *menu = (menuDef_t*)p;
+ playerState_t *ps = &cg.snap->ps;
+ int i, red, blue;
+ red = blue = 0;
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == TEAM_RED) {
+ red++;
+ } else if (cg.scores[i].team == TEAM_BLUE) {
+ blue++;
+ }
+ if (ps->clientNum == cg.scores[i].client) {
+ cg.selectedScore = i;
+ }
+ }
+
+ if (menu == NULL) {
+ // just interested in setting the selected score
+ return;
+ }
+
+ if ( cgs.gametype >= GT_TEAM ) {
+ int feeder = FEEDER_REDTEAM_LIST;
+ i = red;
+ if (cg.scores[cg.selectedScore].team == TEAM_BLUE) {
+ feeder = FEEDER_BLUETEAM_LIST;
+ i = blue;
+ }
+ Menu_SetFeederSelection(menu, feeder, i, NULL);
+ } else {
+ Menu_SetFeederSelection(menu, FEEDER_SCOREBOARD, cg.selectedScore, NULL);
+ }
+}
+
+// FIXME: might need to cache this info
+static clientInfo_t * CG_InfoFromScoreIndex(int index, int team, int *scoreIndex) {
+ int i, count;
+ if ( cgs.gametype >= GT_TEAM ) {
+ count = 0;
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == team) {
+ if (count == index) {
+ *scoreIndex = i;
+ return &cgs.clientinfo[cg.scores[i].client];
+ }
+ count++;
+ }
+ }
+ }
+ *scoreIndex = index;
+ return &cgs.clientinfo[ cg.scores[index].client ];
+}
+
+static const char *CG_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
+ gitem_t *item;
+ int scoreIndex = 0;
+ clientInfo_t *info = NULL;
+ int team = -1;
+ score_t *sp = NULL;
+
+ *handle = -1;
+
+ if (feederID == FEEDER_REDTEAM_LIST) {
+ team = TEAM_RED;
+ } else if (feederID == FEEDER_BLUETEAM_LIST) {
+ team = TEAM_BLUE;
+ }
+
+ info = CG_InfoFromScoreIndex(index, team, &scoreIndex);
+ sp = &cg.scores[scoreIndex];
+
+ if (info && info->infoValid) {
+ switch (column) {
+ case 0:
+ if ( info->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+ *handle = cg_items[ ITEM_INDEX(item) ].icon;
+ } else if ( info->powerups & ( 1 << PW_REDFLAG ) ) {
+ item = BG_FindItemForPowerup( PW_REDFLAG );
+ *handle = cg_items[ ITEM_INDEX(item) ].icon;
+ } else if ( info->powerups & ( 1 << PW_BLUEFLAG ) ) {
+ item = BG_FindItemForPowerup( PW_BLUEFLAG );
+ *handle = cg_items[ ITEM_INDEX(item) ].icon;
+ } else {
+ if ( info->botSkill > 0 && info->botSkill <= 5 ) {
+ *handle = cgs.media.botSkillShaders[ info->botSkill - 1 ];
+ } else if ( info->handicap < 100 ) {
+ return va("%i", info->handicap );
+ }
+ }
+ break;
+ case 1:
+ if (team == -1) {
+ return "";
+ } else {
+ *handle = CG_StatusHandle(info->teamTask);
+ }
+ break;
+ case 2:
+ if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << sp->client ) ) {
+ return "Ready";
+ }
+ if (team == -1) {
+ if (cgs.gametype == GT_TOURNAMENT) {
+ return va("%i/%i", info->wins, info->losses);
+ } else if (info->infoValid && info->team == TEAM_SPECTATOR ) {
+ return "Spectator";
+ } else {
+ return "";
+ }
+ } else {
+ if (info->teamLeader) {
+ return "Leader";
+ }
+ }
+ break;
+ case 3:
+ return info->name;
+ break;
+ case 4:
+ return va("%i", info->score);
+ break;
+ case 5:
+ return va("%4i", sp->time);
+ break;
+ case 6:
+ if ( sp->ping == -1 ) {
+ return "connecting";
+ }
+ return va("%4i", sp->ping);
+ break;
+ }
+ }
+
+ return "";
+}
+
+static qhandle_t CG_FeederItemImage(float feederID, int index) {
+ return 0;
+}
+
+static void CG_FeederSelection(float feederID, int index) {
+ if ( cgs.gametype >= GT_TEAM ) {
+ int i, count;
+ int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE;
+ count = 0;
+ for (i = 0; i < cg.numScores; i++) {
+ if (cg.scores[i].team == team) {
+ if (index == count) {
+ cg.selectedScore = i;
+ }
+ count++;
+ }
+ }
+ } else {
+ cg.selectedScore = index;
+ }
+}
+#endif
+
+#ifdef MISSIONPACK // bk001204 - only needed there
+static float CG_Cvar_Get(const char *cvar) {
+ char buff[128];
+ memset(buff, 0, sizeof(buff));
+ trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff));
+ return atof(buff);
+}
+#endif
+
+#ifdef MISSIONPACK
+void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
+ CG_Text_Paint(x, y, scale, color, text, 0, limit, style);
+}
+
+static int CG_OwnerDrawWidth(int ownerDraw, float scale) {
+ switch (ownerDraw) {
+ case CG_GAME_TYPE:
+ return CG_Text_Width(CG_GameTypeString(), scale, 0);
+ case CG_GAME_STATUS:
+ return CG_Text_Width(CG_GetGameStatusText(), scale, 0);
+ break;
+ case CG_KILLER:
+ return CG_Text_Width(CG_GetKillerText(), scale, 0);
+ break;
+ case CG_RED_NAME:
+ return CG_Text_Width(cg_redTeamName.string, scale, 0);
+ break;
+ case CG_BLUE_NAME:
+ return CG_Text_Width(cg_blueTeamName.string, scale, 0);
+ break;
+
+
+ }
+ return 0;
+}
+
+static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
+ return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
+}
+
+static void CG_StopCinematic(int handle) {
+ trap_CIN_StopCinematic(handle);
+}
+
+static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
+ trap_CIN_SetExtents(handle, x, y, w, h);
+ trap_CIN_DrawCinematic(handle);
+}
+
+static void CG_RunCinematicFrame(int handle) {
+ trap_CIN_RunCinematic(handle);
+}
+
+/*
+=================
+CG_LoadHudMenu();
+
+=================
+*/
+void CG_LoadHudMenu() {
+ char buff[1024];
+ const char *hudSet;
+
+ cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
+ cgDC.setColor = &trap_R_SetColor;
+ cgDC.drawHandlePic = &CG_DrawPic;
+ cgDC.drawStretchPic = &trap_R_DrawStretchPic;
+ cgDC.drawText = &CG_Text_Paint;
+ cgDC.textWidth = &CG_Text_Width;
+ cgDC.textHeight = &CG_Text_Height;
+ cgDC.registerModel = &trap_R_RegisterModel;
+ cgDC.modelBounds = &trap_R_ModelBounds;
+ cgDC.fillRect = &CG_FillRect;
+ cgDC.drawRect = &CG_DrawRect;
+ cgDC.drawSides = &CG_DrawSides;
+ cgDC.drawTopBottom = &CG_DrawTopBottom;
+ cgDC.clearScene = &trap_R_ClearScene;
+ cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
+ cgDC.renderScene = &trap_R_RenderScene;
+ cgDC.registerFont = &trap_R_RegisterFont;
+ cgDC.ownerDrawItem = &CG_OwnerDraw;
+ cgDC.getValue = &CG_GetValue;
+ cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
+ cgDC.runScript = &CG_RunMenuScript;
+ cgDC.getTeamColor = &CG_GetTeamColor;
+ cgDC.setCVar = trap_Cvar_Set;
+ cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
+ cgDC.getCVarValue = CG_Cvar_Get;
+ cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
+ //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
+ //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
+ cgDC.startLocalSound = &trap_S_StartLocalSound;
+ cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
+ cgDC.feederCount = &CG_FeederCount;
+ cgDC.feederItemImage = &CG_FeederItemImage;
+ cgDC.feederItemText = &CG_FeederItemText;
+ cgDC.feederSelection = &CG_FeederSelection;
+ //cgDC.setBinding = &trap_Key_SetBinding;
+ //cgDC.getBindingBuf = &trap_Key_GetBindingBuf;
+ //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
+ //cgDC.executeText = &trap_Cmd_ExecuteText;
+ cgDC.Error = &Com_Error;
+ cgDC.Print = &Com_Printf;
+ cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
+ //cgDC.Pause = &CG_Pause;
+ cgDC.registerSound = &trap_S_RegisterSound;
+ cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
+ cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
+ cgDC.playCinematic = &CG_PlayCinematic;
+ cgDC.stopCinematic = &CG_StopCinematic;
+ cgDC.drawCinematic = &CG_DrawCinematic;
+ cgDC.runCinematicFrame = &CG_RunCinematicFrame;
+
+ Init_Display(&cgDC);
+
+ Menu_Reset();
+
+ trap_Cvar_VariableStringBuffer("cg_hudFiles", buff, sizeof(buff));
+ hudSet = buff;
+ if (hudSet[0] == '\0') {
+ hudSet = "ui/hud.txt";
+ }
+
+ CG_LoadMenus(hudSet);
+}
+
+void CG_AssetCache() {
+ //if (Assets.textFont == NULL) {
+ // trap_R_RegisterFont("fonts/arial.ttf", 72, &Assets.textFont);
+ //}
+ //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
+ //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
+ cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
+ cgDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
+ cgDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
+ cgDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
+ cgDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
+ cgDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
+ cgDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
+ cgDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
+ cgDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
+ cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
+ cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
+ cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
+ cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
+ cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
+ cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
+ cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
+ cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
+}
+#endif
+/*
+=================
+CG_Init
+
+Called after every level change or subsystem restart
+Will perform callbacks to make the loading info screen update.
+=================
+*/
+void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {
+ const char *s;
+
+ // clear everything
+ memset( &cgs, 0, sizeof( cgs ) );
+ memset( &cg, 0, sizeof( cg ) );
+ memset( cg_entities, 0, sizeof(cg_entities) );
+ memset( cg_weapons, 0, sizeof(cg_weapons) );
+ memset( cg_items, 0, sizeof(cg_items) );
+
+ cg.clientNum = clientNum;
+
+ cgs.processedSnapshotNum = serverMessageNum;
+ cgs.serverCommandSequence = serverCommandSequence;
+
+ // load a few needed things before we do any screen updates
+ cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" );
+ cgs.media.whiteShader = trap_R_RegisterShader( "white" );
+ cgs.media.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
+ cgs.media.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
+ cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
+
+ CG_RegisterCvars();
+
+ CG_InitConsoleCommands();
+
+ cg.weaponSelect = WP_MACHINEGUN;
+
+ cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for
+ cgs.flagStatus = -1;
+ // old servers
+
+ // get the rendering configuration from the client system
+ trap_GetGlconfig( &cgs.glconfig );
+ cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
+ cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
+
+ // get the gamestate from the client system
+ trap_GetGameState( &cgs.gameState );
+
+ // check version
+ s = CG_ConfigString( CS_GAME_VERSION );
+ if ( strcmp( s, GAME_VERSION ) ) {
+ CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
+ }
+
+ s = CG_ConfigString( CS_LEVEL_START_TIME );
+ cgs.levelStartTime = atoi( s );
+
+ CG_ParseServerinfo();
+
+ // load the new map
+ CG_LoadingString( "collision map" );
+
+ trap_CM_LoadMap( cgs.mapname );
+
+#ifdef MISSIONPACK
+ String_Init();
+#endif
+
+ cg.loading = qtrue; // force players to load instead of defer
+
+ CG_LoadingString( "sounds" );
+
+ CG_RegisterSounds();
+
+ CG_LoadingString( "graphics" );
+
+ CG_RegisterGraphics();
+
+ CG_LoadingString( "clients" );
+
+ CG_RegisterClients(); // if low on memory, some clients will be deferred
+
+#ifdef MISSIONPACK
+ CG_AssetCache();
+ CG_LoadHudMenu(); // load new hud stuff
+#endif
+
+ cg.loading = qfalse; // future players will be deferred
+
+ CG_InitLocalEntities();
+
+ CG_InitMarkPolys();
+
+ // remove the last loading update
+ cg.infoScreenText[0] = 0;
+
+ // Make sure we have update values (scores)
+ CG_SetConfigValues();
+
+ CG_StartMusic();
+
+ CG_LoadingString( "" );
+
+#ifdef MISSIONPACK
+ CG_InitTeamChat();
+#endif
+
+ CG_ShaderStateChanged();
+
+ trap_S_ClearLoopingSounds( qtrue );
+}
+
+/*
+=================
+CG_Shutdown
+
+Called before every level change or subsystem restart
+=================
+*/
+void CG_Shutdown( void ) {
+ // some mods may need to do cleanup work here,
+ // like closing files or archiving session data
+}
+
+
+/*
+==================
+CG_EventHandling
+==================
+ type 0 - no event handling
+ 1 - team menu
+ 2 - hud editor
+
+*/
+#ifndef MISSIONPACK
+void CG_EventHandling(int type) {
+}
+
+
+
+void CG_KeyEvent(int key, qboolean down) {
+}
+
+void CG_MouseEvent(int x, int y) {
+}
+#endif
+
diff --git a/code/cgame/cg_marks.c b/code/cgame/cg_marks.c
index 4c648d2..d0fecaa 100755
--- a/code/cgame/cg_marks.c
+++ b/code/cgame/cg_marks.c
@@ -1,2274 +1,2274 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_marks.c -- wall marks
-
-#include "cg_local.h"
-
-/*
-===================================================================
-
-MARK POLYS
-
-===================================================================
-*/
-
-
-markPoly_t cg_activeMarkPolys; // double linked list
-markPoly_t *cg_freeMarkPolys; // single linked list
-markPoly_t cg_markPolys[MAX_MARK_POLYS];
-static int markTotal;
-
-/*
-===================
-CG_InitMarkPolys
-
-This is called at startup and for tournement restarts
-===================
-*/
-void CG_InitMarkPolys( void ) {
- int i;
-
- memset( cg_markPolys, 0, sizeof(cg_markPolys) );
-
- cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
- cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
- cg_freeMarkPolys = cg_markPolys;
- for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
- cg_markPolys[i].nextMark = &cg_markPolys[i+1];
- }
-}
-
-
-/*
-==================
-CG_FreeMarkPoly
-==================
-*/
-void CG_FreeMarkPoly( markPoly_t *le ) {
- if ( !le->prevMark ) {
- CG_Error( "CG_FreeLocalEntity: not active" );
- }
-
- // remove from the doubly linked active list
- le->prevMark->nextMark = le->nextMark;
- le->nextMark->prevMark = le->prevMark;
-
- // the free list is only singly linked
- le->nextMark = cg_freeMarkPolys;
- cg_freeMarkPolys = le;
-}
-
-/*
-===================
-CG_AllocMark
-
-Will allways succeed, even if it requires freeing an old active mark
-===================
-*/
-markPoly_t *CG_AllocMark( void ) {
- markPoly_t *le;
- int time;
-
- if ( !cg_freeMarkPolys ) {
- // no free entities, so free the one at the end of the chain
- // remove the oldest active entity
- time = cg_activeMarkPolys.prevMark->time;
- while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
- CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
- }
- }
-
- le = cg_freeMarkPolys;
- cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
-
- memset( le, 0, sizeof( *le ) );
-
- // link into the active list
- le->nextMark = cg_activeMarkPolys.nextMark;
- le->prevMark = &cg_activeMarkPolys;
- cg_activeMarkPolys.nextMark->prevMark = le;
- cg_activeMarkPolys.nextMark = le;
- return le;
-}
-
-
-
-/*
-=================
-CG_ImpactMark
-
-origin should be a point within a unit of the plane
-dir should be the plane normal
-
-temporary marks will not be stored or randomly oriented, but immediately
-passed to the renderer.
-=================
-*/
-#define MAX_MARK_FRAGMENTS 128
-#define MAX_MARK_POINTS 384
-
-void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
- float orientation, float red, float green, float blue, float alpha,
- qboolean alphaFade, float radius, qboolean temporary ) {
- vec3_t axis[3];
- float texCoordScale;
- vec3_t originalPoints[4];
- byte colors[4];
- int i, j;
- int numFragments;
- markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
- vec3_t markPoints[MAX_MARK_POINTS];
- vec3_t projection;
-
- if ( !cg_addMarks.integer ) {
- return;
- }
-
- if ( radius <= 0 ) {
- CG_Error( "CG_ImpactMark called with <= 0 radius" );
- }
-
- //if ( markTotal >= MAX_MARK_POLYS ) {
- // return;
- //}
-
- // create the texture axis
- VectorNormalize2( dir, axis[0] );
- PerpendicularVector( axis[1], axis[0] );
- RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
- CrossProduct( axis[0], axis[2], axis[1] );
-
- texCoordScale = 0.5 * 1.0 / radius;
-
- // create the full polygon
- for ( i = 0 ; i < 3 ; i++ ) {
- originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
- originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
- originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
- originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
- }
-
- // get the fragments
- VectorScale( dir, -20, projection );
- numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
- projection, MAX_MARK_POINTS, markPoints[0],
- MAX_MARK_FRAGMENTS, markFragments );
-
- colors[0] = red * 255;
- colors[1] = green * 255;
- colors[2] = blue * 255;
- colors[3] = alpha * 255;
-
- for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
- polyVert_t *v;
- polyVert_t verts[MAX_VERTS_ON_POLY];
- markPoly_t *mark;
-
- // we have an upper limit on the complexity of polygons
- // that we store persistantly
- if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
- mf->numPoints = MAX_VERTS_ON_POLY;
- }
- for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
- vec3_t delta;
-
- VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
-
- VectorSubtract( v->xyz, origin, delta );
- v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
- v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
- *(int *)v->modulate = *(int *)colors;
- }
-
- // if it is a temporary (shadow) mark, add it immediately and forget about it
- if ( temporary ) {
- trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
- continue;
- }
-
- // otherwise save it persistantly
- mark = CG_AllocMark();
- mark->time = cg.time;
- mark->alphaFade = alphaFade;
- mark->markShader = markShader;
- mark->poly.numVerts = mf->numPoints;
- mark->color[0] = red;
- mark->color[1] = green;
- mark->color[2] = blue;
- mark->color[3] = alpha;
- memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
- markTotal++;
- }
-}
-
-
-/*
-===============
-CG_AddMarks
-===============
-*/
-#define MARK_TOTAL_TIME 10000
-#define MARK_FADE_TIME 1000
-
-void CG_AddMarks( void ) {
- int j;
- markPoly_t *mp, *next;
- int t;
- int fade;
-
- if ( !cg_addMarks.integer ) {
- return;
- }
-
- mp = cg_activeMarkPolys.nextMark;
- for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
- // grab next now, so if the local entity is freed we
- // still have it
- next = mp->nextMark;
-
- // see if it is time to completely remove it
- if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
- CG_FreeMarkPoly( mp );
- continue;
- }
-
- // fade out the energy bursts
- if ( mp->markShader == cgs.media.energyMarkShader ) {
-
- fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
- if ( fade < 255 ) {
- if ( fade < 0 ) {
- fade = 0;
- }
- if ( mp->verts[0].modulate[0] != 0 ) {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[0] = mp->color[0] * fade;
- mp->verts[j].modulate[1] = mp->color[1] * fade;
- mp->verts[j].modulate[2] = mp->color[2] * fade;
- }
- }
- }
- }
-
- // fade all marks out with time
- t = mp->time + MARK_TOTAL_TIME - cg.time;
- if ( t < MARK_FADE_TIME ) {
- fade = 255 * t / MARK_FADE_TIME;
- if ( mp->alphaFade ) {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[3] = fade;
- }
- } else {
- for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
- mp->verts[j].modulate[0] = mp->color[0] * fade;
- mp->verts[j].modulate[1] = mp->color[1] * fade;
- mp->verts[j].modulate[2] = mp->color[2] * fade;
- }
- }
- }
-
-
- trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
- }
-}
-
-// cg_particles.c
-
-#define BLOODRED 2
-#define EMISIVEFADE 3
-#define GREY75 4
-
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
- float endtime;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- int color;
- float colorvel;
- float alpha;
- float alphavel;
- int type;
- qhandle_t pshader;
-
- float height;
- float width;
-
- float endheight;
- float endwidth;
-
- float start;
- float end;
-
- float startfade;
- qboolean rotate;
- int snum;
-
- qboolean link;
-
- // Ridah
- int shaderAnim;
- int roll;
-
- int accumroll;
-
-} cparticle_t;
-
-typedef enum
-{
- P_NONE,
- P_WEATHER,
- P_FLAT,
- P_SMOKE,
- P_ROTATE,
- P_WEATHER_TURBULENT,
- P_ANIM, // Ridah
- P_BAT,
- P_BLEED,
- P_FLAT_SCALEUP,
- P_FLAT_SCALEUP_FADE,
- P_WEATHER_FLURRY,
- P_SMOKE_IMPACT,
- P_BUBBLE,
- P_BUBBLE_TURBULENT,
- P_SPRITE
-} particle_type_t;
-
-#define MAX_SHADER_ANIMS 32
-#define MAX_SHADER_ANIM_FRAMES 64
-
-static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
- "explode1",
- NULL
-};
-static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
-static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
- 23
-};
-static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
- 1.0f
-};
-static int numShaderAnims;
-// done.
-
-#define PARTICLE_GRAVITY 40
-#define MAX_PARTICLES 1024
-
-cparticle_t *active_particles, *free_particles;
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-qboolean initparticles = qfalse;
-vec3_t pvforward, pvright, pvup;
-vec3_t rforward, rright, rup;
-
-float oldtime;
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CG_ClearParticles (void)
-{
- int i;
-
- memset( particles, 0, sizeof(particles) );
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- {
- particles[i].next = &particles[i+1];
- particles[i].type = 0;
- }
- particles[cl_numparticles-1].next = NULL;
-
- oldtime = cg.time;
-
- // Ridah, init the shaderAnims
- for (i=0; shaderAnimNames[i]; i++) {
- int j;
-
- for (j=0; j<shaderAnimCounts[i]; j++) {
- shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
- }
- }
- numShaderAnims = i;
- // done.
-
- initparticles = qtrue;
-}
-
-
-/*
-=====================
-CG_AddParticleToScene
-=====================
-*/
-void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
-{
-
- vec3_t point;
- polyVert_t verts[4];
- float width;
- float height;
- float time, time2;
- float ratio;
- float invratio;
- vec3_t color;
- polyVert_t TRIverts[3];
- vec3_t rright2, rup2;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
- || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {// create a front facing polygon
-
- if (p->type != P_WEATHER_FLURRY)
- {
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- if (org[2] > p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- p->org[2] = ( p->start + crandom () * 4 );
-
-
- if (p->type == P_BUBBLE_TURBULENT)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- }
- }
- else
- {
- if (org[2] < p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- while (p->org[2] < p->end)
- {
- p->org[2] += (p->start - p->end);
- }
-
-
- if (p->type == P_WEATHER_TURBULENT)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- }
- }
-
-
- // Rafael snow pvs check
- if (!p->link)
- return;
-
- p->alpha = 1;
- }
-
- // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
- if (Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
- // done.
-
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255 * p->alpha;
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy( point, TRIverts[0].xyz );
- TRIverts[0].st[0] = 1;
- TRIverts[0].st[1] = 0;
- TRIverts[0].modulate[0] = 255;
- TRIverts[0].modulate[1] = 255;
- TRIverts[0].modulate[2] = 255;
- TRIverts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- VectorCopy (point, TRIverts[1].xyz);
- TRIverts[1].st[0] = 0;
- TRIverts[1].st[1] = 0;
- TRIverts[1].modulate[0] = 255;
- TRIverts[1].modulate[1] = 255;
- TRIverts[1].modulate[2] = 255;
- TRIverts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- VectorCopy (point, TRIverts[2].xyz);
- TRIverts[2].st[0] = 0;
- TRIverts[2].st[1] = 1;
- TRIverts[2].modulate[0] = 255;
- TRIverts[2].modulate[1] = 255;
- TRIverts[2].modulate[2] = 255;
- TRIverts[2].modulate[3] = 255 * p->alpha;
- }
-
- }
- else if (p->type == P_SPRITE)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
-
- VectorSet (color, 1.0, 1.0, 0.5);
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, pvup, point);
- VectorMA (point, -width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, pvup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, pvup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
- {// create a front rotating facing polygon
-
- if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
-
- if (p->color == BLOODRED)
- VectorSet (color, 0.22f, 0.0f, 0.0f);
- else if (p->color == GREY75)
- {
- float len;
- float greyit;
- float val;
- len = Distance (cg.snap->ps.origin, org);
- if (!len)
- len = 1;
-
- val = 4096/len;
- greyit = 0.25 * val;
- if (greyit > 0.5)
- greyit = 0.5;
-
- VectorSet (color, greyit, greyit, greyit);
- }
- else
- VectorSet (color, 1.0, 1.0, 1.0);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- if (cg.time > p->startfade)
- {
- invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
-
- if (p->color == EMISIVEFADE)
- {
- float fval;
- fval = (invratio * invratio);
- if (fval < 0)
- fval = 0;
- VectorSet (color, fval , fval , fval );
- }
- invratio *= p->alpha;
- }
- else
- invratio = 1 * p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- invratio = 1;
-
- if (invratio > 1)
- invratio = 1;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->type != P_SMOKE_IMPACT)
- {
- vec3_t temp;
-
- vectoangles (rforward, temp);
- p->accumroll += p->roll;
- temp[ROLL] += p->accumroll * 0.1;
- AngleVectors ( temp, NULL, rright2, rup2);
- }
- else
- {
- VectorCopy (rright, rright2);
- VectorCopy (rup, rup2);
- }
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, p->width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, pvup, point);
- VectorMA (point, -p->width, pvright, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255 * invratio;
-
- }
- else if (p->type == P_BLEED)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- float alpha;
-
- alpha = p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- alpha = 1;
-
- if (p->roll)
- {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
- else
- {
- VectorCopy (pvup, ru);
- VectorCopy (pvright, rr);
- }
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 111;
- verts[0].modulate[1] = 19;
- verts[0].modulate[2] = 9;
- verts[0].modulate[3] = 255 * alpha;
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 111;
- verts[1].modulate[1] = 19;
- verts[1].modulate[2] = 9;
- verts[1].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 111;
- verts[2].modulate[1] = 19;
- verts[2].modulate[2] = 9;
- verts[2].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 111;
- verts[3].modulate[1] = 19;
- verts[3].modulate[2] = 9;
- verts[3].modulate[3] = 255 * alpha;
-
- }
- else if (p->type == P_FLAT_SCALEUP)
- {
- float width, height;
- float sinR, cosR;
-
- if (p->color == BLOODRED)
- VectorSet (color, 1, 1, 1);
- else
- VectorSet (color, 0.5, 0.5, 0.5);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (width > p->endwidth)
- width = p->endwidth;
-
- if (height > p->endheight)
- height = p->endheight;
-
- sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
- cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= sinR;
- verts[0].xyz[1] -= cosR;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= cosR;
- verts[1].xyz[1] += sinR;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += sinR;
- verts[2].xyz[1] += cosR;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += cosR;
- verts[3].xyz[1] -= sinR;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_FLAT)
- {
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= p->height;
- verts[0].xyz[1] -= p->width;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= p->height;
- verts[1].xyz[1] += p->width;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += p->height;
- verts[2].xyz[1] += p->width;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += p->height;
- verts[3].xyz[1] -= p->width;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- }
- // Ridah
- else if (p->type == P_ANIM) {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- int i, j;
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
- if (ratio >= 1.0f) {
- ratio = 0.9999f;
- }
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- // if we are "inside" this sprite, don't draw
- if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
- return;
- }
-
- i = p->shaderAnim;
- j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
- p->pshader = shaderAnims[i][j];
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, pvup, point);
- VectorMA (point, -width, pvright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, pvup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, pvright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, pvup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- // done.
-
- if (!p->pshader) {
-// (SA) temp commented out for DM
-// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
- return;
- }
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
- trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
- else
- trap_R_AddPolyToScene( p->pshader, 4, verts );
-
-}
-
-// Ridah, made this static so it doesn't interfere with other files
-static float roll = 0.0;
-
-/*
-===============
-CG_AddParticles
-===============
-*/
-void CG_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
- int type;
- vec3_t rotate_ang;
-
- if (!initparticles)
- CG_ClearParticles ();
-
- VectorCopy( cg.refdef.viewaxis[0], pvforward );
- VectorCopy( cg.refdef.viewaxis[1], pvright );
- VectorCopy( cg.refdef.viewaxis[2], pvup );
-
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- roll += ((cg.time - oldtime) * 0.1) ;
- rotate_ang[ROLL] += (roll*0.9);
- AngleVectors ( rotate_ang, rforward, rright, rup);
-
- oldtime = cg.time;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
-
- next = p->next;
-
- time = (cg.time - p->time)*0.001;
-
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
-
- }
-
- if (p->type == P_WEATHER_FLURRY)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
- }
-
-
- if (p->type == P_FLAT_SCALEUP_FADE)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- }
-
- if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
- // temporary sprite
- CG_AddParticleToScene (p, p->org, alpha);
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- 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;
-
- type = p->type;
-
- CG_AddParticleToScene (p, org, alpha);
- }
-
- active_particles = active;
-}
-
-/*
-======================
-CG_AddParticles
-======================
-*/
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
- qboolean turb = qtrue;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.90f;
- p->alphavel = 0;
-
- p->start = cent->currentState.origin2[0];
- p->end = cent->currentState.origin2[1];
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->pshader = pshader;
-
- if (rand()%100 > 90)
- {
- p->height = 32;
- p->width = 32;
- p->alpha = 0.10f;
- }
- else
- {
- p->height = 1;
- p->width = 1;
- }
-
- p->vel[2] = -20;
-
- p->type = P_WEATHER_FLURRY;
-
- if (turb)
- p->vel[2] = -10;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->org[0] = p->org[0];
- p->org[1] = p->org[1];
- p->org[2] = p->org[2];
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
- p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
- p->vel[2] += cent->currentState.angles[2];
-
- if (turb)
- {
- p->accel[0] = crandom () * 16;
- p->accel[1] = crandom () * 16;
- }
-
-}
-
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
- p->height = 1;
- p->width = 1;
-
- p->vel[2] = -50;
-
- if (turb)
- {
- p->type = P_WEATHER_TURBULENT;
- p->vel[2] = -50 * 1.3;
- }
- else
- {
- p->type = P_WEATHER;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
- float randsize;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
-
- randsize = 1 + (crandom() * 0.5);
-
- p->height = randsize;
- p->width = randsize;
-
- p->vel[2] = 50 + ( crandom() * 10 );
-
- if (turb)
- {
- p->type = P_BUBBLE_TURBULENT;
- p->vel[2] = 50 * 1.3;
- }
- else
- {
- p->type = P_BUBBLE;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
-{
-
- // using cent->density = enttime
- // cent->frame = startfade
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSmoke == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->color = 0;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->start = cent->currentState.origin[2];
- p->end = cent->currentState.origin2[2];
- p->pshader = pshader;
- p->rotate = qfalse;
- p->height = 8;
- p->width = 8;
- p->endheight = 32;
- p->endwidth = 32;
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->vel[0] = p->vel[1] = 0;
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[2] = 5;
-
- if (cent->currentState.frame == 1)// reverse gravity
- p->vel[2] *= -1;
-
- p->roll = 8 + (crandom() * 4);
-}
-
-
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
-{
-
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->accel[2] = -60;
- p->vel[2] += -20;
-
-}
-
-/*
-======================
-CG_ParticleExplosion
-======================
-*/
-
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
-{
- cparticle_t *p;
- int anim;
-
- if (animStr < (char *)10)
- CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
-
- // find the animation string
- for (anim=0; shaderAnimNames[anim]; anim++) {
- if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
- break;
- }
- if (!shaderAnimNames[anim]) {
- CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
- return;
- }
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.5;
- p->alphavel = 0;
-
- if (duration < 0) {
- duration *= -1;
- p->roll = 0;
- } else {
- p->roll = crandom()*179;
- }
-
- p->shaderAnim = anim;
-
- p->width = sizeStart;
- p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
-
- p->endheight = sizeEnd;
- p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
-
- p->endtime = cg.time + duration;
-
- p->type = P_ANIM;
-
- VectorCopy( origin, p->org );
- VectorCopy( vel, p->vel );
- VectorClear( p->accel );
-
-}
-
-// Rafael Shrapnel
-void CG_AddParticleShrapnel (localEntity_t *le)
-{
- return;
-}
-// done.
-
-int CG_NewParticleArea (int num)
-{
- // const char *str;
- char *str;
- char *token;
- int type;
- vec3_t origin, origin2;
- int i;
- float range = 0;
- int turb;
- int numparticles;
- int snum;
-
- str = (char *) CG_ConfigString (num);
- if (!str[0])
- return (0);
-
- // returns type 128 64 or 32
- token = COM_Parse (&str);
- type = atoi (token);
-
- if (type == 1)
- range = 128;
- else if (type == 2)
- range = 64;
- else if (type == 3)
- range = 32;
- else if (type == 0)
- range = 256;
- else if (type == 4)
- range = 8;
- else if (type == 5)
- range = 16;
- else if (type == 6)
- range = 32;
- else if (type == 7)
- range = 64;
-
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin[i] = atof (token);
- }
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin2[i] = atof (token);
- }
-
- token = COM_Parse (&str);
- numparticles = atoi (token);
-
- token = COM_Parse (&str);
- turb = atoi (token);
-
- token = COM_Parse (&str);
- snum = atoi (token);
-
- for (i=0; i<numparticles; i++)
- {
- if (type >= 4)
- CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- else
- CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- }
-
- return (1);
-}
-
-void CG_SnowLink (centity_t *cent, qboolean particleOn)
-{
- cparticle_t *p, *next;
- int id;
-
- id = cent->currentState.frame;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
- {
- if (p->snum == id)
- {
- if (particleOn)
- p->link = qtrue;
- else
- p->link = qfalse;
- }
- }
-
- }
-}
-
-void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.25;
- p->alphavel = 0;
- p->roll = crandom()*179;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + 1000;
- p->startfade = cg.time + 100;
-
- p->width = rand()%4 + 8;
- p->height = rand()%4 + 8;
-
- p->endheight = p->height *2;
- p->endwidth = p->width * 2;
-
- p->endtime = cg.time + 500;
-
- p->type = P_SMOKE_IMPACT;
-
- VectorCopy( origin, p->org );
- VectorSet(p->vel, 0, 0, 20);
- VectorSet(p->accel, 0, 0, 20);
-
- p->rotate = qtrue;
-}
-
-void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- if (fleshEntityNum)
- p->startfade = cg.time;
- else
- p->startfade = cg.time + 100;
-
- p->width = 4;
- p->height = 4;
-
- p->endheight = 4+rand()%3;
- p->endwidth = p->endheight;
-
- p->type = P_SMOKE;
-
- VectorCopy( start, p->org );
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -20;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
- p->alpha = 0.75;
-
-}
-
-void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- int time;
- int time2;
- float ratio;
-
- float duration = 1500;
-
- time = cg.time;
- time2 = cg.time + cent->currentState.time;
-
- ratio =(float)1 - ((float)time / (float)time2);
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- p->startfade = p->endtime;
-
- p->width = 1;
- p->height = 3;
-
- p->endheight = 3;
- p->endwidth = 1;
-
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
- p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
- p->vel[2] = (cent->currentState.origin2[2]);
-
- p->snum = 1.0f;
-
- VectorClear( p->accel );
-
- p->accel[2] = -20;
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-
-void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- if (cent->currentState.angles2[2])
- p->endtime = cg.time + cent->currentState.angles2[2];
- else
- p->endtime = cg.time + 60000;
-
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
- {
- p->width = cent->currentState.angles2[0];
- p->height = cent->currentState.angles2[0];
-
- p->endheight = cent->currentState.angles2[1];
- p->endwidth = cent->currentState.angles2[1];
- }
- else
- {
- p->width = 8;
- p->height = 8;
-
- p->endheight = 16;
- p->endwidth = 16;
- }
-
- p->type = P_FLAT_SCALEUP;
-
- p->snum = 1.0;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->org[2]+= 0.55 + (crandom() * 0.5);
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-void CG_OilSlickRemove (centity_t *cent)
-{
- cparticle_t *p, *next;
- int id;
-
- id = 1.0f;
-
- if (!id)
- CG_Printf ("CG_OilSlickRevove NULL id\n");
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_FLAT_SCALEUP)
- {
- if (p->snum == id)
- {
- p->endtime = cg.time + 100;
- p->startfade = p->endtime;
- p->type = P_FLAT_SCALEUP_FADE;
-
- }
- }
-
- }
-}
-
-qboolean ValidBloodPool (vec3_t start)
-{
-#define EXTRUDE_DIST 0.5
-
- vec3_t angles;
- vec3_t right, up;
- vec3_t this_pos, x_pos, center_pos, end_pos;
- float x, y;
- float fwidth, fheight;
- trace_t trace;
- vec3_t normal;
-
- fwidth = 16;
- fheight = 16;
-
- VectorSet (normal, 0, 0, 1);
-
- vectoangles (normal, angles);
- AngleVectors (angles, NULL, right, up);
-
- VectorMA (start, EXTRUDE_DIST, normal, center_pos);
-
- for (x= -fwidth/2; x<fwidth; x+= fwidth)
- {
- VectorMA (center_pos, x, right, x_pos);
-
- for (y= -fheight/2; y<fheight; y+= fheight)
- {
- VectorMA (x_pos, y, up, this_pos);
- VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
-
- CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
-
-
- if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
- return qfalse;
-
- if (!(!trace.startsolid && trace.fraction < 1))
- return qfalse;
-
- }
- }
-
- return qtrue;
-}
-
-void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
-{
- cparticle_t *p;
- qboolean legit;
- vec3_t start;
- float rndSize;
-
- if (!pshader)
- CG_Printf ("CG_BloodPool pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- VectorCopy (tr->endpos, start);
- legit = ValidBloodPool (start);
-
- if (!legit)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + 3000;
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- rndSize = 0.4 + random()*0.6;
-
- p->width = 8*rndSize;
- p->height = 8*rndSize;
-
- p->endheight = 16*rndSize;
- p->endwidth = 16*rndSize;
-
- p->type = P_FLAT_SCALEUP;
-
- VectorCopy(start, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- p->color = BLOODRED;
-}
-
-#define NORMALSIZE 16
-#define LARGESIZE 32
-
-void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- p->endtime = cg.time + 350 + (crandom() * 100);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
- p->endheight = LARGESIZE;
- p->endwidth = LARGESIZE;
-
- p->type = P_SMOKE;
-
- VectorCopy( origin, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -1;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.4f;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 4);
- p->vel[1] += (crandom() * 4);
- p->vel[2] += (20 + (crandom() * 10)) * speed;
-
- p->accel[0] = crandom () * 4;
- p->accel[1] = crandom () * 4;
-
-}
-
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- VectorNegate (dir, dir);
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 5.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- // RF, stay around for long enough to expand and dissipate naturally
- if (length)
- p->endtime = cg.time + 4500 + (crandom() * 3500);
- else
- p->endtime = cg.time + 750 + (crandom() * 500);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
-
- // RF, expand while falling
- p->endheight = LARGESIZE*3.0;
- p->endwidth = LARGESIZE*3.0;
-
- if (!length)
- {
- p->width *= 0.2f;
- p->height *= 0.2f;
-
- p->endheight = NORMALSIZE;
- p->endwidth = NORMALSIZE;
- }
-
- p->type = P_SMOKE;
-
- VectorCopy( point, p->org );
-
- p->vel[0] = crandom()*6;
- p->vel[1] = crandom()*6;
- p->vel[2] = random()*20;
-
- // RF, add some gravity/randomness
- p->accel[0] = crandom()*3;
- p->accel[1] = crandom()*3;
- p->accel[2] = -PARTICLE_GRAVITY*0.4;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = rand()%179;
-
- p->pshader = pshader;
-
- if (duration > 0)
- p->endtime = cg.time + duration;
- else
- p->endtime = duration;
-
- p->startfade = cg.time;
-
- p->width = size;
- p->height = size;
-
- p->endheight = size;
- p->endwidth = size;
-
- p->type = P_SPRITE;
-
- VectorCopy( origin, p->org );
-
- p->rotate = qfalse;
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_marks.c -- wall marks
+
+#include "cg_local.h"
+
+/*
+===================================================================
+
+MARK POLYS
+
+===================================================================
+*/
+
+
+markPoly_t cg_activeMarkPolys; // double linked list
+markPoly_t *cg_freeMarkPolys; // single linked list
+markPoly_t cg_markPolys[MAX_MARK_POLYS];
+static int markTotal;
+
+/*
+===================
+CG_InitMarkPolys
+
+This is called at startup and for tournement restarts
+===================
+*/
+void CG_InitMarkPolys( void ) {
+ int i;
+
+ memset( cg_markPolys, 0, sizeof(cg_markPolys) );
+
+ cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
+ cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
+ cg_freeMarkPolys = cg_markPolys;
+ for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
+ cg_markPolys[i].nextMark = &cg_markPolys[i+1];
+ }
+}
+
+
+/*
+==================
+CG_FreeMarkPoly
+==================
+*/
+void CG_FreeMarkPoly( markPoly_t *le ) {
+ if ( !le->prevMark ) {
+ CG_Error( "CG_FreeLocalEntity: not active" );
+ }
+
+ // remove from the doubly linked active list
+ le->prevMark->nextMark = le->nextMark;
+ le->nextMark->prevMark = le->prevMark;
+
+ // the free list is only singly linked
+ le->nextMark = cg_freeMarkPolys;
+ cg_freeMarkPolys = le;
+}
+
+/*
+===================
+CG_AllocMark
+
+Will allways succeed, even if it requires freeing an old active mark
+===================
+*/
+markPoly_t *CG_AllocMark( void ) {
+ markPoly_t *le;
+ int time;
+
+ if ( !cg_freeMarkPolys ) {
+ // no free entities, so free the one at the end of the chain
+ // remove the oldest active entity
+ time = cg_activeMarkPolys.prevMark->time;
+ while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
+ CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
+ }
+ }
+
+ le = cg_freeMarkPolys;
+ cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
+
+ memset( le, 0, sizeof( *le ) );
+
+ // link into the active list
+ le->nextMark = cg_activeMarkPolys.nextMark;
+ le->prevMark = &cg_activeMarkPolys;
+ cg_activeMarkPolys.nextMark->prevMark = le;
+ cg_activeMarkPolys.nextMark = le;
+ return le;
+}
+
+
+
+/*
+=================
+CG_ImpactMark
+
+origin should be a point within a unit of the plane
+dir should be the plane normal
+
+temporary marks will not be stored or randomly oriented, but immediately
+passed to the renderer.
+=================
+*/
+#define MAX_MARK_FRAGMENTS 128
+#define MAX_MARK_POINTS 384
+
+void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
+ float orientation, float red, float green, float blue, float alpha,
+ qboolean alphaFade, float radius, qboolean temporary ) {
+ vec3_t axis[3];
+ float texCoordScale;
+ vec3_t originalPoints[4];
+ byte colors[4];
+ int i, j;
+ int numFragments;
+ markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf;
+ vec3_t markPoints[MAX_MARK_POINTS];
+ vec3_t projection;
+
+ if ( !cg_addMarks.integer ) {
+ return;
+ }
+
+ if ( radius <= 0 ) {
+ CG_Error( "CG_ImpactMark called with <= 0 radius" );
+ }
+
+ //if ( markTotal >= MAX_MARK_POLYS ) {
+ // return;
+ //}
+
+ // create the texture axis
+ VectorNormalize2( dir, axis[0] );
+ PerpendicularVector( axis[1], axis[0] );
+ RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
+ CrossProduct( axis[0], axis[2], axis[1] );
+
+ texCoordScale = 0.5 * 1.0 / radius;
+
+ // create the full polygon
+ for ( i = 0 ; i < 3 ; i++ ) {
+ originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
+ originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
+ originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
+ originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
+ }
+
+ // get the fragments
+ VectorScale( dir, -20, projection );
+ numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
+ projection, MAX_MARK_POINTS, markPoints[0],
+ MAX_MARK_FRAGMENTS, markFragments );
+
+ colors[0] = red * 255;
+ colors[1] = green * 255;
+ colors[2] = blue * 255;
+ colors[3] = alpha * 255;
+
+ for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
+ polyVert_t *v;
+ polyVert_t verts[MAX_VERTS_ON_POLY];
+ markPoly_t *mark;
+
+ // we have an upper limit on the complexity of polygons
+ // that we store persistantly
+ if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
+ mf->numPoints = MAX_VERTS_ON_POLY;
+ }
+ for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
+ vec3_t delta;
+
+ VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
+
+ VectorSubtract( v->xyz, origin, delta );
+ v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
+ v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
+ *(int *)v->modulate = *(int *)colors;
+ }
+
+ // if it is a temporary (shadow) mark, add it immediately and forget about it
+ if ( temporary ) {
+ trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
+ continue;
+ }
+
+ // otherwise save it persistantly
+ mark = CG_AllocMark();
+ mark->time = cg.time;
+ mark->alphaFade = alphaFade;
+ mark->markShader = markShader;
+ mark->poly.numVerts = mf->numPoints;
+ mark->color[0] = red;
+ mark->color[1] = green;
+ mark->color[2] = blue;
+ mark->color[3] = alpha;
+ memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
+ markTotal++;
+ }
+}
+
+
+/*
+===============
+CG_AddMarks
+===============
+*/
+#define MARK_TOTAL_TIME 10000
+#define MARK_FADE_TIME 1000
+
+void CG_AddMarks( void ) {
+ int j;
+ markPoly_t *mp, *next;
+ int t;
+ int fade;
+
+ if ( !cg_addMarks.integer ) {
+ return;
+ }
+
+ mp = cg_activeMarkPolys.nextMark;
+ for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
+ // grab next now, so if the local entity is freed we
+ // still have it
+ next = mp->nextMark;
+
+ // see if it is time to completely remove it
+ if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
+ CG_FreeMarkPoly( mp );
+ continue;
+ }
+
+ // fade out the energy bursts
+ if ( mp->markShader == cgs.media.energyMarkShader ) {
+
+ fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
+ if ( fade < 255 ) {
+ if ( fade < 0 ) {
+ fade = 0;
+ }
+ if ( mp->verts[0].modulate[0] != 0 ) {
+ for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
+ mp->verts[j].modulate[0] = mp->color[0] * fade;
+ mp->verts[j].modulate[1] = mp->color[1] * fade;
+ mp->verts[j].modulate[2] = mp->color[2] * fade;
+ }
+ }
+ }
+ }
+
+ // fade all marks out with time
+ t = mp->time + MARK_TOTAL_TIME - cg.time;
+ if ( t < MARK_FADE_TIME ) {
+ fade = 255 * t / MARK_FADE_TIME;
+ if ( mp->alphaFade ) {
+ for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
+ mp->verts[j].modulate[3] = fade;
+ }
+ } else {
+ for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
+ mp->verts[j].modulate[0] = mp->color[0] * fade;
+ mp->verts[j].modulate[1] = mp->color[1] * fade;
+ mp->verts[j].modulate[2] = mp->color[2] * fade;
+ }
+ }
+ }
+
+
+ trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
+ }
+}
+
+// cg_particles.c
+
+#define BLOODRED 2
+#define EMISIVEFADE 3
+#define GREY75 4
+
+typedef struct particle_s
+{
+ struct particle_s *next;
+
+ float time;
+ float endtime;
+
+ vec3_t org;
+ vec3_t vel;
+ vec3_t accel;
+ int color;
+ float colorvel;
+ float alpha;
+ float alphavel;
+ int type;
+ qhandle_t pshader;
+
+ float height;
+ float width;
+
+ float endheight;
+ float endwidth;
+
+ float start;
+ float end;
+
+ float startfade;
+ qboolean rotate;
+ int snum;
+
+ qboolean link;
+
+ // Ridah
+ int shaderAnim;
+ int roll;
+
+ int accumroll;
+
+} cparticle_t;
+
+typedef enum
+{
+ P_NONE,
+ P_WEATHER,
+ P_FLAT,
+ P_SMOKE,
+ P_ROTATE,
+ P_WEATHER_TURBULENT,
+ P_ANIM, // Ridah
+ P_BAT,
+ P_BLEED,
+ P_FLAT_SCALEUP,
+ P_FLAT_SCALEUP_FADE,
+ P_WEATHER_FLURRY,
+ P_SMOKE_IMPACT,
+ P_BUBBLE,
+ P_BUBBLE_TURBULENT,
+ P_SPRITE
+} particle_type_t;
+
+#define MAX_SHADER_ANIMS 32
+#define MAX_SHADER_ANIM_FRAMES 64
+
+static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
+ "explode1",
+ NULL
+};
+static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
+static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
+ 23
+};
+static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
+ 1.0f
+};
+static int numShaderAnims;
+// done.
+
+#define PARTICLE_GRAVITY 40
+#define MAX_PARTICLES 1024
+
+cparticle_t *active_particles, *free_particles;
+cparticle_t particles[MAX_PARTICLES];
+int cl_numparticles = MAX_PARTICLES;
+
+qboolean initparticles = qfalse;
+vec3_t pvforward, pvright, pvup;
+vec3_t rforward, rright, rup;
+
+float oldtime;
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CG_ClearParticles (void)
+{
+ int i;
+
+ memset( particles, 0, sizeof(particles) );
+
+ free_particles = &particles[0];
+ active_particles = NULL;
+
+ for (i=0 ;i<cl_numparticles ; i++)
+ {
+ particles[i].next = &particles[i+1];
+ particles[i].type = 0;
+ }
+ particles[cl_numparticles-1].next = NULL;
+
+ oldtime = cg.time;
+
+ // Ridah, init the shaderAnims
+ for (i=0; shaderAnimNames[i]; i++) {
+ int j;
+
+ for (j=0; j<shaderAnimCounts[i]; j++) {
+ shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
+ }
+ }
+ numShaderAnims = i;
+ // done.
+
+ initparticles = qtrue;
+}
+
+
+/*
+=====================
+CG_AddParticleToScene
+=====================
+*/
+void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
+{
+
+ vec3_t point;
+ polyVert_t verts[4];
+ float width;
+ float height;
+ float time, time2;
+ float ratio;
+ float invratio;
+ vec3_t color;
+ polyVert_t TRIverts[3];
+ vec3_t rright2, rup2;
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
+ || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {// create a front facing polygon
+
+ if (p->type != P_WEATHER_FLURRY)
+ {
+ if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {
+ if (org[2] > p->end)
+ {
+ p->time = cg.time;
+ VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
+
+ p->org[2] = ( p->start + crandom () * 4 );
+
+
+ if (p->type == P_BUBBLE_TURBULENT)
+ {
+ p->vel[0] = crandom() * 4;
+ p->vel[1] = crandom() * 4;
+ }
+
+ }
+ }
+ else
+ {
+ if (org[2] < p->end)
+ {
+ p->time = cg.time;
+ VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
+
+ while (p->org[2] < p->end)
+ {
+ p->org[2] += (p->start - p->end);
+ }
+
+
+ if (p->type == P_WEATHER_TURBULENT)
+ {
+ p->vel[0] = crandom() * 16;
+ p->vel[1] = crandom() * 16;
+ }
+
+ }
+ }
+
+
+ // Rafael snow pvs check
+ if (!p->link)
+ return;
+
+ p->alpha = 1;
+ }
+
+ // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
+ if (Distance( cg.snap->ps.origin, org ) > 1024) {
+ return;
+ }
+ // done.
+
+ if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255 * p->alpha;
+ }
+ else
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy( point, TRIverts[0].xyz );
+ TRIverts[0].st[0] = 1;
+ TRIverts[0].st[1] = 0;
+ TRIverts[0].modulate[0] = 255;
+ TRIverts[0].modulate[1] = 255;
+ TRIverts[0].modulate[2] = 255;
+ TRIverts[0].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ VectorCopy (point, TRIverts[1].xyz);
+ TRIverts[1].st[0] = 0;
+ TRIverts[1].st[1] = 0;
+ TRIverts[1].modulate[0] = 255;
+ TRIverts[1].modulate[1] = 255;
+ TRIverts[1].modulate[2] = 255;
+ TRIverts[1].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ VectorCopy (point, TRIverts[2].xyz);
+ TRIverts[2].st[0] = 0;
+ TRIverts[2].st[1] = 1;
+ TRIverts[2].modulate[0] = 255;
+ TRIverts[2].modulate[1] = 255;
+ TRIverts[2].modulate[2] = 255;
+ TRIverts[2].modulate[3] = 255 * p->alpha;
+ }
+
+ }
+ else if (p->type == P_SPRITE)
+ {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+
+ VectorSet (color, 1.0, 1.0, 0.5);
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (p->roll) {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+
+ if (p->roll) {
+ VectorMA (org, -height, ru, point);
+ VectorMA (point, -width, rr, point);
+ } else {
+ VectorMA (org, -height, pvup, point);
+ VectorMA (point, -width, pvright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*height, ru, point);
+ } else {
+ VectorMA (point, 2*height, pvup, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*width, rr, point);
+ } else {
+ VectorMA (point, 2*width, pvright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, -2*height, ru, point);
+ } else {
+ VectorMA (point, -2*height, pvup, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+ }
+ else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
+ {// create a front rotating facing polygon
+
+ if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
+ return;
+ }
+
+ if (p->color == BLOODRED)
+ VectorSet (color, 0.22f, 0.0f, 0.0f);
+ else if (p->color == GREY75)
+ {
+ float len;
+ float greyit;
+ float val;
+ len = Distance (cg.snap->ps.origin, org);
+ if (!len)
+ len = 1;
+
+ val = 4096/len;
+ greyit = 0.25 * val;
+ if (greyit > 0.5)
+ greyit = 0.5;
+
+ VectorSet (color, greyit, greyit, greyit);
+ }
+ else
+ VectorSet (color, 1.0, 1.0, 1.0);
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ if (cg.time > p->startfade)
+ {
+ invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
+
+ if (p->color == EMISIVEFADE)
+ {
+ float fval;
+ fval = (invratio * invratio);
+ if (fval < 0)
+ fval = 0;
+ VectorSet (color, fval , fval , fval );
+ }
+ invratio *= p->alpha;
+ }
+ else
+ invratio = 1 * p->alpha;
+
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
+ invratio = 1;
+
+ if (invratio > 1)
+ invratio = 1;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (p->type != P_SMOKE_IMPACT)
+ {
+ vec3_t temp;
+
+ vectoangles (rforward, temp);
+ p->accumroll += p->roll;
+ temp[ROLL] += p->accumroll * 0.1;
+ AngleVectors ( temp, NULL, rright2, rup2);
+ }
+ else
+ {
+ VectorCopy (rright, rright2);
+ VectorCopy (rup, rup2);
+ }
+
+ if (p->rotate)
+ {
+ VectorMA (org, -height, rup2, point);
+ VectorMA (point, -width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255 * color[0];
+ verts[0].modulate[1] = 255 * color[1];
+ verts[0].modulate[2] = 255 * color[2];
+ verts[0].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, -height, rup2, point);
+ VectorMA (point, width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, -p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255 * color[0];
+ verts[1].modulate[1] = 255 * color[1];
+ verts[1].modulate[2] = 255 * color[2];
+ verts[1].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, height, rup2, point);
+ VectorMA (point, width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, p->width, pvright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255 * color[0];
+ verts[2].modulate[1] = 255 * color[1];
+ verts[2].modulate[2] = 255 * color[2];
+ verts[2].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, height, rup2, point);
+ VectorMA (point, -width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, p->height, pvup, point);
+ VectorMA (point, -p->width, pvright, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255 * color[0];
+ verts[3].modulate[1] = 255 * color[1];
+ verts[3].modulate[2] = 255 * color[2];
+ verts[3].modulate[3] = 255 * invratio;
+
+ }
+ else if (p->type == P_BLEED)
+ {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+ float alpha;
+
+ alpha = p->alpha;
+
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
+ alpha = 1;
+
+ if (p->roll)
+ {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+ else
+ {
+ VectorCopy (pvup, ru);
+ VectorCopy (pvright, rr);
+ }
+
+ VectorMA (org, -p->height, ru, point);
+ VectorMA (point, -p->width, rr, point);
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 111;
+ verts[0].modulate[1] = 19;
+ verts[0].modulate[2] = 9;
+ verts[0].modulate[3] = 255 * alpha;
+
+ VectorMA (org, -p->height, ru, point);
+ VectorMA (point, p->width, rr, point);
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 111;
+ verts[1].modulate[1] = 19;
+ verts[1].modulate[2] = 9;
+ verts[1].modulate[3] = 255 * alpha;
+
+ VectorMA (org, p->height, ru, point);
+ VectorMA (point, p->width, rr, point);
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 111;
+ verts[2].modulate[1] = 19;
+ verts[2].modulate[2] = 9;
+ verts[2].modulate[3] = 255 * alpha;
+
+ VectorMA (org, p->height, ru, point);
+ VectorMA (point, -p->width, rr, point);
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 111;
+ verts[3].modulate[1] = 19;
+ verts[3].modulate[2] = 9;
+ verts[3].modulate[3] = 255 * alpha;
+
+ }
+ else if (p->type == P_FLAT_SCALEUP)
+ {
+ float width, height;
+ float sinR, cosR;
+
+ if (p->color == BLOODRED)
+ VectorSet (color, 1, 1, 1);
+ else
+ VectorSet (color, 0.5, 0.5, 0.5);
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (width > p->endwidth)
+ width = p->endwidth;
+
+ if (height > p->endheight)
+ height = p->endheight;
+
+ sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
+ cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
+
+ VectorCopy (org, verts[0].xyz);
+ verts[0].xyz[0] -= sinR;
+ verts[0].xyz[1] -= cosR;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255 * color[0];
+ verts[0].modulate[1] = 255 * color[1];
+ verts[0].modulate[2] = 255 * color[2];
+ verts[0].modulate[3] = 255;
+
+ VectorCopy (org, verts[1].xyz);
+ verts[1].xyz[0] -= cosR;
+ verts[1].xyz[1] += sinR;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255 * color[0];
+ verts[1].modulate[1] = 255 * color[1];
+ verts[1].modulate[2] = 255 * color[2];
+ verts[1].modulate[3] = 255;
+
+ VectorCopy (org, verts[2].xyz);
+ verts[2].xyz[0] += sinR;
+ verts[2].xyz[1] += cosR;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255 * color[0];
+ verts[2].modulate[1] = 255 * color[1];
+ verts[2].modulate[2] = 255 * color[2];
+ verts[2].modulate[3] = 255;
+
+ VectorCopy (org, verts[3].xyz);
+ verts[3].xyz[0] += cosR;
+ verts[3].xyz[1] -= sinR;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255 * color[0];
+ verts[3].modulate[1] = 255 * color[1];
+ verts[3].modulate[2] = 255 * color[2];
+ verts[3].modulate[3] = 255;
+ }
+ else if (p->type == P_FLAT)
+ {
+
+ VectorCopy (org, verts[0].xyz);
+ verts[0].xyz[0] -= p->height;
+ verts[0].xyz[1] -= p->width;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorCopy (org, verts[1].xyz);
+ verts[1].xyz[0] -= p->height;
+ verts[1].xyz[1] += p->width;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorCopy (org, verts[2].xyz);
+ verts[2].xyz[0] += p->height;
+ verts[2].xyz[1] += p->width;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorCopy (org, verts[3].xyz);
+ verts[3].xyz[0] += p->height;
+ verts[3].xyz[1] -= p->width;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ }
+ // Ridah
+ else if (p->type == P_ANIM) {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+ int i, j;
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+ if (ratio >= 1.0f) {
+ ratio = 0.9999f;
+ }
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ // if we are "inside" this sprite, don't draw
+ if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
+ return;
+ }
+
+ i = p->shaderAnim;
+ j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
+ p->pshader = shaderAnims[i][j];
+
+ if (p->roll) {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+
+ if (p->roll) {
+ VectorMA (org, -height, ru, point);
+ VectorMA (point, -width, rr, point);
+ } else {
+ VectorMA (org, -height, pvup, point);
+ VectorMA (point, -width, pvright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*height, ru, point);
+ } else {
+ VectorMA (point, 2*height, pvup, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*width, rr, point);
+ } else {
+ VectorMA (point, 2*width, pvright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, -2*height, ru, point);
+ } else {
+ VectorMA (point, -2*height, pvup, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+ }
+ // done.
+
+ if (!p->pshader) {
+// (SA) temp commented out for DM
+// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
+ return;
+ }
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
+ trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
+ else
+ trap_R_AddPolyToScene( p->pshader, 4, verts );
+
+}
+
+// Ridah, made this static so it doesn't interfere with other files
+static float roll = 0.0;
+
+/*
+===============
+CG_AddParticles
+===============
+*/
+void CG_AddParticles (void)
+{
+ cparticle_t *p, *next;
+ float alpha;
+ float time, time2;
+ vec3_t org;
+ int color;
+ cparticle_t *active, *tail;
+ int type;
+ vec3_t rotate_ang;
+
+ if (!initparticles)
+ CG_ClearParticles ();
+
+ VectorCopy( cg.refdef.viewaxis[0], pvforward );
+ VectorCopy( cg.refdef.viewaxis[1], pvright );
+ VectorCopy( cg.refdef.viewaxis[2], pvup );
+
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ roll += ((cg.time - oldtime) * 0.1) ;
+ rotate_ang[ROLL] += (roll*0.9);
+ AngleVectors ( rotate_ang, rforward, rright, rup);
+
+ oldtime = cg.time;
+
+ active = NULL;
+ tail = NULL;
+
+ for (p=active_particles ; p ; p=next)
+ {
+
+ next = p->next;
+
+ time = (cg.time - p->time)*0.001;
+
+ alpha = p->alpha + time*p->alphavel;
+ if (alpha <= 0)
+ { // faded out
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+
+ continue;
+ }
+
+ }
+
+ if (p->type == P_WEATHER_FLURRY)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+
+ continue;
+ }
+ }
+
+
+ if (p->type == P_FLAT_SCALEUP_FADE)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ }
+
+ if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
+ // temporary sprite
+ CG_AddParticleToScene (p, p->org, alpha);
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ 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;
+
+ type = p->type;
+
+ CG_AddParticleToScene (p, org, alpha);
+ }
+
+ active_particles = active;
+}
+
+/*
+======================
+CG_AddParticles
+======================
+*/
+void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+ qboolean turb = qtrue;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.90f;
+ p->alphavel = 0;
+
+ p->start = cent->currentState.origin2[0];
+ p->end = cent->currentState.origin2[1];
+
+ p->endtime = cg.time + cent->currentState.time;
+ p->startfade = cg.time + cent->currentState.time2;
+
+ p->pshader = pshader;
+
+ if (rand()%100 > 90)
+ {
+ p->height = 32;
+ p->width = 32;
+ p->alpha = 0.10f;
+ }
+ else
+ {
+ p->height = 1;
+ p->width = 1;
+ }
+
+ p->vel[2] = -20;
+
+ p->type = P_WEATHER_FLURRY;
+
+ if (turb)
+ p->vel[2] = -10;
+
+ VectorCopy(cent->currentState.origin, p->org);
+
+ p->org[0] = p->org[0];
+ p->org[1] = p->org[1];
+ p->org[2] = p->org[2];
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
+ p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
+ p->vel[2] += cent->currentState.angles[2];
+
+ if (turb)
+ {
+ p->accel[0] = crandom () * 16;
+ p->accel[1] = crandom () * 16;
+ }
+
+}
+
+void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.40f;
+ p->alphavel = 0;
+ p->start = origin[2];
+ p->end = origin2[2];
+ p->pshader = pshader;
+ p->height = 1;
+ p->width = 1;
+
+ p->vel[2] = -50;
+
+ if (turb)
+ {
+ p->type = P_WEATHER_TURBULENT;
+ p->vel[2] = -50 * 1.3;
+ }
+ else
+ {
+ p->type = P_WEATHER;
+ }
+
+ VectorCopy(origin, p->org);
+
+ p->org[0] = p->org[0] + ( crandom() * range);
+ p->org[1] = p->org[1] + ( crandom() * range);
+ p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ if (turb)
+ {
+ p->vel[0] = crandom() * 16;
+ p->vel[1] = crandom() * 16;
+ }
+
+ // Rafael snow pvs check
+ p->snum = snum;
+ p->link = qtrue;
+
+}
+
+void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
+{
+ cparticle_t *p;
+ float randsize;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.40f;
+ p->alphavel = 0;
+ p->start = origin[2];
+ p->end = origin2[2];
+ p->pshader = pshader;
+
+ randsize = 1 + (crandom() * 0.5);
+
+ p->height = randsize;
+ p->width = randsize;
+
+ p->vel[2] = 50 + ( crandom() * 10 );
+
+ if (turb)
+ {
+ p->type = P_BUBBLE_TURBULENT;
+ p->vel[2] = 50 * 1.3;
+ }
+ else
+ {
+ p->type = P_BUBBLE;
+ }
+
+ VectorCopy(origin, p->org);
+
+ p->org[0] = p->org[0] + ( crandom() * range);
+ p->org[1] = p->org[1] + ( crandom() * range);
+ p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ if (turb)
+ {
+ p->vel[0] = crandom() * 4;
+ p->vel[1] = crandom() * 4;
+ }
+
+ // Rafael snow pvs check
+ p->snum = snum;
+ p->link = qtrue;
+
+}
+
+void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
+{
+
+ // using cent->density = enttime
+ // cent->frame = startfade
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSmoke == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + cent->currentState.time;
+ p->startfade = cg.time + cent->currentState.time2;
+
+ p->color = 0;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->start = cent->currentState.origin[2];
+ p->end = cent->currentState.origin2[2];
+ p->pshader = pshader;
+ p->rotate = qfalse;
+ p->height = 8;
+ p->width = 8;
+ p->endheight = 32;
+ p->endwidth = 32;
+ p->type = P_SMOKE;
+
+ VectorCopy(cent->currentState.origin, p->org);
+
+ p->vel[0] = p->vel[1] = 0;
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[2] = 5;
+
+ if (cent->currentState.frame == 1)// reverse gravity
+ p->vel[2] *= -1;
+
+ p->roll = 8 + (crandom() * 4);
+}
+
+
+void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
+{
+
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+
+ p->height = 0.5;
+ p->width = 0.5;
+ p->endheight = 0.5;
+ p->endwidth = 0.5;
+
+ p->pshader = cgs.media.tracerShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->vel[0] = vel[0];
+ p->vel[1] = vel[1];
+ p->vel[2] = vel[2];
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->accel[2] = -60;
+ p->vel[2] += -20;
+
+}
+
+/*
+======================
+CG_ParticleExplosion
+======================
+*/
+
+void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
+{
+ cparticle_t *p;
+ int anim;
+
+ if (animStr < (char *)10)
+ CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
+
+ // find the animation string
+ for (anim=0; shaderAnimNames[anim]; anim++) {
+ if (!Q_stricmp( animStr, shaderAnimNames[anim] ))
+ break;
+ }
+ if (!shaderAnimNames[anim]) {
+ CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
+ return;
+ }
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 0.5;
+ p->alphavel = 0;
+
+ if (duration < 0) {
+ duration *= -1;
+ p->roll = 0;
+ } else {
+ p->roll = crandom()*179;
+ }
+
+ p->shaderAnim = anim;
+
+ p->width = sizeStart;
+ p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
+
+ p->endheight = sizeEnd;
+ p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
+
+ p->endtime = cg.time + duration;
+
+ p->type = P_ANIM;
+
+ VectorCopy( origin, p->org );
+ VectorCopy( vel, p->vel );
+ VectorClear( p->accel );
+
+}
+
+// Rafael Shrapnel
+void CG_AddParticleShrapnel (localEntity_t *le)
+{
+ return;
+}
+// done.
+
+int CG_NewParticleArea (int num)
+{
+ // const char *str;
+ char *str;
+ char *token;
+ int type;
+ vec3_t origin, origin2;
+ int i;
+ float range = 0;
+ int turb;
+ int numparticles;
+ int snum;
+
+ str = (char *) CG_ConfigString (num);
+ if (!str[0])
+ return (0);
+
+ // returns type 128 64 or 32
+ token = COM_Parse (&str);
+ type = atoi (token);
+
+ if (type == 1)
+ range = 128;
+ else if (type == 2)
+ range = 64;
+ else if (type == 3)
+ range = 32;
+ else if (type == 0)
+ range = 256;
+ else if (type == 4)
+ range = 8;
+ else if (type == 5)
+ range = 16;
+ else if (type == 6)
+ range = 32;
+ else if (type == 7)
+ range = 64;
+
+
+ for (i=0; i<3; i++)
+ {
+ token = COM_Parse (&str);
+ origin[i] = atof (token);
+ }
+
+ for (i=0; i<3; i++)
+ {
+ token = COM_Parse (&str);
+ origin2[i] = atof (token);
+ }
+
+ token = COM_Parse (&str);
+ numparticles = atoi (token);
+
+ token = COM_Parse (&str);
+ turb = atoi (token);
+
+ token = COM_Parse (&str);
+ snum = atoi (token);
+
+ for (i=0; i<numparticles; i++)
+ {
+ if (type >= 4)
+ CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
+ else
+ CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
+ }
+
+ return (1);
+}
+
+void CG_SnowLink (centity_t *cent, qboolean particleOn)
+{
+ cparticle_t *p, *next;
+ int id;
+
+ id = cent->currentState.frame;
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
+ {
+ if (p->snum == id)
+ {
+ if (particleOn)
+ p->link = qtrue;
+ else
+ p->link = qfalse;
+ }
+ }
+
+ }
+}
+
+void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 0.25;
+ p->alphavel = 0;
+ p->roll = crandom()*179;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + 1000;
+ p->startfade = cg.time + 100;
+
+ p->width = rand()%4 + 8;
+ p->height = rand()%4 + 8;
+
+ p->endheight = p->height *2;
+ p->endwidth = p->width * 2;
+
+ p->endtime = cg.time + 500;
+
+ p->type = P_SMOKE_IMPACT;
+
+ VectorCopy( origin, p->org );
+ VectorSet(p->vel, 0, 0, 20);
+ VectorSet(p->accel, 0, 0, 20);
+
+ p->rotate = qtrue;
+}
+
+void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + duration;
+
+ if (fleshEntityNum)
+ p->startfade = cg.time;
+ else
+ p->startfade = cg.time + 100;
+
+ p->width = 4;
+ p->height = 4;
+
+ p->endheight = 4+rand()%3;
+ p->endwidth = p->endheight;
+
+ p->type = P_SMOKE;
+
+ VectorCopy( start, p->org );
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -20;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->color = BLOODRED;
+ p->alpha = 0.75;
+
+}
+
+void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+
+ int time;
+ int time2;
+ float ratio;
+
+ float duration = 1500;
+
+ time = cg.time;
+ time2 = cg.time + cent->currentState.time;
+
+ ratio =(float)1 - ((float)time / (float)time2);
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + duration;
+
+ p->startfade = p->endtime;
+
+ p->width = 1;
+ p->height = 3;
+
+ p->endheight = 3;
+ p->endwidth = 1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(cent->currentState.origin, p->org );
+
+ p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
+ p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
+ p->vel[2] = (cent->currentState.origin2[2]);
+
+ p->snum = 1.0f;
+
+ VectorClear( p->accel );
+
+ p->accel[2] = -20;
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+}
+
+
+void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ if (cent->currentState.angles2[2])
+ p->endtime = cg.time + cent->currentState.angles2[2];
+ else
+ p->endtime = cg.time + 60000;
+
+ p->startfade = p->endtime;
+
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
+ {
+ p->width = cent->currentState.angles2[0];
+ p->height = cent->currentState.angles2[0];
+
+ p->endheight = cent->currentState.angles2[1];
+ p->endwidth = cent->currentState.angles2[1];
+ }
+ else
+ {
+ p->width = 8;
+ p->height = 8;
+
+ p->endheight = 16;
+ p->endwidth = 16;
+ }
+
+ p->type = P_FLAT_SCALEUP;
+
+ p->snum = 1.0;
+
+ VectorCopy(cent->currentState.origin, p->org );
+
+ p->org[2]+= 0.55 + (crandom() * 0.5);
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+}
+
+void CG_OilSlickRemove (centity_t *cent)
+{
+ cparticle_t *p, *next;
+ int id;
+
+ id = 1.0f;
+
+ if (!id)
+ CG_Printf ("CG_OilSlickRevove NULL id\n");
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ if (p->type == P_FLAT_SCALEUP)
+ {
+ if (p->snum == id)
+ {
+ p->endtime = cg.time + 100;
+ p->startfade = p->endtime;
+ p->type = P_FLAT_SCALEUP_FADE;
+
+ }
+ }
+
+ }
+}
+
+qboolean ValidBloodPool (vec3_t start)
+{
+#define EXTRUDE_DIST 0.5
+
+ vec3_t angles;
+ vec3_t right, up;
+ vec3_t this_pos, x_pos, center_pos, end_pos;
+ float x, y;
+ float fwidth, fheight;
+ trace_t trace;
+ vec3_t normal;
+
+ fwidth = 16;
+ fheight = 16;
+
+ VectorSet (normal, 0, 0, 1);
+
+ vectoangles (normal, angles);
+ AngleVectors (angles, NULL, right, up);
+
+ VectorMA (start, EXTRUDE_DIST, normal, center_pos);
+
+ for (x= -fwidth/2; x<fwidth; x+= fwidth)
+ {
+ VectorMA (center_pos, x, right, x_pos);
+
+ for (y= -fheight/2; y<fheight; y+= fheight)
+ {
+ VectorMA (x_pos, y, up, this_pos);
+ VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
+
+ CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
+
+
+ if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
+ return qfalse;
+
+ if (!(!trace.startsolid && trace.fraction < 1))
+ return qfalse;
+
+ }
+ }
+
+ return qtrue;
+}
+
+void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
+{
+ cparticle_t *p;
+ qboolean legit;
+ vec3_t start;
+ float rndSize;
+
+ if (!pshader)
+ CG_Printf ("CG_BloodPool pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+
+ VectorCopy (tr->endpos, start);
+ legit = ValidBloodPool (start);
+
+ if (!legit)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + 3000;
+ p->startfade = p->endtime;
+
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ rndSize = 0.4 + random()*0.6;
+
+ p->width = 8*rndSize;
+ p->height = 8*rndSize;
+
+ p->endheight = 16*rndSize;
+ p->endwidth = 16*rndSize;
+
+ p->type = P_FLAT_SCALEUP;
+
+ VectorCopy(start, p->org );
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+ p->color = BLOODRED;
+}
+
+#define NORMALSIZE 16
+#define LARGESIZE 32
+
+void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
+{
+ float length;
+ float dist;
+ float crittersize;
+ vec3_t angles, forward;
+ vec3_t point;
+ cparticle_t *p;
+ int i;
+
+ dist = 0;
+
+ length = VectorLength (dir);
+ vectoangles (dir, angles);
+ AngleVectors (angles, forward, NULL, NULL);
+
+ crittersize = LARGESIZE;
+
+ if (length)
+ dist = length / crittersize;
+
+ if (dist < 1)
+ dist = 1;
+
+ VectorCopy (origin, point);
+
+ for (i=0; i<dist; i++)
+ {
+ VectorMA (point, crittersize, forward, point);
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = cgs.media.smokePuffShader;
+
+ p->endtime = cg.time + 350 + (crandom() * 100);
+
+ p->startfade = cg.time;
+
+ p->width = LARGESIZE;
+ p->height = LARGESIZE;
+ p->endheight = LARGESIZE;
+ p->endwidth = LARGESIZE;
+
+ p->type = P_SMOKE;
+
+ VectorCopy( origin, p->org );
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -1;
+
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->color = BLOODRED;
+
+ p->alpha = 0.75;
+
+ }
+
+
+}
+
+void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.4f;
+ p->alphavel = 0;
+
+ p->height = 0.5;
+ p->width = 0.5;
+ p->endheight = 0.5;
+ p->endwidth = 0.5;
+
+ p->pshader = cgs.media.tracerShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0];
+ p->vel[1] = vel[1];
+ p->vel[2] = vel[2];
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 4);
+ p->vel[1] += (crandom() * 4);
+ p->vel[2] += (20 + (crandom() * 10)) * speed;
+
+ p->accel[0] = crandom () * 4;
+ p->accel[1] = crandom () * 4;
+
+}
+
+void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
+{
+ float length;
+ float dist;
+ float crittersize;
+ vec3_t angles, forward;
+ vec3_t point;
+ cparticle_t *p;
+ int i;
+
+ dist = 0;
+
+ VectorNegate (dir, dir);
+ length = VectorLength (dir);
+ vectoangles (dir, angles);
+ AngleVectors (angles, forward, NULL, NULL);
+
+ crittersize = LARGESIZE;
+
+ if (length)
+ dist = length / crittersize;
+
+ if (dist < 1)
+ dist = 1;
+
+ VectorCopy (origin, point);
+
+ for (i=0; i<dist; i++)
+ {
+ VectorMA (point, crittersize, forward, point);
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cg.time;
+ p->alpha = 5.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = cgs.media.smokePuffShader;
+
+ // RF, stay around for long enough to expand and dissipate naturally
+ if (length)
+ p->endtime = cg.time + 4500 + (crandom() * 3500);
+ else
+ p->endtime = cg.time + 750 + (crandom() * 500);
+
+ p->startfade = cg.time;
+
+ p->width = LARGESIZE;
+ p->height = LARGESIZE;
+
+ // RF, expand while falling
+ p->endheight = LARGESIZE*3.0;
+ p->endwidth = LARGESIZE*3.0;
+
+ if (!length)
+ {
+ p->width *= 0.2f;
+ p->height *= 0.2f;
+
+ p->endheight = NORMALSIZE;
+ p->endwidth = NORMALSIZE;
+ }
+
+ p->type = P_SMOKE;
+
+ VectorCopy( point, p->org );
+
+ p->vel[0] = crandom()*6;
+ p->vel[1] = crandom()*6;
+ p->vel[2] = random()*20;
+
+ // RF, add some gravity/randomness
+ p->accel[0] = crandom()*3;
+ p->accel[1] = crandom()*3;
+ p->accel[2] = -PARTICLE_GRAVITY*0.4;
+
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+ }
+
+
+}
+
+void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = rand()%179;
+
+ p->pshader = pshader;
+
+ if (duration > 0)
+ p->endtime = cg.time + duration;
+ else
+ p->endtime = duration;
+
+ p->startfade = cg.time;
+
+ p->width = size;
+ p->height = size;
+
+ p->endheight = size;
+ p->endwidth = size;
+
+ p->type = P_SPRITE;
+
+ VectorCopy( origin, p->org );
+
+ p->rotate = qfalse;
+}
+
diff --git a/code/cgame/cg_newdraw.c b/code/cgame/cg_newdraw.c
index 28335fe..c78fff9 100755
--- a/code/cgame/cg_newdraw.c
+++ b/code/cgame/cg_newdraw.c
@@ -1,1852 +1,1852 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#ifndef MISSIONPACK // bk001204
-#error This file not be used for classic Q3A.
-#endif
-
-#include "cg_local.h"
-#include "../ui/ui_shared.h"
-
-extern displayContextDef_t cgDC;
-
-
-// set in CG_ParseTeamInfo
-
-//static int sortedTeamPlayers[TEAM_MAXOVERLAY];
-//static int numSortedTeamPlayers;
-int drawTeamOverlayModificationCount = -1;
-
-//static char systemChat[256];
-//static char teamChat1[256];
-//static char teamChat2[256];
-
-void CG_InitTeamChat() {
- memset(teamChat1, 0, sizeof(teamChat1));
- memset(teamChat2, 0, sizeof(teamChat2));
- memset(systemChat, 0, sizeof(systemChat));
-}
-
-void CG_SetPrintString(int type, const char *p) {
- if (type == SYSTEM_PRINT) {
- strcpy(systemChat, p);
- } else {
- strcpy(teamChat2, teamChat1);
- strcpy(teamChat1, p);
- }
-}
-
-void CG_CheckOrderPending() {
- if (cgs.gametype < GT_CTF) {
- return;
- }
- if (cgs.orderPending) {
- //clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
- const char *p1, *p2, *b;
- p1 = p2 = b = NULL;
- switch (cgs.currentOrder) {
- case TEAMTASK_OFFENSE:
- p1 = VOICECHAT_ONOFFENSE;
- p2 = VOICECHAT_OFFENSE;
- b = "+button7; wait; -button7";
- break;
- case TEAMTASK_DEFENSE:
- p1 = VOICECHAT_ONDEFENSE;
- p2 = VOICECHAT_DEFEND;
- b = "+button8; wait; -button8";
- break;
- case TEAMTASK_PATROL:
- p1 = VOICECHAT_ONPATROL;
- p2 = VOICECHAT_PATROL;
- b = "+button9; wait; -button9";
- break;
- case TEAMTASK_FOLLOW:
- p1 = VOICECHAT_ONFOLLOW;
- p2 = VOICECHAT_FOLLOWME;
- b = "+button10; wait; -button10";
- break;
- case TEAMTASK_CAMP:
- p1 = VOICECHAT_ONCAMPING;
- p2 = VOICECHAT_CAMP;
- break;
- case TEAMTASK_RETRIEVE:
- p1 = VOICECHAT_ONGETFLAG;
- p2 = VOICECHAT_RETURNFLAG;
- break;
- case TEAMTASK_ESCORT:
- p1 = VOICECHAT_ONFOLLOWCARRIER;
- p2 = VOICECHAT_FOLLOWFLAGCARRIER;
- break;
- }
-
- if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
- // to everyone
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", p2));
- } else {
- // for the player self
- if (sortedTeamPlayers[cg_currentSelectedPlayer.integer] == cg.snap->ps.clientNum && p1) {
- trap_SendConsoleCommand(va("teamtask %i\n", cgs.currentOrder));
- //trap_SendConsoleCommand(va("cmd say_team %s\n", p2));
- trap_SendConsoleCommand(va("cmd vsay_team %s\n", p1));
- } else if (p2) {
- //trap_SendConsoleCommand(va("cmd say_team %s, %s\n", ci->name,p));
- trap_SendConsoleCommand(va("cmd vtell %d %s\n", sortedTeamPlayers[cg_currentSelectedPlayer.integer], p2));
- }
- }
- if (b) {
- trap_SendConsoleCommand(b);
- }
- cgs.orderPending = qfalse;
- }
-}
-
-static void CG_SetSelectedPlayerName() {
- if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
- clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
- if (ci) {
- trap_Cvar_Set("cg_selectedPlayerName", ci->name);
- trap_Cvar_Set("cg_selectedPlayer", va("%d", sortedTeamPlayers[cg_currentSelectedPlayer.integer]));
- cgs.currentOrder = ci->teamTask;
- }
- } else {
- trap_Cvar_Set("cg_selectedPlayerName", "Everyone");
- }
-}
-int CG_GetSelectedPlayer() {
- if (cg_currentSelectedPlayer.integer < 0 || cg_currentSelectedPlayer.integer >= numSortedTeamPlayers) {
- cg_currentSelectedPlayer.integer = 0;
- }
- return cg_currentSelectedPlayer.integer;
-}
-
-void CG_SelectNextPlayer() {
- CG_CheckOrderPending();
- if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
- cg_currentSelectedPlayer.integer++;
- } else {
- cg_currentSelectedPlayer.integer = 0;
- }
- CG_SetSelectedPlayerName();
-}
-
-void CG_SelectPrevPlayer() {
- CG_CheckOrderPending();
- if (cg_currentSelectedPlayer.integer > 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
- cg_currentSelectedPlayer.integer--;
- } else {
- cg_currentSelectedPlayer.integer = numSortedTeamPlayers;
- }
- CG_SetSelectedPlayerName();
-}
-
-
-static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) {
- centity_t *cent;
- playerState_t *ps;
- vec3_t angles;
- vec3_t origin;
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses
- CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon );
- } else if (cg_draw3dIcons.integer) {
- VectorClear( angles );
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
-
- CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles );
- }
-
-}
-
-static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- char num[16];
- int value;
- centity_t *cent;
- playerState_t *ps;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- value = ps->stats[STAT_ARMOR];
-
-
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
-}
-
-#ifndef MISSIONPACK // bk001206
-static float healthColors[4][4] = {
-// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
- // bk0101016 - float const
- { 1.0f, 0.69f, 0.0f, 1.0f } , // normal
- { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
- { 0.5f, 0.5f, 0.5f, 1.0f}, // weapon firing
- { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
-#endif
-
-static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) {
- centity_t *cent;
- playerState_t *ps;
- vec3_t angles;
- vec3_t origin;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses
- qhandle_t icon;
- icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
- if ( icon ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon );
- }
- } else if (cg_draw3dIcons.integer) {
- if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
- VectorClear( angles );
- origin[0] = 70;
- origin[1] = 0;
- origin[2] = 0;
- angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
- CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
- }
- }
-}
-
-static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- char num[16];
- int value;
- centity_t *cent;
- playerState_t *ps;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- if ( cent->currentState.weapon ) {
- value = ps->ammo[cent->currentState.weapon];
- if ( value > -1 ) {
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
- }
- }
-
-}
-
-
-
-static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) {
- vec3_t angles;
- float size, stretch;
- float frac;
- float x = rect->x;
-
- VectorClear( angles );
-
- if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
- frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
- size = rect->w * 1.25 * ( 1.5 - frac * 0.5 );
-
- stretch = size - rect->w * 1.25;
- // kick in the direction of damage
- x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
-
- cg.headStartYaw = 180 + cg.damageX * 45;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
-
- cg.headStartTime = cg.time;
- cg.headEndTime = cg.time + 100 + random() * 2000;
- } else {
- if ( cg.time >= cg.headEndTime ) {
- // select a new head angle
- cg.headStartYaw = cg.headEndYaw;
- cg.headStartPitch = cg.headEndPitch;
- cg.headStartTime = cg.headEndTime;
- cg.headEndTime = cg.time + 100 + random() * 2000;
-
- cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
- cg.headEndPitch = 5 * cos( crandom()*M_PI );
- }
-
- size = rect->w * 1.25;
- }
-
- // if the server was frozen for a while we may have a bad head start time
- if ( cg.headStartTime > cg.time ) {
- cg.headStartTime = cg.time;
- }
-
- frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
- frac = frac * frac * ( 3 - 2 * frac );
- angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
- angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
-
- CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles );
-}
-
-static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- clientInfo_t *ci;
- int value;
- char num[16];
-
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", ci->health);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
- }
-}
-
-static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- clientInfo_t *ci;
- int value;
- char num[16];
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- if (ci->armor > 0) {
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", ci->armor);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
- }
- }
-}
-
-qhandle_t CG_StatusHandle(int task) {
- qhandle_t h = cgs.media.assaultShader;
- switch (task) {
- case TEAMTASK_OFFENSE :
- h = cgs.media.assaultShader;
- break;
- case TEAMTASK_DEFENSE :
- h = cgs.media.defendShader;
- break;
- case TEAMTASK_PATROL :
- h = cgs.media.patrolShader;
- break;
- case TEAMTASK_FOLLOW :
- h = cgs.media.followShader;
- break;
- case TEAMTASK_CAMP :
- h = cgs.media.campShader;
- break;
- case TEAMTASK_RETRIEVE :
- h = cgs.media.retrieveShader;
- break;
- case TEAMTASK_ESCORT :
- h = cgs.media.escortShader;
- break;
- default :
- h = cgs.media.assaultShader;
- break;
- }
- return h;
-}
-
-static void CG_DrawSelectedPlayerStatus( rectDef_t *rect ) {
- clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- qhandle_t h;
- if (cgs.orderPending) {
- // blink the icon
- if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) {
- return;
- }
- h = CG_StatusHandle(cgs.currentOrder);
- } else {
- h = CG_StatusHandle(ci->teamTask);
- }
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h );
- }
-}
-
-
-static void CG_DrawPlayerStatus( rectDef_t *rect ) {
- clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
- if (ci) {
- qhandle_t h = CG_StatusHandle(ci->teamTask);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h);
- }
-}
-
-
-static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) {
- clientInfo_t *ci;
- ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
- if (ci) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle);
- }
-}
-
-static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- clientInfo_t *ci;
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p) {
- p = "unknown";
- }
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
- }
-}
-
-static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
- if (ci) {
- const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p) {
- p = "unknown";
- }
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
- }
-}
-
-
-
-static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) {
- clientInfo_t *ci;
-
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader);
- }
- }
-}
-
-static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- char num[16];
- int value = cg.snap->ps.persistant[PERS_SCORE];
-
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
-}
-
-static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) {
- int value;
- vec3_t origin, angles;
-
- value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
- if ( value ) {
- CG_RegisterItemVisuals( value );
-
- if (qtrue) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
- } else {
- VectorClear( angles );
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles );
- }
- }
-
-}
-
-
-static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) {
- clientInfo_t *ci;
- int j;
- float x, y;
-
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- if (ci) {
- x = rect->x;
- y = rect->y;
-
- for (j = 0; j < PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
- gitem_t *item;
- item = BG_FindItemForPowerup( j );
- if (item) {
- CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) );
- x += 3;
- y += 3;
- return;
- }
- }
- }
-
- }
-}
-
-
-static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) {
- clipHandle_t cm;
- clientInfo_t *ci;
- float len;
- vec3_t origin;
- vec3_t mins, maxs, angles;
-
-
- ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
-
- if (ci) {
- if ( cg_draw3dIcons.integer ) {
- cm = ci->headModel;
- if ( !cm ) {
- return;
- }
-
- // offset the origin y and z to center the head
- trap_R_ModelBounds( cm, mins, maxs );
-
- origin[2] = -0.5 * ( mins[2] + maxs[2] );
- origin[1] = 0.5 * ( mins[1] + maxs[1] );
-
- // calculate distance so the head nearly fills the box
- // assume heads are taller than wide
- len = 0.7 * ( maxs[2] - mins[2] );
- origin[0] = len / 0.268; // len / tan( fov/2 )
-
- // allow per-model tweaking
- VectorAdd( origin, ci->headOffset, origin );
-
- angles[PITCH] = 0;
- angles[YAW] = 180;
- angles[ROLL] = 0;
-
- CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles );
- } else if ( cg_drawIcons.integer ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon );
- }
-
- // if they are deferred, draw a cross out
- if ( ci->deferred ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader );
- }
- }
-
-}
-
-
-static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- playerState_t *ps;
- int value;
- char num[16];
-
- ps = &cg.snap->ps;
-
- value = ps->stats[STAT_HEALTH];
-
- if (shader) {
- trap_R_SetColor( color );
- CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
- trap_R_SetColor( NULL );
- } else {
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
- }
-}
-
-
-static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- int value;
- char num[16];
- if ( cgs.scores1 == SCORE_NOT_PRESENT ) {
- Com_sprintf (num, sizeof(num), "-");
- }
- else {
- Com_sprintf (num, sizeof(num), "%i", cgs.scores1);
- }
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
-}
-
-static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- int value;
- char num[16];
-
- if ( cgs.scores2 == SCORE_NOT_PRESENT ) {
- Com_sprintf (num, sizeof(num), "-");
- }
- else {
- Com_sprintf (num, sizeof(num), "%i", cgs.scores2);
- }
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
-}
-
-// FIXME: team name support
-static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle);
-}
-
-static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle);
-}
-
-static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
- return;
- }
- }
-}
-
-static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) {
- if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
- if (cgs.gametype == GT_HARVESTER) {
- vec4_t color = {0, 0, 1, 1};
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.blueCubeIcon );
- trap_R_SetColor(NULL);
- }
- return;
- }
- if (shader) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
- } else {
- gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG );
- if (item) {
- vec4_t color = {0, 0, 1, 1};
- trap_R_SetColor(color);
- if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] );
- } else {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
- }
- trap_R_SetColor(NULL);
- }
- }
-}
-
-static void CG_DrawBlueFlagHead(rectDef_t *rect) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
- vec3_t angles;
- VectorClear( angles );
- angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
- CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
- return;
- }
- }
-}
-
-static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
- return;
- }
- }
-}
-
-static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) {
- if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
- if (cgs.gametype == GT_HARVESTER) {
- vec4_t color = {1, 0, 0, 1};
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.redCubeIcon );
- trap_R_SetColor(NULL);
- }
- return;
- }
- if (shader) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
- } else {
- gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG );
- if (item) {
- vec4_t color = {1, 0, 0, 1};
- trap_R_SetColor(color);
- if( cgs.redflag >= 0 && cgs.redflag <= 2) {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] );
- } else {
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
- }
- trap_R_SetColor(NULL);
- }
- }
-}
-
-static void CG_DrawRedFlagHead(rectDef_t *rect) {
- int i;
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
- vec3_t angles;
- VectorClear( angles );
- angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
- CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
- return;
- }
- }
-}
-
-static void CG_HarvesterSkulls(rectDef_t *rect, float scale, vec4_t color, qboolean force2D, int textStyle ) {
- char num[16];
- vec3_t origin, angles;
- qhandle_t handle;
- int value = cg.snap->ps.generic1;
-
- if (cgs.gametype != GT_HARVESTER) {
- return;
- }
-
- if( value > 99 ) {
- value = 99;
- }
-
- Com_sprintf (num, sizeof(num), "%i", value);
- value = CG_Text_Width(num, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value), rect->y + rect->h, scale, color, num, 0, 0, textStyle);
-
- if (cg_drawIcons.integer) {
- if (!force2D && cg_draw3dIcons.integer) {
- VectorClear(angles);
- origin[0] = 90;
- origin[1] = 0;
- origin[2] = -10;
- angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeModel;
- } else {
- handle = cgs.media.blueCubeModel;
- }
- CG_Draw3DModel( rect->x, rect->y, 35, 35, handle, 0, origin, angles );
- } else {
- if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
- handle = cgs.media.redCubeIcon;
- } else {
- handle = cgs.media.blueCubeIcon;
- }
- CG_DrawPic( rect->x + 3, rect->y + 16, 20, 20, handle );
- }
- }
-}
-
-static void CG_OneFlagStatus(rectDef_t *rect) {
- if (cgs.gametype != GT_1FCTF) {
- return;
- } else {
- gitem_t *item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
- if (item) {
- if( cgs.flagStatus >= 0 && cgs.flagStatus <= 4 ) {
- vec4_t color = {1, 1, 1, 1};
- int index = 0;
- if (cgs.flagStatus == FLAG_TAKEN_RED) {
- color[1] = color[2] = 0;
- index = 1;
- } else if (cgs.flagStatus == FLAG_TAKEN_BLUE) {
- color[0] = color[1] = 0;
- index = 1;
- } else if (cgs.flagStatus == FLAG_DROPPED) {
- index = 2;
- }
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[index] );
- }
- }
- }
-}
-
-
-static void CG_DrawCTFPowerUp(rectDef_t *rect) {
- int value;
-
- if (cgs.gametype < GT_CTF) {
- return;
- }
- value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
- if ( value ) {
- CG_RegisterItemVisuals( value );
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
- }
-}
-
-
-
-static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) {
- CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]);
-}
-
-static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) {
- char num[16];
- int sorted[MAX_POWERUPS];
- int sortedTime[MAX_POWERUPS];
- int i, j, k;
- int active;
- playerState_t *ps;
- int t;
- gitem_t *item;
- float f;
- rectDef_t r2;
- float *inc;
- r2.x = rect->x;
- r2.y = rect->y;
- r2.w = rect->w;
- r2.h = rect->h;
-
- inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x;
-
- ps = &cg.snap->ps;
-
- if ( ps->stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- // sort the list by time remaining
- active = 0;
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- if ( !ps->powerups[ i ] ) {
- continue;
- }
- t = ps->powerups[ i ] - cg.time;
- // ZOID--don't draw if the power up has unlimited time (999 seconds)
- // This is true of the CTF flags
- if ( t <= 0 || t >= 999000) {
- continue;
- }
-
- // insert into the list
- for ( j = 0 ; j < active ; j++ ) {
- if ( sortedTime[j] >= t ) {
- for ( k = active - 1 ; k >= j ; k-- ) {
- sorted[k+1] = sorted[k];
- sortedTime[k+1] = sortedTime[k];
- }
- break;
- }
- }
- sorted[j] = i;
- sortedTime[j] = t;
- active++;
- }
-
- // draw the icons and timers
- for ( i = 0 ; i < active ; i++ ) {
- item = BG_FindItemForPowerup( sorted[i] );
-
- if (item) {
- t = ps->powerups[ sorted[i] ];
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- trap_R_SetColor( NULL );
- } else {
- vec4_t modulate;
-
- f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
- f -= (int)f;
- modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
- trap_R_SetColor( modulate );
- }
-
- CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) );
-
- Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000);
- CG_Text_Paint(r2.x + (r2.w * .75) + 3 , r2.y + r2.h, scale, color, num, 0, 0, 0);
- *inc += r2.w + special;
- }
-
- }
- trap_R_SetColor( NULL );
-
-}
-
-float CG_GetValue(int ownerDraw) {
- centity_t *cent;
- clientInfo_t *ci;
- playerState_t *ps;
-
- cent = &cg_entities[cg.snap->ps.clientNum];
- ps = &cg.snap->ps;
-
- switch (ownerDraw) {
- case CG_SELECTEDPLAYER_ARMOR:
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- return ci->armor;
- break;
- case CG_SELECTEDPLAYER_HEALTH:
- ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
- return ci->health;
- break;
- case CG_PLAYER_ARMOR_VALUE:
- return ps->stats[STAT_ARMOR];
- break;
- case CG_PLAYER_AMMO_VALUE:
- if ( cent->currentState.weapon ) {
- return ps->ammo[cent->currentState.weapon];
- }
- break;
- case CG_PLAYER_SCORE:
- return cg.snap->ps.persistant[PERS_SCORE];
- break;
- case CG_PLAYER_HEALTH:
- return ps->stats[STAT_HEALTH];
- break;
- case CG_RED_SCORE:
- return cgs.scores1;
- break;
- case CG_BLUE_SCORE:
- return cgs.scores2;
- break;
- default:
- break;
- }
- return -1;
-}
-
-qboolean CG_OtherTeamHasFlag() {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
- int team = cg.snap->ps.persistant[PERS_TEAM];
- if (cgs.gametype == GT_1FCTF) {
- if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_BLUE) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_RED) {
- return qtrue;
- } else {
- return qfalse;
- }
- } else {
- if (team == TEAM_RED && cgs.redflag == FLAG_TAKEN) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.blueflag == FLAG_TAKEN) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
- }
- return qfalse;
-}
-
-qboolean CG_YourTeamHasFlag() {
- if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
- int team = cg.snap->ps.persistant[PERS_TEAM];
- if (cgs.gametype == GT_1FCTF) {
- if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_RED) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_BLUE) {
- return qtrue;
- } else {
- return qfalse;
- }
- } else {
- if (team == TEAM_RED && cgs.blueflag == FLAG_TAKEN) {
- return qtrue;
- } else if (team == TEAM_BLUE && cgs.redflag == FLAG_TAKEN) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
- }
- return qfalse;
-}
-
-// THINKABOUTME: should these be exclusive or inclusive..
-//
-qboolean CG_OwnerDrawVisible(int flags) {
-
- if (flags & CG_SHOW_TEAMINFO) {
- return (cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
- }
-
- if (flags & CG_SHOW_NOTEAMINFO) {
- return !(cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
- }
-
- if (flags & CG_SHOW_OTHERTEAMHASFLAG) {
- return CG_OtherTeamHasFlag();
- }
-
- if (flags & CG_SHOW_YOURTEAMHASENEMYFLAG) {
- return CG_YourTeamHasFlag();
- }
-
- if (flags & (CG_SHOW_BLUE_TEAM_HAS_REDFLAG | CG_SHOW_RED_TEAM_HAS_BLUEFLAG)) {
- if (flags & CG_SHOW_BLUE_TEAM_HAS_REDFLAG && (cgs.redflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_RED)) {
- return qtrue;
- } else if (flags & CG_SHOW_RED_TEAM_HAS_BLUEFLAG && (cgs.blueflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_BLUE)) {
- return qtrue;
- }
- return qfalse;
- }
-
- if (flags & CG_SHOW_ANYTEAMGAME) {
- if( cgs.gametype >= GT_TEAM) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_ANYNONTEAMGAME) {
- if( cgs.gametype < GT_TEAM) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_HARVESTER) {
- if( cgs.gametype == GT_HARVESTER ) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
-
- if (flags & CG_SHOW_ONEFLAG) {
- if( cgs.gametype == GT_1FCTF ) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
-
- if (flags & CG_SHOW_CTF) {
- if( cgs.gametype == GT_CTF ) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_OBELISK) {
- if( cgs.gametype == GT_OBELISK ) {
- return qtrue;
- } else {
- return qfalse;
- }
- }
-
- if (flags & CG_SHOW_HEALTHCRITICAL) {
- if (cg.snap->ps.stats[STAT_HEALTH] < 25) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_HEALTHOK) {
- if (cg.snap->ps.stats[STAT_HEALTH] >= 25) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_SINGLEPLAYER) {
- if( cgs.gametype == GT_SINGLE_PLAYER ) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_TOURNAMENT) {
- if( cgs.gametype == GT_TOURNAMENT ) {
- return qtrue;
- }
- }
-
- if (flags & CG_SHOW_DURINGINCOMINGVOICE) {
- }
-
- if (flags & CG_SHOW_IF_PLAYER_HAS_FLAG) {
- if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
- return qtrue;
- }
- }
- return qfalse;
-}
-
-
-
-static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) {
- int adj = (force2D) ? 0 : 2;
- if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
- CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D);
- } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
- CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D);
- } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
- CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D);
- }
-}
-
-static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0);
-}
-
-static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0);
-}
-
-static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0);
-}
-
-const char *CG_GetKillerText() {
- const char *s = "";
- if ( cg.killerName[0] ) {
- s = va("Fragged by %s", cg.killerName );
- }
- return s;
-}
-
-
-static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- // fragged by ... line
- if ( cg.killerName[0] ) {
- int x = rect->x + rect->w / 2;
- CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle);
- }
-
-}
-
-
-static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit;
- CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle);
-}
-
-static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- if (cgs.scores1 != SCORE_NOT_PRESENT) {
- CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle);
- }
-}
-
-static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- if (cgs.scores2 != SCORE_NOT_PRESENT) {
- CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle);
- }
-}
-
-const char *CG_GetGameStatusText() {
- const char *s = "";
- if ( cgs.gametype < GT_TEAM) {
- if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] );
- }
- } else {
- if ( cg.teamScores[0] == cg.teamScores[1] ) {
- s = va("Teams are tied at %i", cg.teamScores[0] );
- } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] );
- } else {
- s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] );
- }
- }
- return s;
-}
-
-static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle);
-}
-
-const char *CG_GameTypeString() {
- if ( cgs.gametype == GT_FFA ) {
- return "Free For All";
- } else if ( cgs.gametype == GT_TEAM ) {
- return "Team Deathmatch";
- } else if ( cgs.gametype == GT_CTF ) {
- return "Capture the Flag";
- } else if ( cgs.gametype == GT_1FCTF ) {
- return "One Flag CTF";
- } else if ( cgs.gametype == GT_OBELISK ) {
- return "Overload";
- } else if ( cgs.gametype == GT_HARVESTER ) {
- return "Harvester";
- }
- return "";
-}
-static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
- CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle);
-}
-
-static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
- int len, count;
- vec4_t newColor;
- glyphInfo_t *glyph;
- if (text) {
-// TTimo: FIXME
-// const unsigned char *s = text; // bk001206 - unsigned
- const char *s = text;
- float max = *maxX;
- float useScale;
- fontInfo_t *font = &cgDC.Assets.textFont;
- if (scale <= cg_smallFont.value) {
- font = &cgDC.Assets.smallFont;
- } else if (scale > cg_bigFont.value) {
- font = &cgDC.Assets.bigFont;
- }
- useScale = scale * font->glyphScale;
- trap_R_SetColor( color );
- len = strlen(text);
- if (limit > 0 && len > limit) {
- len = limit;
- }
- count = 0;
- while (s && *s && count < len) {
- glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
- if ( Q_IsColorString( s ) ) {
- memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
- newColor[3] = color[3];
- trap_R_SetColor( newColor );
- s += 2;
- continue;
- } else {
- float yadj = useScale * glyph->top;
- if (CG_Text_Width(s, useScale, 1) + x > max) {
- *maxX = 0;
- break;
- }
- CG_Text_PaintChar(x, y - yadj,
- glyph->imageWidth,
- glyph->imageHeight,
- useScale,
- glyph->s,
- glyph->t,
- glyph->s2,
- glyph->t2,
- glyph->glyph);
- x += (glyph->xSkip * useScale) + adjust;
- *maxX = x;
- count++;
- s++;
- }
- }
- trap_R_SetColor( NULL );
- }
-
-}
-
-
-
-#define PIC_WIDTH 12
-
-void CG_DrawNewTeamInfo(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, qhandle_t shader) {
- int xx;
- float y;
- int i, j, len, count;
- const char *p;
- vec4_t hcolor;
- float pwidth, lwidth, maxx, leftOver;
- clientInfo_t *ci;
- gitem_t *item;
- qhandle_t h;
-
- // max player name width
- pwidth = 0;
- count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
- len = CG_Text_Width( ci->name, scale, 0);
- if (len > pwidth)
- pwidth = len;
- }
- }
-
- // max location name width
- lwidth = 0;
- for (i = 1; i < MAX_LOCATIONS; i++) {
- p = CG_ConfigString(CS_LOCATIONS + i);
- if (p && *p) {
- len = CG_Text_Width(p, scale, 0);
- if (len > lwidth)
- lwidth = len;
- }
- }
-
- y = rect->y;
-
- for (i = 0; i < count; i++) {
- ci = cgs.clientinfo + sortedTeamPlayers[i];
- if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
-
- xx = rect->x + 1;
- for (j = 0; j <= PW_NUM_POWERUPS; j++) {
- if (ci->powerups & (1 << j)) {
-
- item = BG_FindItemForPowerup( j );
-
- if (item) {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, trap_R_RegisterShader( item->icon ) );
- xx += PIC_WIDTH;
- }
- }
- }
-
- // FIXME: max of 3 powerups shown properly
- xx = rect->x + (PIC_WIDTH * 3) + 2;
-
- CG_GetColorForHealth( ci->health, ci->armor, hcolor );
- trap_R_SetColor(hcolor);
- CG_DrawPic( xx, y + 1, PIC_WIDTH - 2, PIC_WIDTH - 2, cgs.media.heartShader );
-
- //Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
- //CG_Text_Paint(xx, y + text_y, scale, hcolor, st, 0, 0);
-
- // draw weapon icon
- xx += PIC_WIDTH + 1;
-
-// weapon used is not that useful, use the space for task
-#if 0
- if ( cg_weapons[ci->curWeapon].weaponIcon ) {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cg_weapons[ci->curWeapon].weaponIcon );
- } else {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cgs.media.deferShader );
- }
-#endif
-
- trap_R_SetColor(NULL);
- if (cgs.orderPending) {
- // blink the icon
- if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) {
- h = 0;
- } else {
- h = CG_StatusHandle(cgs.currentOrder);
- }
- } else {
- h = CG_StatusHandle(ci->teamTask);
- }
-
- if (h) {
- CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, h);
- }
-
- xx += PIC_WIDTH + 1;
-
- leftOver = rect->w - xx;
- maxx = xx + leftOver / 3;
-
-
-
- CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, ci->name, 0, 0);
-
- p = CG_ConfigString(CS_LOCATIONS + ci->location);
- if (!p || !*p) {
- p = "unknown";
- }
-
- xx += leftOver / 3 + 2;
- maxx = rect->w - 4;
-
- CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, p, 0, 0);
- y += text_y + 2;
- if ( y + text_y + 2 > rect->y + rect->h ) {
- break;
- }
-
- }
- }
-}
-
-
-void CG_DrawTeamSpectators(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- if (cg.spectatorLen) {
- float maxX;
-
- if (cg.spectatorWidth == -1) {
- cg.spectatorWidth = 0;
- cg.spectatorPaintX = rect->x + 1;
- cg.spectatorPaintX2 = -1;
- }
-
- if (cg.spectatorOffset > cg.spectatorLen) {
- cg.spectatorOffset = 0;
- cg.spectatorPaintX = rect->x + 1;
- cg.spectatorPaintX2 = -1;
- }
-
- if (cg.time > cg.spectatorTime) {
- cg.spectatorTime = cg.time + 10;
- if (cg.spectatorPaintX <= rect->x + 2) {
- if (cg.spectatorOffset < cg.spectatorLen) {
- cg.spectatorPaintX += CG_Text_Width(&cg.spectatorList[cg.spectatorOffset], scale, 1) - 1;
- cg.spectatorOffset++;
- } else {
- cg.spectatorOffset = 0;
- if (cg.spectatorPaintX2 >= 0) {
- cg.spectatorPaintX = cg.spectatorPaintX2;
- } else {
- cg.spectatorPaintX = rect->x + rect->w - 2;
- }
- cg.spectatorPaintX2 = -1;
- }
- } else {
- cg.spectatorPaintX--;
- if (cg.spectatorPaintX2 >= 0) {
- cg.spectatorPaintX2--;
- }
- }
- }
-
- maxX = rect->x + rect->w - 2;
- CG_Text_Paint_Limit(&maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, &cg.spectatorList[cg.spectatorOffset], 0, 0);
- if (cg.spectatorPaintX2 >= 0) {
- float maxX2 = rect->x + rect->w - 2;
- CG_Text_Paint_Limit(&maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, color, cg.spectatorList, 0, cg.spectatorOffset);
- }
- if (cg.spectatorOffset && maxX > 0) {
- // if we have an offset ( we are skipping the first part of the string ) and we fit the string
- if (cg.spectatorPaintX2 == -1) {
- cg.spectatorPaintX2 = rect->x + rect->w - 2;
- }
- } else {
- cg.spectatorPaintX2 = -1;
- }
-
- }
-}
-
-
-
-void CG_DrawMedal(int ownerDraw, rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
- score_t *score = &cg.scores[cg.selectedScore];
- float value = 0;
- char *text = NULL;
- color[3] = 0.25;
-
- switch (ownerDraw) {
- case CG_ACCURACY:
- value = score->accuracy;
- break;
- case CG_ASSISTS:
- value = score->assistCount;
- break;
- case CG_DEFEND:
- value = score->defendCount;
- break;
- case CG_EXCELLENT:
- value = score->excellentCount;
- break;
- case CG_IMPRESSIVE:
- value = score->impressiveCount;
- break;
- case CG_PERFECT:
- value = score->perfect;
- break;
- case CG_GAUNTLET:
- value = score->guantletCount;
- break;
- case CG_CAPTURES:
- value = score->captures;
- break;
- }
-
- if (value > 0) {
- if (ownerDraw != CG_PERFECT) {
- if (ownerDraw == CG_ACCURACY) {
- text = va("%i%%", (int)value);
- if (value > 50) {
- color[3] = 1.0;
- }
- } else {
- text = va("%i", (int)value);
- color[3] = 1.0;
- }
- } else {
- if (value) {
- color[3] = 1.0;
- }
- text = "Wow";
- }
- }
-
- trap_R_SetColor(color);
- CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
-
- if (text) {
- color[3] = 1.0;
- value = CG_Text_Width(text, scale, 0);
- CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h + 10 , scale, color, text, 0, 0, 0);
- }
- trap_R_SetColor(NULL);
-
-}
-
-
-//
-void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
- rectDef_t rect;
-
- if ( cg_drawStatus.integer == 0 ) {
- return;
- }
-
- //if (ownerDrawFlags != 0 && !CG_OwnerDrawVisible(ownerDrawFlags)) {
- // return;
- //}
-
- rect.x = x;
- rect.y = y;
- rect.w = w;
- rect.h = h;
-
- switch (ownerDraw) {
- case CG_PLAYER_ARMOR_ICON:
- CG_DrawPlayerArmorIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_ARMOR_ICON2D:
- CG_DrawPlayerArmorIcon(&rect, qtrue);
- break;
- case CG_PLAYER_ARMOR_VALUE:
- CG_DrawPlayerArmorValue(&rect, scale, color, shader, textStyle);
- break;
- case CG_PLAYER_AMMO_ICON:
- CG_DrawPlayerAmmoIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_AMMO_ICON2D:
- CG_DrawPlayerAmmoIcon(&rect, qtrue);
- break;
- case CG_PLAYER_AMMO_VALUE:
- CG_DrawPlayerAmmoValue(&rect, scale, color, shader, textStyle);
- break;
- case CG_SELECTEDPLAYER_HEAD:
- CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qfalse);
- break;
- case CG_VOICE_HEAD:
- CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qtrue);
- break;
- case CG_VOICE_NAME:
- CG_DrawSelectedPlayerName(&rect, scale, color, qtrue, textStyle);
- break;
- case CG_SELECTEDPLAYER_STATUS:
- CG_DrawSelectedPlayerStatus(&rect);
- break;
- case CG_SELECTEDPLAYER_ARMOR:
- CG_DrawSelectedPlayerArmor(&rect, scale, color, shader, textStyle);
- break;
- case CG_SELECTEDPLAYER_HEALTH:
- CG_DrawSelectedPlayerHealth(&rect, scale, color, shader, textStyle);
- break;
- case CG_SELECTEDPLAYER_NAME:
- CG_DrawSelectedPlayerName(&rect, scale, color, qfalse, textStyle);
- break;
- case CG_SELECTEDPLAYER_LOCATION:
- CG_DrawSelectedPlayerLocation(&rect, scale, color, textStyle);
- break;
- case CG_SELECTEDPLAYER_WEAPON:
- CG_DrawSelectedPlayerWeapon(&rect);
- break;
- case CG_SELECTEDPLAYER_POWERUP:
- CG_DrawSelectedPlayerPowerup(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_HEAD:
- CG_DrawPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_ITEM:
- CG_DrawPlayerItem(&rect, scale, ownerDrawFlags & CG_SHOW_2DONLY);
- break;
- case CG_PLAYER_SCORE:
- CG_DrawPlayerScore(&rect, scale, color, shader, textStyle);
- break;
- case CG_PLAYER_HEALTH:
- CG_DrawPlayerHealth(&rect, scale, color, shader, textStyle);
- break;
- case CG_RED_SCORE:
- CG_DrawRedScore(&rect, scale, color, shader, textStyle);
- break;
- case CG_BLUE_SCORE:
- CG_DrawBlueScore(&rect, scale, color, shader, textStyle);
- break;
- case CG_RED_NAME:
- CG_DrawRedName(&rect, scale, color, textStyle);
- break;
- case CG_BLUE_NAME:
- CG_DrawBlueName(&rect, scale, color, textStyle);
- break;
- case CG_BLUE_FLAGHEAD:
- CG_DrawBlueFlagHead(&rect);
- break;
- case CG_BLUE_FLAGSTATUS:
- CG_DrawBlueFlagStatus(&rect, shader);
- break;
- case CG_BLUE_FLAGNAME:
- CG_DrawBlueFlagName(&rect, scale, color, textStyle);
- break;
- case CG_RED_FLAGHEAD:
- CG_DrawRedFlagHead(&rect);
- break;
- case CG_RED_FLAGSTATUS:
- CG_DrawRedFlagStatus(&rect, shader);
- break;
- case CG_RED_FLAGNAME:
- CG_DrawRedFlagName(&rect, scale, color, textStyle);
- break;
- case CG_HARVESTER_SKULLS:
- CG_HarvesterSkulls(&rect, scale, color, qfalse, textStyle);
- break;
- case CG_HARVESTER_SKULLS2D:
- CG_HarvesterSkulls(&rect, scale, color, qtrue, textStyle);
- break;
- case CG_ONEFLAG_STATUS:
- CG_OneFlagStatus(&rect);
- break;
- case CG_PLAYER_LOCATION:
- CG_DrawPlayerLocation(&rect, scale, color, textStyle);
- break;
- case CG_TEAM_COLOR:
- CG_DrawTeamColor(&rect, color);
- break;
- case CG_CTF_POWERUP:
- CG_DrawCTFPowerUp(&rect);
- break;
- case CG_AREA_POWERUP:
- CG_DrawAreaPowerUp(&rect, align, special, scale, color);
- break;
- case CG_PLAYER_STATUS:
- CG_DrawPlayerStatus(&rect);
- break;
- case CG_PLAYER_HASFLAG:
- CG_DrawPlayerHasFlag(&rect, qfalse);
- break;
- case CG_PLAYER_HASFLAG2D:
- CG_DrawPlayerHasFlag(&rect, qtrue);
- break;
- case CG_AREA_SYSTEMCHAT:
- CG_DrawAreaSystemChat(&rect, scale, color, shader);
- break;
- case CG_AREA_TEAMCHAT:
- CG_DrawAreaTeamChat(&rect, scale, color, shader);
- break;
- case CG_AREA_CHAT:
- CG_DrawAreaChat(&rect, scale, color, shader);
- break;
- case CG_GAME_TYPE:
- CG_DrawGameType(&rect, scale, color, shader, textStyle);
- break;
- case CG_GAME_STATUS:
- CG_DrawGameStatus(&rect, scale, color, shader, textStyle);
- break;
- case CG_KILLER:
- CG_DrawKiller(&rect, scale, color, shader, textStyle);
- break;
- case CG_ACCURACY:
- case CG_ASSISTS:
- case CG_DEFEND:
- case CG_EXCELLENT:
- case CG_IMPRESSIVE:
- case CG_PERFECT:
- case CG_GAUNTLET:
- case CG_CAPTURES:
- CG_DrawMedal(ownerDraw, &rect, scale, color, shader);
- break;
- case CG_SPECTATORS:
- CG_DrawTeamSpectators(&rect, scale, color, shader);
- break;
- case CG_TEAMINFO:
- if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
- CG_DrawNewTeamInfo(&rect, text_x, text_y, scale, color, shader);
- }
- break;
- case CG_CAPFRAGLIMIT:
- CG_DrawCapFragLimit(&rect, scale, color, shader, textStyle);
- break;
- case CG_1STPLACE:
- CG_Draw1stPlace(&rect, scale, color, shader, textStyle);
- break;
- case CG_2NDPLACE:
- CG_Draw2ndPlace(&rect, scale, color, shader, textStyle);
- break;
- default:
- break;
- }
-}
-
-void CG_MouseEvent(int x, int y) {
- int n;
-
- if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse) {
- trap_Key_SetCatcher(0);
- return;
- }
-
- cgs.cursorX+= x;
- if (cgs.cursorX < 0)
- cgs.cursorX = 0;
- else if (cgs.cursorX > 640)
- cgs.cursorX = 640;
-
- cgs.cursorY += y;
- if (cgs.cursorY < 0)
- cgs.cursorY = 0;
- else if (cgs.cursorY > 480)
- cgs.cursorY = 480;
-
- n = Display_CursorType(cgs.cursorX, cgs.cursorY);
- cgs.activeCursor = 0;
- if (n == CURSOR_ARROW) {
- cgs.activeCursor = cgs.media.selectCursor;
- } else if (n == CURSOR_SIZER) {
- cgs.activeCursor = cgs.media.sizeCursor;
- }
-
- if (cgs.capturedItem) {
- Display_MouseMove(cgs.capturedItem, x, y);
- } else {
- Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY);
- }
-
-}
-
-/*
-==================
-CG_HideTeamMenus
-==================
-
-*/
-void CG_HideTeamMenu() {
- Menus_CloseByName("teamMenu");
- Menus_CloseByName("getMenu");
-}
-
-/*
-==================
-CG_ShowTeamMenus
-==================
-
-*/
-void CG_ShowTeamMenu() {
- Menus_OpenByName("teamMenu");
-}
-
-
-
-
-/*
-==================
-CG_EventHandling
-==================
- type 0 - no event handling
- 1 - team menu
- 2 - hud editor
-
-*/
-void CG_EventHandling(int type) {
- cgs.eventHandling = type;
- if (type == CGAME_EVENT_NONE) {
- CG_HideTeamMenu();
- } else if (type == CGAME_EVENT_TEAMMENU) {
- //CG_ShowTeamMenu();
- } else if (type == CGAME_EVENT_SCOREBOARD) {
- }
-
-}
-
-
-
-void CG_KeyEvent(int key, qboolean down) {
-
- if (!down) {
- return;
- }
-
- if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse)) {
- CG_EventHandling(CGAME_EVENT_NONE);
- trap_Key_SetCatcher(0);
- return;
- }
-
- //if (key == trap_Key_GetKey("teamMenu") || !Display_CaptureItem(cgs.cursorX, cgs.cursorY)) {
- // if we see this then we should always be visible
- // CG_EventHandling(CGAME_EVENT_NONE);
- // trap_Key_SetCatcher(0);
- //}
-
-
-
- Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY);
-
- if (cgs.capturedItem) {
- cgs.capturedItem = NULL;
- } else {
- if (key == K_MOUSE2 && down) {
- cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY);
- }
- }
-}
-
-int CG_ClientNumFromName(const char *p) {
- int i;
- for (i = 0; i < cgs.maxclients; i++) {
- if (cgs.clientinfo[i].infoValid && Q_stricmp(cgs.clientinfo[i].name, p) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-void CG_ShowResponseHead() {
- Menus_OpenByName("voiceMenu");
- trap_Cvar_Set("cl_conXOffset", "72");
- cg.voiceTime = cg.time;
-}
-
-void CG_RunMenuScript(char **args) {
-}
-
-
-void CG_GetTeamColor(vec4_t *color) {
- if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) {
- (*color)[0] = 1.0f;
- (*color)[3] = 0.25f;
- (*color)[1] = (*color)[2] = 0.0f;
- } else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) {
- (*color)[0] = (*color)[1] = 0.0f;
- (*color)[2] = 1.0f;
- (*color)[3] = 0.25f;
- } else {
- (*color)[0] = (*color)[2] = 0.0f;
- (*color)[1] = 0.17f;
- (*color)[3] = 0.25f;
- }
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#ifndef MISSIONPACK // bk001204
+#error This file not be used for classic Q3A.
+#endif
+
+#include "cg_local.h"
+#include "../ui/ui_shared.h"
+
+extern displayContextDef_t cgDC;
+
+
+// set in CG_ParseTeamInfo
+
+//static int sortedTeamPlayers[TEAM_MAXOVERLAY];
+//static int numSortedTeamPlayers;
+int drawTeamOverlayModificationCount = -1;
+
+//static char systemChat[256];
+//static char teamChat1[256];
+//static char teamChat2[256];
+
+void CG_InitTeamChat() {
+ memset(teamChat1, 0, sizeof(teamChat1));
+ memset(teamChat2, 0, sizeof(teamChat2));
+ memset(systemChat, 0, sizeof(systemChat));
+}
+
+void CG_SetPrintString(int type, const char *p) {
+ if (type == SYSTEM_PRINT) {
+ strcpy(systemChat, p);
+ } else {
+ strcpy(teamChat2, teamChat1);
+ strcpy(teamChat1, p);
+ }
+}
+
+void CG_CheckOrderPending() {
+ if (cgs.gametype < GT_CTF) {
+ return;
+ }
+ if (cgs.orderPending) {
+ //clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
+ const char *p1, *p2, *b;
+ p1 = p2 = b = NULL;
+ switch (cgs.currentOrder) {
+ case TEAMTASK_OFFENSE:
+ p1 = VOICECHAT_ONOFFENSE;
+ p2 = VOICECHAT_OFFENSE;
+ b = "+button7; wait; -button7";
+ break;
+ case TEAMTASK_DEFENSE:
+ p1 = VOICECHAT_ONDEFENSE;
+ p2 = VOICECHAT_DEFEND;
+ b = "+button8; wait; -button8";
+ break;
+ case TEAMTASK_PATROL:
+ p1 = VOICECHAT_ONPATROL;
+ p2 = VOICECHAT_PATROL;
+ b = "+button9; wait; -button9";
+ break;
+ case TEAMTASK_FOLLOW:
+ p1 = VOICECHAT_ONFOLLOW;
+ p2 = VOICECHAT_FOLLOWME;
+ b = "+button10; wait; -button10";
+ break;
+ case TEAMTASK_CAMP:
+ p1 = VOICECHAT_ONCAMPING;
+ p2 = VOICECHAT_CAMP;
+ break;
+ case TEAMTASK_RETRIEVE:
+ p1 = VOICECHAT_ONGETFLAG;
+ p2 = VOICECHAT_RETURNFLAG;
+ break;
+ case TEAMTASK_ESCORT:
+ p1 = VOICECHAT_ONFOLLOWCARRIER;
+ p2 = VOICECHAT_FOLLOWFLAGCARRIER;
+ break;
+ }
+
+ if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
+ // to everyone
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", p2));
+ } else {
+ // for the player self
+ if (sortedTeamPlayers[cg_currentSelectedPlayer.integer] == cg.snap->ps.clientNum && p1) {
+ trap_SendConsoleCommand(va("teamtask %i\n", cgs.currentOrder));
+ //trap_SendConsoleCommand(va("cmd say_team %s\n", p2));
+ trap_SendConsoleCommand(va("cmd vsay_team %s\n", p1));
+ } else if (p2) {
+ //trap_SendConsoleCommand(va("cmd say_team %s, %s\n", ci->name,p));
+ trap_SendConsoleCommand(va("cmd vtell %d %s\n", sortedTeamPlayers[cg_currentSelectedPlayer.integer], p2));
+ }
+ }
+ if (b) {
+ trap_SendConsoleCommand(b);
+ }
+ cgs.orderPending = qfalse;
+ }
+}
+
+static void CG_SetSelectedPlayerName() {
+ if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
+ clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
+ if (ci) {
+ trap_Cvar_Set("cg_selectedPlayerName", ci->name);
+ trap_Cvar_Set("cg_selectedPlayer", va("%d", sortedTeamPlayers[cg_currentSelectedPlayer.integer]));
+ cgs.currentOrder = ci->teamTask;
+ }
+ } else {
+ trap_Cvar_Set("cg_selectedPlayerName", "Everyone");
+ }
+}
+int CG_GetSelectedPlayer() {
+ if (cg_currentSelectedPlayer.integer < 0 || cg_currentSelectedPlayer.integer >= numSortedTeamPlayers) {
+ cg_currentSelectedPlayer.integer = 0;
+ }
+ return cg_currentSelectedPlayer.integer;
+}
+
+void CG_SelectNextPlayer() {
+ CG_CheckOrderPending();
+ if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
+ cg_currentSelectedPlayer.integer++;
+ } else {
+ cg_currentSelectedPlayer.integer = 0;
+ }
+ CG_SetSelectedPlayerName();
+}
+
+void CG_SelectPrevPlayer() {
+ CG_CheckOrderPending();
+ if (cg_currentSelectedPlayer.integer > 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
+ cg_currentSelectedPlayer.integer--;
+ } else {
+ cg_currentSelectedPlayer.integer = numSortedTeamPlayers;
+ }
+ CG_SetSelectedPlayerName();
+}
+
+
+static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) {
+ centity_t *cent;
+ playerState_t *ps;
+ vec3_t angles;
+ vec3_t origin;
+
+ if ( cg_drawStatus.integer == 0 ) {
+ return;
+ }
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses
+ CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon );
+ } else if (cg_draw3dIcons.integer) {
+ VectorClear( angles );
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+
+ CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles );
+ }
+
+}
+
+static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ char num[16];
+ int value;
+ centity_t *cent;
+ playerState_t *ps;
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ value = ps->stats[STAT_ARMOR];
+
+
+ if (shader) {
+ trap_R_SetColor( color );
+ CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
+ trap_R_SetColor( NULL );
+ } else {
+ Com_sprintf (num, sizeof(num), "%i", value);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+ }
+}
+
+#ifndef MISSIONPACK // bk001206
+static float healthColors[4][4] = {
+// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
+ // bk0101016 - float const
+ { 1.0f, 0.69f, 0.0f, 1.0f } , // normal
+ { 1.0f, 0.2f, 0.2f, 1.0f }, // low health
+ { 0.5f, 0.5f, 0.5f, 1.0f}, // weapon firing
+ { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100
+#endif
+
+static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) {
+ centity_t *cent;
+ playerState_t *ps;
+ vec3_t angles;
+ vec3_t origin;
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses
+ qhandle_t icon;
+ icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
+ if ( icon ) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon );
+ }
+ } else if (cg_draw3dIcons.integer) {
+ if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
+ VectorClear( angles );
+ origin[0] = 70;
+ origin[1] = 0;
+ origin[2] = 0;
+ angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
+ CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
+ }
+ }
+}
+
+static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ char num[16];
+ int value;
+ centity_t *cent;
+ playerState_t *ps;
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ if ( cent->currentState.weapon ) {
+ value = ps->ammo[cent->currentState.weapon];
+ if ( value > -1 ) {
+ if (shader) {
+ trap_R_SetColor( color );
+ CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
+ trap_R_SetColor( NULL );
+ } else {
+ Com_sprintf (num, sizeof(num), "%i", value);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+ }
+ }
+ }
+
+}
+
+
+
+static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) {
+ vec3_t angles;
+ float size, stretch;
+ float frac;
+ float x = rect->x;
+
+ VectorClear( angles );
+
+ if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
+ frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
+ size = rect->w * 1.25 * ( 1.5 - frac * 0.5 );
+
+ stretch = size - rect->w * 1.25;
+ // kick in the direction of damage
+ x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
+
+ cg.headStartYaw = 180 + cg.damageX * 45;
+
+ cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
+ cg.headEndPitch = 5 * cos( crandom()*M_PI );
+
+ cg.headStartTime = cg.time;
+ cg.headEndTime = cg.time + 100 + random() * 2000;
+ } else {
+ if ( cg.time >= cg.headEndTime ) {
+ // select a new head angle
+ cg.headStartYaw = cg.headEndYaw;
+ cg.headStartPitch = cg.headEndPitch;
+ cg.headStartTime = cg.headEndTime;
+ cg.headEndTime = cg.time + 100 + random() * 2000;
+
+ cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
+ cg.headEndPitch = 5 * cos( crandom()*M_PI );
+ }
+
+ size = rect->w * 1.25;
+ }
+
+ // if the server was frozen for a while we may have a bad head start time
+ if ( cg.headStartTime > cg.time ) {
+ cg.headStartTime = cg.time;
+ }
+
+ frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
+ frac = frac * frac * ( 3 - 2 * frac );
+ angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
+ angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
+
+ CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles );
+}
+
+static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ clientInfo_t *ci;
+ int value;
+ char num[16];
+
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ if (ci) {
+ if (shader) {
+ trap_R_SetColor( color );
+ CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
+ trap_R_SetColor( NULL );
+ } else {
+ Com_sprintf (num, sizeof(num), "%i", ci->health);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+ }
+ }
+}
+
+static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ clientInfo_t *ci;
+ int value;
+ char num[16];
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ if (ci) {
+ if (ci->armor > 0) {
+ if (shader) {
+ trap_R_SetColor( color );
+ CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
+ trap_R_SetColor( NULL );
+ } else {
+ Com_sprintf (num, sizeof(num), "%i", ci->armor);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+ }
+ }
+ }
+}
+
+qhandle_t CG_StatusHandle(int task) {
+ qhandle_t h = cgs.media.assaultShader;
+ switch (task) {
+ case TEAMTASK_OFFENSE :
+ h = cgs.media.assaultShader;
+ break;
+ case TEAMTASK_DEFENSE :
+ h = cgs.media.defendShader;
+ break;
+ case TEAMTASK_PATROL :
+ h = cgs.media.patrolShader;
+ break;
+ case TEAMTASK_FOLLOW :
+ h = cgs.media.followShader;
+ break;
+ case TEAMTASK_CAMP :
+ h = cgs.media.campShader;
+ break;
+ case TEAMTASK_RETRIEVE :
+ h = cgs.media.retrieveShader;
+ break;
+ case TEAMTASK_ESCORT :
+ h = cgs.media.escortShader;
+ break;
+ default :
+ h = cgs.media.assaultShader;
+ break;
+ }
+ return h;
+}
+
+static void CG_DrawSelectedPlayerStatus( rectDef_t *rect ) {
+ clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ if (ci) {
+ qhandle_t h;
+ if (cgs.orderPending) {
+ // blink the icon
+ if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) {
+ return;
+ }
+ h = CG_StatusHandle(cgs.currentOrder);
+ } else {
+ h = CG_StatusHandle(ci->teamTask);
+ }
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h );
+ }
+}
+
+
+static void CG_DrawPlayerStatus( rectDef_t *rect ) {
+ clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
+ if (ci) {
+ qhandle_t h = CG_StatusHandle(ci->teamTask);
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h);
+ }
+}
+
+
+static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) {
+ clientInfo_t *ci;
+ ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
+ if (ci) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle);
+ }
+}
+
+static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
+ clientInfo_t *ci;
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ if (ci) {
+ const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
+ if (!p || !*p) {
+ p = "unknown";
+ }
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
+ }
+}
+
+static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
+ clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
+ if (ci) {
+ const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
+ if (!p || !*p) {
+ p = "unknown";
+ }
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
+ }
+}
+
+
+
+static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) {
+ clientInfo_t *ci;
+
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ if (ci) {
+ if ( cg_weapons[ci->curWeapon].weaponIcon ) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon );
+ } else {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader);
+ }
+ }
+}
+
+static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ char num[16];
+ int value = cg.snap->ps.persistant[PERS_SCORE];
+
+ if (shader) {
+ trap_R_SetColor( color );
+ CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
+ trap_R_SetColor( NULL );
+ } else {
+ Com_sprintf (num, sizeof(num), "%i", value);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+ }
+}
+
+static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) {
+ int value;
+ vec3_t origin, angles;
+
+ value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
+ if ( value ) {
+ CG_RegisterItemVisuals( value );
+
+ if (qtrue) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
+ } else {
+ VectorClear( angles );
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+ CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles );
+ }
+ }
+
+}
+
+
+static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) {
+ clientInfo_t *ci;
+ int j;
+ float x, y;
+
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ if (ci) {
+ x = rect->x;
+ y = rect->y;
+
+ for (j = 0; j < PW_NUM_POWERUPS; j++) {
+ if (ci->powerups & (1 << j)) {
+ gitem_t *item;
+ item = BG_FindItemForPowerup( j );
+ if (item) {
+ CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) );
+ x += 3;
+ y += 3;
+ return;
+ }
+ }
+ }
+
+ }
+}
+
+
+static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) {
+ clipHandle_t cm;
+ clientInfo_t *ci;
+ float len;
+ vec3_t origin;
+ vec3_t mins, maxs, angles;
+
+
+ ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
+
+ if (ci) {
+ if ( cg_draw3dIcons.integer ) {
+ cm = ci->headModel;
+ if ( !cm ) {
+ return;
+ }
+
+ // offset the origin y and z to center the head
+ trap_R_ModelBounds( cm, mins, maxs );
+
+ origin[2] = -0.5 * ( mins[2] + maxs[2] );
+ origin[1] = 0.5 * ( mins[1] + maxs[1] );
+
+ // calculate distance so the head nearly fills the box
+ // assume heads are taller than wide
+ len = 0.7 * ( maxs[2] - mins[2] );
+ origin[0] = len / 0.268; // len / tan( fov/2 )
+
+ // allow per-model tweaking
+ VectorAdd( origin, ci->headOffset, origin );
+
+ angles[PITCH] = 0;
+ angles[YAW] = 180;
+ angles[ROLL] = 0;
+
+ CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles );
+ } else if ( cg_drawIcons.integer ) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon );
+ }
+
+ // if they are deferred, draw a cross out
+ if ( ci->deferred ) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader );
+ }
+ }
+
+}
+
+
+static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ playerState_t *ps;
+ int value;
+ char num[16];
+
+ ps = &cg.snap->ps;
+
+ value = ps->stats[STAT_HEALTH];
+
+ if (shader) {
+ trap_R_SetColor( color );
+ CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
+ trap_R_SetColor( NULL );
+ } else {
+ Com_sprintf (num, sizeof(num), "%i", value);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+ }
+}
+
+
+static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ int value;
+ char num[16];
+ if ( cgs.scores1 == SCORE_NOT_PRESENT ) {
+ Com_sprintf (num, sizeof(num), "-");
+ }
+ else {
+ Com_sprintf (num, sizeof(num), "%i", cgs.scores1);
+ }
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+}
+
+static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ int value;
+ char num[16];
+
+ if ( cgs.scores2 == SCORE_NOT_PRESENT ) {
+ Com_sprintf (num, sizeof(num), "-");
+ }
+ else {
+ Com_sprintf (num, sizeof(num), "%i", cgs.scores2);
+ }
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+}
+
+// FIXME: team name support
+static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle);
+}
+
+static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle);
+}
+
+static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
+ int i;
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
+ return;
+ }
+ }
+}
+
+static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) {
+ if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
+ if (cgs.gametype == GT_HARVESTER) {
+ vec4_t color = {0, 0, 1, 1};
+ trap_R_SetColor(color);
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.blueCubeIcon );
+ trap_R_SetColor(NULL);
+ }
+ return;
+ }
+ if (shader) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
+ } else {
+ gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG );
+ if (item) {
+ vec4_t color = {0, 0, 1, 1};
+ trap_R_SetColor(color);
+ if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] );
+ } else {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
+ }
+ trap_R_SetColor(NULL);
+ }
+ }
+}
+
+static void CG_DrawBlueFlagHead(rectDef_t *rect) {
+ int i;
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
+ vec3_t angles;
+ VectorClear( angles );
+ angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
+ CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
+ return;
+ }
+ }
+}
+
+static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
+ int i;
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
+ return;
+ }
+ }
+}
+
+static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) {
+ if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
+ if (cgs.gametype == GT_HARVESTER) {
+ vec4_t color = {1, 0, 0, 1};
+ trap_R_SetColor(color);
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.redCubeIcon );
+ trap_R_SetColor(NULL);
+ }
+ return;
+ }
+ if (shader) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
+ } else {
+ gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG );
+ if (item) {
+ vec4_t color = {1, 0, 0, 1};
+ trap_R_SetColor(color);
+ if( cgs.redflag >= 0 && cgs.redflag <= 2) {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] );
+ } else {
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
+ }
+ trap_R_SetColor(NULL);
+ }
+ }
+}
+
+static void CG_DrawRedFlagHead(rectDef_t *rect) {
+ int i;
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
+ vec3_t angles;
+ VectorClear( angles );
+ angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
+ CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
+ return;
+ }
+ }
+}
+
+static void CG_HarvesterSkulls(rectDef_t *rect, float scale, vec4_t color, qboolean force2D, int textStyle ) {
+ char num[16];
+ vec3_t origin, angles;
+ qhandle_t handle;
+ int value = cg.snap->ps.generic1;
+
+ if (cgs.gametype != GT_HARVESTER) {
+ return;
+ }
+
+ if( value > 99 ) {
+ value = 99;
+ }
+
+ Com_sprintf (num, sizeof(num), "%i", value);
+ value = CG_Text_Width(num, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value), rect->y + rect->h, scale, color, num, 0, 0, textStyle);
+
+ if (cg_drawIcons.integer) {
+ if (!force2D && cg_draw3dIcons.integer) {
+ VectorClear(angles);
+ origin[0] = 90;
+ origin[1] = 0;
+ origin[2] = -10;
+ angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
+ if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ handle = cgs.media.redCubeModel;
+ } else {
+ handle = cgs.media.blueCubeModel;
+ }
+ CG_Draw3DModel( rect->x, rect->y, 35, 35, handle, 0, origin, angles );
+ } else {
+ if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
+ handle = cgs.media.redCubeIcon;
+ } else {
+ handle = cgs.media.blueCubeIcon;
+ }
+ CG_DrawPic( rect->x + 3, rect->y + 16, 20, 20, handle );
+ }
+ }
+}
+
+static void CG_OneFlagStatus(rectDef_t *rect) {
+ if (cgs.gametype != GT_1FCTF) {
+ return;
+ } else {
+ gitem_t *item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
+ if (item) {
+ if( cgs.flagStatus >= 0 && cgs.flagStatus <= 4 ) {
+ vec4_t color = {1, 1, 1, 1};
+ int index = 0;
+ if (cgs.flagStatus == FLAG_TAKEN_RED) {
+ color[1] = color[2] = 0;
+ index = 1;
+ } else if (cgs.flagStatus == FLAG_TAKEN_BLUE) {
+ color[0] = color[1] = 0;
+ index = 1;
+ } else if (cgs.flagStatus == FLAG_DROPPED) {
+ index = 2;
+ }
+ trap_R_SetColor(color);
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[index] );
+ }
+ }
+ }
+}
+
+
+static void CG_DrawCTFPowerUp(rectDef_t *rect) {
+ int value;
+
+ if (cgs.gametype < GT_CTF) {
+ return;
+ }
+ value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
+ if ( value ) {
+ CG_RegisterItemVisuals( value );
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
+ }
+}
+
+
+
+static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) {
+ CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]);
+}
+
+static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) {
+ char num[16];
+ int sorted[MAX_POWERUPS];
+ int sortedTime[MAX_POWERUPS];
+ int i, j, k;
+ int active;
+ playerState_t *ps;
+ int t;
+ gitem_t *item;
+ float f;
+ rectDef_t r2;
+ float *inc;
+ r2.x = rect->x;
+ r2.y = rect->y;
+ r2.w = rect->w;
+ r2.h = rect->h;
+
+ inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x;
+
+ ps = &cg.snap->ps;
+
+ if ( ps->stats[STAT_HEALTH] <= 0 ) {
+ return;
+ }
+
+ // sort the list by time remaining
+ active = 0;
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ if ( !ps->powerups[ i ] ) {
+ continue;
+ }
+ t = ps->powerups[ i ] - cg.time;
+ // ZOID--don't draw if the power up has unlimited time (999 seconds)
+ // This is true of the CTF flags
+ if ( t <= 0 || t >= 999000) {
+ continue;
+ }
+
+ // insert into the list
+ for ( j = 0 ; j < active ; j++ ) {
+ if ( sortedTime[j] >= t ) {
+ for ( k = active - 1 ; k >= j ; k-- ) {
+ sorted[k+1] = sorted[k];
+ sortedTime[k+1] = sortedTime[k];
+ }
+ break;
+ }
+ }
+ sorted[j] = i;
+ sortedTime[j] = t;
+ active++;
+ }
+
+ // draw the icons and timers
+ for ( i = 0 ; i < active ; i++ ) {
+ item = BG_FindItemForPowerup( sorted[i] );
+
+ if (item) {
+ t = ps->powerups[ sorted[i] ];
+ if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
+ trap_R_SetColor( NULL );
+ } else {
+ vec4_t modulate;
+
+ f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
+ f -= (int)f;
+ modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
+ trap_R_SetColor( modulate );
+ }
+
+ CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) );
+
+ Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000);
+ CG_Text_Paint(r2.x + (r2.w * .75) + 3 , r2.y + r2.h, scale, color, num, 0, 0, 0);
+ *inc += r2.w + special;
+ }
+
+ }
+ trap_R_SetColor( NULL );
+
+}
+
+float CG_GetValue(int ownerDraw) {
+ centity_t *cent;
+ clientInfo_t *ci;
+ playerState_t *ps;
+
+ cent = &cg_entities[cg.snap->ps.clientNum];
+ ps = &cg.snap->ps;
+
+ switch (ownerDraw) {
+ case CG_SELECTEDPLAYER_ARMOR:
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ return ci->armor;
+ break;
+ case CG_SELECTEDPLAYER_HEALTH:
+ ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
+ return ci->health;
+ break;
+ case CG_PLAYER_ARMOR_VALUE:
+ return ps->stats[STAT_ARMOR];
+ break;
+ case CG_PLAYER_AMMO_VALUE:
+ if ( cent->currentState.weapon ) {
+ return ps->ammo[cent->currentState.weapon];
+ }
+ break;
+ case CG_PLAYER_SCORE:
+ return cg.snap->ps.persistant[PERS_SCORE];
+ break;
+ case CG_PLAYER_HEALTH:
+ return ps->stats[STAT_HEALTH];
+ break;
+ case CG_RED_SCORE:
+ return cgs.scores1;
+ break;
+ case CG_BLUE_SCORE:
+ return cgs.scores2;
+ break;
+ default:
+ break;
+ }
+ return -1;
+}
+
+qboolean CG_OtherTeamHasFlag() {
+ if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
+ int team = cg.snap->ps.persistant[PERS_TEAM];
+ if (cgs.gametype == GT_1FCTF) {
+ if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_BLUE) {
+ return qtrue;
+ } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_RED) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ } else {
+ if (team == TEAM_RED && cgs.redflag == FLAG_TAKEN) {
+ return qtrue;
+ } else if (team == TEAM_BLUE && cgs.blueflag == FLAG_TAKEN) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ }
+ }
+ return qfalse;
+}
+
+qboolean CG_YourTeamHasFlag() {
+ if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
+ int team = cg.snap->ps.persistant[PERS_TEAM];
+ if (cgs.gametype == GT_1FCTF) {
+ if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_RED) {
+ return qtrue;
+ } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_BLUE) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ } else {
+ if (team == TEAM_RED && cgs.blueflag == FLAG_TAKEN) {
+ return qtrue;
+ } else if (team == TEAM_BLUE && cgs.redflag == FLAG_TAKEN) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ }
+ }
+ return qfalse;
+}
+
+// THINKABOUTME: should these be exclusive or inclusive..
+//
+qboolean CG_OwnerDrawVisible(int flags) {
+
+ if (flags & CG_SHOW_TEAMINFO) {
+ return (cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
+ }
+
+ if (flags & CG_SHOW_NOTEAMINFO) {
+ return !(cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
+ }
+
+ if (flags & CG_SHOW_OTHERTEAMHASFLAG) {
+ return CG_OtherTeamHasFlag();
+ }
+
+ if (flags & CG_SHOW_YOURTEAMHASENEMYFLAG) {
+ return CG_YourTeamHasFlag();
+ }
+
+ if (flags & (CG_SHOW_BLUE_TEAM_HAS_REDFLAG | CG_SHOW_RED_TEAM_HAS_BLUEFLAG)) {
+ if (flags & CG_SHOW_BLUE_TEAM_HAS_REDFLAG && (cgs.redflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_RED)) {
+ return qtrue;
+ } else if (flags & CG_SHOW_RED_TEAM_HAS_BLUEFLAG && (cgs.blueflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_BLUE)) {
+ return qtrue;
+ }
+ return qfalse;
+ }
+
+ if (flags & CG_SHOW_ANYTEAMGAME) {
+ if( cgs.gametype >= GT_TEAM) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_ANYNONTEAMGAME) {
+ if( cgs.gametype < GT_TEAM) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_HARVESTER) {
+ if( cgs.gametype == GT_HARVESTER ) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ }
+
+ if (flags & CG_SHOW_ONEFLAG) {
+ if( cgs.gametype == GT_1FCTF ) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ }
+
+ if (flags & CG_SHOW_CTF) {
+ if( cgs.gametype == GT_CTF ) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_OBELISK) {
+ if( cgs.gametype == GT_OBELISK ) {
+ return qtrue;
+ } else {
+ return qfalse;
+ }
+ }
+
+ if (flags & CG_SHOW_HEALTHCRITICAL) {
+ if (cg.snap->ps.stats[STAT_HEALTH] < 25) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_HEALTHOK) {
+ if (cg.snap->ps.stats[STAT_HEALTH] >= 25) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_SINGLEPLAYER) {
+ if( cgs.gametype == GT_SINGLE_PLAYER ) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_TOURNAMENT) {
+ if( cgs.gametype == GT_TOURNAMENT ) {
+ return qtrue;
+ }
+ }
+
+ if (flags & CG_SHOW_DURINGINCOMINGVOICE) {
+ }
+
+ if (flags & CG_SHOW_IF_PLAYER_HAS_FLAG) {
+ if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+
+
+static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) {
+ int adj = (force2D) ? 0 : 2;
+ if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
+ CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D);
+ } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
+ CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D);
+ } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
+ CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D);
+ }
+}
+
+static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0);
+}
+
+static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0);
+}
+
+static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0);
+}
+
+const char *CG_GetKillerText() {
+ const char *s = "";
+ if ( cg.killerName[0] ) {
+ s = va("Fragged by %s", cg.killerName );
+ }
+ return s;
+}
+
+
+static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ // fragged by ... line
+ if ( cg.killerName[0] ) {
+ int x = rect->x + rect->w / 2;
+ CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle);
+ }
+
+}
+
+
+static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit;
+ CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle);
+}
+
+static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ if (cgs.scores1 != SCORE_NOT_PRESENT) {
+ CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle);
+ }
+}
+
+static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ if (cgs.scores2 != SCORE_NOT_PRESENT) {
+ CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle);
+ }
+}
+
+const char *CG_GetGameStatusText() {
+ const char *s = "";
+ if ( cgs.gametype < GT_TEAM) {
+ if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
+ s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] );
+ }
+ } else {
+ if ( cg.teamScores[0] == cg.teamScores[1] ) {
+ s = va("Teams are tied at %i", cg.teamScores[0] );
+ } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
+ s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] );
+ } else {
+ s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] );
+ }
+ }
+ return s;
+}
+
+static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle);
+}
+
+const char *CG_GameTypeString() {
+ if ( cgs.gametype == GT_FFA ) {
+ return "Free For All";
+ } else if ( cgs.gametype == GT_TEAM ) {
+ return "Team Deathmatch";
+ } else if ( cgs.gametype == GT_CTF ) {
+ return "Capture the Flag";
+ } else if ( cgs.gametype == GT_1FCTF ) {
+ return "One Flag CTF";
+ } else if ( cgs.gametype == GT_OBELISK ) {
+ return "Overload";
+ } else if ( cgs.gametype == GT_HARVESTER ) {
+ return "Harvester";
+ }
+ return "";
+}
+static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
+ CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle);
+}
+
+static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
+ int len, count;
+ vec4_t newColor;
+ glyphInfo_t *glyph;
+ if (text) {
+// TTimo: FIXME
+// const unsigned char *s = text; // bk001206 - unsigned
+ const char *s = text;
+ float max = *maxX;
+ float useScale;
+ fontInfo_t *font = &cgDC.Assets.textFont;
+ if (scale <= cg_smallFont.value) {
+ font = &cgDC.Assets.smallFont;
+ } else if (scale > cg_bigFont.value) {
+ font = &cgDC.Assets.bigFont;
+ }
+ useScale = scale * font->glyphScale;
+ trap_R_SetColor( color );
+ len = strlen(text);
+ if (limit > 0 && len > limit) {
+ len = limit;
+ }
+ count = 0;
+ while (s && *s && count < len) {
+ glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
+ if ( Q_IsColorString( s ) ) {
+ memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
+ newColor[3] = color[3];
+ trap_R_SetColor( newColor );
+ s += 2;
+ continue;
+ } else {
+ float yadj = useScale * glyph->top;
+ if (CG_Text_Width(s, useScale, 1) + x > max) {
+ *maxX = 0;
+ break;
+ }
+ CG_Text_PaintChar(x, y - yadj,
+ glyph->imageWidth,
+ glyph->imageHeight,
+ useScale,
+ glyph->s,
+ glyph->t,
+ glyph->s2,
+ glyph->t2,
+ glyph->glyph);
+ x += (glyph->xSkip * useScale) + adjust;
+ *maxX = x;
+ count++;
+ s++;
+ }
+ }
+ trap_R_SetColor( NULL );
+ }
+
+}
+
+
+
+#define PIC_WIDTH 12
+
+void CG_DrawNewTeamInfo(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, qhandle_t shader) {
+ int xx;
+ float y;
+ int i, j, len, count;
+ const char *p;
+ vec4_t hcolor;
+ float pwidth, lwidth, maxx, leftOver;
+ clientInfo_t *ci;
+ gitem_t *item;
+ qhandle_t h;
+
+ // max player name width
+ pwidth = 0;
+ count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
+ for (i = 0; i < count; i++) {
+ ci = cgs.clientinfo + sortedTeamPlayers[i];
+ if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
+ len = CG_Text_Width( ci->name, scale, 0);
+ if (len > pwidth)
+ pwidth = len;
+ }
+ }
+
+ // max location name width
+ lwidth = 0;
+ for (i = 1; i < MAX_LOCATIONS; i++) {
+ p = CG_ConfigString(CS_LOCATIONS + i);
+ if (p && *p) {
+ len = CG_Text_Width(p, scale, 0);
+ if (len > lwidth)
+ lwidth = len;
+ }
+ }
+
+ y = rect->y;
+
+ for (i = 0; i < count; i++) {
+ ci = cgs.clientinfo + sortedTeamPlayers[i];
+ if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
+
+ xx = rect->x + 1;
+ for (j = 0; j <= PW_NUM_POWERUPS; j++) {
+ if (ci->powerups & (1 << j)) {
+
+ item = BG_FindItemForPowerup( j );
+
+ if (item) {
+ CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, trap_R_RegisterShader( item->icon ) );
+ xx += PIC_WIDTH;
+ }
+ }
+ }
+
+ // FIXME: max of 3 powerups shown properly
+ xx = rect->x + (PIC_WIDTH * 3) + 2;
+
+ CG_GetColorForHealth( ci->health, ci->armor, hcolor );
+ trap_R_SetColor(hcolor);
+ CG_DrawPic( xx, y + 1, PIC_WIDTH - 2, PIC_WIDTH - 2, cgs.media.heartShader );
+
+ //Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
+ //CG_Text_Paint(xx, y + text_y, scale, hcolor, st, 0, 0);
+
+ // draw weapon icon
+ xx += PIC_WIDTH + 1;
+
+// weapon used is not that useful, use the space for task
+#if 0
+ if ( cg_weapons[ci->curWeapon].weaponIcon ) {
+ CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cg_weapons[ci->curWeapon].weaponIcon );
+ } else {
+ CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cgs.media.deferShader );
+ }
+#endif
+
+ trap_R_SetColor(NULL);
+ if (cgs.orderPending) {
+ // blink the icon
+ if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) {
+ h = 0;
+ } else {
+ h = CG_StatusHandle(cgs.currentOrder);
+ }
+ } else {
+ h = CG_StatusHandle(ci->teamTask);
+ }
+
+ if (h) {
+ CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, h);
+ }
+
+ xx += PIC_WIDTH + 1;
+
+ leftOver = rect->w - xx;
+ maxx = xx + leftOver / 3;
+
+
+
+ CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, ci->name, 0, 0);
+
+ p = CG_ConfigString(CS_LOCATIONS + ci->location);
+ if (!p || !*p) {
+ p = "unknown";
+ }
+
+ xx += leftOver / 3 + 2;
+ maxx = rect->w - 4;
+
+ CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, p, 0, 0);
+ y += text_y + 2;
+ if ( y + text_y + 2 > rect->y + rect->h ) {
+ break;
+ }
+
+ }
+ }
+}
+
+
+void CG_DrawTeamSpectators(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
+ if (cg.spectatorLen) {
+ float maxX;
+
+ if (cg.spectatorWidth == -1) {
+ cg.spectatorWidth = 0;
+ cg.spectatorPaintX = rect->x + 1;
+ cg.spectatorPaintX2 = -1;
+ }
+
+ if (cg.spectatorOffset > cg.spectatorLen) {
+ cg.spectatorOffset = 0;
+ cg.spectatorPaintX = rect->x + 1;
+ cg.spectatorPaintX2 = -1;
+ }
+
+ if (cg.time > cg.spectatorTime) {
+ cg.spectatorTime = cg.time + 10;
+ if (cg.spectatorPaintX <= rect->x + 2) {
+ if (cg.spectatorOffset < cg.spectatorLen) {
+ cg.spectatorPaintX += CG_Text_Width(&cg.spectatorList[cg.spectatorOffset], scale, 1) - 1;
+ cg.spectatorOffset++;
+ } else {
+ cg.spectatorOffset = 0;
+ if (cg.spectatorPaintX2 >= 0) {
+ cg.spectatorPaintX = cg.spectatorPaintX2;
+ } else {
+ cg.spectatorPaintX = rect->x + rect->w - 2;
+ }
+ cg.spectatorPaintX2 = -1;
+ }
+ } else {
+ cg.spectatorPaintX--;
+ if (cg.spectatorPaintX2 >= 0) {
+ cg.spectatorPaintX2--;
+ }
+ }
+ }
+
+ maxX = rect->x + rect->w - 2;
+ CG_Text_Paint_Limit(&maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, &cg.spectatorList[cg.spectatorOffset], 0, 0);
+ if (cg.spectatorPaintX2 >= 0) {
+ float maxX2 = rect->x + rect->w - 2;
+ CG_Text_Paint_Limit(&maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, color, cg.spectatorList, 0, cg.spectatorOffset);
+ }
+ if (cg.spectatorOffset && maxX > 0) {
+ // if we have an offset ( we are skipping the first part of the string ) and we fit the string
+ if (cg.spectatorPaintX2 == -1) {
+ cg.spectatorPaintX2 = rect->x + rect->w - 2;
+ }
+ } else {
+ cg.spectatorPaintX2 = -1;
+ }
+
+ }
+}
+
+
+
+void CG_DrawMedal(int ownerDraw, rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
+ score_t *score = &cg.scores[cg.selectedScore];
+ float value = 0;
+ char *text = NULL;
+ color[3] = 0.25;
+
+ switch (ownerDraw) {
+ case CG_ACCURACY:
+ value = score->accuracy;
+ break;
+ case CG_ASSISTS:
+ value = score->assistCount;
+ break;
+ case CG_DEFEND:
+ value = score->defendCount;
+ break;
+ case CG_EXCELLENT:
+ value = score->excellentCount;
+ break;
+ case CG_IMPRESSIVE:
+ value = score->impressiveCount;
+ break;
+ case CG_PERFECT:
+ value = score->perfect;
+ break;
+ case CG_GAUNTLET:
+ value = score->guantletCount;
+ break;
+ case CG_CAPTURES:
+ value = score->captures;
+ break;
+ }
+
+ if (value > 0) {
+ if (ownerDraw != CG_PERFECT) {
+ if (ownerDraw == CG_ACCURACY) {
+ text = va("%i%%", (int)value);
+ if (value > 50) {
+ color[3] = 1.0;
+ }
+ } else {
+ text = va("%i", (int)value);
+ color[3] = 1.0;
+ }
+ } else {
+ if (value) {
+ color[3] = 1.0;
+ }
+ text = "Wow";
+ }
+ }
+
+ trap_R_SetColor(color);
+ CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
+
+ if (text) {
+ color[3] = 1.0;
+ value = CG_Text_Width(text, scale, 0);
+ CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h + 10 , scale, color, text, 0, 0, 0);
+ }
+ trap_R_SetColor(NULL);
+
+}
+
+
+//
+void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
+ rectDef_t rect;
+
+ if ( cg_drawStatus.integer == 0 ) {
+ return;
+ }
+
+ //if (ownerDrawFlags != 0 && !CG_OwnerDrawVisible(ownerDrawFlags)) {
+ // return;
+ //}
+
+ rect.x = x;
+ rect.y = y;
+ rect.w = w;
+ rect.h = h;
+
+ switch (ownerDraw) {
+ case CG_PLAYER_ARMOR_ICON:
+ CG_DrawPlayerArmorIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
+ break;
+ case CG_PLAYER_ARMOR_ICON2D:
+ CG_DrawPlayerArmorIcon(&rect, qtrue);
+ break;
+ case CG_PLAYER_ARMOR_VALUE:
+ CG_DrawPlayerArmorValue(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_PLAYER_AMMO_ICON:
+ CG_DrawPlayerAmmoIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
+ break;
+ case CG_PLAYER_AMMO_ICON2D:
+ CG_DrawPlayerAmmoIcon(&rect, qtrue);
+ break;
+ case CG_PLAYER_AMMO_VALUE:
+ CG_DrawPlayerAmmoValue(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_SELECTEDPLAYER_HEAD:
+ CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qfalse);
+ break;
+ case CG_VOICE_HEAD:
+ CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qtrue);
+ break;
+ case CG_VOICE_NAME:
+ CG_DrawSelectedPlayerName(&rect, scale, color, qtrue, textStyle);
+ break;
+ case CG_SELECTEDPLAYER_STATUS:
+ CG_DrawSelectedPlayerStatus(&rect);
+ break;
+ case CG_SELECTEDPLAYER_ARMOR:
+ CG_DrawSelectedPlayerArmor(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_SELECTEDPLAYER_HEALTH:
+ CG_DrawSelectedPlayerHealth(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_SELECTEDPLAYER_NAME:
+ CG_DrawSelectedPlayerName(&rect, scale, color, qfalse, textStyle);
+ break;
+ case CG_SELECTEDPLAYER_LOCATION:
+ CG_DrawSelectedPlayerLocation(&rect, scale, color, textStyle);
+ break;
+ case CG_SELECTEDPLAYER_WEAPON:
+ CG_DrawSelectedPlayerWeapon(&rect);
+ break;
+ case CG_SELECTEDPLAYER_POWERUP:
+ CG_DrawSelectedPlayerPowerup(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
+ break;
+ case CG_PLAYER_HEAD:
+ CG_DrawPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
+ break;
+ case CG_PLAYER_ITEM:
+ CG_DrawPlayerItem(&rect, scale, ownerDrawFlags & CG_SHOW_2DONLY);
+ break;
+ case CG_PLAYER_SCORE:
+ CG_DrawPlayerScore(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_PLAYER_HEALTH:
+ CG_DrawPlayerHealth(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_RED_SCORE:
+ CG_DrawRedScore(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_BLUE_SCORE:
+ CG_DrawBlueScore(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_RED_NAME:
+ CG_DrawRedName(&rect, scale, color, textStyle);
+ break;
+ case CG_BLUE_NAME:
+ CG_DrawBlueName(&rect, scale, color, textStyle);
+ break;
+ case CG_BLUE_FLAGHEAD:
+ CG_DrawBlueFlagHead(&rect);
+ break;
+ case CG_BLUE_FLAGSTATUS:
+ CG_DrawBlueFlagStatus(&rect, shader);
+ break;
+ case CG_BLUE_FLAGNAME:
+ CG_DrawBlueFlagName(&rect, scale, color, textStyle);
+ break;
+ case CG_RED_FLAGHEAD:
+ CG_DrawRedFlagHead(&rect);
+ break;
+ case CG_RED_FLAGSTATUS:
+ CG_DrawRedFlagStatus(&rect, shader);
+ break;
+ case CG_RED_FLAGNAME:
+ CG_DrawRedFlagName(&rect, scale, color, textStyle);
+ break;
+ case CG_HARVESTER_SKULLS:
+ CG_HarvesterSkulls(&rect, scale, color, qfalse, textStyle);
+ break;
+ case CG_HARVESTER_SKULLS2D:
+ CG_HarvesterSkulls(&rect, scale, color, qtrue, textStyle);
+ break;
+ case CG_ONEFLAG_STATUS:
+ CG_OneFlagStatus(&rect);
+ break;
+ case CG_PLAYER_LOCATION:
+ CG_DrawPlayerLocation(&rect, scale, color, textStyle);
+ break;
+ case CG_TEAM_COLOR:
+ CG_DrawTeamColor(&rect, color);
+ break;
+ case CG_CTF_POWERUP:
+ CG_DrawCTFPowerUp(&rect);
+ break;
+ case CG_AREA_POWERUP:
+ CG_DrawAreaPowerUp(&rect, align, special, scale, color);
+ break;
+ case CG_PLAYER_STATUS:
+ CG_DrawPlayerStatus(&rect);
+ break;
+ case CG_PLAYER_HASFLAG:
+ CG_DrawPlayerHasFlag(&rect, qfalse);
+ break;
+ case CG_PLAYER_HASFLAG2D:
+ CG_DrawPlayerHasFlag(&rect, qtrue);
+ break;
+ case CG_AREA_SYSTEMCHAT:
+ CG_DrawAreaSystemChat(&rect, scale, color, shader);
+ break;
+ case CG_AREA_TEAMCHAT:
+ CG_DrawAreaTeamChat(&rect, scale, color, shader);
+ break;
+ case CG_AREA_CHAT:
+ CG_DrawAreaChat(&rect, scale, color, shader);
+ break;
+ case CG_GAME_TYPE:
+ CG_DrawGameType(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_GAME_STATUS:
+ CG_DrawGameStatus(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_KILLER:
+ CG_DrawKiller(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_ACCURACY:
+ case CG_ASSISTS:
+ case CG_DEFEND:
+ case CG_EXCELLENT:
+ case CG_IMPRESSIVE:
+ case CG_PERFECT:
+ case CG_GAUNTLET:
+ case CG_CAPTURES:
+ CG_DrawMedal(ownerDraw, &rect, scale, color, shader);
+ break;
+ case CG_SPECTATORS:
+ CG_DrawTeamSpectators(&rect, scale, color, shader);
+ break;
+ case CG_TEAMINFO:
+ if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
+ CG_DrawNewTeamInfo(&rect, text_x, text_y, scale, color, shader);
+ }
+ break;
+ case CG_CAPFRAGLIMIT:
+ CG_DrawCapFragLimit(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_1STPLACE:
+ CG_Draw1stPlace(&rect, scale, color, shader, textStyle);
+ break;
+ case CG_2NDPLACE:
+ CG_Draw2ndPlace(&rect, scale, color, shader, textStyle);
+ break;
+ default:
+ break;
+ }
+}
+
+void CG_MouseEvent(int x, int y) {
+ int n;
+
+ if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse) {
+ trap_Key_SetCatcher(0);
+ return;
+ }
+
+ cgs.cursorX+= x;
+ if (cgs.cursorX < 0)
+ cgs.cursorX = 0;
+ else if (cgs.cursorX > 640)
+ cgs.cursorX = 640;
+
+ cgs.cursorY += y;
+ if (cgs.cursorY < 0)
+ cgs.cursorY = 0;
+ else if (cgs.cursorY > 480)
+ cgs.cursorY = 480;
+
+ n = Display_CursorType(cgs.cursorX, cgs.cursorY);
+ cgs.activeCursor = 0;
+ if (n == CURSOR_ARROW) {
+ cgs.activeCursor = cgs.media.selectCursor;
+ } else if (n == CURSOR_SIZER) {
+ cgs.activeCursor = cgs.media.sizeCursor;
+ }
+
+ if (cgs.capturedItem) {
+ Display_MouseMove(cgs.capturedItem, x, y);
+ } else {
+ Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY);
+ }
+
+}
+
+/*
+==================
+CG_HideTeamMenus
+==================
+
+*/
+void CG_HideTeamMenu() {
+ Menus_CloseByName("teamMenu");
+ Menus_CloseByName("getMenu");
+}
+
+/*
+==================
+CG_ShowTeamMenus
+==================
+
+*/
+void CG_ShowTeamMenu() {
+ Menus_OpenByName("teamMenu");
+}
+
+
+
+
+/*
+==================
+CG_EventHandling
+==================
+ type 0 - no event handling
+ 1 - team menu
+ 2 - hud editor
+
+*/
+void CG_EventHandling(int type) {
+ cgs.eventHandling = type;
+ if (type == CGAME_EVENT_NONE) {
+ CG_HideTeamMenu();
+ } else if (type == CGAME_EVENT_TEAMMENU) {
+ //CG_ShowTeamMenu();
+ } else if (type == CGAME_EVENT_SCOREBOARD) {
+ }
+
+}
+
+
+
+void CG_KeyEvent(int key, qboolean down) {
+
+ if (!down) {
+ return;
+ }
+
+ if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse)) {
+ CG_EventHandling(CGAME_EVENT_NONE);
+ trap_Key_SetCatcher(0);
+ return;
+ }
+
+ //if (key == trap_Key_GetKey("teamMenu") || !Display_CaptureItem(cgs.cursorX, cgs.cursorY)) {
+ // if we see this then we should always be visible
+ // CG_EventHandling(CGAME_EVENT_NONE);
+ // trap_Key_SetCatcher(0);
+ //}
+
+
+
+ Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY);
+
+ if (cgs.capturedItem) {
+ cgs.capturedItem = NULL;
+ } else {
+ if (key == K_MOUSE2 && down) {
+ cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY);
+ }
+ }
+}
+
+int CG_ClientNumFromName(const char *p) {
+ int i;
+ for (i = 0; i < cgs.maxclients; i++) {
+ if (cgs.clientinfo[i].infoValid && Q_stricmp(cgs.clientinfo[i].name, p) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void CG_ShowResponseHead() {
+ Menus_OpenByName("voiceMenu");
+ trap_Cvar_Set("cl_conXOffset", "72");
+ cg.voiceTime = cg.time;
+}
+
+void CG_RunMenuScript(char **args) {
+}
+
+
+void CG_GetTeamColor(vec4_t *color) {
+ if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) {
+ (*color)[0] = 1.0f;
+ (*color)[3] = 0.25f;
+ (*color)[1] = (*color)[2] = 0.0f;
+ } else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) {
+ (*color)[0] = (*color)[1] = 0.0f;
+ (*color)[2] = 1.0f;
+ (*color)[3] = 0.25f;
+ } else {
+ (*color)[0] = (*color)[2] = 0.0f;
+ (*color)[1] = 0.17f;
+ (*color)[3] = 0.25f;
+ }
+}
+
diff --git a/code/cgame/cg_particles.c b/code/cgame/cg_particles.c
index b3ce322..d9c3e7e 100755
--- a/code/cgame/cg_particles.c
+++ b/code/cgame/cg_particles.c
@@ -1,2018 +1,2018 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// Rafael particles
-// cg_particles.c
-
-#include "cg_local.h"
-
-#define BLOODRED 2
-#define EMISIVEFADE 3
-#define GREY75 4
-
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
- float endtime;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- int color;
- float colorvel;
- float alpha;
- float alphavel;
- int type;
- qhandle_t pshader;
-
- float height;
- float width;
-
- float endheight;
- float endwidth;
-
- float start;
- float end;
-
- float startfade;
- qboolean rotate;
- int snum;
-
- qboolean link;
-
- // Ridah
- int shaderAnim;
- int roll;
-
- int accumroll;
-
-} cparticle_t;
-
-typedef enum
-{
- P_NONE,
- P_WEATHER,
- P_FLAT,
- P_SMOKE,
- P_ROTATE,
- P_WEATHER_TURBULENT,
- P_ANIM, // Ridah
- P_BAT,
- P_BLEED,
- P_FLAT_SCALEUP,
- P_FLAT_SCALEUP_FADE,
- P_WEATHER_FLURRY,
- P_SMOKE_IMPACT,
- P_BUBBLE,
- P_BUBBLE_TURBULENT,
- P_SPRITE
-} particle_type_t;
-
-#define MAX_SHADER_ANIMS 32
-#define MAX_SHADER_ANIM_FRAMES 64
-
-static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
- "explode1",
- "blacksmokeanim",
- "twiltb2",
- "expblue",
- "blacksmokeanimb", // uses 'explode1' sequence
- "blood",
- NULL
-};
-static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
-static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
- 23,
- 25,
- 45,
- 25,
- 23,
- 5,
-};
-static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
- 1.405f,
- 1.0f,
- 1.0f,
- 1.0f,
- 1.0f,
- 1.0f,
-};
-static int numShaderAnims;
-// done.
-
-#define PARTICLE_GRAVITY 40
-#define MAX_PARTICLES 1024 * 8
-
-cparticle_t *active_particles, *free_particles;
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-qboolean initparticles = qfalse;
-vec3_t vforward, vright, vup;
-vec3_t rforward, rright, rup;
-
-float oldtime;
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CG_ClearParticles (void)
-{
- int i;
-
- memset( particles, 0, sizeof(particles) );
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- {
- particles[i].next = &particles[i+1];
- particles[i].type = 0;
- }
- particles[cl_numparticles-1].next = NULL;
-
- oldtime = cg.time;
-
- // Ridah, init the shaderAnims
- for (i=0; shaderAnimNames[i]; i++) {
- int j;
-
- for (j=0; j<shaderAnimCounts[i]; j++) {
- shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
- }
- }
- numShaderAnims = i;
- // done.
-
- initparticles = qtrue;
-}
-
-
-/*
-=====================
-CG_AddParticleToScene
-=====================
-*/
-void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
-{
-
- vec3_t point;
- polyVert_t verts[4];
- float width;
- float height;
- float time, time2;
- float ratio;
- float invratio;
- vec3_t color;
- polyVert_t TRIverts[3];
- vec3_t rright2, rup2;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
- || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {// create a front facing polygon
-
- if (p->type != P_WEATHER_FLURRY)
- {
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- if (org[2] > p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- p->org[2] = ( p->start + crandom () * 4 );
-
-
- if (p->type == P_BUBBLE_TURBULENT)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- }
- }
- else
- {
- if (org[2] < p->end)
- {
- p->time = cg.time;
- VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
-
- while (p->org[2] < p->end)
- {
- p->org[2] += (p->start - p->end);
- }
-
-
- if (p->type == P_WEATHER_TURBULENT)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- }
- }
-
-
- // Rafael snow pvs check
- if (!p->link)
- return;
-
- p->alpha = 1;
- }
-
- // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
- if (Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
- // done.
-
- if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255 * p->alpha;
- }
- else
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy( point, TRIverts[0].xyz );
- TRIverts[0].st[0] = 1;
- TRIverts[0].st[1] = 0;
- TRIverts[0].modulate[0] = 255;
- TRIverts[0].modulate[1] = 255;
- TRIverts[0].modulate[2] = 255;
- TRIverts[0].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- VectorCopy (point, TRIverts[1].xyz);
- TRIverts[1].st[0] = 0;
- TRIverts[1].st[1] = 0;
- TRIverts[1].modulate[0] = 255;
- TRIverts[1].modulate[1] = 255;
- TRIverts[1].modulate[2] = 255;
- TRIverts[1].modulate[3] = 255 * p->alpha;
-
- VectorMA (org, p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- VectorCopy (point, TRIverts[2].xyz);
- TRIverts[2].st[0] = 0;
- TRIverts[2].st[1] = 1;
- TRIverts[2].modulate[0] = 255;
- TRIverts[2].modulate[1] = 255;
- TRIverts[2].modulate[2] = 255;
- TRIverts[2].modulate[3] = 255 * p->alpha;
- }
-
- }
- else if (p->type == P_SPRITE)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
-
- VectorSet (color, 1.0, 1.0, 1.0);
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, vup, point);
- VectorMA (point, -width, vright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, vup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, vright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, vup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
- {// create a front rotating facing polygon
-
- if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
- return;
- }
-
- if (p->color == BLOODRED)
- VectorSet (color, 0.22f, 0.0f, 0.0f);
- else if (p->color == GREY75)
- {
- float len;
- float greyit;
- float val;
- len = Distance (cg.snap->ps.origin, org);
- if (!len)
- len = 1;
-
- val = 4096/len;
- greyit = 0.25 * val;
- if (greyit > 0.5)
- greyit = 0.5;
-
- VectorSet (color, greyit, greyit, greyit);
- }
- else
- VectorSet (color, 1.0, 1.0, 1.0);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- if (cg.time > p->startfade)
- {
- invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
-
- if (p->color == EMISIVEFADE)
- {
- float fval;
- fval = (invratio * invratio);
- if (fval < 0)
- fval = 0;
- VectorSet (color, fval , fval , fval );
- }
- invratio *= p->alpha;
- }
- else
- invratio = 1 * p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- invratio = 1;
-
- if (invratio > 1)
- invratio = 1;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (p->type != P_SMOKE_IMPACT)
- {
- vec3_t temp;
-
- vectoangles (rforward, temp);
- p->accumroll += p->roll;
- temp[ROLL] += p->accumroll * 0.1;
- AngleVectors ( temp, NULL, rright2, rup2);
- }
- else
- {
- VectorCopy (rright, rright2);
- VectorCopy (rup, rup2);
- }
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, -height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, -p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, vup, point);
- VectorMA (point, p->width, vright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255 * invratio;
-
- if (p->rotate)
- {
- VectorMA (org, height, rup2, point);
- VectorMA (point, -width, rright2, point);
- }
- else
- {
- VectorMA (org, p->height, vup, point);
- VectorMA (point, -p->width, vright, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255 * invratio;
-
- }
- else if (p->type == P_BLEED)
- {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- float alpha;
-
- alpha = p->alpha;
-
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
- alpha = 1;
-
- if (p->roll)
- {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
- else
- {
- VectorCopy (vup, ru);
- VectorCopy (vright, rr);
- }
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 111;
- verts[0].modulate[1] = 19;
- verts[0].modulate[2] = 9;
- verts[0].modulate[3] = 255 * alpha;
-
- VectorMA (org, -p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 111;
- verts[1].modulate[1] = 19;
- verts[1].modulate[2] = 9;
- verts[1].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, p->width, rr, point);
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 111;
- verts[2].modulate[1] = 19;
- verts[2].modulate[2] = 9;
- verts[2].modulate[3] = 255 * alpha;
-
- VectorMA (org, p->height, ru, point);
- VectorMA (point, -p->width, rr, point);
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 111;
- verts[3].modulate[1] = 19;
- verts[3].modulate[2] = 9;
- verts[3].modulate[3] = 255 * alpha;
-
- }
- else if (p->type == P_FLAT_SCALEUP)
- {
- float width, height;
- float sinR, cosR;
-
- if (p->color == BLOODRED)
- VectorSet (color, 1, 1, 1);
- else
- VectorSet (color, 0.5, 0.5, 0.5);
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- if (width > p->endwidth)
- width = p->endwidth;
-
- if (height > p->endheight)
- height = p->endheight;
-
- sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
- cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= sinR;
- verts[0].xyz[1] -= cosR;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255 * color[0];
- verts[0].modulate[1] = 255 * color[1];
- verts[0].modulate[2] = 255 * color[2];
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= cosR;
- verts[1].xyz[1] += sinR;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255 * color[0];
- verts[1].modulate[1] = 255 * color[1];
- verts[1].modulate[2] = 255 * color[2];
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += sinR;
- verts[2].xyz[1] += cosR;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255 * color[0];
- verts[2].modulate[1] = 255 * color[1];
- verts[2].modulate[2] = 255 * color[2];
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += cosR;
- verts[3].xyz[1] -= sinR;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255 * color[0];
- verts[3].modulate[1] = 255 * color[1];
- verts[3].modulate[2] = 255 * color[2];
- verts[3].modulate[3] = 255;
- }
- else if (p->type == P_FLAT)
- {
-
- VectorCopy (org, verts[0].xyz);
- verts[0].xyz[0] -= p->height;
- verts[0].xyz[1] -= p->width;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy (org, verts[1].xyz);
- verts[1].xyz[0] -= p->height;
- verts[1].xyz[1] += p->width;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy (org, verts[2].xyz);
- verts[2].xyz[0] += p->height;
- verts[2].xyz[1] += p->width;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy (org, verts[3].xyz);
- verts[3].xyz[0] += p->height;
- verts[3].xyz[1] -= p->width;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- }
- // Ridah
- else if (p->type == P_ANIM) {
- vec3_t rr, ru;
- vec3_t rotate_ang;
- int i, j;
-
- time = cg.time - p->time;
- time2 = p->endtime - p->time;
- ratio = time / time2;
- if (ratio >= 1.0f) {
- ratio = 0.9999f;
- }
-
- width = p->width + ( ratio * ( p->endwidth - p->width) );
- height = p->height + ( ratio * ( p->endheight - p->height) );
-
- // if we are "inside" this sprite, don't draw
- if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
- return;
- }
-
- i = p->shaderAnim;
- j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
- p->pshader = shaderAnims[i][j];
-
- if (p->roll) {
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- rotate_ang[ROLL] += p->roll;
- AngleVectors ( rotate_ang, NULL, rr, ru);
- }
-
- if (p->roll) {
- VectorMA (org, -height, ru, point);
- VectorMA (point, -width, rr, point);
- } else {
- VectorMA (org, -height, vup, point);
- VectorMA (point, -width, vright, point);
- }
- VectorCopy (point, verts[0].xyz);
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*height, ru, point);
- } else {
- VectorMA (point, 2*height, vup, point);
- }
- VectorCopy (point, verts[1].xyz);
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, 2*width, rr, point);
- } else {
- VectorMA (point, 2*width, vright, point);
- }
- VectorCopy (point, verts[2].xyz);
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- if (p->roll) {
- VectorMA (point, -2*height, ru, point);
- } else {
- VectorMA (point, -2*height, vup, point);
- }
- VectorCopy (point, verts[3].xyz);
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
- }
- // done.
-
- if (!p->pshader) {
-// (SA) temp commented out for DM
-// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
- return;
- }
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
- trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
- else
- trap_R_AddPolyToScene( p->pshader, 4, verts );
-
-}
-
-// Ridah, made this static so it doesn't interfere with other files
-static float roll = 0.0;
-
-/*
-===============
-CG_AddParticles
-===============
-*/
-void CG_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
- int type;
- vec3_t rotate_ang;
-
- if (!initparticles)
- CG_ClearParticles ();
-
- VectorCopy( cg.refdef.viewaxis[0], vforward );
- VectorCopy( cg.refdef.viewaxis[1], vright );
- VectorCopy( cg.refdef.viewaxis[2], vup );
-
- vectoangles( cg.refdef.viewaxis[0], rotate_ang );
- roll += ((cg.time - oldtime) * 0.1) ;
- rotate_ang[ROLL] += (roll*0.9);
- AngleVectors ( rotate_ang, rforward, rright, rup);
-
- oldtime = cg.time;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
-
- next = p->next;
-
- time = (cg.time - p->time)*0.001;
-
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
-
- }
-
- if (p->type == P_WEATHER_FLURRY)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
-
- continue;
- }
- }
-
-
- if (p->type == P_FLAT_SCALEUP_FADE)
- {
- if (cg.time > p->endtime)
- {
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- }
-
- if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
- // temporary sprite
- CG_AddParticleToScene (p, p->org, alpha);
- p->next = free_particles;
- free_particles = p;
- p->type = 0;
- p->color = 0;
- p->alpha = 0;
- continue;
- }
-
- 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;
-
- type = p->type;
-
- CG_AddParticleToScene (p, org, alpha);
- }
-
- active_particles = active;
-}
-
-/*
-======================
-CG_AddParticles
-======================
-*/
-void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
- qboolean turb = qtrue;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.90f;
- p->alphavel = 0;
-
- p->start = cent->currentState.origin2[0];
- p->end = cent->currentState.origin2[1];
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->pshader = pshader;
-
- if (rand()%100 > 90)
- {
- p->height = 32;
- p->width = 32;
- p->alpha = 0.10f;
- }
- else
- {
- p->height = 1;
- p->width = 1;
- }
-
- p->vel[2] = -20;
-
- p->type = P_WEATHER_FLURRY;
-
- if (turb)
- p->vel[2] = -10;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->org[0] = p->org[0];
- p->org[1] = p->org[1];
- p->org[2] = p->org[2];
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
- p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
- p->vel[2] += cent->currentState.angles[2];
-
- if (turb)
- {
- p->accel[0] = crandom () * 16;
- p->accel[1] = crandom () * 16;
- }
-
-}
-
-void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
- p->height = 1;
- p->width = 1;
-
- p->vel[2] = -50;
-
- if (turb)
- {
- p->type = P_WEATHER_TURBULENT;
- p->vel[2] = -50 * 1.3;
- }
- else
- {
- p->type = P_WEATHER;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 16;
- p->vel[1] = crandom() * 16;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
-{
- cparticle_t *p;
- float randsize;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->color = 0;
- p->alpha = 0.40f;
- p->alphavel = 0;
- p->start = origin[2];
- p->end = origin2[2];
- p->pshader = pshader;
-
- randsize = 1 + (crandom() * 0.5);
-
- p->height = randsize;
- p->width = randsize;
-
- p->vel[2] = 50 + ( crandom() * 10 );
-
- if (turb)
- {
- p->type = P_BUBBLE_TURBULENT;
- p->vel[2] = 50 * 1.3;
- }
- else
- {
- p->type = P_BUBBLE;
- }
-
- VectorCopy(origin, p->org);
-
- p->org[0] = p->org[0] + ( crandom() * range);
- p->org[1] = p->org[1] + ( crandom() * range);
- p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
-
- p->vel[0] = p->vel[1] = 0;
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- if (turb)
- {
- p->vel[0] = crandom() * 4;
- p->vel[1] = crandom() * 4;
- }
-
- // Rafael snow pvs check
- p->snum = snum;
- p->link = qtrue;
-
-}
-
-void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
-{
-
- // using cent->density = enttime
- // cent->frame = startfade
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleSmoke == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + cent->currentState.time;
- p->startfade = cg.time + cent->currentState.time2;
-
- p->color = 0;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->start = cent->currentState.origin[2];
- p->end = cent->currentState.origin2[2];
- p->pshader = pshader;
- p->rotate = qfalse;
- p->height = 8;
- p->width = 8;
- p->endheight = 32;
- p->endwidth = 32;
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org);
-
- p->vel[0] = p->vel[1] = 0;
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[2] = 5;
-
- if (cent->currentState.frame == 1)// reverse gravity
- p->vel[2] *= -1;
-
- p->roll = 8 + (crandom() * 4);
-}
-
-
-void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
-{
-
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->accel[2] = -60;
- p->vel[2] += -20;
-
-}
-
-/*
-======================
-CG_ParticleExplosion
-======================
-*/
-
-void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
-{
- cparticle_t *p;
- int anim;
-
- if (animStr < (char *)10)
- CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
-
- // find the animation string
- for (anim=0; shaderAnimNames[anim]; anim++) {
- if (!stricmp( animStr, shaderAnimNames[anim] ))
- break;
- }
- if (!shaderAnimNames[anim]) {
- CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
- return;
- }
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
-
- if (duration < 0) {
- duration *= -1;
- p->roll = 0;
- } else {
- p->roll = crandom()*179;
- }
-
- p->shaderAnim = anim;
-
- p->width = sizeStart;
- p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
-
- p->endheight = sizeEnd;
- p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
-
- p->endtime = cg.time + duration;
-
- p->type = P_ANIM;
-
- VectorCopy( origin, p->org );
- VectorCopy( vel, p->vel );
- VectorClear( p->accel );
-
-}
-
-// Rafael Shrapnel
-void CG_AddParticleShrapnel (localEntity_t *le)
-{
- return;
-}
-// done.
-
-int CG_NewParticleArea (int num)
-{
- // const char *str;
- char *str;
- char *token;
- int type;
- vec3_t origin, origin2;
- int i;
- float range = 0;
- int turb;
- int numparticles;
- int snum;
-
- str = (char *) CG_ConfigString (num);
- if (!str[0])
- return (0);
-
- // returns type 128 64 or 32
- token = COM_Parse (&str);
- type = atoi (token);
-
- if (type == 1)
- range = 128;
- else if (type == 2)
- range = 64;
- else if (type == 3)
- range = 32;
- else if (type == 0)
- range = 256;
- else if (type == 4)
- range = 8;
- else if (type == 5)
- range = 16;
- else if (type == 6)
- range = 32;
- else if (type == 7)
- range = 64;
-
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin[i] = atof (token);
- }
-
- for (i=0; i<3; i++)
- {
- token = COM_Parse (&str);
- origin2[i] = atof (token);
- }
-
- token = COM_Parse (&str);
- numparticles = atoi (token);
-
- token = COM_Parse (&str);
- turb = atoi (token);
-
- token = COM_Parse (&str);
- snum = atoi (token);
-
- for (i=0; i<numparticles; i++)
- {
- if (type >= 4)
- CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- else
- CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
- }
-
- return (1);
-}
-
-void CG_SnowLink (centity_t *cent, qboolean particleOn)
-{
- cparticle_t *p, *next;
- int id;
-
- id = cent->currentState.frame;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
- {
- if (p->snum == id)
- {
- if (particleOn)
- p->link = qtrue;
- else
- p->link = qfalse;
- }
- }
-
- }
-}
-
-void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 0.25;
- p->alphavel = 0;
- p->roll = crandom()*179;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + 1000;
- p->startfade = cg.time + 100;
-
- p->width = rand()%4 + 8;
- p->height = rand()%4 + 8;
-
- p->endheight = p->height *2;
- p->endwidth = p->width * 2;
-
- p->endtime = cg.time + 500;
-
- p->type = P_SMOKE_IMPACT;
-
- VectorCopy( origin, p->org );
- VectorSet(p->vel, 0, 0, 20);
- VectorSet(p->accel, 0, 0, 20);
-
- p->rotate = qtrue;
-}
-
-void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- if (fleshEntityNum)
- p->startfade = cg.time;
- else
- p->startfade = cg.time + 100;
-
- p->width = 4;
- p->height = 4;
-
- p->endheight = 4+rand()%3;
- p->endwidth = p->endheight;
-
- p->type = P_SMOKE;
-
- VectorCopy( start, p->org );
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -20;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
- p->alpha = 0.75;
-
-}
-
-void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- int time;
- int time2;
- float ratio;
-
- float duration = 1500;
-
- time = cg.time;
- time2 = cg.time + cent->currentState.time;
-
- ratio =(float)1 - ((float)time / (float)time2);
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- p->endtime = cg.time + duration;
-
- p->startfade = p->endtime;
-
- p->width = 1;
- p->height = 3;
-
- p->endheight = 3;
- p->endwidth = 1;
-
- p->type = P_SMOKE;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
- p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
- p->vel[2] = (cent->currentState.origin2[2]);
-
- p->snum = 1.0f;
-
- VectorClear( p->accel );
-
- p->accel[2] = -20;
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-
-void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- if (cent->currentState.angles2[2])
- p->endtime = cg.time + cent->currentState.angles2[2];
- else
- p->endtime = cg.time + 60000;
-
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
- {
- p->width = cent->currentState.angles2[0];
- p->height = cent->currentState.angles2[0];
-
- p->endheight = cent->currentState.angles2[1];
- p->endwidth = cent->currentState.angles2[1];
- }
- else
- {
- p->width = 8;
- p->height = 8;
-
- p->endheight = 16;
- p->endwidth = 16;
- }
-
- p->type = P_FLAT_SCALEUP;
-
- p->snum = 1.0;
-
- VectorCopy(cent->currentState.origin, p->org );
-
- p->org[2]+= 0.55 + (crandom() * 0.5);
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
-}
-
-void CG_OilSlickRemove (centity_t *cent)
-{
- cparticle_t *p, *next;
- int id;
-
- id = 1.0f;
-
- if (!id)
- CG_Printf ("CG_OilSlickRevove NULL id\n");
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- if (p->type == P_FLAT_SCALEUP)
- {
- if (p->snum == id)
- {
- p->endtime = cg.time + 100;
- p->startfade = p->endtime;
- p->type = P_FLAT_SCALEUP_FADE;
-
- }
- }
-
- }
-}
-
-qboolean ValidBloodPool (vec3_t start)
-{
-#define EXTRUDE_DIST 0.5
-
- vec3_t angles;
- vec3_t right, up;
- vec3_t this_pos, x_pos, center_pos, end_pos;
- float x, y;
- float fwidth, fheight;
- trace_t trace;
- vec3_t normal;
-
- fwidth = 16;
- fheight = 16;
-
- VectorSet (normal, 0, 0, 1);
-
- vectoangles (normal, angles);
- AngleVectors (angles, NULL, right, up);
-
- VectorMA (start, EXTRUDE_DIST, normal, center_pos);
-
- for (x= -fwidth/2; x<fwidth; x+= fwidth)
- {
- VectorMA (center_pos, x, right, x_pos);
-
- for (y= -fheight/2; y<fheight; y+= fheight)
- {
- VectorMA (x_pos, y, up, this_pos);
- VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
-
- CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
-
-
- if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
- return qfalse;
-
- if (!(!trace.startsolid && trace.fraction < 1))
- return qfalse;
-
- }
- }
-
- return qtrue;
-}
-
-void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
-{
- cparticle_t *p;
- qboolean legit;
- vec3_t start;
- float rndSize;
-
- if (!pshader)
- CG_Printf ("CG_BloodPool pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- VectorCopy (tr->endpos, start);
- legit = ValidBloodPool (start);
-
- if (!legit)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + 3000;
- p->startfade = p->endtime;
-
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = pshader;
-
- rndSize = 0.4 + random()*0.6;
-
- p->width = 8*rndSize;
- p->height = 8*rndSize;
-
- p->endheight = 16*rndSize;
- p->endwidth = 16*rndSize;
-
- p->type = P_FLAT_SCALEUP;
-
- VectorCopy(start, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = 0;
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- p->color = BLOODRED;
-}
-
-#define NORMALSIZE 16
-#define LARGESIZE 32
-
-void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- p->endtime = cg.time + 350 + (crandom() * 100);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
- p->endheight = LARGESIZE;
- p->endwidth = LARGESIZE;
-
- p->type = P_SMOKE;
-
- VectorCopy( origin, p->org );
-
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -1;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->color = BLOODRED;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
-{
- cparticle_t *p;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
-
- p->endtime = cg.time + duration;
- p->startfade = cg.time + duration/2;
-
- p->color = EMISIVEFADE;
- p->alpha = 0.4f;
- p->alphavel = 0;
-
- p->height = 0.5;
- p->width = 0.5;
- p->endheight = 0.5;
- p->endwidth = 0.5;
-
- p->pshader = cgs.media.tracerShader;
-
- p->type = P_SMOKE;
-
- VectorCopy(org, p->org);
-
- p->org[0] += (crandom() * x);
- p->org[1] += (crandom() * y);
-
- p->vel[0] = vel[0];
- p->vel[1] = vel[1];
- p->vel[2] = vel[2];
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
-
- p->vel[0] += (crandom() * 4);
- p->vel[1] += (crandom() * 4);
- p->vel[2] += (20 + (crandom() * 10)) * speed;
-
- p->accel[0] = crandom () * 4;
- p->accel[1] = crandom () * 4;
-
-}
-
-void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
-{
- float length;
- float dist;
- float crittersize;
- vec3_t angles, forward;
- vec3_t point;
- cparticle_t *p;
- int i;
-
- dist = 0;
-
- VectorNegate (dir, dir);
- length = VectorLength (dir);
- vectoangles (dir, angles);
- AngleVectors (angles, forward, NULL, NULL);
-
- crittersize = LARGESIZE;
-
- if (length)
- dist = length / crittersize;
-
- if (dist < 1)
- dist = 1;
-
- VectorCopy (origin, point);
-
- for (i=0; i<dist; i++)
- {
- VectorMA (point, crittersize, forward, point);
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cg.time;
- p->alpha = 5.0;
- p->alphavel = 0;
- p->roll = 0;
-
- p->pshader = cgs.media.smokePuffShader;
-
- // RF, stay around for long enough to expand and dissipate naturally
- if (length)
- p->endtime = cg.time + 4500 + (crandom() * 3500);
- else
- p->endtime = cg.time + 750 + (crandom() * 500);
-
- p->startfade = cg.time;
-
- p->width = LARGESIZE;
- p->height = LARGESIZE;
-
- // RF, expand while falling
- p->endheight = LARGESIZE*3.0;
- p->endwidth = LARGESIZE*3.0;
-
- if (!length)
- {
- p->width *= 0.2f;
- p->height *= 0.2f;
-
- p->endheight = NORMALSIZE;
- p->endwidth = NORMALSIZE;
- }
-
- p->type = P_SMOKE;
-
- VectorCopy( point, p->org );
-
- p->vel[0] = crandom()*6;
- p->vel[1] = crandom()*6;
- p->vel[2] = random()*20;
-
- // RF, add some gravity/randomness
- p->accel[0] = crandom()*3;
- p->accel[1] = crandom()*3;
- p->accel[2] = -PARTICLE_GRAVITY*0.4;
-
- VectorClear( p->accel );
-
- p->rotate = qfalse;
-
- p->roll = rand()%179;
-
- p->alpha = 0.75;
-
- }
-
-
-}
-
-void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
-{
- cparticle_t *p;
-
- if (!pshader)
- CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- p->time = cg.time;
- p->alpha = 1.0;
- p->alphavel = 0;
- p->roll = rand()%179;
-
- p->pshader = pshader;
-
- if (duration > 0)
- p->endtime = cg.time + duration;
- else
- p->endtime = duration;
-
- p->startfade = cg.time;
-
- p->width = size;
- p->height = size;
-
- p->endheight = size;
- p->endwidth = size;
-
- p->type = P_SPRITE;
-
- VectorCopy( origin, p->org );
-
- p->rotate = qfalse;
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// Rafael particles
+// cg_particles.c
+
+#include "cg_local.h"
+
+#define BLOODRED 2
+#define EMISIVEFADE 3
+#define GREY75 4
+
+typedef struct particle_s
+{
+ struct particle_s *next;
+
+ float time;
+ float endtime;
+
+ vec3_t org;
+ vec3_t vel;
+ vec3_t accel;
+ int color;
+ float colorvel;
+ float alpha;
+ float alphavel;
+ int type;
+ qhandle_t pshader;
+
+ float height;
+ float width;
+
+ float endheight;
+ float endwidth;
+
+ float start;
+ float end;
+
+ float startfade;
+ qboolean rotate;
+ int snum;
+
+ qboolean link;
+
+ // Ridah
+ int shaderAnim;
+ int roll;
+
+ int accumroll;
+
+} cparticle_t;
+
+typedef enum
+{
+ P_NONE,
+ P_WEATHER,
+ P_FLAT,
+ P_SMOKE,
+ P_ROTATE,
+ P_WEATHER_TURBULENT,
+ P_ANIM, // Ridah
+ P_BAT,
+ P_BLEED,
+ P_FLAT_SCALEUP,
+ P_FLAT_SCALEUP_FADE,
+ P_WEATHER_FLURRY,
+ P_SMOKE_IMPACT,
+ P_BUBBLE,
+ P_BUBBLE_TURBULENT,
+ P_SPRITE
+} particle_type_t;
+
+#define MAX_SHADER_ANIMS 32
+#define MAX_SHADER_ANIM_FRAMES 64
+
+static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
+ "explode1",
+ "blacksmokeanim",
+ "twiltb2",
+ "expblue",
+ "blacksmokeanimb", // uses 'explode1' sequence
+ "blood",
+ NULL
+};
+static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
+static int shaderAnimCounts[MAX_SHADER_ANIMS] = {
+ 23,
+ 25,
+ 45,
+ 25,
+ 23,
+ 5,
+};
+static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
+ 1.405f,
+ 1.0f,
+ 1.0f,
+ 1.0f,
+ 1.0f,
+ 1.0f,
+};
+static int numShaderAnims;
+// done.
+
+#define PARTICLE_GRAVITY 40
+#define MAX_PARTICLES 1024 * 8
+
+cparticle_t *active_particles, *free_particles;
+cparticle_t particles[MAX_PARTICLES];
+int cl_numparticles = MAX_PARTICLES;
+
+qboolean initparticles = qfalse;
+vec3_t vforward, vright, vup;
+vec3_t rforward, rright, rup;
+
+float oldtime;
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CG_ClearParticles (void)
+{
+ int i;
+
+ memset( particles, 0, sizeof(particles) );
+
+ free_particles = &particles[0];
+ active_particles = NULL;
+
+ for (i=0 ;i<cl_numparticles ; i++)
+ {
+ particles[i].next = &particles[i+1];
+ particles[i].type = 0;
+ }
+ particles[cl_numparticles-1].next = NULL;
+
+ oldtime = cg.time;
+
+ // Ridah, init the shaderAnims
+ for (i=0; shaderAnimNames[i]; i++) {
+ int j;
+
+ for (j=0; j<shaderAnimCounts[i]; j++) {
+ shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
+ }
+ }
+ numShaderAnims = i;
+ // done.
+
+ initparticles = qtrue;
+}
+
+
+/*
+=====================
+CG_AddParticleToScene
+=====================
+*/
+void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
+{
+
+ vec3_t point;
+ polyVert_t verts[4];
+ float width;
+ float height;
+ float time, time2;
+ float ratio;
+ float invratio;
+ vec3_t color;
+ polyVert_t TRIverts[3];
+ vec3_t rright2, rup2;
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
+ || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {// create a front facing polygon
+
+ if (p->type != P_WEATHER_FLURRY)
+ {
+ if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {
+ if (org[2] > p->end)
+ {
+ p->time = cg.time;
+ VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
+
+ p->org[2] = ( p->start + crandom () * 4 );
+
+
+ if (p->type == P_BUBBLE_TURBULENT)
+ {
+ p->vel[0] = crandom() * 4;
+ p->vel[1] = crandom() * 4;
+ }
+
+ }
+ }
+ else
+ {
+ if (org[2] < p->end)
+ {
+ p->time = cg.time;
+ VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
+
+ while (p->org[2] < p->end)
+ {
+ p->org[2] += (p->start - p->end);
+ }
+
+
+ if (p->type == P_WEATHER_TURBULENT)
+ {
+ p->vel[0] = crandom() * 16;
+ p->vel[1] = crandom() * 16;
+ }
+
+ }
+ }
+
+
+ // Rafael snow pvs check
+ if (!p->link)
+ return;
+
+ p->alpha = 1;
+ }
+
+ // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
+ if (Distance( cg.snap->ps.origin, org ) > 1024) {
+ return;
+ }
+ // done.
+
+ if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
+ {
+ VectorMA (org, -p->height, vup, point);
+ VectorMA (point, -p->width, vright, point);
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, -p->height, vup, point);
+ VectorMA (point, p->width, vright, point);
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, vup, point);
+ VectorMA (point, p->width, vright, point);
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, vup, point);
+ VectorMA (point, -p->width, vright, point);
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255 * p->alpha;
+ }
+ else
+ {
+ VectorMA (org, -p->height, vup, point);
+ VectorMA (point, -p->width, vright, point);
+ VectorCopy( point, TRIverts[0].xyz );
+ TRIverts[0].st[0] = 1;
+ TRIverts[0].st[1] = 0;
+ TRIverts[0].modulate[0] = 255;
+ TRIverts[0].modulate[1] = 255;
+ TRIverts[0].modulate[2] = 255;
+ TRIverts[0].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, vup, point);
+ VectorMA (point, -p->width, vright, point);
+ VectorCopy (point, TRIverts[1].xyz);
+ TRIverts[1].st[0] = 0;
+ TRIverts[1].st[1] = 0;
+ TRIverts[1].modulate[0] = 255;
+ TRIverts[1].modulate[1] = 255;
+ TRIverts[1].modulate[2] = 255;
+ TRIverts[1].modulate[3] = 255 * p->alpha;
+
+ VectorMA (org, p->height, vup, point);
+ VectorMA (point, p->width, vright, point);
+ VectorCopy (point, TRIverts[2].xyz);
+ TRIverts[2].st[0] = 0;
+ TRIverts[2].st[1] = 1;
+ TRIverts[2].modulate[0] = 255;
+ TRIverts[2].modulate[1] = 255;
+ TRIverts[2].modulate[2] = 255;
+ TRIverts[2].modulate[3] = 255 * p->alpha;
+ }
+
+ }
+ else if (p->type == P_SPRITE)
+ {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+
+ VectorSet (color, 1.0, 1.0, 1.0);
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (p->roll) {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+
+ if (p->roll) {
+ VectorMA (org, -height, ru, point);
+ VectorMA (point, -width, rr, point);
+ } else {
+ VectorMA (org, -height, vup, point);
+ VectorMA (point, -width, vright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*height, ru, point);
+ } else {
+ VectorMA (point, 2*height, vup, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*width, rr, point);
+ } else {
+ VectorMA (point, 2*width, vright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, -2*height, ru, point);
+ } else {
+ VectorMA (point, -2*height, vup, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+ }
+ else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
+ {// create a front rotating facing polygon
+
+ if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
+ return;
+ }
+
+ if (p->color == BLOODRED)
+ VectorSet (color, 0.22f, 0.0f, 0.0f);
+ else if (p->color == GREY75)
+ {
+ float len;
+ float greyit;
+ float val;
+ len = Distance (cg.snap->ps.origin, org);
+ if (!len)
+ len = 1;
+
+ val = 4096/len;
+ greyit = 0.25 * val;
+ if (greyit > 0.5)
+ greyit = 0.5;
+
+ VectorSet (color, greyit, greyit, greyit);
+ }
+ else
+ VectorSet (color, 1.0, 1.0, 1.0);
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ if (cg.time > p->startfade)
+ {
+ invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
+
+ if (p->color == EMISIVEFADE)
+ {
+ float fval;
+ fval = (invratio * invratio);
+ if (fval < 0)
+ fval = 0;
+ VectorSet (color, fval , fval , fval );
+ }
+ invratio *= p->alpha;
+ }
+ else
+ invratio = 1 * p->alpha;
+
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
+ invratio = 1;
+
+ if (invratio > 1)
+ invratio = 1;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (p->type != P_SMOKE_IMPACT)
+ {
+ vec3_t temp;
+
+ vectoangles (rforward, temp);
+ p->accumroll += p->roll;
+ temp[ROLL] += p->accumroll * 0.1;
+ AngleVectors ( temp, NULL, rright2, rup2);
+ }
+ else
+ {
+ VectorCopy (rright, rright2);
+ VectorCopy (rup, rup2);
+ }
+
+ if (p->rotate)
+ {
+ VectorMA (org, -height, rup2, point);
+ VectorMA (point, -width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, -p->height, vup, point);
+ VectorMA (point, -p->width, vright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255 * color[0];
+ verts[0].modulate[1] = 255 * color[1];
+ verts[0].modulate[2] = 255 * color[2];
+ verts[0].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, -height, rup2, point);
+ VectorMA (point, width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, -p->height, vup, point);
+ VectorMA (point, p->width, vright, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255 * color[0];
+ verts[1].modulate[1] = 255 * color[1];
+ verts[1].modulate[2] = 255 * color[2];
+ verts[1].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, height, rup2, point);
+ VectorMA (point, width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, p->height, vup, point);
+ VectorMA (point, p->width, vright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255 * color[0];
+ verts[2].modulate[1] = 255 * color[1];
+ verts[2].modulate[2] = 255 * color[2];
+ verts[2].modulate[3] = 255 * invratio;
+
+ if (p->rotate)
+ {
+ VectorMA (org, height, rup2, point);
+ VectorMA (point, -width, rright2, point);
+ }
+ else
+ {
+ VectorMA (org, p->height, vup, point);
+ VectorMA (point, -p->width, vright, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255 * color[0];
+ verts[3].modulate[1] = 255 * color[1];
+ verts[3].modulate[2] = 255 * color[2];
+ verts[3].modulate[3] = 255 * invratio;
+
+ }
+ else if (p->type == P_BLEED)
+ {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+ float alpha;
+
+ alpha = p->alpha;
+
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
+ alpha = 1;
+
+ if (p->roll)
+ {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+ else
+ {
+ VectorCopy (vup, ru);
+ VectorCopy (vright, rr);
+ }
+
+ VectorMA (org, -p->height, ru, point);
+ VectorMA (point, -p->width, rr, point);
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 111;
+ verts[0].modulate[1] = 19;
+ verts[0].modulate[2] = 9;
+ verts[0].modulate[3] = 255 * alpha;
+
+ VectorMA (org, -p->height, ru, point);
+ VectorMA (point, p->width, rr, point);
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 111;
+ verts[1].modulate[1] = 19;
+ verts[1].modulate[2] = 9;
+ verts[1].modulate[3] = 255 * alpha;
+
+ VectorMA (org, p->height, ru, point);
+ VectorMA (point, p->width, rr, point);
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 111;
+ verts[2].modulate[1] = 19;
+ verts[2].modulate[2] = 9;
+ verts[2].modulate[3] = 255 * alpha;
+
+ VectorMA (org, p->height, ru, point);
+ VectorMA (point, -p->width, rr, point);
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 111;
+ verts[3].modulate[1] = 19;
+ verts[3].modulate[2] = 9;
+ verts[3].modulate[3] = 255 * alpha;
+
+ }
+ else if (p->type == P_FLAT_SCALEUP)
+ {
+ float width, height;
+ float sinR, cosR;
+
+ if (p->color == BLOODRED)
+ VectorSet (color, 1, 1, 1);
+ else
+ VectorSet (color, 0.5, 0.5, 0.5);
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ if (width > p->endwidth)
+ width = p->endwidth;
+
+ if (height > p->endheight)
+ height = p->endheight;
+
+ sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
+ cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
+
+ VectorCopy (org, verts[0].xyz);
+ verts[0].xyz[0] -= sinR;
+ verts[0].xyz[1] -= cosR;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255 * color[0];
+ verts[0].modulate[1] = 255 * color[1];
+ verts[0].modulate[2] = 255 * color[2];
+ verts[0].modulate[3] = 255;
+
+ VectorCopy (org, verts[1].xyz);
+ verts[1].xyz[0] -= cosR;
+ verts[1].xyz[1] += sinR;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255 * color[0];
+ verts[1].modulate[1] = 255 * color[1];
+ verts[1].modulate[2] = 255 * color[2];
+ verts[1].modulate[3] = 255;
+
+ VectorCopy (org, verts[2].xyz);
+ verts[2].xyz[0] += sinR;
+ verts[2].xyz[1] += cosR;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255 * color[0];
+ verts[2].modulate[1] = 255 * color[1];
+ verts[2].modulate[2] = 255 * color[2];
+ verts[2].modulate[3] = 255;
+
+ VectorCopy (org, verts[3].xyz);
+ verts[3].xyz[0] += cosR;
+ verts[3].xyz[1] -= sinR;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255 * color[0];
+ verts[3].modulate[1] = 255 * color[1];
+ verts[3].modulate[2] = 255 * color[2];
+ verts[3].modulate[3] = 255;
+ }
+ else if (p->type == P_FLAT)
+ {
+
+ VectorCopy (org, verts[0].xyz);
+ verts[0].xyz[0] -= p->height;
+ verts[0].xyz[1] -= p->width;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorCopy (org, verts[1].xyz);
+ verts[1].xyz[0] -= p->height;
+ verts[1].xyz[1] += p->width;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorCopy (org, verts[2].xyz);
+ verts[2].xyz[0] += p->height;
+ verts[2].xyz[1] += p->width;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorCopy (org, verts[3].xyz);
+ verts[3].xyz[0] += p->height;
+ verts[3].xyz[1] -= p->width;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ }
+ // Ridah
+ else if (p->type == P_ANIM) {
+ vec3_t rr, ru;
+ vec3_t rotate_ang;
+ int i, j;
+
+ time = cg.time - p->time;
+ time2 = p->endtime - p->time;
+ ratio = time / time2;
+ if (ratio >= 1.0f) {
+ ratio = 0.9999f;
+ }
+
+ width = p->width + ( ratio * ( p->endwidth - p->width) );
+ height = p->height + ( ratio * ( p->endheight - p->height) );
+
+ // if we are "inside" this sprite, don't draw
+ if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
+ return;
+ }
+
+ i = p->shaderAnim;
+ j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
+ p->pshader = shaderAnims[i][j];
+
+ if (p->roll) {
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ rotate_ang[ROLL] += p->roll;
+ AngleVectors ( rotate_ang, NULL, rr, ru);
+ }
+
+ if (p->roll) {
+ VectorMA (org, -height, ru, point);
+ VectorMA (point, -width, rr, point);
+ } else {
+ VectorMA (org, -height, vup, point);
+ VectorMA (point, -width, vright, point);
+ }
+ VectorCopy (point, verts[0].xyz);
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*height, ru, point);
+ } else {
+ VectorMA (point, 2*height, vup, point);
+ }
+ VectorCopy (point, verts[1].xyz);
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, 2*width, rr, point);
+ } else {
+ VectorMA (point, 2*width, vright, point);
+ }
+ VectorCopy (point, verts[2].xyz);
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ if (p->roll) {
+ VectorMA (point, -2*height, ru, point);
+ } else {
+ VectorMA (point, -2*height, vup, point);
+ }
+ VectorCopy (point, verts[3].xyz);
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+ }
+ // done.
+
+ if (!p->pshader) {
+// (SA) temp commented out for DM
+// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
+ return;
+ }
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
+ trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
+ else
+ trap_R_AddPolyToScene( p->pshader, 4, verts );
+
+}
+
+// Ridah, made this static so it doesn't interfere with other files
+static float roll = 0.0;
+
+/*
+===============
+CG_AddParticles
+===============
+*/
+void CG_AddParticles (void)
+{
+ cparticle_t *p, *next;
+ float alpha;
+ float time, time2;
+ vec3_t org;
+ int color;
+ cparticle_t *active, *tail;
+ int type;
+ vec3_t rotate_ang;
+
+ if (!initparticles)
+ CG_ClearParticles ();
+
+ VectorCopy( cg.refdef.viewaxis[0], vforward );
+ VectorCopy( cg.refdef.viewaxis[1], vright );
+ VectorCopy( cg.refdef.viewaxis[2], vup );
+
+ vectoangles( cg.refdef.viewaxis[0], rotate_ang );
+ roll += ((cg.time - oldtime) * 0.1) ;
+ rotate_ang[ROLL] += (roll*0.9);
+ AngleVectors ( rotate_ang, rforward, rright, rup);
+
+ oldtime = cg.time;
+
+ active = NULL;
+ tail = NULL;
+
+ for (p=active_particles ; p ; p=next)
+ {
+
+ next = p->next;
+
+ time = (cg.time - p->time)*0.001;
+
+ alpha = p->alpha + time*p->alphavel;
+ if (alpha <= 0)
+ { // faded out
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+
+ continue;
+ }
+
+ }
+
+ if (p->type == P_WEATHER_FLURRY)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+
+ continue;
+ }
+ }
+
+
+ if (p->type == P_FLAT_SCALEUP_FADE)
+ {
+ if (cg.time > p->endtime)
+ {
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ }
+
+ if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
+ // temporary sprite
+ CG_AddParticleToScene (p, p->org, alpha);
+ p->next = free_particles;
+ free_particles = p;
+ p->type = 0;
+ p->color = 0;
+ p->alpha = 0;
+ continue;
+ }
+
+ 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;
+
+ type = p->type;
+
+ CG_AddParticleToScene (p, org, alpha);
+ }
+
+ active_particles = active;
+}
+
+/*
+======================
+CG_AddParticles
+======================
+*/
+void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+ qboolean turb = qtrue;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.90f;
+ p->alphavel = 0;
+
+ p->start = cent->currentState.origin2[0];
+ p->end = cent->currentState.origin2[1];
+
+ p->endtime = cg.time + cent->currentState.time;
+ p->startfade = cg.time + cent->currentState.time2;
+
+ p->pshader = pshader;
+
+ if (rand()%100 > 90)
+ {
+ p->height = 32;
+ p->width = 32;
+ p->alpha = 0.10f;
+ }
+ else
+ {
+ p->height = 1;
+ p->width = 1;
+ }
+
+ p->vel[2] = -20;
+
+ p->type = P_WEATHER_FLURRY;
+
+ if (turb)
+ p->vel[2] = -10;
+
+ VectorCopy(cent->currentState.origin, p->org);
+
+ p->org[0] = p->org[0];
+ p->org[1] = p->org[1];
+ p->org[2] = p->org[2];
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
+ p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
+ p->vel[2] += cent->currentState.angles[2];
+
+ if (turb)
+ {
+ p->accel[0] = crandom () * 16;
+ p->accel[1] = crandom () * 16;
+ }
+
+}
+
+void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.40f;
+ p->alphavel = 0;
+ p->start = origin[2];
+ p->end = origin2[2];
+ p->pshader = pshader;
+ p->height = 1;
+ p->width = 1;
+
+ p->vel[2] = -50;
+
+ if (turb)
+ {
+ p->type = P_WEATHER_TURBULENT;
+ p->vel[2] = -50 * 1.3;
+ }
+ else
+ {
+ p->type = P_WEATHER;
+ }
+
+ VectorCopy(origin, p->org);
+
+ p->org[0] = p->org[0] + ( crandom() * range);
+ p->org[1] = p->org[1] + ( crandom() * range);
+ p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ if (turb)
+ {
+ p->vel[0] = crandom() * 16;
+ p->vel[1] = crandom() * 16;
+ }
+
+ // Rafael snow pvs check
+ p->snum = snum;
+ p->link = qtrue;
+
+}
+
+void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
+{
+ cparticle_t *p;
+ float randsize;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->color = 0;
+ p->alpha = 0.40f;
+ p->alphavel = 0;
+ p->start = origin[2];
+ p->end = origin2[2];
+ p->pshader = pshader;
+
+ randsize = 1 + (crandom() * 0.5);
+
+ p->height = randsize;
+ p->width = randsize;
+
+ p->vel[2] = 50 + ( crandom() * 10 );
+
+ if (turb)
+ {
+ p->type = P_BUBBLE_TURBULENT;
+ p->vel[2] = 50 * 1.3;
+ }
+ else
+ {
+ p->type = P_BUBBLE;
+ }
+
+ VectorCopy(origin, p->org);
+
+ p->org[0] = p->org[0] + ( crandom() * range);
+ p->org[1] = p->org[1] + ( crandom() * range);
+ p->org[2] = p->org[2] + ( crandom() * (p->start - p->end));
+
+ p->vel[0] = p->vel[1] = 0;
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ if (turb)
+ {
+ p->vel[0] = crandom() * 4;
+ p->vel[1] = crandom() * 4;
+ }
+
+ // Rafael snow pvs check
+ p->snum = snum;
+ p->link = qtrue;
+
+}
+
+void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
+{
+
+ // using cent->density = enttime
+ // cent->frame = startfade
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleSmoke == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + cent->currentState.time;
+ p->startfade = cg.time + cent->currentState.time2;
+
+ p->color = 0;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->start = cent->currentState.origin[2];
+ p->end = cent->currentState.origin2[2];
+ p->pshader = pshader;
+ p->rotate = qfalse;
+ p->height = 8;
+ p->width = 8;
+ p->endheight = 32;
+ p->endwidth = 32;
+ p->type = P_SMOKE;
+
+ VectorCopy(cent->currentState.origin, p->org);
+
+ p->vel[0] = p->vel[1] = 0;
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[2] = 5;
+
+ if (cent->currentState.frame == 1)// reverse gravity
+ p->vel[2] *= -1;
+
+ p->roll = 8 + (crandom() * 4);
+}
+
+
+void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
+{
+
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+
+ p->height = 0.5;
+ p->width = 0.5;
+ p->endheight = 0.5;
+ p->endwidth = 0.5;
+
+ p->pshader = cgs.media.tracerShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->vel[0] = vel[0];
+ p->vel[1] = vel[1];
+ p->vel[2] = vel[2];
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->accel[2] = -60;
+ p->vel[2] += -20;
+
+}
+
+/*
+======================
+CG_ParticleExplosion
+======================
+*/
+
+void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
+{
+ cparticle_t *p;
+ int anim;
+
+ if (animStr < (char *)10)
+ CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
+
+ // find the animation string
+ for (anim=0; shaderAnimNames[anim]; anim++) {
+ if (!stricmp( animStr, shaderAnimNames[anim] ))
+ break;
+ }
+ if (!shaderAnimNames[anim]) {
+ CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
+ return;
+ }
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+
+ if (duration < 0) {
+ duration *= -1;
+ p->roll = 0;
+ } else {
+ p->roll = crandom()*179;
+ }
+
+ p->shaderAnim = anim;
+
+ p->width = sizeStart;
+ p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction
+
+ p->endheight = sizeEnd;
+ p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
+
+ p->endtime = cg.time + duration;
+
+ p->type = P_ANIM;
+
+ VectorCopy( origin, p->org );
+ VectorCopy( vel, p->vel );
+ VectorClear( p->accel );
+
+}
+
+// Rafael Shrapnel
+void CG_AddParticleShrapnel (localEntity_t *le)
+{
+ return;
+}
+// done.
+
+int CG_NewParticleArea (int num)
+{
+ // const char *str;
+ char *str;
+ char *token;
+ int type;
+ vec3_t origin, origin2;
+ int i;
+ float range = 0;
+ int turb;
+ int numparticles;
+ int snum;
+
+ str = (char *) CG_ConfigString (num);
+ if (!str[0])
+ return (0);
+
+ // returns type 128 64 or 32
+ token = COM_Parse (&str);
+ type = atoi (token);
+
+ if (type == 1)
+ range = 128;
+ else if (type == 2)
+ range = 64;
+ else if (type == 3)
+ range = 32;
+ else if (type == 0)
+ range = 256;
+ else if (type == 4)
+ range = 8;
+ else if (type == 5)
+ range = 16;
+ else if (type == 6)
+ range = 32;
+ else if (type == 7)
+ range = 64;
+
+
+ for (i=0; i<3; i++)
+ {
+ token = COM_Parse (&str);
+ origin[i] = atof (token);
+ }
+
+ for (i=0; i<3; i++)
+ {
+ token = COM_Parse (&str);
+ origin2[i] = atof (token);
+ }
+
+ token = COM_Parse (&str);
+ numparticles = atoi (token);
+
+ token = COM_Parse (&str);
+ turb = atoi (token);
+
+ token = COM_Parse (&str);
+ snum = atoi (token);
+
+ for (i=0; i<numparticles; i++)
+ {
+ if (type >= 4)
+ CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
+ else
+ CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
+ }
+
+ return (1);
+}
+
+void CG_SnowLink (centity_t *cent, qboolean particleOn)
+{
+ cparticle_t *p, *next;
+ int id;
+
+ id = cent->currentState.frame;
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
+ {
+ if (p->snum == id)
+ {
+ if (particleOn)
+ p->link = qtrue;
+ else
+ p->link = qfalse;
+ }
+ }
+
+ }
+}
+
+void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 0.25;
+ p->alphavel = 0;
+ p->roll = crandom()*179;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + 1000;
+ p->startfade = cg.time + 100;
+
+ p->width = rand()%4 + 8;
+ p->height = rand()%4 + 8;
+
+ p->endheight = p->height *2;
+ p->endwidth = p->width * 2;
+
+ p->endtime = cg.time + 500;
+
+ p->type = P_SMOKE_IMPACT;
+
+ VectorCopy( origin, p->org );
+ VectorSet(p->vel, 0, 0, 20);
+ VectorSet(p->accel, 0, 0, 20);
+
+ p->rotate = qtrue;
+}
+
+void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + duration;
+
+ if (fleshEntityNum)
+ p->startfade = cg.time;
+ else
+ p->startfade = cg.time + 100;
+
+ p->width = 4;
+ p->height = 4;
+
+ p->endheight = 4+rand()%3;
+ p->endwidth = p->endheight;
+
+ p->type = P_SMOKE;
+
+ VectorCopy( start, p->org );
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -20;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->color = BLOODRED;
+ p->alpha = 0.75;
+
+}
+
+void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+
+ int time;
+ int time2;
+ float ratio;
+
+ float duration = 1500;
+
+ time = cg.time;
+ time2 = cg.time + cent->currentState.time;
+
+ ratio =(float)1 - ((float)time / (float)time2);
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ p->endtime = cg.time + duration;
+
+ p->startfade = p->endtime;
+
+ p->width = 1;
+ p->height = 3;
+
+ p->endheight = 3;
+ p->endwidth = 1;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(cent->currentState.origin, p->org );
+
+ p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
+ p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
+ p->vel[2] = (cent->currentState.origin2[2]);
+
+ p->snum = 1.0f;
+
+ VectorClear( p->accel );
+
+ p->accel[2] = -20;
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+}
+
+
+void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ if (cent->currentState.angles2[2])
+ p->endtime = cg.time + cent->currentState.angles2[2];
+ else
+ p->endtime = cg.time + 60000;
+
+ p->startfade = p->endtime;
+
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
+ {
+ p->width = cent->currentState.angles2[0];
+ p->height = cent->currentState.angles2[0];
+
+ p->endheight = cent->currentState.angles2[1];
+ p->endwidth = cent->currentState.angles2[1];
+ }
+ else
+ {
+ p->width = 8;
+ p->height = 8;
+
+ p->endheight = 16;
+ p->endwidth = 16;
+ }
+
+ p->type = P_FLAT_SCALEUP;
+
+ p->snum = 1.0;
+
+ VectorCopy(cent->currentState.origin, p->org );
+
+ p->org[2]+= 0.55 + (crandom() * 0.5);
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+}
+
+void CG_OilSlickRemove (centity_t *cent)
+{
+ cparticle_t *p, *next;
+ int id;
+
+ id = 1.0f;
+
+ if (!id)
+ CG_Printf ("CG_OilSlickRevove NULL id\n");
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ if (p->type == P_FLAT_SCALEUP)
+ {
+ if (p->snum == id)
+ {
+ p->endtime = cg.time + 100;
+ p->startfade = p->endtime;
+ p->type = P_FLAT_SCALEUP_FADE;
+
+ }
+ }
+
+ }
+}
+
+qboolean ValidBloodPool (vec3_t start)
+{
+#define EXTRUDE_DIST 0.5
+
+ vec3_t angles;
+ vec3_t right, up;
+ vec3_t this_pos, x_pos, center_pos, end_pos;
+ float x, y;
+ float fwidth, fheight;
+ trace_t trace;
+ vec3_t normal;
+
+ fwidth = 16;
+ fheight = 16;
+
+ VectorSet (normal, 0, 0, 1);
+
+ vectoangles (normal, angles);
+ AngleVectors (angles, NULL, right, up);
+
+ VectorMA (start, EXTRUDE_DIST, normal, center_pos);
+
+ for (x= -fwidth/2; x<fwidth; x+= fwidth)
+ {
+ VectorMA (center_pos, x, right, x_pos);
+
+ for (y= -fheight/2; y<fheight; y+= fheight)
+ {
+ VectorMA (x_pos, y, up, this_pos);
+ VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
+
+ CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
+
+
+ if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
+ return qfalse;
+
+ if (!(!trace.startsolid && trace.fraction < 1))
+ return qfalse;
+
+ }
+ }
+
+ return qtrue;
+}
+
+void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
+{
+ cparticle_t *p;
+ qboolean legit;
+ vec3_t start;
+ float rndSize;
+
+ if (!pshader)
+ CG_Printf ("CG_BloodPool pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+
+ VectorCopy (tr->endpos, start);
+ legit = ValidBloodPool (start);
+
+ if (!legit)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + 3000;
+ p->startfade = p->endtime;
+
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = pshader;
+
+ rndSize = 0.4 + random()*0.6;
+
+ p->width = 8*rndSize;
+ p->height = 8*rndSize;
+
+ p->endheight = 16*rndSize;
+ p->endwidth = 16*rndSize;
+
+ p->type = P_FLAT_SCALEUP;
+
+ VectorCopy(start, p->org );
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+ p->color = BLOODRED;
+}
+
+#define NORMALSIZE 16
+#define LARGESIZE 32
+
+void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
+{
+ float length;
+ float dist;
+ float crittersize;
+ vec3_t angles, forward;
+ vec3_t point;
+ cparticle_t *p;
+ int i;
+
+ dist = 0;
+
+ length = VectorLength (dir);
+ vectoangles (dir, angles);
+ AngleVectors (angles, forward, NULL, NULL);
+
+ crittersize = LARGESIZE;
+
+ if (length)
+ dist = length / crittersize;
+
+ if (dist < 1)
+ dist = 1;
+
+ VectorCopy (origin, point);
+
+ for (i=0; i<dist; i++)
+ {
+ VectorMA (point, crittersize, forward, point);
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = cgs.media.smokePuffShader;
+
+ p->endtime = cg.time + 350 + (crandom() * 100);
+
+ p->startfade = cg.time;
+
+ p->width = LARGESIZE;
+ p->height = LARGESIZE;
+ p->endheight = LARGESIZE;
+ p->endwidth = LARGESIZE;
+
+ p->type = P_SMOKE;
+
+ VectorCopy( origin, p->org );
+
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -1;
+
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->color = BLOODRED;
+
+ p->alpha = 0.75;
+
+ }
+
+
+}
+
+void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
+{
+ cparticle_t *p;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+
+ p->endtime = cg.time + duration;
+ p->startfade = cg.time + duration/2;
+
+ p->color = EMISIVEFADE;
+ p->alpha = 0.4f;
+ p->alphavel = 0;
+
+ p->height = 0.5;
+ p->width = 0.5;
+ p->endheight = 0.5;
+ p->endwidth = 0.5;
+
+ p->pshader = cgs.media.tracerShader;
+
+ p->type = P_SMOKE;
+
+ VectorCopy(org, p->org);
+
+ p->org[0] += (crandom() * x);
+ p->org[1] += (crandom() * y);
+
+ p->vel[0] = vel[0];
+ p->vel[1] = vel[1];
+ p->vel[2] = vel[2];
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+
+ p->vel[0] += (crandom() * 4);
+ p->vel[1] += (crandom() * 4);
+ p->vel[2] += (20 + (crandom() * 10)) * speed;
+
+ p->accel[0] = crandom () * 4;
+ p->accel[1] = crandom () * 4;
+
+}
+
+void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
+{
+ float length;
+ float dist;
+ float crittersize;
+ vec3_t angles, forward;
+ vec3_t point;
+ cparticle_t *p;
+ int i;
+
+ dist = 0;
+
+ VectorNegate (dir, dir);
+ length = VectorLength (dir);
+ vectoangles (dir, angles);
+ AngleVectors (angles, forward, NULL, NULL);
+
+ crittersize = LARGESIZE;
+
+ if (length)
+ dist = length / crittersize;
+
+ if (dist < 1)
+ dist = 1;
+
+ VectorCopy (origin, point);
+
+ for (i=0; i<dist; i++)
+ {
+ VectorMA (point, crittersize, forward, point);
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cg.time;
+ p->alpha = 5.0;
+ p->alphavel = 0;
+ p->roll = 0;
+
+ p->pshader = cgs.media.smokePuffShader;
+
+ // RF, stay around for long enough to expand and dissipate naturally
+ if (length)
+ p->endtime = cg.time + 4500 + (crandom() * 3500);
+ else
+ p->endtime = cg.time + 750 + (crandom() * 500);
+
+ p->startfade = cg.time;
+
+ p->width = LARGESIZE;
+ p->height = LARGESIZE;
+
+ // RF, expand while falling
+ p->endheight = LARGESIZE*3.0;
+ p->endwidth = LARGESIZE*3.0;
+
+ if (!length)
+ {
+ p->width *= 0.2f;
+ p->height *= 0.2f;
+
+ p->endheight = NORMALSIZE;
+ p->endwidth = NORMALSIZE;
+ }
+
+ p->type = P_SMOKE;
+
+ VectorCopy( point, p->org );
+
+ p->vel[0] = crandom()*6;
+ p->vel[1] = crandom()*6;
+ p->vel[2] = random()*20;
+
+ // RF, add some gravity/randomness
+ p->accel[0] = crandom()*3;
+ p->accel[1] = crandom()*3;
+ p->accel[2] = -PARTICLE_GRAVITY*0.4;
+
+ VectorClear( p->accel );
+
+ p->rotate = qfalse;
+
+ p->roll = rand()%179;
+
+ p->alpha = 0.75;
+
+ }
+
+
+}
+
+void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
+{
+ cparticle_t *p;
+
+ if (!pshader)
+ CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ p->time = cg.time;
+ p->alpha = 1.0;
+ p->alphavel = 0;
+ p->roll = rand()%179;
+
+ p->pshader = pshader;
+
+ if (duration > 0)
+ p->endtime = cg.time + duration;
+ else
+ p->endtime = duration;
+
+ p->startfade = cg.time;
+
+ p->width = size;
+ p->height = size;
+
+ p->endheight = size;
+ p->endwidth = size;
+
+ p->type = P_SPRITE;
+
+ VectorCopy( origin, p->org );
+
+ p->rotate = qfalse;
+}
diff --git a/code/cgame/cg_players.c b/code/cgame/cg_players.c
index 2fd7b73..6987442 100755
--- a/code/cgame/cg_players.c
+++ b/code/cgame/cg_players.c
@@ -1,2619 +1,2619 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_players.c -- handle the media and animation for player entities
-#include "cg_local.h"
-
-char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {
- "*death1.wav",
- "*death2.wav",
- "*death3.wav",
- "*jump1.wav",
- "*pain25_1.wav",
- "*pain50_1.wav",
- "*pain75_1.wav",
- "*pain100_1.wav",
- "*falling1.wav",
- "*gasp.wav",
- "*drown.wav",
- "*fall1.wav",
- "*taunt.wav"
-};
-
-
-/*
-================
-CG_CustomSound
-
-================
-*/
-sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) {
- clientInfo_t *ci;
- int i;
-
- if ( soundName[0] != '*' ) {
- return trap_S_RegisterSound( soundName, qfalse );
- }
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- for ( i = 0 ; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[i] ; i++ ) {
- if ( !strcmp( soundName, cg_customSoundNames[i] ) ) {
- return ci->sounds[i];
- }
- }
-
- CG_Error( "Unknown custom sound: %s", soundName );
- return 0;
-}
-
-
-
-/*
-=============================================================================
-
-CLIENT INFO
-
-=============================================================================
-*/
-
-/*
-======================
-CG_ParseAnimationFile
-
-Read a configuration file containing animation coutns and rates
-models/players/visor/animation.cfg, etc
-======================
-*/
-static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) {
- char *text_p, *prev;
- int len;
- int i;
- char *token;
- float fps;
- int skip;
- char text[20000];
- fileHandle_t f;
- animation_t *animations;
-
- animations = ci->animations;
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 ) {
- return qfalse;
- }
- if ( len >= sizeof( text ) - 1 ) {
- CG_Printf( "File %s too long\n", filename );
- return qfalse;
- }
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
- skip = 0; // quite the compiler warning
-
- ci->footsteps = FOOTSTEP_NORMAL;
- VectorClear( ci->headOffset );
- ci->gender = GENDER_MALE;
- ci->fixedlegs = qfalse;
- ci->fixedtorso = qfalse;
-
- // read optional parameters
- while ( 1 ) {
- prev = text_p; // so we can unget
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "footsteps" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) {
- ci->footsteps = FOOTSTEP_NORMAL;
- } else if ( !Q_stricmp( token, "boot" ) ) {
- ci->footsteps = FOOTSTEP_BOOT;
- } else if ( !Q_stricmp( token, "flesh" ) ) {
- ci->footsteps = FOOTSTEP_FLESH;
- } else if ( !Q_stricmp( token, "mech" ) ) {
- ci->footsteps = FOOTSTEP_MECH;
- } else if ( !Q_stricmp( token, "energy" ) ) {
- ci->footsteps = FOOTSTEP_ENERGY;
- } else {
- CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token );
- }
- continue;
- } else if ( !Q_stricmp( token, "headoffset" ) ) {
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- ci->headOffset[i] = atof( token );
- }
- continue;
- } else if ( !Q_stricmp( token, "sex" ) ) {
- token = COM_Parse( &text_p );
- if ( !token ) {
- break;
- }
- if ( token[0] == 'f' || token[0] == 'F' ) {
- ci->gender = GENDER_FEMALE;
- } else if ( token[0] == 'n' || token[0] == 'N' ) {
- ci->gender = GENDER_NEUTER;
- } else {
- ci->gender = GENDER_MALE;
- }
- continue;
- } else if ( !Q_stricmp( token, "fixedlegs" ) ) {
- ci->fixedlegs = qtrue;
- continue;
- } else if ( !Q_stricmp( token, "fixedtorso" ) ) {
- ci->fixedtorso = qtrue;
- continue;
- }
-
- // if it is a number, start parsing animations
- if ( token[0] >= '0' && token[0] <= '9' ) {
- text_p = prev; // unget the token
- break;
- }
- Com_Printf( "unknown token '%s' is %s\n", token, filename );
- }
-
- // read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
- animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
- animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
- animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
- animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
- animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
- animations[i].reversed = qfalse;
- animations[i].flipflop = qfalse;
- continue;
- }
- break;
- }
- animations[i].firstFrame = atoi( token );
- // leg only frames are adjusted to not count the upper body only frames
- if ( i == LEGS_WALKCR ) {
- skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
- }
- if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
- animations[i].firstFrame -= skip;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- animations[i].numFrames = atoi( token );
-
- animations[i].reversed = qfalse;
- animations[i].flipflop = qfalse;
- // if numFrames is negative the animation is reversed
- if (animations[i].numFrames < 0) {
- animations[i].numFrames = -animations[i].numFrames;
- animations[i].reversed = qtrue;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !*token ) {
- break;
- }
- fps = atof( token );
- if ( fps == 0 ) {
- fps = 1;
- }
- animations[i].frameLerp = 1000 / fps;
- animations[i].initialLerp = 1000 / fps;
- }
-
- if ( i != MAX_ANIMATIONS ) {
- CG_Printf( "Error parsing animation file: %s", filename );
- return qfalse;
- }
-
- // crouch backward animation
- memcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t));
- animations[LEGS_BACKCR].reversed = qtrue;
- // walk backward animation
- memcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t));
- animations[LEGS_BACKWALK].reversed = qtrue;
- // flag moving fast
- animations[FLAG_RUN].firstFrame = 0;
- animations[FLAG_RUN].numFrames = 16;
- animations[FLAG_RUN].loopFrames = 16;
- animations[FLAG_RUN].frameLerp = 1000 / 15;
- animations[FLAG_RUN].initialLerp = 1000 / 15;
- animations[FLAG_RUN].reversed = qfalse;
- // flag not moving or moving slowly
- animations[FLAG_STAND].firstFrame = 16;
- animations[FLAG_STAND].numFrames = 5;
- animations[FLAG_STAND].loopFrames = 0;
- animations[FLAG_STAND].frameLerp = 1000 / 20;
- animations[FLAG_STAND].initialLerp = 1000 / 20;
- animations[FLAG_STAND].reversed = qfalse;
- // flag speeding up
- animations[FLAG_STAND2RUN].firstFrame = 16;
- animations[FLAG_STAND2RUN].numFrames = 5;
- animations[FLAG_STAND2RUN].loopFrames = 1;
- animations[FLAG_STAND2RUN].frameLerp = 1000 / 15;
- animations[FLAG_STAND2RUN].initialLerp = 1000 / 15;
- animations[FLAG_STAND2RUN].reversed = qtrue;
- //
- // new anims changes
- //
-// animations[TORSO_GETFLAG].flipflop = qtrue;
-// animations[TORSO_GUARDBASE].flipflop = qtrue;
-// animations[TORSO_PATROL].flipflop = qtrue;
-// animations[TORSO_AFFIRMATIVE].flipflop = qtrue;
-// animations[TORSO_NEGATIVE].flipflop = qtrue;
- //
- return qtrue;
-}
-
-/*
-==========================
-CG_FileExists
-==========================
-*/
-static qboolean CG_FileExists(const char *filename) {
- int len;
-
- len = trap_FS_FOpenFile( filename, 0, FS_READ );
- if (len>0) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-==========================
-CG_FindClientModelFile
-==========================
-*/
-static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) {
- char *team, *charactersFolder;
- int i;
-
- if ( cgs.gametype >= GT_TEAM ) {
- switch ( ci->team ) {
- case TEAM_BLUE: {
- team = "blue";
- break;
- }
- default: {
- team = "red";
- break;
- }
- }
- }
- else {
- team = "default";
- }
- charactersFolder = "";
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/james/stroggs/lower_lily_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext );
- }
- else {
- // "models/players/characters/james/lower_lily_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext );
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( cgs.gametype >= GT_TEAM ) {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/james/stroggs/lower_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext );
- }
- else {
- // "models/players/characters/james/lower_red.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext );
- }
- }
- else {
- if ( i == 0 && teamName && *teamName ) {
- // "models/players/characters/james/stroggs/lower_lily.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext );
- }
- else {
- // "models/players/characters/james/lower_lily.skin"
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext );
- }
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( charactersFolder[0] ) {
- break;
- }
- charactersFolder = "characters/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-CG_FindClientHeadFile
-==========================
-*/
-static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
- char *team, *headsFolder;
- int i;
-
- if ( cgs.gametype >= GT_TEAM ) {
- switch ( ci->team ) {
- case TEAM_BLUE: {
- team = "blue";
- break;
- }
- default: {
- team = "red";
- break;
- }
- }
- }
- else {
- team = "default";
- }
-
- if ( headModelName[0] == '*' ) {
- headsFolder = "heads/";
- headModelName++;
- }
- else {
- headsFolder = "";
- }
- while(1) {
- for ( i = 0; i < 2; i++ ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( cgs.gametype >= GT_TEAM ) {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext );
- }
- }
- else {
- if ( i == 0 && teamName && *teamName ) {
- Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
- }
- else {
- Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
- }
- }
- if ( CG_FileExists( filename ) ) {
- return qtrue;
- }
- if ( !teamName || !*teamName ) {
- break;
- }
- }
- // if tried the heads folder first
- if ( headsFolder[0] ) {
- break;
- }
- headsFolder = "heads/";
- }
-
- return qfalse;
-}
-
-/*
-==========================
-CG_RegisterClientSkin
-==========================
-*/
-static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) {
- char filename[MAX_QPATH];
-
- /*
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName );
- ci->legsSkin = trap_R_RegisterSkin( filename );
- if (!ci->legsSkin) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName );
- ci->legsSkin = trap_R_RegisterSkin( filename );
- if (!ci->legsSkin) {
- Com_Printf( "Leg skin load failure: %s\n", filename );
- }
- }
-
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName );
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- if (!ci->torsoSkin) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName );
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- if (!ci->torsoSkin) {
- Com_Printf( "Torso skin load failure: %s\n", filename );
- }
- }
- */
- if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) {
- ci->legsSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->legsSkin) {
- Com_Printf( "Leg skin load failure: %s\n", filename );
- }
-
- if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) {
- ci->torsoSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->torsoSkin) {
- Com_Printf( "Torso skin load failure: %s\n", filename );
- }
-
- if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) {
- ci->headSkin = trap_R_RegisterSkin( filename );
- }
- if (!ci->headSkin) {
- Com_Printf( "Head skin load failure: %s\n", filename );
- }
-
- // if any skins failed to load
- if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-==========================
-CG_RegisterClientModelname
-==========================
-*/
-static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {
- char filename[MAX_QPATH*2];
- const char *headName;
- char newTeamName[MAX_QPATH*2];
-
- if ( headModelName[0] == '\0' ) {
- headName = modelName;
- }
- else {
- headName = headModelName;
- }
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
- ci->legsModel = trap_R_RegisterModel( filename );
- if ( !ci->legsModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
- ci->legsModel = trap_R_RegisterModel( filename );
- if ( !ci->legsModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
- ci->torsoModel = trap_R_RegisterModel( filename );
- if ( !ci->torsoModel ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
- ci->torsoModel = trap_R_RegisterModel( filename );
- if ( !ci->torsoModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
- }
-
- if( headName[0] == '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
- }
- else {
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName );
- }
- ci->headModel = trap_R_RegisterModel( filename );
- // if the head model could not be found and we didn't load from the heads folder try to load from there
- if ( !ci->headModel && headName[0] != '*' ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
- ci->headModel = trap_R_RegisterModel( filename );
- }
- if ( !ci->headModel ) {
- Com_Printf( "Failed to load model file %s\n", filename );
- return qfalse;
- }
-
- // if any skins failed to load, return failure
- if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {
- if ( teamName && *teamName) {
- Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName );
- if( ci->team == TEAM_BLUE ) {
- Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME);
- }
- else {
- Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME);
- }
- if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {
- Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName );
- return qfalse;
- }
- } else {
- Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName );
- return qfalse;
- }
- }
-
- // load the animations
- Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
- if ( !CG_ParseAnimationFile( filename, ci ) ) {
- Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
- if ( !CG_ParseAnimationFile( filename, ci ) ) {
- Com_Printf( "Failed to load animation file %s\n", filename );
- return qfalse;
- }
- }
-
- if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) {
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- }
- else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) {
- ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
- }
-
- if ( !ci->modelIcon ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-====================
-CG_ColorFromString
-====================
-*/
-static void CG_ColorFromString( const char *v, vec3_t color ) {
- int val;
-
- VectorClear( color );
-
- val = atoi( v );
-
- if ( val < 1 || val > 7 ) {
- VectorSet( color, 1, 1, 1 );
- return;
- }
-
- if ( val & 1 ) {
- color[2] = 1.0f;
- }
- if ( val & 2 ) {
- color[1] = 1.0f;
- }
- if ( val & 4 ) {
- color[0] = 1.0f;
- }
-}
-
-/*
-===================
-CG_LoadClientInfo
-
-Load it now, taking the disk hits.
-This will usually be deferred to a safe time
-===================
-*/
-static void CG_LoadClientInfo( clientInfo_t *ci ) {
- const char *dir, *fallback;
- int i, modelloaded;
- const char *s;
- int clientNum;
- char teamname[MAX_QPATH];
-
- teamname[0] = 0;
-#ifdef MISSIONPACK
- if( cgs.gametype >= GT_TEAM) {
- if( ci->team == TEAM_BLUE ) {
- Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) );
- } else {
- Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) );
- }
- }
- if( teamname[0] ) {
- strcat( teamname, "/" );
- }
-#endif
- modelloaded = qtrue;
- if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {
- if ( cg_buildScript.integer ) {
- CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
- }
-
- // fall back to default team name
- if( cgs.gametype >= GT_TEAM) {
- // keep skin name
- if( ci->team == TEAM_BLUE ) {
- Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
- } else {
- Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
- }
- if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {
- CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName );
- }
- } else {
- if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) {
- CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
- }
- }
- modelloaded = qfalse;
- }
-
- ci->newAnims = qfalse;
- if ( ci->torsoModel ) {
- orientation_t tag;
- // if the torso model has the "tag_flag"
- if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
- ci->newAnims = qtrue;
- }
- }
-
- // sounds
- dir = ci->modelName;
- fallback = (cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;
-
- for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {
- s = cg_customSoundNames[i];
- if ( !s ) {
- break;
- }
- ci->sounds[i] = 0;
- // if the model didn't load use the sounds of the default model
- if (modelloaded) {
- ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse );
- }
- if ( !ci->sounds[i] ) {
- ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse );
- }
- }
-
- ci->deferred = qfalse;
-
- // reset any existing players and bodies, because they might be in bad
- // frames for this new model
- clientNum = ci - cgs.clientinfo;
- for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
- if ( cg_entities[i].currentState.clientNum == clientNum
- && cg_entities[i].currentState.eType == ET_PLAYER ) {
- CG_ResetPlayerEntity( &cg_entities[i] );
- }
- }
-}
-
-/*
-======================
-CG_CopyClientInfoModel
-======================
-*/
-static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {
- VectorCopy( from->headOffset, to->headOffset );
- to->footsteps = from->footsteps;
- to->gender = from->gender;
-
- to->legsModel = from->legsModel;
- to->legsSkin = from->legsSkin;
- to->torsoModel = from->torsoModel;
- to->torsoSkin = from->torsoSkin;
- to->headModel = from->headModel;
- to->headSkin = from->headSkin;
- to->modelIcon = from->modelIcon;
-
- to->newAnims = from->newAnims;
-
- memcpy( to->animations, from->animations, sizeof( to->animations ) );
- memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
-}
-
-/*
-======================
-CG_ScanForExistingClientInfo
-======================
-*/
-static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {
- int i;
- clientInfo_t *match;
-
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid ) {
- continue;
- }
- if ( match->deferred ) {
- continue;
- }
- if ( !Q_stricmp( ci->modelName, match->modelName )
- && !Q_stricmp( ci->skinName, match->skinName )
- && !Q_stricmp( ci->headModelName, match->headModelName )
- && !Q_stricmp( ci->headSkinName, match->headSkinName )
- && !Q_stricmp( ci->blueTeam, match->blueTeam )
- && !Q_stricmp( ci->redTeam, match->redTeam )
- && (cgs.gametype < GT_TEAM || ci->team == match->team) ) {
- // this clientinfo is identical, so use it's handles
-
- ci->deferred = qfalse;
-
- CG_CopyClientInfoModel( match, ci );
-
- return qtrue;
- }
- }
-
- // nothing matches, so defer the load
- return qfalse;
-}
-
-/*
-======================
-CG_SetDeferredClientInfo
-
-We aren't going to load it now, so grab some other
-client's info to use until we have some spare time.
-======================
-*/
-static void CG_SetDeferredClientInfo( clientInfo_t *ci ) {
- int i;
- clientInfo_t *match;
-
- // if someone else is already the same models and skins we
- // can just load the client info
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid || match->deferred ) {
- continue;
- }
- if ( Q_stricmp( ci->skinName, match->skinName ) ||
- Q_stricmp( ci->modelName, match->modelName ) ||
-// Q_stricmp( ci->headModelName, match->headModelName ) ||
-// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
- (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
- continue;
- }
- // just load the real info cause it uses the same models and skins
- CG_LoadClientInfo( ci );
- return;
- }
-
- // if we are in teamplay, only grab a model if the skin is correct
- if ( cgs.gametype >= GT_TEAM ) {
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid || match->deferred ) {
- continue;
- }
- if ( Q_stricmp( ci->skinName, match->skinName ) ||
- (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
- continue;
- }
- ci->deferred = qtrue;
- CG_CopyClientInfoModel( match, ci );
- return;
- }
- // load the full model, because we don't ever want to show
- // an improper team skin. This will cause a hitch for the first
- // player, when the second enters. Combat shouldn't be going on
- // yet, so it shouldn't matter
- CG_LoadClientInfo( ci );
- return;
- }
-
- // find the first valid clientinfo and grab its stuff
- for ( i = 0 ; i < cgs.maxclients ; i++ ) {
- match = &cgs.clientinfo[ i ];
- if ( !match->infoValid ) {
- continue;
- }
-
- ci->deferred = qtrue;
- CG_CopyClientInfoModel( match, ci );
- return;
- }
-
- // we should never get here...
- CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
-
- CG_LoadClientInfo( ci );
-}
-
-
-/*
-======================
-CG_NewClientInfo
-======================
-*/
-void CG_NewClientInfo( int clientNum ) {
- clientInfo_t *ci;
- clientInfo_t newInfo;
- const char *configstring;
- const char *v;
- char *slash;
-
- ci = &cgs.clientinfo[clientNum];
-
- configstring = CG_ConfigString( clientNum + CS_PLAYERS );
- if ( !configstring[0] ) {
- memset( ci, 0, sizeof( *ci ) );
- return; // player just left
- }
-
- // build into a temp buffer so the defer checks can use
- // the old value
- memset( &newInfo, 0, sizeof( newInfo ) );
-
- // isolate the player's name
- v = Info_ValueForKey(configstring, "n");
- Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
-
- // colors
- v = Info_ValueForKey( configstring, "c1" );
- CG_ColorFromString( v, newInfo.color1 );
-
- v = Info_ValueForKey( configstring, "c2" );
- CG_ColorFromString( v, newInfo.color2 );
-
- // bot skill
- v = Info_ValueForKey( configstring, "skill" );
- newInfo.botSkill = atoi( v );
-
- // handicap
- v = Info_ValueForKey( configstring, "hc" );
- newInfo.handicap = atoi( v );
-
- // wins
- v = Info_ValueForKey( configstring, "w" );
- newInfo.wins = atoi( v );
-
- // losses
- v = Info_ValueForKey( configstring, "l" );
- newInfo.losses = atoi( v );
-
- // team
- v = Info_ValueForKey( configstring, "t" );
- newInfo.team = atoi( v );
-
- // team task
- v = Info_ValueForKey( configstring, "tt" );
- newInfo.teamTask = atoi(v);
-
- // team leader
- v = Info_ValueForKey( configstring, "tl" );
- newInfo.teamLeader = atoi(v);
-
- v = Info_ValueForKey( configstring, "g_redteam" );
- Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
-
- v = Info_ValueForKey( configstring, "g_blueteam" );
- Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
-
- // model
- v = Info_ValueForKey( configstring, "model" );
- if ( cg_forceModel.integer ) {
- // forcemodel makes everyone use a single model
- // to prevent load hitches
- char modelStr[MAX_QPATH];
- char *skin;
-
- if( cgs.gametype >= GT_TEAM ) {
- Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- } else {
- trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
- skin = "default";
- } else {
- *skin++ = 0;
- }
-
- Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
- Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- }
- }
- } else {
- Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );
-
- slash = strchr( newInfo.modelName, '/' );
- if ( !slash ) {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
- } else {
- Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
- // truncate modelName
- *slash = 0;
- }
- }
-
- // head model
- v = Info_ValueForKey( configstring, "hmodel" );
- if ( cg_forceModel.integer ) {
- // forcemodel makes everyone use a single model
- // to prevent load hitches
- char modelStr[MAX_QPATH];
- char *skin;
-
- if( cgs.gametype >= GT_TEAM ) {
- Q_strncpyz( newInfo.headModelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.headModelName ) );
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- } else {
- trap_Cvar_VariableStringBuffer( "headmodel", modelStr, sizeof( modelStr ) );
- if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
- skin = "default";
- } else {
- *skin++ = 0;
- }
-
- Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );
- Q_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) );
- }
-
- if ( cgs.gametype >= GT_TEAM ) {
- // keep skin name
- slash = strchr( v, '/' );
- if ( slash ) {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- }
- }
- } else {
- Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );
-
- slash = strchr( newInfo.headModelName, '/' );
- if ( !slash ) {
- // modelName didn not include a skin name
- Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
- } else {
- Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
- // truncate modelName
- *slash = 0;
- }
- }
-
- // scan for an existing clientinfo that matches this modelname
- // so we can avoid loading checks if possible
- if ( !CG_ScanForExistingClientInfo( &newInfo ) ) {
- qboolean forceDefer;
-
- forceDefer = trap_MemoryRemaining() < 4000000;
-
- // if we are defering loads, just have it pick the first valid
- if ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) {
- // keep whatever they had if it won't violate team skins
- CG_SetDeferredClientInfo( &newInfo );
- // if we are low on memory, leave them with this model
- if ( forceDefer ) {
- CG_Printf( "Memory is low. Using deferred model.\n" );
- newInfo.deferred = qfalse;
- }
- } else {
- CG_LoadClientInfo( &newInfo );
- }
- }
-
- // replace whatever was there with the new one
- newInfo.infoValid = qtrue;
- *ci = newInfo;
-}
-
-
-
-/*
-======================
-CG_LoadDeferredPlayers
-
-Called each frame when a player is dead
-and the scoreboard is up
-so deferred players can be loaded
-======================
-*/
-void CG_LoadDeferredPlayers( void ) {
- int i;
- clientInfo_t *ci;
-
- // scan for a deferred player to load
- for ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {
- if ( ci->infoValid && ci->deferred ) {
- // if we are low on memory, leave it deferred
- if ( trap_MemoryRemaining() < 4000000 ) {
- CG_Printf( "Memory is low. Using deferred model.\n" );
- ci->deferred = qfalse;
- continue;
- }
- CG_LoadClientInfo( ci );
-// break;
- }
- }
-}
-
-/*
-=============================================================================
-
-PLAYER ANIMATION
-
-=============================================================================
-*/
-
-
-/*
-===============
-CG_SetLerpFrameAnimation
-
-may include ANIM_TOGGLEBIT
-===============
-*/
-static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
- newAnimation &= ~ANIM_TOGGLEBIT;
-
- if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
- CG_Error( "Bad animation number: %i", newAnimation );
- }
-
- anim = &ci->animations[ newAnimation ];
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-
- if ( cg_debugAnim.integer ) {
- CG_Printf( "Anim: %i\n", newAnimation );
- }
-}
-
-/*
-===============
-CG_RunLerpFrame
-
-Sets cg.snap, cg.oldFrame, and cg.backlerp
-cg.time should be between oldFrameTime and frameTime after exit
-===============
-*/
-static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) {
- int f, numFrames;
- animation_t *anim;
-
- // debugging tool to get no animations
- if ( cg_animSpeed.integer == 0 ) {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
- // see if the animation sequence is switching
- if ( newAnimation != lf->animationNumber || !lf->animation ) {
- CG_SetLerpFrameAnimation( ci, lf, newAnimation );
- }
-
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if ( cg.time >= lf->frameTime ) {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
-
- // get the next frame based on the animation
- anim = lf->animation;
- if ( !anim->frameLerp ) {
- return; // shouldn't happen
- }
- if ( cg.time < lf->animationTime ) {
- lf->frameTime = lf->animationTime; // initial lerp
- } else {
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
- }
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- f *= speedScale; // adjust for haste, etc
-
- numFrames = anim->numFrames;
- if (anim->flipflop) {
- numFrames *= 2;
- }
- if ( f >= numFrames ) {
- f -= numFrames;
- if ( anim->loopFrames ) {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- } else {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- }
- }
- if ( anim->reversed ) {
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- }
- else if (anim->flipflop && f>=anim->numFrames) {
- lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
- }
- else {
- lf->frame = anim->firstFrame + f;
- }
- if ( cg.time > lf->frameTime ) {
- lf->frameTime = cg.time;
- if ( cg_debugAnim.integer ) {
- CG_Printf( "Clamp lf->frameTime\n");
- }
- }
- }
-
- if ( lf->frameTime > cg.time + 200 ) {
- lf->frameTime = cg.time;
- }
-
- if ( lf->oldFrameTime > cg.time ) {
- lf->oldFrameTime = cg.time;
- }
- // calculate current lerp value
- if ( lf->frameTime == lf->oldFrameTime ) {
- lf->backlerp = 0;
- } else {
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
- }
-}
-
-
-/*
-===============
-CG_ClearLerpFrame
-===============
-*/
-static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) {
- lf->frameTime = lf->oldFrameTime = cg.time;
- CG_SetLerpFrameAnimation( ci, lf, animationNumber );
- lf->oldFrame = lf->frame = lf->animation->firstFrame;
-}
-
-
-/*
-===============
-CG_PlayerAnimation
-===============
-*/
-static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,
- int *torsoOld, int *torso, float *torsoBackLerp ) {
- clientInfo_t *ci;
- int clientNum;
- float speedScale;
-
- clientNum = cent->currentState.clientNum;
-
- if ( cg_noPlayerAnims.integer ) {
- *legsOld = *legs = *torsoOld = *torso = 0;
- return;
- }
-
- if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) {
- speedScale = 1.5;
- } else {
- speedScale = 1;
- }
-
- ci = &cgs.clientinfo[ clientNum ];
-
- // do the shuffle turn frames locally
- if ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
- CG_RunLerpFrame( ci, &cent->pe.legs, LEGS_TURN, speedScale );
- } else {
- CG_RunLerpFrame( ci, &cent->pe.legs, cent->currentState.legsAnim, speedScale );
- }
-
- *legsOld = cent->pe.legs.oldFrame;
- *legs = cent->pe.legs.frame;
- *legsBackLerp = cent->pe.legs.backlerp;
-
- CG_RunLerpFrame( ci, &cent->pe.torso, cent->currentState.torsoAnim, speedScale );
-
- *torsoOld = cent->pe.torso.oldFrame;
- *torso = cent->pe.torso.frame;
- *torsoBackLerp = cent->pe.torso.backlerp;
-}
-
-/*
-=============================================================================
-
-PLAYER ANGLES
-
-=============================================================================
-*/
-
-/*
-==================
-CG_SwingAngles
-==================
-*/
-static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance,
- float speed, float *angle, qboolean *swinging ) {
- float swing;
- float move;
- float scale;
-
- if ( !*swinging ) {
- // see if a swing should be started
- swing = AngleSubtract( *angle, destination );
- if ( swing > swingTolerance || swing < -swingTolerance ) {
- *swinging = qtrue;
- }
- }
-
- if ( !*swinging ) {
- return;
- }
-
- // modify the speed depending on the delta
- // so it doesn't seem so linear
- swing = AngleSubtract( destination, *angle );
- scale = fabs( swing );
- if ( scale < swingTolerance * 0.5 ) {
- scale = 0.5;
- } else if ( scale < swingTolerance ) {
- scale = 1.0;
- } else {
- scale = 2.0;
- }
-
- // swing towards the destination angle
- if ( swing >= 0 ) {
- move = cg.frametime * scale * speed;
- if ( move >= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- } else if ( swing < 0 ) {
- move = cg.frametime * scale * -speed;
- if ( move <= swing ) {
- move = swing;
- *swinging = qfalse;
- }
- *angle = AngleMod( *angle + move );
- }
-
- // clamp to no more than tolerance
- swing = AngleSubtract( destination, *angle );
- if ( swing > clampTolerance ) {
- *angle = AngleMod( destination - (clampTolerance - 1) );
- } else if ( swing < -clampTolerance ) {
- *angle = AngleMod( destination + (clampTolerance - 1) );
- }
-}
-
-/*
-=================
-CG_AddPainTwitch
-=================
-*/
-static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) {
- int t;
- float f;
-
- t = cg.time - cent->pe.painTime;
- if ( t >= PAIN_TWITCH_TIME ) {
- return;
- }
-
- f = 1.0 - (float)t / PAIN_TWITCH_TIME;
-
- if ( cent->pe.painDirection ) {
- torsoAngles[ROLL] += 20 * f;
- } else {
- torsoAngles[ROLL] -= 20 * f;
- }
-}
-
-
-/*
-===============
-CG_PlayerAngles
-
-Handles seperate torso motion
-
- legs pivot based on direction of movement
-
- head always looks exactly at cent->lerpAngles
-
- if motion < 20 degrees, show in head only
- if < 45 degrees, also show in torso
-===============
-*/
-static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
- vec3_t legsAngles, torsoAngles, headAngles;
- float dest;
- static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };
- vec3_t velocity;
- float speed;
- int dir, clientNum;
- clientInfo_t *ci;
-
- VectorCopy( cent->lerpAngles, headAngles );
- headAngles[YAW] = AngleMod( headAngles[YAW] );
- VectorClear( legsAngles );
- VectorClear( torsoAngles );
-
- // --------- yaw -------------
-
- // allow yaw to drift a bit
- if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
- || ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
- // if not standing still, always point all in the same direction
- cent->pe.torso.yawing = qtrue; // always center
- cent->pe.torso.pitching = qtrue; // always center
- cent->pe.legs.yawing = qtrue; // always center
- }
-
- // adjust legs for movement dir
- if ( cent->currentState.eFlags & EF_DEAD ) {
- // don't let dead bodies twitch
- dir = 0;
- } else {
- dir = cent->currentState.angles2[YAW];
- if ( dir < 0 || dir > 7 ) {
- CG_Error( "Bad player movement angle" );
- }
- }
- legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ];
- torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ];
-
- // torso
- CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, &cent->pe.torso.yawAngle, &cent->pe.torso.yawing );
- CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, &cent->pe.legs.yawAngle, &cent->pe.legs.yawing );
-
- torsoAngles[YAW] = cent->pe.torso.yawAngle;
- legsAngles[YAW] = cent->pe.legs.yawAngle;
-
-
- // --------- pitch -------------
-
- // only show a fraction of the pitch angle in the torso
- if ( headAngles[PITCH] > 180 ) {
- dest = (-360 + headAngles[PITCH]) * 0.75f;
- } else {
- dest = headAngles[PITCH] * 0.75f;
- }
- CG_SwingAngles( dest, 15, 30, 0.1f, &cent->pe.torso.pitchAngle, &cent->pe.torso.pitching );
- torsoAngles[PITCH] = cent->pe.torso.pitchAngle;
-
- //
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- if ( ci->fixedtorso ) {
- torsoAngles[PITCH] = 0.0f;
- }
- }
-
- // --------- roll -------------
-
-
- // lean towards the direction of travel
- VectorCopy( cent->currentState.pos.trDelta, velocity );
- speed = VectorNormalize( velocity );
- if ( speed ) {
- vec3_t axis[3];
- float side;
-
- speed *= 0.05f;
-
- AnglesToAxis( legsAngles, axis );
- side = speed * DotProduct( velocity, axis[1] );
- legsAngles[ROLL] -= side;
-
- side = speed * DotProduct( velocity, axis[0] );
- legsAngles[PITCH] += side;
- }
-
- //
- clientNum = cent->currentState.clientNum;
- if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
- ci = &cgs.clientinfo[ clientNum ];
- if ( ci->fixedlegs ) {
- legsAngles[YAW] = torsoAngles[YAW];
- legsAngles[PITCH] = 0.0f;
- legsAngles[ROLL] = 0.0f;
- }
- }
-
- // pain twitch
- CG_AddPainTwitch( cent, torsoAngles );
-
- // pull the angles back out of the hierarchial chain
- AnglesSubtract( headAngles, torsoAngles, headAngles );
- AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
- AnglesToAxis( legsAngles, legs );
- AnglesToAxis( torsoAngles, torso );
- AnglesToAxis( headAngles, head );
-}
-
-
-//==========================================================================
-
-/*
-===============
-CG_HasteTrail
-===============
-*/
-static void CG_HasteTrail( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- int anim;
-
- if ( cent->trailTime > cg.time ) {
- return;
- }
- anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
- if ( anim != LEGS_RUN && anim != LEGS_BACK ) {
- return;
- }
-
- cent->trailTime += 100;
- if ( cent->trailTime < cg.time ) {
- cent->trailTime = cg.time;
- }
-
- VectorCopy( cent->lerpOrigin, origin );
- origin[2] -= 16;
-
- smoke = CG_SmokePuff( origin, vec3_origin,
- 8,
- 1, 1, 1, 1,
- 500,
- cg.time,
- 0,
- 0,
- cgs.media.hastePuffShader );
-
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
-}
-
-#ifdef MISSIONPACK
-/*
-===============
-CG_BreathPuffs
-===============
-*/
-static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) {
- clientInfo_t *ci;
- vec3_t up, origin;
- int contents;
-
- ci = &cgs.clientinfo[ cent->currentState.number ];
-
- if (!cg_enableBreath.integer) {
- return;
- }
- if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) {
- return;
- }
- if ( cent->currentState.eFlags & EF_DEAD ) {
- return;
- }
- contents = trap_CM_PointContents( head->origin, 0 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
- if ( ci->breathPuffTime > cg.time ) {
- return;
- }
-
- VectorSet( up, 0, 0, 8 );
- VectorMA(head->origin, 8, head->axis[0], origin);
- VectorMA(origin, -4, head->axis[2], origin);
- CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
- ci->breathPuffTime = cg.time + 2000;
-}
-
-/*
-===============
-CG_DustTrail
-===============
-*/
-static void CG_DustTrail( centity_t *cent ) {
- int anim;
- localEntity_t *dust;
- vec3_t end, vel;
- trace_t tr;
-
- if (!cg_enableDust.integer)
- return;
-
- if ( cent->dustTrailTime > cg.time ) {
- return;
- }
-
- anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
- if ( anim != LEGS_LANDB && anim != LEGS_LAND ) {
- return;
- }
-
- cent->dustTrailTime += 40;
- if ( cent->dustTrailTime < cg.time ) {
- cent->dustTrailTime = cg.time;
- }
-
- VectorCopy(cent->currentState.pos.trBase, end);
- end[2] -= 64;
- CG_Trace( &tr, cent->currentState.pos.trBase, NULL, NULL, end, cent->currentState.number, MASK_PLAYERSOLID );
-
- if ( !(tr.surfaceFlags & SURF_DUST) )
- return;
-
- VectorCopy( cent->currentState.pos.trBase, end );
- end[2] -= 16;
-
- VectorSet(vel, 0, 0, -30);
- dust = CG_SmokePuff( end, vel,
- 24,
- .8f, .8f, 0.7f, 0.33f,
- 500,
- cg.time,
- 0,
- 0,
- cgs.media.dustPuffShader );
-}
-
-#endif
-
-/*
-===============
-CG_TrailItem
-===============
-*/
-static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {
- refEntity_t ent;
- vec3_t angles;
- vec3_t axis[3];
-
- VectorCopy( cent->lerpAngles, angles );
- angles[PITCH] = 0;
- angles[ROLL] = 0;
- AnglesToAxis( angles, axis );
-
- memset( &ent, 0, sizeof( ent ) );
- VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );
- ent.origin[2] += 16;
- angles[YAW] += 90;
- AnglesToAxis( angles, ent.axis );
-
- ent.hModel = hModel;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-===============
-CG_PlayerFlag
-===============
-*/
-static void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) {
- clientInfo_t *ci;
- refEntity_t pole;
- refEntity_t flag;
- vec3_t angles, dir;
- int legsAnim, flagAnim, updateangles;
- float angle, d;
-
- // show the flag pole model
- memset( &pole, 0, sizeof(pole) );
- pole.hModel = cgs.media.flagPoleModel;
- VectorCopy( torso->lightingOrigin, pole.lightingOrigin );
- pole.shadowPlane = torso->shadowPlane;
- pole.renderfx = torso->renderfx;
- CG_PositionEntityOnTag( &pole, torso, torso->hModel, "tag_flag" );
- trap_R_AddRefEntityToScene( &pole );
-
- // show the flag model
- memset( &flag, 0, sizeof(flag) );
- flag.hModel = cgs.media.flagFlapModel;
- flag.customSkin = hSkin;
- VectorCopy( torso->lightingOrigin, flag.lightingOrigin );
- flag.shadowPlane = torso->shadowPlane;
- flag.renderfx = torso->renderfx;
-
- VectorClear(angles);
-
- updateangles = qfalse;
- legsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) {
- flagAnim = FLAG_STAND;
- } else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) {
- flagAnim = FLAG_STAND;
- updateangles = qtrue;
- } else {
- flagAnim = FLAG_RUN;
- updateangles = qtrue;
- }
-
- if ( updateangles ) {
-
- VectorCopy( cent->currentState.pos.trDelta, dir );
- // add gravity
- dir[2] += 100;
- VectorNormalize( dir );
- d = DotProduct(pole.axis[2], dir);
- // if there is anough movement orthogonal to the flag pole
- if (fabs(d) < 0.9) {
- //
- d = DotProduct(pole.axis[0], dir);
- if (d > 1.0f) {
- d = 1.0f;
- }
- else if (d < -1.0f) {
- d = -1.0f;
- }
- angle = acos(d);
-
- d = DotProduct(pole.axis[1], dir);
- if (d < 0) {
- angles[YAW] = 360 - angle * 180 / M_PI;
- }
- else {
- angles[YAW] = angle * 180 / M_PI;
- }
- if (angles[YAW] < 0)
- angles[YAW] += 360;
- if (angles[YAW] > 360)
- angles[YAW] -= 360;
-
- //vectoangles( cent->currentState.pos.trDelta, tmpangles );
- //angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle;
- // change the yaw angle
- CG_SwingAngles( angles[YAW], 25, 90, 0.15f, &cent->pe.flag.yawAngle, &cent->pe.flag.yawing );
- }
-
- /*
- d = DotProduct(pole.axis[2], dir);
- angle = Q_acos(d);
-
- d = DotProduct(pole.axis[1], dir);
- if (d < 0) {
- angle = 360 - angle * 180 / M_PI;
- }
- else {
- angle = angle * 180 / M_PI;
- }
- if (angle > 340 && angle < 20) {
- flagAnim = FLAG_RUNUP;
- }
- if (angle > 160 && angle < 200) {
- flagAnim = FLAG_RUNDOWN;
- }
- */
- }
-
- // set the yaw angle
- angles[YAW] = cent->pe.flag.yawAngle;
- // lerp the flag animation frames
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RunLerpFrame( ci, &cent->pe.flag, flagAnim, 1 );
- flag.oldframe = cent->pe.flag.oldFrame;
- flag.frame = cent->pe.flag.frame;
- flag.backlerp = cent->pe.flag.backlerp;
-
- AnglesToAxis( angles, flag.axis );
- CG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, "tag_flag" );
-
- trap_R_AddRefEntityToScene( &flag );
-}
-
-
-#ifdef MISSIONPACK // bk001204
-/*
-===============
-CG_PlayerTokens
-===============
-*/
-static void CG_PlayerTokens( centity_t *cent, int renderfx ) {
- int tokens, i, j;
- float angle;
- refEntity_t ent;
- vec3_t dir, origin;
- skulltrail_t *trail;
- trail = &cg.skulltrails[cent->currentState.number];
- tokens = cent->currentState.generic1;
- if ( !tokens ) {
- trail->numpositions = 0;
- return;
- }
-
- if ( tokens > MAX_SKULLTRAIL ) {
- tokens = MAX_SKULLTRAIL;
- }
-
- // add skulls if there are more than last time
- for (i = 0; i < tokens - trail->numpositions; i++) {
- for (j = trail->numpositions; j > 0; j--) {
- VectorCopy(trail->positions[j-1], trail->positions[j]);
- }
- VectorCopy(cent->lerpOrigin, trail->positions[0]);
- }
- trail->numpositions = tokens;
-
- // move all the skulls along the trail
- VectorCopy(cent->lerpOrigin, origin);
- for (i = 0; i < trail->numpositions; i++) {
- VectorSubtract(trail->positions[i], origin, dir);
- if (VectorNormalize(dir) > 30) {
- VectorMA(origin, 30, dir, trail->positions[i]);
- }
- VectorCopy(trail->positions[i], origin);
- }
-
- memset( &ent, 0, sizeof( ent ) );
- if( cgs.clientinfo[ cent->currentState.clientNum ].team == TEAM_BLUE ) {
- ent.hModel = cgs.media.redCubeModel;
- } else {
- ent.hModel = cgs.media.blueCubeModel;
- }
- ent.renderfx = renderfx;
-
- VectorCopy(cent->lerpOrigin, origin);
- for (i = 0; i < trail->numpositions; i++) {
- VectorSubtract(origin, trail->positions[i], ent.axis[0]);
- ent.axis[0][2] = 0;
- VectorNormalize(ent.axis[0]);
- VectorSet(ent.axis[2], 0, 0, 1);
- CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]);
-
- VectorCopy(trail->positions[i], ent.origin);
- angle = (((cg.time + 500 * MAX_SKULLTRAIL - 500 * i) / 16) & 255) * (M_PI * 2) / 255;
- ent.origin[2] += sin(angle) * 10;
- trap_R_AddRefEntityToScene( &ent );
- VectorCopy(trail->positions[i], origin);
- }
-}
-#endif
-
-
-/*
-===============
-CG_PlayerPowerups
-===============
-*/
-static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {
- int powerups;
- clientInfo_t *ci;
-
- powerups = cent->currentState.powerups;
- if ( !powerups ) {
- return;
- }
-
- // quad gives a dlight
- if ( powerups & ( 1 << PW_QUAD ) ) {
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );
- }
-
- // flight plays a looped sound
- if ( powerups & ( 1 << PW_FLIGHT ) ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound );
- }
-
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- // redflag
- if ( powerups & ( 1 << PW_REDFLAG ) ) {
- if (ci->newAnims) {
- CG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.redFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );
- }
-
- // blueflag
- if ( powerups & ( 1 << PW_BLUEFLAG ) ) {
- if (ci->newAnims){
- CG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.blueFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );
- }
-
- // neutralflag
- if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if (ci->newAnims) {
- CG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso );
- }
- else {
- CG_TrailItem( cent, cgs.media.neutralFlagModel );
- }
- trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );
- }
-
- // haste leaves smoke trails
- if ( powerups & ( 1 << PW_HASTE ) ) {
- CG_HasteTrail( cent );
- }
-}
-
-
-/*
-===============
-CG_PlayerFloatSprite
-
-Float a sprite over the player's head
-===============
-*/
-static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
- int rf;
- refEntity_t ent;
-
- if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
- rf = RF_THIRD_PERSON; // only show in mirrors
- } else {
- rf = 0;
- }
-
- memset( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin );
- ent.origin[2] += 48;
- ent.reType = RT_SPRITE;
- ent.customShader = shader;
- ent.radius = 10;
- ent.renderfx = rf;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 255;
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-
-/*
-===============
-CG_PlayerSprites
-
-Float sprites over the player's head
-===============
-*/
-static void CG_PlayerSprites( centity_t *cent ) {
- int team;
-
- if ( cent->currentState.eFlags & EF_CONNECTION ) {
- CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_TALK ) {
- CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalImpressive );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalExcellent );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalDefend );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalAssist );
- return;
- }
-
- if ( cent->currentState.eFlags & EF_AWARD_CAP ) {
- CG_PlayerFloatSprite( cent, cgs.media.medalCapture );
- return;
- }
-
- team = cgs.clientinfo[ cent->currentState.clientNum ].team;
- if ( !(cent->currentState.eFlags & EF_DEAD) &&
- cg.snap->ps.persistant[PERS_TEAM] == team &&
- cgs.gametype >= GT_TEAM) {
- if (cg_drawFriend.integer) {
- CG_PlayerFloatSprite( cent, cgs.media.friendShader );
- }
- return;
- }
-}
-
-/*
-===============
-CG_PlayerShadow
-
-Returns the Z component of the surface being shadowed
-
- should it return a full plane instead of a Z?
-===============
-*/
-#define SHADOW_DISTANCE 128
-static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
- vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
- trace_t trace;
- float alpha;
-
- *shadowPlane = 0;
-
- if ( cg_shadows.integer == 0 ) {
- return qfalse;
- }
-
- // no shadows when invisible
- if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) {
- return qfalse;
- }
-
- // send a trace down from the player to the ground
- VectorCopy( cent->lerpOrigin, end );
- end[2] -= SHADOW_DISTANCE;
-
- trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
-
- // no shadow if too high
- if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
- return qfalse;
- }
-
- *shadowPlane = trace.endpos[2] + 1;
-
- if ( cg_shadows.integer != 1 ) { // no mark for stencil or projection shadows
- return qtrue;
- }
-
- // fade the shadow out with height
- alpha = 1.0 - trace.fraction;
-
- // bk0101022 - hack / FPE - bogus planes?
- //assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
-
- // add the mark as a temporary, so it goes directly to the renderer
- // without taking a spot in the cg_marks array
- CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
- cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue );
-
- return qtrue;
-}
-
-
-/*
-===============
-CG_PlayerSplash
-
-Draw a mark at the water surface
-===============
-*/
-static void CG_PlayerSplash( centity_t *cent ) {
- vec3_t start, end;
- trace_t trace;
- int contents;
- polyVert_t verts[4];
-
- if ( !cg_shadows.integer ) {
- return;
- }
-
- VectorCopy( cent->lerpOrigin, end );
- end[2] -= 24;
-
- // if the feet aren't in liquid, don't make a mark
- // this won't handle moving water brushes, but they wouldn't draw right anyway...
- contents = trap_CM_PointContents( end, 0 );
- if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
- return;
- }
-
- VectorCopy( cent->lerpOrigin, start );
- start[2] += 32;
-
- // if the head isn't out of liquid, don't make a mark
- contents = trap_CM_PointContents( start, 0 );
- if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- return;
- }
-
- // trace down to find the surface
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
-
- if ( trace.fraction == 1.0 ) {
- return;
- }
-
- // create a mark polygon
- VectorCopy( trace.endpos, verts[0].xyz );
- verts[0].xyz[0] -= 32;
- verts[0].xyz[1] -= 32;
- verts[0].st[0] = 0;
- verts[0].st[1] = 0;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[1].xyz );
- verts[1].xyz[0] -= 32;
- verts[1].xyz[1] += 32;
- verts[1].st[0] = 0;
- verts[1].st[1] = 1;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[2].xyz );
- verts[2].xyz[0] += 32;
- verts[2].xyz[1] += 32;
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorCopy( trace.endpos, verts[3].xyz );
- verts[3].xyz[0] += 32;
- verts[3].xyz[1] -= 32;
- verts[3].st[0] = 1;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
-}
-
-
-
-/*
-===============
-CG_AddRefEntityWithPowerups
-
-Adds a piece with modifications or duplications for powerups
-Also called by CG_Missile for quad rockets, but nobody can tell...
-===============
-*/
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) {
-
- if ( state->powerups & ( 1 << PW_INVIS ) ) {
- ent->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( ent );
- } else {
- /*
- if ( state->eFlags & EF_KAMIKAZE ) {
- if (team == TEAM_BLUE)
- ent->customShader = cgs.media.blueKamikazeShader;
- else
- ent->customShader = cgs.media.redKamikazeShader;
- trap_R_AddRefEntityToScene( ent );
- }
- else {*/
- trap_R_AddRefEntityToScene( ent );
- //}
-
- if ( state->powerups & ( 1 << PW_QUAD ) )
- {
- if (team == TEAM_RED)
- ent->customShader = cgs.media.redQuadShader;
- else
- ent->customShader = cgs.media.quadShader;
- trap_R_AddRefEntityToScene( ent );
- }
- if ( state->powerups & ( 1 << PW_REGEN ) ) {
- if ( ( ( cg.time / 100 ) % 10 ) == 1 ) {
- ent->customShader = cgs.media.regenShader;
- trap_R_AddRefEntityToScene( ent );
- }
- }
- if ( state->powerups & ( 1 << PW_BATTLESUIT ) ) {
- ent->customShader = cgs.media.battleSuitShader;
- trap_R_AddRefEntityToScene( ent );
- }
- }
-}
-
-/*
-=================
-CG_LightVerts
-=================
-*/
-int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
-{
- int i, j;
- float incoming;
- vec3_t ambientLight;
- vec3_t lightDir;
- vec3_t directedLight;
-
- trap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir );
-
- for (i = 0; i < numVerts; i++) {
- incoming = DotProduct (normal, lightDir);
- if ( incoming <= 0 ) {
- verts[i].modulate[0] = ambientLight[0];
- verts[i].modulate[1] = ambientLight[1];
- verts[i].modulate[2] = ambientLight[2];
- verts[i].modulate[3] = 255;
- continue;
- }
- j = ( ambientLight[0] + incoming * directedLight[0] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[0] = j;
-
- j = ( ambientLight[1] + incoming * directedLight[1] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[1] = j;
-
- j = ( ambientLight[2] + incoming * directedLight[2] );
- if ( j > 255 ) {
- j = 255;
- }
- verts[i].modulate[2] = j;
-
- verts[i].modulate[3] = 255;
- }
- return qtrue;
-}
-
-/*
-===============
-CG_Player
-===============
-*/
-void CG_Player( centity_t *cent ) {
- clientInfo_t *ci;
- refEntity_t legs;
- refEntity_t torso;
- refEntity_t head;
- int clientNum;
- int renderfx;
- qboolean shadow;
- float shadowPlane;
-#ifdef MISSIONPACK
- refEntity_t skull;
- refEntity_t powerup;
- int t;
- float c;
- float angle;
- vec3_t dir, angles;
-#endif
-
- // the client number is stored in clientNum. It can't be derived
- // from the entity number, because a single client may have
- // multiple corpses on the level using the same clientinfo
- clientNum = cent->currentState.clientNum;
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- CG_Error( "Bad clientNum on player entity");
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- // it is possible to see corpses from disconnected players that may
- // not have valid clientinfo
- if ( !ci->infoValid ) {
- return;
- }
-
- // get the player model information
- renderfx = 0;
- if ( cent->currentState.number == cg.snap->ps.clientNum) {
- if (!cg.renderingThirdPerson) {
- renderfx = RF_THIRD_PERSON; // only draw in mirrors
- } else {
- if (cg_cameraMode.integer) {
- return;
- }
- }
- }
-
-
- memset( &legs, 0, sizeof(legs) );
- memset( &torso, 0, sizeof(torso) );
- memset( &head, 0, sizeof(head) );
-
- // get the rotation information
- CG_PlayerAngles( cent, legs.axis, torso.axis, head.axis );
-
- // get the animation state (after rotation, to allow feet shuffle)
- CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp,
- &torso.oldframe, &torso.frame, &torso.backlerp );
-
- // add the talk baloon or disconnect icon
- CG_PlayerSprites( cent );
-
- // add the shadow
- shadow = CG_PlayerShadow( cent, &shadowPlane );
-
- // add a water splash if partially in and out of water
- CG_PlayerSplash( cent );
-
- if ( cg_shadows.integer == 3 && shadow ) {
- renderfx |= RF_SHADOW_PLANE;
- }
- renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all
-#ifdef MISSIONPACK
- if( cgs.gametype == GT_HARVESTER ) {
- CG_PlayerTokens( cent, renderfx );
- }
-#endif
- //
- // add the legs
- //
- legs.hModel = ci->legsModel;
- legs.customSkin = ci->legsSkin;
-
- VectorCopy( cent->lerpOrigin, legs.origin );
-
- VectorCopy( cent->lerpOrigin, legs.lightingOrigin );
- legs.shadowPlane = shadowPlane;
- legs.renderfx = renderfx;
- VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all
-
- CG_AddRefEntityWithPowerups( &legs, &cent->currentState, ci->team );
-
- // if the model failed, allow the default nullmodel to be displayed
- if (!legs.hModel) {
- return;
- }
-
- //
- // add the torso
- //
- torso.hModel = ci->torsoModel;
- if (!torso.hModel) {
- return;
- }
-
- torso.customSkin = ci->torsoSkin;
-
- VectorCopy( cent->lerpOrigin, torso.lightingOrigin );
-
- CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso");
-
- torso.shadowPlane = shadowPlane;
- torso.renderfx = renderfx;
-
- CG_AddRefEntityWithPowerups( &torso, &cent->currentState, ci->team );
-
-#ifdef MISSIONPACK
- if ( cent->currentState.eFlags & EF_KAMIKAZE ) {
-
- memset( &skull, 0, sizeof(skull) );
-
- VectorCopy( cent->lerpOrigin, skull.lightingOrigin );
- skull.shadowPlane = shadowPlane;
- skull.renderfx = renderfx;
-
- if ( cent->currentState.eFlags & EF_DEAD ) {
- // one skull bobbing above the dead body
- angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
- dir[2] = 15 + sin(angle) * 8;
- VectorAdd(torso.origin, dir, skull.origin);
-
- dir[2] = 0;
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
- }
- else {
- // three skulls spinning around the player
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
- dir[0] = cos(angle) * 20;
- dir[1] = sin(angle) * 20;
- dir[2] = cos(angle) * 20;
- VectorAdd(torso.origin, dir, skull.origin);
-
- angles[0] = sin(angle) * 30;
- angles[1] = (angle * 180 / M_PI) + 90;
- if (angles[1] > 360)
- angles[1] -= 360;
- angles[2] = 0;
- AnglesToAxis( angles, skull.axis );
-
- /*
- dir[2] = 0;
- VectorInverse(dir);
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
- */
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- // flip the trail because this skull is spinning in the other direction
- VectorInverse(skull.axis[1]);
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
-
- angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255 + M_PI;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- dir[2] = cos(angle) * 20;
- VectorAdd(torso.origin, dir, skull.origin);
-
- angles[0] = cos(angle - 0.5 * M_PI) * 30;
- angles[1] = 360 - (angle * 180 / M_PI);
- if (angles[1] > 360)
- angles[1] -= 360;
- angles[2] = 0;
- AnglesToAxis( angles, skull.axis );
-
- /*
- dir[2] = 0;
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
- */
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
-
- angle = ((cg.time / 3) & 255) * (M_PI * 2) / 255 + 0.5 * M_PI;
- if (angle > M_PI * 2)
- angle -= (float)M_PI * 2;
- dir[0] = sin(angle) * 20;
- dir[1] = cos(angle) * 20;
- dir[2] = 0;
- VectorAdd(torso.origin, dir, skull.origin);
-
- VectorCopy(dir, skull.axis[1]);
- VectorNormalize(skull.axis[1]);
- VectorSet(skull.axis[2], 0, 0, 1);
- CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
-
- skull.hModel = cgs.media.kamikazeHeadModel;
- trap_R_AddRefEntityToScene( &skull );
- skull.hModel = cgs.media.kamikazeHeadTrail;
- trap_R_AddRefEntityToScene( &skull );
- }
- }
-
- if ( cent->currentState.powerups & ( 1 << PW_GUARD ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.guardPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_SCOUT ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.scoutPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_DOUBLER ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.doublerPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_AMMOREGEN ) ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.ammoRegenPowerupModel;
- powerup.frame = 0;
- powerup.oldframe = 0;
- powerup.customSkin = 0;
- trap_R_AddRefEntityToScene( &powerup );
- }
- if ( cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) {
- if ( !ci->invulnerabilityStartTime ) {
- ci->invulnerabilityStartTime = cg.time;
- }
- ci->invulnerabilityStopTime = cg.time;
- }
- else {
- ci->invulnerabilityStartTime = 0;
- }
- if ( (cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) ||
- cg.time - ci->invulnerabilityStopTime < 250 ) {
-
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.invulnerabilityPowerupModel;
- powerup.customSkin = 0;
- // always draw
- powerup.renderfx &= ~RF_THIRD_PERSON;
- VectorCopy(cent->lerpOrigin, powerup.origin);
-
- if ( cg.time - ci->invulnerabilityStartTime < 250 ) {
- c = (float) (cg.time - ci->invulnerabilityStartTime) / 250;
- }
- else if (cg.time - ci->invulnerabilityStopTime < 250 ) {
- c = (float) (250 - (cg.time - ci->invulnerabilityStopTime)) / 250;
- }
- else {
- c = 1;
- }
- VectorSet( powerup.axis[0], c, 0, 0 );
- VectorSet( powerup.axis[1], 0, c, 0 );
- VectorSet( powerup.axis[2], 0, 0, c );
- trap_R_AddRefEntityToScene( &powerup );
- }
-
- t = cg.time - ci->medkitUsageTime;
- if ( ci->medkitUsageTime && t < 500 ) {
- memcpy(&powerup, &torso, sizeof(torso));
- powerup.hModel = cgs.media.medkitUsageModel;
- powerup.customSkin = 0;
- // always draw
- powerup.renderfx &= ~RF_THIRD_PERSON;
- VectorClear(angles);
- AnglesToAxis(angles, powerup.axis);
- VectorCopy(cent->lerpOrigin, powerup.origin);
- powerup.origin[2] += -24 + (float) t * 80 / 500;
- if ( t > 400 ) {
- c = (float) (t - 1000) * 0xff / 100;
- powerup.shaderRGBA[0] = 0xff - c;
- powerup.shaderRGBA[1] = 0xff - c;
- powerup.shaderRGBA[2] = 0xff - c;
- powerup.shaderRGBA[3] = 0xff - c;
- }
- else {
- powerup.shaderRGBA[0] = 0xff;
- powerup.shaderRGBA[1] = 0xff;
- powerup.shaderRGBA[2] = 0xff;
- powerup.shaderRGBA[3] = 0xff;
- }
- trap_R_AddRefEntityToScene( &powerup );
- }
-#endif // MISSIONPACK
-
- //
- // add the head
- //
- head.hModel = ci->headModel;
- if (!head.hModel) {
- return;
- }
- head.customSkin = ci->headSkin;
-
- VectorCopy( cent->lerpOrigin, head.lightingOrigin );
-
- CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head");
-
- head.shadowPlane = shadowPlane;
- head.renderfx = renderfx;
-
- CG_AddRefEntityWithPowerups( &head, &cent->currentState, ci->team );
-
-#ifdef MISSIONPACK
- CG_BreathPuffs(cent, &head);
-
- CG_DustTrail(cent);
-#endif
-
- //
- // add the gun / barrel / flash
- //
- CG_AddPlayerWeapon( &torso, NULL, cent, ci->team );
-
- // add powerups floating behind the player
- CG_PlayerPowerups( cent, &torso );
-}
-
-
-//=====================================================================
-
-/*
-===============
-CG_ResetPlayerEntity
-
-A player just came into view or teleported, so reset all animation info
-===============
-*/
-void CG_ResetPlayerEntity( centity_t *cent ) {
- cent->errorTime = -99999; // guarantee no error decay added
- cent->extrapolated = qfalse;
-
- CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], &cent->pe.legs, cent->currentState.legsAnim );
- CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], &cent->pe.torso, cent->currentState.torsoAnim );
-
- BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
- BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
-
- VectorCopy( cent->lerpOrigin, cent->rawOrigin );
- VectorCopy( cent->lerpAngles, cent->rawAngles );
-
- memset( &cent->pe.legs, 0, sizeof( cent->pe.legs ) );
- cent->pe.legs.yawAngle = cent->rawAngles[YAW];
- cent->pe.legs.yawing = qfalse;
- cent->pe.legs.pitchAngle = 0;
- cent->pe.legs.pitching = qfalse;
-
- memset( &cent->pe.torso, 0, sizeof( cent->pe.legs ) );
- cent->pe.torso.yawAngle = cent->rawAngles[YAW];
- cent->pe.torso.yawing = qfalse;
- cent->pe.torso.pitchAngle = cent->rawAngles[PITCH];
- cent->pe.torso.pitching = qfalse;
-
- if ( cg_debugPosition.integer ) {
- CG_Printf("%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle );
- }
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_players.c -- handle the media and animation for player entities
+#include "cg_local.h"
+
+char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {
+ "*death1.wav",
+ "*death2.wav",
+ "*death3.wav",
+ "*jump1.wav",
+ "*pain25_1.wav",
+ "*pain50_1.wav",
+ "*pain75_1.wav",
+ "*pain100_1.wav",
+ "*falling1.wav",
+ "*gasp.wav",
+ "*drown.wav",
+ "*fall1.wav",
+ "*taunt.wav"
+};
+
+
+/*
+================
+CG_CustomSound
+
+================
+*/
+sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) {
+ clientInfo_t *ci;
+ int i;
+
+ if ( soundName[0] != '*' ) {
+ return trap_S_RegisterSound( soundName, qfalse );
+ }
+
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ for ( i = 0 ; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[i] ; i++ ) {
+ if ( !strcmp( soundName, cg_customSoundNames[i] ) ) {
+ return ci->sounds[i];
+ }
+ }
+
+ CG_Error( "Unknown custom sound: %s", soundName );
+ return 0;
+}
+
+
+
+/*
+=============================================================================
+
+CLIENT INFO
+
+=============================================================================
+*/
+
+/*
+======================
+CG_ParseAnimationFile
+
+Read a configuration file containing animation coutns and rates
+models/players/visor/animation.cfg, etc
+======================
+*/
+static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) {
+ char *text_p, *prev;
+ int len;
+ int i;
+ char *token;
+ float fps;
+ int skip;
+ char text[20000];
+ fileHandle_t f;
+ animation_t *animations;
+
+ animations = ci->animations;
+
+ // load the file
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( len <= 0 ) {
+ return qfalse;
+ }
+ if ( len >= sizeof( text ) - 1 ) {
+ CG_Printf( "File %s too long\n", filename );
+ return qfalse;
+ }
+ trap_FS_Read( text, len, f );
+ text[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ // parse the text
+ text_p = text;
+ skip = 0; // quite the compiler warning
+
+ ci->footsteps = FOOTSTEP_NORMAL;
+ VectorClear( ci->headOffset );
+ ci->gender = GENDER_MALE;
+ ci->fixedlegs = qfalse;
+ ci->fixedtorso = qfalse;
+
+ // read optional parameters
+ while ( 1 ) {
+ prev = text_p; // so we can unget
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( !Q_stricmp( token, "footsteps" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) {
+ ci->footsteps = FOOTSTEP_NORMAL;
+ } else if ( !Q_stricmp( token, "boot" ) ) {
+ ci->footsteps = FOOTSTEP_BOOT;
+ } else if ( !Q_stricmp( token, "flesh" ) ) {
+ ci->footsteps = FOOTSTEP_FLESH;
+ } else if ( !Q_stricmp( token, "mech" ) ) {
+ ci->footsteps = FOOTSTEP_MECH;
+ } else if ( !Q_stricmp( token, "energy" ) ) {
+ ci->footsteps = FOOTSTEP_ENERGY;
+ } else {
+ CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token );
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "headoffset" ) ) {
+ for ( i = 0 ; i < 3 ; i++ ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ ci->headOffset[i] = atof( token );
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "sex" ) ) {
+ token = COM_Parse( &text_p );
+ if ( !token ) {
+ break;
+ }
+ if ( token[0] == 'f' || token[0] == 'F' ) {
+ ci->gender = GENDER_FEMALE;
+ } else if ( token[0] == 'n' || token[0] == 'N' ) {
+ ci->gender = GENDER_NEUTER;
+ } else {
+ ci->gender = GENDER_MALE;
+ }
+ continue;
+ } else if ( !Q_stricmp( token, "fixedlegs" ) ) {
+ ci->fixedlegs = qtrue;
+ continue;
+ } else if ( !Q_stricmp( token, "fixedtorso" ) ) {
+ ci->fixedtorso = qtrue;
+ continue;
+ }
+
+ // if it is a number, start parsing animations
+ if ( token[0] >= '0' && token[0] <= '9' ) {
+ text_p = prev; // unget the token
+ break;
+ }
+ Com_Printf( "unknown token '%s' is %s\n", token, filename );
+ }
+
+ // read information for each frame
+ for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
+ animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
+ animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
+ animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
+ animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
+ animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
+ animations[i].reversed = qfalse;
+ animations[i].flipflop = qfalse;
+ continue;
+ }
+ break;
+ }
+ animations[i].firstFrame = atoi( token );
+ // leg only frames are adjusted to not count the upper body only frames
+ if ( i == LEGS_WALKCR ) {
+ skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
+ }
+ if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
+ animations[i].firstFrame -= skip;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ break;
+ }
+ animations[i].numFrames = atoi( token );
+
+ animations[i].reversed = qfalse;
+ animations[i].flipflop = qfalse;
+ // if numFrames is negative the animation is reversed
+ if (animations[i].numFrames < 0) {
+ animations[i].numFrames = -animations[i].numFrames;
+ animations[i].reversed = qtrue;
+ }
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ break;
+ }
+ animations[i].loopFrames = atoi( token );
+
+ token = COM_Parse( &text_p );
+ if ( !*token ) {
+ break;
+ }
+ fps = atof( token );
+ if ( fps == 0 ) {
+ fps = 1;
+ }
+ animations[i].frameLerp = 1000 / fps;
+ animations[i].initialLerp = 1000 / fps;
+ }
+
+ if ( i != MAX_ANIMATIONS ) {
+ CG_Printf( "Error parsing animation file: %s", filename );
+ return qfalse;
+ }
+
+ // crouch backward animation
+ memcpy(&animations[LEGS_BACKCR], &animations[LEGS_WALKCR], sizeof(animation_t));
+ animations[LEGS_BACKCR].reversed = qtrue;
+ // walk backward animation
+ memcpy(&animations[LEGS_BACKWALK], &animations[LEGS_WALK], sizeof(animation_t));
+ animations[LEGS_BACKWALK].reversed = qtrue;
+ // flag moving fast
+ animations[FLAG_RUN].firstFrame = 0;
+ animations[FLAG_RUN].numFrames = 16;
+ animations[FLAG_RUN].loopFrames = 16;
+ animations[FLAG_RUN].frameLerp = 1000 / 15;
+ animations[FLAG_RUN].initialLerp = 1000 / 15;
+ animations[FLAG_RUN].reversed = qfalse;
+ // flag not moving or moving slowly
+ animations[FLAG_STAND].firstFrame = 16;
+ animations[FLAG_STAND].numFrames = 5;
+ animations[FLAG_STAND].loopFrames = 0;
+ animations[FLAG_STAND].frameLerp = 1000 / 20;
+ animations[FLAG_STAND].initialLerp = 1000 / 20;
+ animations[FLAG_STAND].reversed = qfalse;
+ // flag speeding up
+ animations[FLAG_STAND2RUN].firstFrame = 16;
+ animations[FLAG_STAND2RUN].numFrames = 5;
+ animations[FLAG_STAND2RUN].loopFrames = 1;
+ animations[FLAG_STAND2RUN].frameLerp = 1000 / 15;
+ animations[FLAG_STAND2RUN].initialLerp = 1000 / 15;
+ animations[FLAG_STAND2RUN].reversed = qtrue;
+ //
+ // new anims changes
+ //
+// animations[TORSO_GETFLAG].flipflop = qtrue;
+// animations[TORSO_GUARDBASE].flipflop = qtrue;
+// animations[TORSO_PATROL].flipflop = qtrue;
+// animations[TORSO_AFFIRMATIVE].flipflop = qtrue;
+// animations[TORSO_NEGATIVE].flipflop = qtrue;
+ //
+ return qtrue;
+}
+
+/*
+==========================
+CG_FileExists
+==========================
+*/
+static qboolean CG_FileExists(const char *filename) {
+ int len;
+
+ len = trap_FS_FOpenFile( filename, 0, FS_READ );
+ if (len>0) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+==========================
+CG_FindClientModelFile
+==========================
+*/
+static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) {
+ char *team, *charactersFolder;
+ int i;
+
+ if ( cgs.gametype >= GT_TEAM ) {
+ switch ( ci->team ) {
+ case TEAM_BLUE: {
+ team = "blue";
+ break;
+ }
+ default: {
+ team = "red";
+ break;
+ }
+ }
+ }
+ else {
+ team = "default";
+ }
+ charactersFolder = "";
+ while(1) {
+ for ( i = 0; i < 2; i++ ) {
+ if ( i == 0 && teamName && *teamName ) {
+ // "models/players/characters/james/stroggs/lower_lily_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext );
+ }
+ else {
+ // "models/players/characters/james/lower_lily_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext );
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( cgs.gametype >= GT_TEAM ) {
+ if ( i == 0 && teamName && *teamName ) {
+ // "models/players/characters/james/stroggs/lower_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext );
+ }
+ else {
+ // "models/players/characters/james/lower_red.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext );
+ }
+ }
+ else {
+ if ( i == 0 && teamName && *teamName ) {
+ // "models/players/characters/james/stroggs/lower_lily.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext );
+ }
+ else {
+ // "models/players/characters/james/lower_lily.skin"
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext );
+ }
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( !teamName || !*teamName ) {
+ break;
+ }
+ }
+ // if tried the heads folder first
+ if ( charactersFolder[0] ) {
+ break;
+ }
+ charactersFolder = "characters/";
+ }
+
+ return qfalse;
+}
+
+/*
+==========================
+CG_FindClientHeadFile
+==========================
+*/
+static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) {
+ char *team, *headsFolder;
+ int i;
+
+ if ( cgs.gametype >= GT_TEAM ) {
+ switch ( ci->team ) {
+ case TEAM_BLUE: {
+ team = "blue";
+ break;
+ }
+ default: {
+ team = "red";
+ break;
+ }
+ }
+ }
+ else {
+ team = "default";
+ }
+
+ if ( headModelName[0] == '*' ) {
+ headsFolder = "heads/";
+ headModelName++;
+ }
+ else {
+ headsFolder = "";
+ }
+ while(1) {
+ for ( i = 0; i < 2; i++ ) {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext );
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( cgs.gametype >= GT_TEAM ) {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext );
+ }
+ }
+ else {
+ if ( i == 0 && teamName && *teamName ) {
+ Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext );
+ }
+ else {
+ Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext );
+ }
+ }
+ if ( CG_FileExists( filename ) ) {
+ return qtrue;
+ }
+ if ( !teamName || !*teamName ) {
+ break;
+ }
+ }
+ // if tried the heads folder first
+ if ( headsFolder[0] ) {
+ break;
+ }
+ headsFolder = "heads/";
+ }
+
+ return qfalse;
+}
+
+/*
+==========================
+CG_RegisterClientSkin
+==========================
+*/
+static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) {
+ char filename[MAX_QPATH];
+
+ /*
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName );
+ ci->legsSkin = trap_R_RegisterSkin( filename );
+ if (!ci->legsSkin) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName );
+ ci->legsSkin = trap_R_RegisterSkin( filename );
+ if (!ci->legsSkin) {
+ Com_Printf( "Leg skin load failure: %s\n", filename );
+ }
+ }
+
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName );
+ ci->torsoSkin = trap_R_RegisterSkin( filename );
+ if (!ci->torsoSkin) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName );
+ ci->torsoSkin = trap_R_RegisterSkin( filename );
+ if (!ci->torsoSkin) {
+ Com_Printf( "Torso skin load failure: %s\n", filename );
+ }
+ }
+ */
+ if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) {
+ ci->legsSkin = trap_R_RegisterSkin( filename );
+ }
+ if (!ci->legsSkin) {
+ Com_Printf( "Leg skin load failure: %s\n", filename );
+ }
+
+ if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) {
+ ci->torsoSkin = trap_R_RegisterSkin( filename );
+ }
+ if (!ci->torsoSkin) {
+ Com_Printf( "Torso skin load failure: %s\n", filename );
+ }
+
+ if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) {
+ ci->headSkin = trap_R_RegisterSkin( filename );
+ }
+ if (!ci->headSkin) {
+ Com_Printf( "Head skin load failure: %s\n", filename );
+ }
+
+ // if any skins failed to load
+ if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==========================
+CG_RegisterClientModelname
+==========================
+*/
+static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {
+ char filename[MAX_QPATH*2];
+ const char *headName;
+ char newTeamName[MAX_QPATH*2];
+
+ if ( headModelName[0] == '\0' ) {
+ headName = modelName;
+ }
+ else {
+ headName = headModelName;
+ }
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
+ ci->legsModel = trap_R_RegisterModel( filename );
+ if ( !ci->legsModel ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
+ ci->legsModel = trap_R_RegisterModel( filename );
+ if ( !ci->legsModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
+ ci->torsoModel = trap_R_RegisterModel( filename );
+ if ( !ci->torsoModel ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
+ ci->torsoModel = trap_R_RegisterModel( filename );
+ if ( !ci->torsoModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ if( headName[0] == '*' ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
+ }
+ else {
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName );
+ }
+ ci->headModel = trap_R_RegisterModel( filename );
+ // if the head model could not be found and we didn't load from the heads folder try to load from there
+ if ( !ci->headModel && headName[0] != '*' ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
+ ci->headModel = trap_R_RegisterModel( filename );
+ }
+ if ( !ci->headModel ) {
+ Com_Printf( "Failed to load model file %s\n", filename );
+ return qfalse;
+ }
+
+ // if any skins failed to load, return failure
+ if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {
+ if ( teamName && *teamName) {
+ Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName );
+ if( ci->team == TEAM_BLUE ) {
+ Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME);
+ }
+ else {
+ Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME);
+ }
+ if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {
+ Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName );
+ return qfalse;
+ }
+ } else {
+ Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName );
+ return qfalse;
+ }
+ }
+
+ // load the animations
+ Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
+ if ( !CG_ParseAnimationFile( filename, ci ) ) {
+ Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
+ if ( !CG_ParseAnimationFile( filename, ci ) ) {
+ Com_Printf( "Failed to load animation file %s\n", filename );
+ return qfalse;
+ }
+ }
+
+ if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) {
+ ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
+ }
+ else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) {
+ ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
+ }
+
+ if ( !ci->modelIcon ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+====================
+CG_ColorFromString
+====================
+*/
+static void CG_ColorFromString( const char *v, vec3_t color ) {
+ int val;
+
+ VectorClear( color );
+
+ val = atoi( v );
+
+ if ( val < 1 || val > 7 ) {
+ VectorSet( color, 1, 1, 1 );
+ return;
+ }
+
+ if ( val & 1 ) {
+ color[2] = 1.0f;
+ }
+ if ( val & 2 ) {
+ color[1] = 1.0f;
+ }
+ if ( val & 4 ) {
+ color[0] = 1.0f;
+ }
+}
+
+/*
+===================
+CG_LoadClientInfo
+
+Load it now, taking the disk hits.
+This will usually be deferred to a safe time
+===================
+*/
+static void CG_LoadClientInfo( clientInfo_t *ci ) {
+ const char *dir, *fallback;
+ int i, modelloaded;
+ const char *s;
+ int clientNum;
+ char teamname[MAX_QPATH];
+
+ teamname[0] = 0;
+#ifdef MISSIONPACK
+ if( cgs.gametype >= GT_TEAM) {
+ if( ci->team == TEAM_BLUE ) {
+ Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) );
+ } else {
+ Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) );
+ }
+ }
+ if( teamname[0] ) {
+ strcat( teamname, "/" );
+ }
+#endif
+ modelloaded = qtrue;
+ if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {
+ if ( cg_buildScript.integer ) {
+ CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
+ }
+
+ // fall back to default team name
+ if( cgs.gametype >= GT_TEAM) {
+ // keep skin name
+ if( ci->team == TEAM_BLUE ) {
+ Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
+ } else {
+ Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
+ }
+ if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {
+ CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName );
+ }
+ } else {
+ if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) {
+ CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
+ }
+ }
+ modelloaded = qfalse;
+ }
+
+ ci->newAnims = qfalse;
+ if ( ci->torsoModel ) {
+ orientation_t tag;
+ // if the torso model has the "tag_flag"
+ if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
+ ci->newAnims = qtrue;
+ }
+ }
+
+ // sounds
+ dir = ci->modelName;
+ fallback = (cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;
+
+ for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {
+ s = cg_customSoundNames[i];
+ if ( !s ) {
+ break;
+ }
+ ci->sounds[i] = 0;
+ // if the model didn't load use the sounds of the default model
+ if (modelloaded) {
+ ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse );
+ }
+ if ( !ci->sounds[i] ) {
+ ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse );
+ }
+ }
+
+ ci->deferred = qfalse;
+
+ // reset any existing players and bodies, because they might be in bad
+ // frames for this new model
+ clientNum = ci - cgs.clientinfo;
+ for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
+ if ( cg_entities[i].currentState.clientNum == clientNum
+ && cg_entities[i].currentState.eType == ET_PLAYER ) {
+ CG_ResetPlayerEntity( &cg_entities[i] );
+ }
+ }
+}
+
+/*
+======================
+CG_CopyClientInfoModel
+======================
+*/
+static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {
+ VectorCopy( from->headOffset, to->headOffset );
+ to->footsteps = from->footsteps;
+ to->gender = from->gender;
+
+ to->legsModel = from->legsModel;
+ to->legsSkin = from->legsSkin;
+ to->torsoModel = from->torsoModel;
+ to->torsoSkin = from->torsoSkin;
+ to->headModel = from->headModel;
+ to->headSkin = from->headSkin;
+ to->modelIcon = from->modelIcon;
+
+ to->newAnims = from->newAnims;
+
+ memcpy( to->animations, from->animations, sizeof( to->animations ) );
+ memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
+}
+
+/*
+======================
+CG_ScanForExistingClientInfo
+======================
+*/
+static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {
+ int i;
+ clientInfo_t *match;
+
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid ) {
+ continue;
+ }
+ if ( match->deferred ) {
+ continue;
+ }
+ if ( !Q_stricmp( ci->modelName, match->modelName )
+ && !Q_stricmp( ci->skinName, match->skinName )
+ && !Q_stricmp( ci->headModelName, match->headModelName )
+ && !Q_stricmp( ci->headSkinName, match->headSkinName )
+ && !Q_stricmp( ci->blueTeam, match->blueTeam )
+ && !Q_stricmp( ci->redTeam, match->redTeam )
+ && (cgs.gametype < GT_TEAM || ci->team == match->team) ) {
+ // this clientinfo is identical, so use it's handles
+
+ ci->deferred = qfalse;
+
+ CG_CopyClientInfoModel( match, ci );
+
+ return qtrue;
+ }
+ }
+
+ // nothing matches, so defer the load
+ return qfalse;
+}
+
+/*
+======================
+CG_SetDeferredClientInfo
+
+We aren't going to load it now, so grab some other
+client's info to use until we have some spare time.
+======================
+*/
+static void CG_SetDeferredClientInfo( clientInfo_t *ci ) {
+ int i;
+ clientInfo_t *match;
+
+ // if someone else is already the same models and skins we
+ // can just load the client info
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid || match->deferred ) {
+ continue;
+ }
+ if ( Q_stricmp( ci->skinName, match->skinName ) ||
+ Q_stricmp( ci->modelName, match->modelName ) ||
+// Q_stricmp( ci->headModelName, match->headModelName ) ||
+// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
+ (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
+ continue;
+ }
+ // just load the real info cause it uses the same models and skins
+ CG_LoadClientInfo( ci );
+ return;
+ }
+
+ // if we are in teamplay, only grab a model if the skin is correct
+ if ( cgs.gametype >= GT_TEAM ) {
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid || match->deferred ) {
+ continue;
+ }
+ if ( Q_stricmp( ci->skinName, match->skinName ) ||
+ (cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
+ continue;
+ }
+ ci->deferred = qtrue;
+ CG_CopyClientInfoModel( match, ci );
+ return;
+ }
+ // load the full model, because we don't ever want to show
+ // an improper team skin. This will cause a hitch for the first
+ // player, when the second enters. Combat shouldn't be going on
+ // yet, so it shouldn't matter
+ CG_LoadClientInfo( ci );
+ return;
+ }
+
+ // find the first valid clientinfo and grab its stuff
+ for ( i = 0 ; i < cgs.maxclients ; i++ ) {
+ match = &cgs.clientinfo[ i ];
+ if ( !match->infoValid ) {
+ continue;
+ }
+
+ ci->deferred = qtrue;
+ CG_CopyClientInfoModel( match, ci );
+ return;
+ }
+
+ // we should never get here...
+ CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
+
+ CG_LoadClientInfo( ci );
+}
+
+
+/*
+======================
+CG_NewClientInfo
+======================
+*/
+void CG_NewClientInfo( int clientNum ) {
+ clientInfo_t *ci;
+ clientInfo_t newInfo;
+ const char *configstring;
+ const char *v;
+ char *slash;
+
+ ci = &cgs.clientinfo[clientNum];
+
+ configstring = CG_ConfigString( clientNum + CS_PLAYERS );
+ if ( !configstring[0] ) {
+ memset( ci, 0, sizeof( *ci ) );
+ return; // player just left
+ }
+
+ // build into a temp buffer so the defer checks can use
+ // the old value
+ memset( &newInfo, 0, sizeof( newInfo ) );
+
+ // isolate the player's name
+ v = Info_ValueForKey(configstring, "n");
+ Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
+
+ // colors
+ v = Info_ValueForKey( configstring, "c1" );
+ CG_ColorFromString( v, newInfo.color1 );
+
+ v = Info_ValueForKey( configstring, "c2" );
+ CG_ColorFromString( v, newInfo.color2 );
+
+ // bot skill
+ v = Info_ValueForKey( configstring, "skill" );
+ newInfo.botSkill = atoi( v );
+
+ // handicap
+ v = Info_ValueForKey( configstring, "hc" );
+ newInfo.handicap = atoi( v );
+
+ // wins
+ v = Info_ValueForKey( configstring, "w" );
+ newInfo.wins = atoi( v );
+
+ // losses
+ v = Info_ValueForKey( configstring, "l" );
+ newInfo.losses = atoi( v );
+
+ // team
+ v = Info_ValueForKey( configstring, "t" );
+ newInfo.team = atoi( v );
+
+ // team task
+ v = Info_ValueForKey( configstring, "tt" );
+ newInfo.teamTask = atoi(v);
+
+ // team leader
+ v = Info_ValueForKey( configstring, "tl" );
+ newInfo.teamLeader = atoi(v);
+
+ v = Info_ValueForKey( configstring, "g_redteam" );
+ Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
+
+ v = Info_ValueForKey( configstring, "g_blueteam" );
+ Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
+
+ // model
+ v = Info_ValueForKey( configstring, "model" );
+ if ( cg_forceModel.integer ) {
+ // forcemodel makes everyone use a single model
+ // to prevent load hitches
+ char modelStr[MAX_QPATH];
+ char *skin;
+
+ if( cgs.gametype >= GT_TEAM ) {
+ Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
+ Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
+ } else {
+ trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
+ if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
+ skin = "default";
+ } else {
+ *skin++ = 0;
+ }
+
+ Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
+ Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
+ }
+
+ if ( cgs.gametype >= GT_TEAM ) {
+ // keep skin name
+ slash = strchr( v, '/' );
+ if ( slash ) {
+ Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
+ }
+ }
+ } else {
+ Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );
+
+ slash = strchr( newInfo.modelName, '/' );
+ if ( !slash ) {
+ // modelName didn not include a skin name
+ Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
+ } else {
+ Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
+ // truncate modelName
+ *slash = 0;
+ }
+ }
+
+ // head model
+ v = Info_ValueForKey( configstring, "hmodel" );
+ if ( cg_forceModel.integer ) {
+ // forcemodel makes everyone use a single model
+ // to prevent load hitches
+ char modelStr[MAX_QPATH];
+ char *skin;
+
+ if( cgs.gametype >= GT_TEAM ) {
+ Q_strncpyz( newInfo.headModelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.headModelName ) );
+ Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
+ } else {
+ trap_Cvar_VariableStringBuffer( "headmodel", modelStr, sizeof( modelStr ) );
+ if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
+ skin = "default";
+ } else {
+ *skin++ = 0;
+ }
+
+ Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) );
+ Q_strncpyz( newInfo.headModelName, modelStr, sizeof( newInfo.headModelName ) );
+ }
+
+ if ( cgs.gametype >= GT_TEAM ) {
+ // keep skin name
+ slash = strchr( v, '/' );
+ if ( slash ) {
+ Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
+ }
+ }
+ } else {
+ Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) );
+
+ slash = strchr( newInfo.headModelName, '/' );
+ if ( !slash ) {
+ // modelName didn not include a skin name
+ Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) );
+ } else {
+ Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) );
+ // truncate modelName
+ *slash = 0;
+ }
+ }
+
+ // scan for an existing clientinfo that matches this modelname
+ // so we can avoid loading checks if possible
+ if ( !CG_ScanForExistingClientInfo( &newInfo ) ) {
+ qboolean forceDefer;
+
+ forceDefer = trap_MemoryRemaining() < 4000000;
+
+ // if we are defering loads, just have it pick the first valid
+ if ( forceDefer || (cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) {
+ // keep whatever they had if it won't violate team skins
+ CG_SetDeferredClientInfo( &newInfo );
+ // if we are low on memory, leave them with this model
+ if ( forceDefer ) {
+ CG_Printf( "Memory is low. Using deferred model.\n" );
+ newInfo.deferred = qfalse;
+ }
+ } else {
+ CG_LoadClientInfo( &newInfo );
+ }
+ }
+
+ // replace whatever was there with the new one
+ newInfo.infoValid = qtrue;
+ *ci = newInfo;
+}
+
+
+
+/*
+======================
+CG_LoadDeferredPlayers
+
+Called each frame when a player is dead
+and the scoreboard is up
+so deferred players can be loaded
+======================
+*/
+void CG_LoadDeferredPlayers( void ) {
+ int i;
+ clientInfo_t *ci;
+
+ // scan for a deferred player to load
+ for ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {
+ if ( ci->infoValid && ci->deferred ) {
+ // if we are low on memory, leave it deferred
+ if ( trap_MemoryRemaining() < 4000000 ) {
+ CG_Printf( "Memory is low. Using deferred model.\n" );
+ ci->deferred = qfalse;
+ continue;
+ }
+ CG_LoadClientInfo( ci );
+// break;
+ }
+ }
+}
+
+/*
+=============================================================================
+
+PLAYER ANIMATION
+
+=============================================================================
+*/
+
+
+/*
+===============
+CG_SetLerpFrameAnimation
+
+may include ANIM_TOGGLEBIT
+===============
+*/
+static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
+ animation_t *anim;
+
+ lf->animationNumber = newAnimation;
+ newAnimation &= ~ANIM_TOGGLEBIT;
+
+ if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
+ CG_Error( "Bad animation number: %i", newAnimation );
+ }
+
+ anim = &ci->animations[ newAnimation ];
+
+ lf->animation = anim;
+ lf->animationTime = lf->frameTime + anim->initialLerp;
+
+ if ( cg_debugAnim.integer ) {
+ CG_Printf( "Anim: %i\n", newAnimation );
+ }
+}
+
+/*
+===============
+CG_RunLerpFrame
+
+Sets cg.snap, cg.oldFrame, and cg.backlerp
+cg.time should be between oldFrameTime and frameTime after exit
+===============
+*/
+static void CG_RunLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) {
+ int f, numFrames;
+ animation_t *anim;
+
+ // debugging tool to get no animations
+ if ( cg_animSpeed.integer == 0 ) {
+ lf->oldFrame = lf->frame = lf->backlerp = 0;
+ return;
+ }
+
+ // see if the animation sequence is switching
+ if ( newAnimation != lf->animationNumber || !lf->animation ) {
+ CG_SetLerpFrameAnimation( ci, lf, newAnimation );
+ }
+
+ // if we have passed the current frame, move it to
+ // oldFrame and calculate a new frame
+ if ( cg.time >= lf->frameTime ) {
+ lf->oldFrame = lf->frame;
+ lf->oldFrameTime = lf->frameTime;
+
+ // get the next frame based on the animation
+ anim = lf->animation;
+ if ( !anim->frameLerp ) {
+ return; // shouldn't happen
+ }
+ if ( cg.time < lf->animationTime ) {
+ lf->frameTime = lf->animationTime; // initial lerp
+ } else {
+ lf->frameTime = lf->oldFrameTime + anim->frameLerp;
+ }
+ f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
+ f *= speedScale; // adjust for haste, etc
+
+ numFrames = anim->numFrames;
+ if (anim->flipflop) {
+ numFrames *= 2;
+ }
+ if ( f >= numFrames ) {
+ f -= numFrames;
+ if ( anim->loopFrames ) {
+ f %= anim->loopFrames;
+ f += anim->numFrames - anim->loopFrames;
+ } else {
+ f = numFrames - 1;
+ // the animation is stuck at the end, so it
+ // can immediately transition to another sequence
+ lf->frameTime = cg.time;
+ }
+ }
+ if ( anim->reversed ) {
+ lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
+ }
+ else if (anim->flipflop && f>=anim->numFrames) {
+ lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
+ }
+ else {
+ lf->frame = anim->firstFrame + f;
+ }
+ if ( cg.time > lf->frameTime ) {
+ lf->frameTime = cg.time;
+ if ( cg_debugAnim.integer ) {
+ CG_Printf( "Clamp lf->frameTime\n");
+ }
+ }
+ }
+
+ if ( lf->frameTime > cg.time + 200 ) {
+ lf->frameTime = cg.time;
+ }
+
+ if ( lf->oldFrameTime > cg.time ) {
+ lf->oldFrameTime = cg.time;
+ }
+ // calculate current lerp value
+ if ( lf->frameTime == lf->oldFrameTime ) {
+ lf->backlerp = 0;
+ } else {
+ lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
+ }
+}
+
+
+/*
+===============
+CG_ClearLerpFrame
+===============
+*/
+static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) {
+ lf->frameTime = lf->oldFrameTime = cg.time;
+ CG_SetLerpFrameAnimation( ci, lf, animationNumber );
+ lf->oldFrame = lf->frame = lf->animation->firstFrame;
+}
+
+
+/*
+===============
+CG_PlayerAnimation
+===============
+*/
+static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,
+ int *torsoOld, int *torso, float *torsoBackLerp ) {
+ clientInfo_t *ci;
+ int clientNum;
+ float speedScale;
+
+ clientNum = cent->currentState.clientNum;
+
+ if ( cg_noPlayerAnims.integer ) {
+ *legsOld = *legs = *torsoOld = *torso = 0;
+ return;
+ }
+
+ if ( cent->currentState.powerups & ( 1 << PW_HASTE ) ) {
+ speedScale = 1.5;
+ } else {
+ speedScale = 1;
+ }
+
+ ci = &cgs.clientinfo[ clientNum ];
+
+ // do the shuffle turn frames locally
+ if ( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
+ CG_RunLerpFrame( ci, &cent->pe.legs, LEGS_TURN, speedScale );
+ } else {
+ CG_RunLerpFrame( ci, &cent->pe.legs, cent->currentState.legsAnim, speedScale );
+ }
+
+ *legsOld = cent->pe.legs.oldFrame;
+ *legs = cent->pe.legs.frame;
+ *legsBackLerp = cent->pe.legs.backlerp;
+
+ CG_RunLerpFrame( ci, &cent->pe.torso, cent->currentState.torsoAnim, speedScale );
+
+ *torsoOld = cent->pe.torso.oldFrame;
+ *torso = cent->pe.torso.frame;
+ *torsoBackLerp = cent->pe.torso.backlerp;
+}
+
+/*
+=============================================================================
+
+PLAYER ANGLES
+
+=============================================================================
+*/
+
+/*
+==================
+CG_SwingAngles
+==================
+*/
+static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance,
+ float speed, float *angle, qboolean *swinging ) {
+ float swing;
+ float move;
+ float scale;
+
+ if ( !*swinging ) {
+ // see if a swing should be started
+ swing = AngleSubtract( *angle, destination );
+ if ( swing > swingTolerance || swing < -swingTolerance ) {
+ *swinging = qtrue;
+ }
+ }
+
+ if ( !*swinging ) {
+ return;
+ }
+
+ // modify the speed depending on the delta
+ // so it doesn't seem so linear
+ swing = AngleSubtract( destination, *angle );
+ scale = fabs( swing );
+ if ( scale < swingTolerance * 0.5 ) {
+ scale = 0.5;
+ } else if ( scale < swingTolerance ) {
+ scale = 1.0;
+ } else {
+ scale = 2.0;
+ }
+
+ // swing towards the destination angle
+ if ( swing >= 0 ) {
+ move = cg.frametime * scale * speed;
+ if ( move >= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ } else if ( swing < 0 ) {
+ move = cg.frametime * scale * -speed;
+ if ( move <= swing ) {
+ move = swing;
+ *swinging = qfalse;
+ }
+ *angle = AngleMod( *angle + move );
+ }
+
+ // clamp to no more than tolerance
+ swing = AngleSubtract( destination, *angle );
+ if ( swing > clampTolerance ) {
+ *angle = AngleMod( destination - (clampTolerance - 1) );
+ } else if ( swing < -clampTolerance ) {
+ *angle = AngleMod( destination + (clampTolerance - 1) );
+ }
+}
+
+/*
+=================
+CG_AddPainTwitch
+=================
+*/
+static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) {
+ int t;
+ float f;
+
+ t = cg.time - cent->pe.painTime;
+ if ( t >= PAIN_TWITCH_TIME ) {
+ return;
+ }
+
+ f = 1.0 - (float)t / PAIN_TWITCH_TIME;
+
+ if ( cent->pe.painDirection ) {
+ torsoAngles[ROLL] += 20 * f;
+ } else {
+ torsoAngles[ROLL] -= 20 * f;
+ }
+}
+
+
+/*
+===============
+CG_PlayerAngles
+
+Handles seperate torso motion
+
+ legs pivot based on direction of movement
+
+ head always looks exactly at cent->lerpAngles
+
+ if motion < 20 degrees, show in head only
+ if < 45 degrees, also show in torso
+===============
+*/
+static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
+ vec3_t legsAngles, torsoAngles, headAngles;
+ float dest;
+ static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 };
+ vec3_t velocity;
+ float speed;
+ int dir, clientNum;
+ clientInfo_t *ci;
+
+ VectorCopy( cent->lerpAngles, headAngles );
+ headAngles[YAW] = AngleMod( headAngles[YAW] );
+ VectorClear( legsAngles );
+ VectorClear( torsoAngles );
+
+ // --------- yaw -------------
+
+ // allow yaw to drift a bit
+ if ( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE
+ || ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) {
+ // if not standing still, always point all in the same direction
+ cent->pe.torso.yawing = qtrue; // always center
+ cent->pe.torso.pitching = qtrue; // always center
+ cent->pe.legs.yawing = qtrue; // always center
+ }
+
+ // adjust legs for movement dir
+ if ( cent->currentState.eFlags & EF_DEAD ) {
+ // don't let dead bodies twitch
+ dir = 0;
+ } else {
+ dir = cent->currentState.angles2[YAW];
+ if ( dir < 0 || dir > 7 ) {
+ CG_Error( "Bad player movement angle" );
+ }
+ }
+ legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ];
+ torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ];
+
+ // torso
+ CG_SwingAngles( torsoAngles[YAW], 25, 90, cg_swingSpeed.value, &cent->pe.torso.yawAngle, &cent->pe.torso.yawing );
+ CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, &cent->pe.legs.yawAngle, &cent->pe.legs.yawing );
+
+ torsoAngles[YAW] = cent->pe.torso.yawAngle;
+ legsAngles[YAW] = cent->pe.legs.yawAngle;
+
+
+ // --------- pitch -------------
+
+ // only show a fraction of the pitch angle in the torso
+ if ( headAngles[PITCH] > 180 ) {
+ dest = (-360 + headAngles[PITCH]) * 0.75f;
+ } else {
+ dest = headAngles[PITCH] * 0.75f;
+ }
+ CG_SwingAngles( dest, 15, 30, 0.1f, &cent->pe.torso.pitchAngle, &cent->pe.torso.pitching );
+ torsoAngles[PITCH] = cent->pe.torso.pitchAngle;
+
+ //
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
+ ci = &cgs.clientinfo[ clientNum ];
+ if ( ci->fixedtorso ) {
+ torsoAngles[PITCH] = 0.0f;
+ }
+ }
+
+ // --------- roll -------------
+
+
+ // lean towards the direction of travel
+ VectorCopy( cent->currentState.pos.trDelta, velocity );
+ speed = VectorNormalize( velocity );
+ if ( speed ) {
+ vec3_t axis[3];
+ float side;
+
+ speed *= 0.05f;
+
+ AnglesToAxis( legsAngles, axis );
+ side = speed * DotProduct( velocity, axis[1] );
+ legsAngles[ROLL] -= side;
+
+ side = speed * DotProduct( velocity, axis[0] );
+ legsAngles[PITCH] += side;
+ }
+
+ //
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
+ ci = &cgs.clientinfo[ clientNum ];
+ if ( ci->fixedlegs ) {
+ legsAngles[YAW] = torsoAngles[YAW];
+ legsAngles[PITCH] = 0.0f;
+ legsAngles[ROLL] = 0.0f;
+ }
+ }
+
+ // pain twitch
+ CG_AddPainTwitch( cent, torsoAngles );
+
+ // pull the angles back out of the hierarchial chain
+ AnglesSubtract( headAngles, torsoAngles, headAngles );
+ AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
+ AnglesToAxis( legsAngles, legs );
+ AnglesToAxis( torsoAngles, torso );
+ AnglesToAxis( headAngles, head );
+}
+
+
+//==========================================================================
+
+/*
+===============
+CG_HasteTrail
+===============
+*/
+static void CG_HasteTrail( centity_t *cent ) {
+ localEntity_t *smoke;
+ vec3_t origin;
+ int anim;
+
+ if ( cent->trailTime > cg.time ) {
+ return;
+ }
+ anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
+ if ( anim != LEGS_RUN && anim != LEGS_BACK ) {
+ return;
+ }
+
+ cent->trailTime += 100;
+ if ( cent->trailTime < cg.time ) {
+ cent->trailTime = cg.time;
+ }
+
+ VectorCopy( cent->lerpOrigin, origin );
+ origin[2] -= 16;
+
+ smoke = CG_SmokePuff( origin, vec3_origin,
+ 8,
+ 1, 1, 1, 1,
+ 500,
+ cg.time,
+ 0,
+ 0,
+ cgs.media.hastePuffShader );
+
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+}
+
+#ifdef MISSIONPACK
+/*
+===============
+CG_BreathPuffs
+===============
+*/
+static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) {
+ clientInfo_t *ci;
+ vec3_t up, origin;
+ int contents;
+
+ ci = &cgs.clientinfo[ cent->currentState.number ];
+
+ if (!cg_enableBreath.integer) {
+ return;
+ }
+ if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) {
+ return;
+ }
+ if ( cent->currentState.eFlags & EF_DEAD ) {
+ return;
+ }
+ contents = trap_CM_PointContents( head->origin, 0 );
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ return;
+ }
+ if ( ci->breathPuffTime > cg.time ) {
+ return;
+ }
+
+ VectorSet( up, 0, 0, 8 );
+ VectorMA(head->origin, 8, head->axis[0], origin);
+ VectorMA(origin, -4, head->axis[2], origin);
+ CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
+ ci->breathPuffTime = cg.time + 2000;
+}
+
+/*
+===============
+CG_DustTrail
+===============
+*/
+static void CG_DustTrail( centity_t *cent ) {
+ int anim;
+ localEntity_t *dust;
+ vec3_t end, vel;
+ trace_t tr;
+
+ if (!cg_enableDust.integer)
+ return;
+
+ if ( cent->dustTrailTime > cg.time ) {
+ return;
+ }
+
+ anim = cent->pe.legs.animationNumber & ~ANIM_TOGGLEBIT;
+ if ( anim != LEGS_LANDB && anim != LEGS_LAND ) {
+ return;
+ }
+
+ cent->dustTrailTime += 40;
+ if ( cent->dustTrailTime < cg.time ) {
+ cent->dustTrailTime = cg.time;
+ }
+
+ VectorCopy(cent->currentState.pos.trBase, end);
+ end[2] -= 64;
+ CG_Trace( &tr, cent->currentState.pos.trBase, NULL, NULL, end, cent->currentState.number, MASK_PLAYERSOLID );
+
+ if ( !(tr.surfaceFlags & SURF_DUST) )
+ return;
+
+ VectorCopy( cent->currentState.pos.trBase, end );
+ end[2] -= 16;
+
+ VectorSet(vel, 0, 0, -30);
+ dust = CG_SmokePuff( end, vel,
+ 24,
+ .8f, .8f, 0.7f, 0.33f,
+ 500,
+ cg.time,
+ 0,
+ 0,
+ cgs.media.dustPuffShader );
+}
+
+#endif
+
+/*
+===============
+CG_TrailItem
+===============
+*/
+static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {
+ refEntity_t ent;
+ vec3_t angles;
+ vec3_t axis[3];
+
+ VectorCopy( cent->lerpAngles, angles );
+ angles[PITCH] = 0;
+ angles[ROLL] = 0;
+ AnglesToAxis( angles, axis );
+
+ memset( &ent, 0, sizeof( ent ) );
+ VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );
+ ent.origin[2] += 16;
+ angles[YAW] += 90;
+ AnglesToAxis( angles, ent.axis );
+
+ ent.hModel = hModel;
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+===============
+CG_PlayerFlag
+===============
+*/
+static void CG_PlayerFlag( centity_t *cent, qhandle_t hSkin, refEntity_t *torso ) {
+ clientInfo_t *ci;
+ refEntity_t pole;
+ refEntity_t flag;
+ vec3_t angles, dir;
+ int legsAnim, flagAnim, updateangles;
+ float angle, d;
+
+ // show the flag pole model
+ memset( &pole, 0, sizeof(pole) );
+ pole.hModel = cgs.media.flagPoleModel;
+ VectorCopy( torso->lightingOrigin, pole.lightingOrigin );
+ pole.shadowPlane = torso->shadowPlane;
+ pole.renderfx = torso->renderfx;
+ CG_PositionEntityOnTag( &pole, torso, torso->hModel, "tag_flag" );
+ trap_R_AddRefEntityToScene( &pole );
+
+ // show the flag model
+ memset( &flag, 0, sizeof(flag) );
+ flag.hModel = cgs.media.flagFlapModel;
+ flag.customSkin = hSkin;
+ VectorCopy( torso->lightingOrigin, flag.lightingOrigin );
+ flag.shadowPlane = torso->shadowPlane;
+ flag.renderfx = torso->renderfx;
+
+ VectorClear(angles);
+
+ updateangles = qfalse;
+ legsAnim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
+ if( legsAnim == LEGS_IDLE || legsAnim == LEGS_IDLECR ) {
+ flagAnim = FLAG_STAND;
+ } else if ( legsAnim == LEGS_WALK || legsAnim == LEGS_WALKCR ) {
+ flagAnim = FLAG_STAND;
+ updateangles = qtrue;
+ } else {
+ flagAnim = FLAG_RUN;
+ updateangles = qtrue;
+ }
+
+ if ( updateangles ) {
+
+ VectorCopy( cent->currentState.pos.trDelta, dir );
+ // add gravity
+ dir[2] += 100;
+ VectorNormalize( dir );
+ d = DotProduct(pole.axis[2], dir);
+ // if there is anough movement orthogonal to the flag pole
+ if (fabs(d) < 0.9) {
+ //
+ d = DotProduct(pole.axis[0], dir);
+ if (d > 1.0f) {
+ d = 1.0f;
+ }
+ else if (d < -1.0f) {
+ d = -1.0f;
+ }
+ angle = acos(d);
+
+ d = DotProduct(pole.axis[1], dir);
+ if (d < 0) {
+ angles[YAW] = 360 - angle * 180 / M_PI;
+ }
+ else {
+ angles[YAW] = angle * 180 / M_PI;
+ }
+ if (angles[YAW] < 0)
+ angles[YAW] += 360;
+ if (angles[YAW] > 360)
+ angles[YAW] -= 360;
+
+ //vectoangles( cent->currentState.pos.trDelta, tmpangles );
+ //angles[YAW] = tmpangles[YAW] + 45 - cent->pe.torso.yawAngle;
+ // change the yaw angle
+ CG_SwingAngles( angles[YAW], 25, 90, 0.15f, &cent->pe.flag.yawAngle, &cent->pe.flag.yawing );
+ }
+
+ /*
+ d = DotProduct(pole.axis[2], dir);
+ angle = Q_acos(d);
+
+ d = DotProduct(pole.axis[1], dir);
+ if (d < 0) {
+ angle = 360 - angle * 180 / M_PI;
+ }
+ else {
+ angle = angle * 180 / M_PI;
+ }
+ if (angle > 340 && angle < 20) {
+ flagAnim = FLAG_RUNUP;
+ }
+ if (angle > 160 && angle < 200) {
+ flagAnim = FLAG_RUNDOWN;
+ }
+ */
+ }
+
+ // set the yaw angle
+ angles[YAW] = cent->pe.flag.yawAngle;
+ // lerp the flag animation frames
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ CG_RunLerpFrame( ci, &cent->pe.flag, flagAnim, 1 );
+ flag.oldframe = cent->pe.flag.oldFrame;
+ flag.frame = cent->pe.flag.frame;
+ flag.backlerp = cent->pe.flag.backlerp;
+
+ AnglesToAxis( angles, flag.axis );
+ CG_PositionRotatedEntityOnTag( &flag, &pole, pole.hModel, "tag_flag" );
+
+ trap_R_AddRefEntityToScene( &flag );
+}
+
+
+#ifdef MISSIONPACK // bk001204
+/*
+===============
+CG_PlayerTokens
+===============
+*/
+static void CG_PlayerTokens( centity_t *cent, int renderfx ) {
+ int tokens, i, j;
+ float angle;
+ refEntity_t ent;
+ vec3_t dir, origin;
+ skulltrail_t *trail;
+ trail = &cg.skulltrails[cent->currentState.number];
+ tokens = cent->currentState.generic1;
+ if ( !tokens ) {
+ trail->numpositions = 0;
+ return;
+ }
+
+ if ( tokens > MAX_SKULLTRAIL ) {
+ tokens = MAX_SKULLTRAIL;
+ }
+
+ // add skulls if there are more than last time
+ for (i = 0; i < tokens - trail->numpositions; i++) {
+ for (j = trail->numpositions; j > 0; j--) {
+ VectorCopy(trail->positions[j-1], trail->positions[j]);
+ }
+ VectorCopy(cent->lerpOrigin, trail->positions[0]);
+ }
+ trail->numpositions = tokens;
+
+ // move all the skulls along the trail
+ VectorCopy(cent->lerpOrigin, origin);
+ for (i = 0; i < trail->numpositions; i++) {
+ VectorSubtract(trail->positions[i], origin, dir);
+ if (VectorNormalize(dir) > 30) {
+ VectorMA(origin, 30, dir, trail->positions[i]);
+ }
+ VectorCopy(trail->positions[i], origin);
+ }
+
+ memset( &ent, 0, sizeof( ent ) );
+ if( cgs.clientinfo[ cent->currentState.clientNum ].team == TEAM_BLUE ) {
+ ent.hModel = cgs.media.redCubeModel;
+ } else {
+ ent.hModel = cgs.media.blueCubeModel;
+ }
+ ent.renderfx = renderfx;
+
+ VectorCopy(cent->lerpOrigin, origin);
+ for (i = 0; i < trail->numpositions; i++) {
+ VectorSubtract(origin, trail->positions[i], ent.axis[0]);
+ ent.axis[0][2] = 0;
+ VectorNormalize(ent.axis[0]);
+ VectorSet(ent.axis[2], 0, 0, 1);
+ CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]);
+
+ VectorCopy(trail->positions[i], ent.origin);
+ angle = (((cg.time + 500 * MAX_SKULLTRAIL - 500 * i) / 16) & 255) * (M_PI * 2) / 255;
+ ent.origin[2] += sin(angle) * 10;
+ trap_R_AddRefEntityToScene( &ent );
+ VectorCopy(trail->positions[i], origin);
+ }
+}
+#endif
+
+
+/*
+===============
+CG_PlayerPowerups
+===============
+*/
+static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {
+ int powerups;
+ clientInfo_t *ci;
+
+ powerups = cent->currentState.powerups;
+ if ( !powerups ) {
+ return;
+ }
+
+ // quad gives a dlight
+ if ( powerups & ( 1 << PW_QUAD ) ) {
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );
+ }
+
+ // flight plays a looped sound
+ if ( powerups & ( 1 << PW_FLIGHT ) ) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound );
+ }
+
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ // redflag
+ if ( powerups & ( 1 << PW_REDFLAG ) ) {
+ if (ci->newAnims) {
+ CG_PlayerFlag( cent, cgs.media.redFlagFlapSkin, torso );
+ }
+ else {
+ CG_TrailItem( cent, cgs.media.redFlagModel );
+ }
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );
+ }
+
+ // blueflag
+ if ( powerups & ( 1 << PW_BLUEFLAG ) ) {
+ if (ci->newAnims){
+ CG_PlayerFlag( cent, cgs.media.blueFlagFlapSkin, torso );
+ }
+ else {
+ CG_TrailItem( cent, cgs.media.blueFlagModel );
+ }
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );
+ }
+
+ // neutralflag
+ if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ if (ci->newAnims) {
+ CG_PlayerFlag( cent, cgs.media.neutralFlagFlapSkin, torso );
+ }
+ else {
+ CG_TrailItem( cent, cgs.media.neutralFlagModel );
+ }
+ trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );
+ }
+
+ // haste leaves smoke trails
+ if ( powerups & ( 1 << PW_HASTE ) ) {
+ CG_HasteTrail( cent );
+ }
+}
+
+
+/*
+===============
+CG_PlayerFloatSprite
+
+Float a sprite over the player's head
+===============
+*/
+static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
+ int rf;
+ refEntity_t ent;
+
+ if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
+ rf = RF_THIRD_PERSON; // only show in mirrors
+ } else {
+ rf = 0;
+ }
+
+ memset( &ent, 0, sizeof( ent ) );
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ ent.origin[2] += 48;
+ ent.reType = RT_SPRITE;
+ ent.customShader = shader;
+ ent.radius = 10;
+ ent.renderfx = rf;
+ ent.shaderRGBA[0] = 255;
+ ent.shaderRGBA[1] = 255;
+ ent.shaderRGBA[2] = 255;
+ ent.shaderRGBA[3] = 255;
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+
+/*
+===============
+CG_PlayerSprites
+
+Float sprites over the player's head
+===============
+*/
+static void CG_PlayerSprites( centity_t *cent ) {
+ int team;
+
+ if ( cent->currentState.eFlags & EF_CONNECTION ) {
+ CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_TALK ) {
+ CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalImpressive );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalExcellent );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalDefend );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalAssist );
+ return;
+ }
+
+ if ( cent->currentState.eFlags & EF_AWARD_CAP ) {
+ CG_PlayerFloatSprite( cent, cgs.media.medalCapture );
+ return;
+ }
+
+ team = cgs.clientinfo[ cent->currentState.clientNum ].team;
+ if ( !(cent->currentState.eFlags & EF_DEAD) &&
+ cg.snap->ps.persistant[PERS_TEAM] == team &&
+ cgs.gametype >= GT_TEAM) {
+ if (cg_drawFriend.integer) {
+ CG_PlayerFloatSprite( cent, cgs.media.friendShader );
+ }
+ return;
+ }
+}
+
+/*
+===============
+CG_PlayerShadow
+
+Returns the Z component of the surface being shadowed
+
+ should it return a full plane instead of a Z?
+===============
+*/
+#define SHADOW_DISTANCE 128
+static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
+ vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
+ trace_t trace;
+ float alpha;
+
+ *shadowPlane = 0;
+
+ if ( cg_shadows.integer == 0 ) {
+ return qfalse;
+ }
+
+ // no shadows when invisible
+ if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) {
+ return qfalse;
+ }
+
+ // send a trace down from the player to the ground
+ VectorCopy( cent->lerpOrigin, end );
+ end[2] -= SHADOW_DISTANCE;
+
+ trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
+
+ // no shadow if too high
+ if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
+ return qfalse;
+ }
+
+ *shadowPlane = trace.endpos[2] + 1;
+
+ if ( cg_shadows.integer != 1 ) { // no mark for stencil or projection shadows
+ return qtrue;
+ }
+
+ // fade the shadow out with height
+ alpha = 1.0 - trace.fraction;
+
+ // bk0101022 - hack / FPE - bogus planes?
+ //assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
+
+ // add the mark as a temporary, so it goes directly to the renderer
+ // without taking a spot in the cg_marks array
+ CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
+ cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, 24, qtrue );
+
+ return qtrue;
+}
+
+
+/*
+===============
+CG_PlayerSplash
+
+Draw a mark at the water surface
+===============
+*/
+static void CG_PlayerSplash( centity_t *cent ) {
+ vec3_t start, end;
+ trace_t trace;
+ int contents;
+ polyVert_t verts[4];
+
+ if ( !cg_shadows.integer ) {
+ return;
+ }
+
+ VectorCopy( cent->lerpOrigin, end );
+ end[2] -= 24;
+
+ // if the feet aren't in liquid, don't make a mark
+ // this won't handle moving water brushes, but they wouldn't draw right anyway...
+ contents = trap_CM_PointContents( end, 0 );
+ if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
+ return;
+ }
+
+ VectorCopy( cent->lerpOrigin, start );
+ start[2] += 32;
+
+ // if the head isn't out of liquid, don't make a mark
+ contents = trap_CM_PointContents( start, 0 );
+ if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ return;
+ }
+
+ // trace down to find the surface
+ trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
+
+ if ( trace.fraction == 1.0 ) {
+ return;
+ }
+
+ // create a mark polygon
+ VectorCopy( trace.endpos, verts[0].xyz );
+ verts[0].xyz[0] -= 32;
+ verts[0].xyz[1] -= 32;
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 0;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorCopy( trace.endpos, verts[1].xyz );
+ verts[1].xyz[0] -= 32;
+ verts[1].xyz[1] += 32;
+ verts[1].st[0] = 0;
+ verts[1].st[1] = 1;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorCopy( trace.endpos, verts[2].xyz );
+ verts[2].xyz[0] += 32;
+ verts[2].xyz[1] += 32;
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorCopy( trace.endpos, verts[3].xyz );
+ verts[3].xyz[0] += 32;
+ verts[3].xyz[1] -= 32;
+ verts[3].st[0] = 1;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
+}
+
+
+
+/*
+===============
+CG_AddRefEntityWithPowerups
+
+Adds a piece with modifications or duplications for powerups
+Also called by CG_Missile for quad rockets, but nobody can tell...
+===============
+*/
+void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) {
+
+ if ( state->powerups & ( 1 << PW_INVIS ) ) {
+ ent->customShader = cgs.media.invisShader;
+ trap_R_AddRefEntityToScene( ent );
+ } else {
+ /*
+ if ( state->eFlags & EF_KAMIKAZE ) {
+ if (team == TEAM_BLUE)
+ ent->customShader = cgs.media.blueKamikazeShader;
+ else
+ ent->customShader = cgs.media.redKamikazeShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ else {*/
+ trap_R_AddRefEntityToScene( ent );
+ //}
+
+ if ( state->powerups & ( 1 << PW_QUAD ) )
+ {
+ if (team == TEAM_RED)
+ ent->customShader = cgs.media.redQuadShader;
+ else
+ ent->customShader = cgs.media.quadShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ if ( state->powerups & ( 1 << PW_REGEN ) ) {
+ if ( ( ( cg.time / 100 ) % 10 ) == 1 ) {
+ ent->customShader = cgs.media.regenShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ }
+ if ( state->powerups & ( 1 << PW_BATTLESUIT ) ) {
+ ent->customShader = cgs.media.battleSuitShader;
+ trap_R_AddRefEntityToScene( ent );
+ }
+ }
+}
+
+/*
+=================
+CG_LightVerts
+=================
+*/
+int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
+{
+ int i, j;
+ float incoming;
+ vec3_t ambientLight;
+ vec3_t lightDir;
+ vec3_t directedLight;
+
+ trap_R_LightForPoint( verts[0].xyz, ambientLight, directedLight, lightDir );
+
+ for (i = 0; i < numVerts; i++) {
+ incoming = DotProduct (normal, lightDir);
+ if ( incoming <= 0 ) {
+ verts[i].modulate[0] = ambientLight[0];
+ verts[i].modulate[1] = ambientLight[1];
+ verts[i].modulate[2] = ambientLight[2];
+ verts[i].modulate[3] = 255;
+ continue;
+ }
+ j = ( ambientLight[0] + incoming * directedLight[0] );
+ if ( j > 255 ) {
+ j = 255;
+ }
+ verts[i].modulate[0] = j;
+
+ j = ( ambientLight[1] + incoming * directedLight[1] );
+ if ( j > 255 ) {
+ j = 255;
+ }
+ verts[i].modulate[1] = j;
+
+ j = ( ambientLight[2] + incoming * directedLight[2] );
+ if ( j > 255 ) {
+ j = 255;
+ }
+ verts[i].modulate[2] = j;
+
+ verts[i].modulate[3] = 255;
+ }
+ return qtrue;
+}
+
+/*
+===============
+CG_Player
+===============
+*/
+void CG_Player( centity_t *cent ) {
+ clientInfo_t *ci;
+ refEntity_t legs;
+ refEntity_t torso;
+ refEntity_t head;
+ int clientNum;
+ int renderfx;
+ qboolean shadow;
+ float shadowPlane;
+#ifdef MISSIONPACK
+ refEntity_t skull;
+ refEntity_t powerup;
+ int t;
+ float c;
+ float angle;
+ vec3_t dir, angles;
+#endif
+
+ // the client number is stored in clientNum. It can't be derived
+ // from the entity number, because a single client may have
+ // multiple corpses on the level using the same clientinfo
+ clientNum = cent->currentState.clientNum;
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ CG_Error( "Bad clientNum on player entity");
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ // it is possible to see corpses from disconnected players that may
+ // not have valid clientinfo
+ if ( !ci->infoValid ) {
+ return;
+ }
+
+ // get the player model information
+ renderfx = 0;
+ if ( cent->currentState.number == cg.snap->ps.clientNum) {
+ if (!cg.renderingThirdPerson) {
+ renderfx = RF_THIRD_PERSON; // only draw in mirrors
+ } else {
+ if (cg_cameraMode.integer) {
+ return;
+ }
+ }
+ }
+
+
+ memset( &legs, 0, sizeof(legs) );
+ memset( &torso, 0, sizeof(torso) );
+ memset( &head, 0, sizeof(head) );
+
+ // get the rotation information
+ CG_PlayerAngles( cent, legs.axis, torso.axis, head.axis );
+
+ // get the animation state (after rotation, to allow feet shuffle)
+ CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp,
+ &torso.oldframe, &torso.frame, &torso.backlerp );
+
+ // add the talk baloon or disconnect icon
+ CG_PlayerSprites( cent );
+
+ // add the shadow
+ shadow = CG_PlayerShadow( cent, &shadowPlane );
+
+ // add a water splash if partially in and out of water
+ CG_PlayerSplash( cent );
+
+ if ( cg_shadows.integer == 3 && shadow ) {
+ renderfx |= RF_SHADOW_PLANE;
+ }
+ renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all
+#ifdef MISSIONPACK
+ if( cgs.gametype == GT_HARVESTER ) {
+ CG_PlayerTokens( cent, renderfx );
+ }
+#endif
+ //
+ // add the legs
+ //
+ legs.hModel = ci->legsModel;
+ legs.customSkin = ci->legsSkin;
+
+ VectorCopy( cent->lerpOrigin, legs.origin );
+
+ VectorCopy( cent->lerpOrigin, legs.lightingOrigin );
+ legs.shadowPlane = shadowPlane;
+ legs.renderfx = renderfx;
+ VectorCopy (legs.origin, legs.oldorigin); // don't positionally lerp at all
+
+ CG_AddRefEntityWithPowerups( &legs, &cent->currentState, ci->team );
+
+ // if the model failed, allow the default nullmodel to be displayed
+ if (!legs.hModel) {
+ return;
+ }
+
+ //
+ // add the torso
+ //
+ torso.hModel = ci->torsoModel;
+ if (!torso.hModel) {
+ return;
+ }
+
+ torso.customSkin = ci->torsoSkin;
+
+ VectorCopy( cent->lerpOrigin, torso.lightingOrigin );
+
+ CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso");
+
+ torso.shadowPlane = shadowPlane;
+ torso.renderfx = renderfx;
+
+ CG_AddRefEntityWithPowerups( &torso, &cent->currentState, ci->team );
+
+#ifdef MISSIONPACK
+ if ( cent->currentState.eFlags & EF_KAMIKAZE ) {
+
+ memset( &skull, 0, sizeof(skull) );
+
+ VectorCopy( cent->lerpOrigin, skull.lightingOrigin );
+ skull.shadowPlane = shadowPlane;
+ skull.renderfx = renderfx;
+
+ if ( cent->currentState.eFlags & EF_DEAD ) {
+ // one skull bobbing above the dead body
+ angle = ((cg.time / 7) & 255) * (M_PI * 2) / 255;
+ if (angle > M_PI * 2)
+ angle -= (float)M_PI * 2;
+ dir[0] = sin(angle) * 20;
+ dir[1] = cos(angle) * 20;
+ angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
+ dir[2] = 15 + sin(angle) * 8;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ dir[2] = 0;
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+ }
+ else {
+ // three skulls spinning around the player
+ angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255;
+ dir[0] = cos(angle) * 20;
+ dir[1] = sin(angle) * 20;
+ dir[2] = cos(angle) * 20;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ angles[0] = sin(angle) * 30;
+ angles[1] = (angle * 180 / M_PI) + 90;
+ if (angles[1] > 360)
+ angles[1] -= 360;
+ angles[2] = 0;
+ AnglesToAxis( angles, skull.axis );
+
+ /*
+ dir[2] = 0;
+ VectorInverse(dir);
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+ */
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ // flip the trail because this skull is spinning in the other direction
+ VectorInverse(skull.axis[1]);
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+
+ angle = ((cg.time / 4) & 255) * (M_PI * 2) / 255 + M_PI;
+ if (angle > M_PI * 2)
+ angle -= (float)M_PI * 2;
+ dir[0] = sin(angle) * 20;
+ dir[1] = cos(angle) * 20;
+ dir[2] = cos(angle) * 20;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ angles[0] = cos(angle - 0.5 * M_PI) * 30;
+ angles[1] = 360 - (angle * 180 / M_PI);
+ if (angles[1] > 360)
+ angles[1] -= 360;
+ angles[2] = 0;
+ AnglesToAxis( angles, skull.axis );
+
+ /*
+ dir[2] = 0;
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+ */
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+
+ angle = ((cg.time / 3) & 255) * (M_PI * 2) / 255 + 0.5 * M_PI;
+ if (angle > M_PI * 2)
+ angle -= (float)M_PI * 2;
+ dir[0] = sin(angle) * 20;
+ dir[1] = cos(angle) * 20;
+ dir[2] = 0;
+ VectorAdd(torso.origin, dir, skull.origin);
+
+ VectorCopy(dir, skull.axis[1]);
+ VectorNormalize(skull.axis[1]);
+ VectorSet(skull.axis[2], 0, 0, 1);
+ CrossProduct(skull.axis[1], skull.axis[2], skull.axis[0]);
+
+ skull.hModel = cgs.media.kamikazeHeadModel;
+ trap_R_AddRefEntityToScene( &skull );
+ skull.hModel = cgs.media.kamikazeHeadTrail;
+ trap_R_AddRefEntityToScene( &skull );
+ }
+ }
+
+ if ( cent->currentState.powerups & ( 1 << PW_GUARD ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.guardPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_SCOUT ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.scoutPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_DOUBLER ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.doublerPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_AMMOREGEN ) ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.ammoRegenPowerupModel;
+ powerup.frame = 0;
+ powerup.oldframe = 0;
+ powerup.customSkin = 0;
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+ if ( cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) {
+ if ( !ci->invulnerabilityStartTime ) {
+ ci->invulnerabilityStartTime = cg.time;
+ }
+ ci->invulnerabilityStopTime = cg.time;
+ }
+ else {
+ ci->invulnerabilityStartTime = 0;
+ }
+ if ( (cent->currentState.powerups & ( 1 << PW_INVULNERABILITY ) ) ||
+ cg.time - ci->invulnerabilityStopTime < 250 ) {
+
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.invulnerabilityPowerupModel;
+ powerup.customSkin = 0;
+ // always draw
+ powerup.renderfx &= ~RF_THIRD_PERSON;
+ VectorCopy(cent->lerpOrigin, powerup.origin);
+
+ if ( cg.time - ci->invulnerabilityStartTime < 250 ) {
+ c = (float) (cg.time - ci->invulnerabilityStartTime) / 250;
+ }
+ else if (cg.time - ci->invulnerabilityStopTime < 250 ) {
+ c = (float) (250 - (cg.time - ci->invulnerabilityStopTime)) / 250;
+ }
+ else {
+ c = 1;
+ }
+ VectorSet( powerup.axis[0], c, 0, 0 );
+ VectorSet( powerup.axis[1], 0, c, 0 );
+ VectorSet( powerup.axis[2], 0, 0, c );
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+
+ t = cg.time - ci->medkitUsageTime;
+ if ( ci->medkitUsageTime && t < 500 ) {
+ memcpy(&powerup, &torso, sizeof(torso));
+ powerup.hModel = cgs.media.medkitUsageModel;
+ powerup.customSkin = 0;
+ // always draw
+ powerup.renderfx &= ~RF_THIRD_PERSON;
+ VectorClear(angles);
+ AnglesToAxis(angles, powerup.axis);
+ VectorCopy(cent->lerpOrigin, powerup.origin);
+ powerup.origin[2] += -24 + (float) t * 80 / 500;
+ if ( t > 400 ) {
+ c = (float) (t - 1000) * 0xff / 100;
+ powerup.shaderRGBA[0] = 0xff - c;
+ powerup.shaderRGBA[1] = 0xff - c;
+ powerup.shaderRGBA[2] = 0xff - c;
+ powerup.shaderRGBA[3] = 0xff - c;
+ }
+ else {
+ powerup.shaderRGBA[0] = 0xff;
+ powerup.shaderRGBA[1] = 0xff;
+ powerup.shaderRGBA[2] = 0xff;
+ powerup.shaderRGBA[3] = 0xff;
+ }
+ trap_R_AddRefEntityToScene( &powerup );
+ }
+#endif // MISSIONPACK
+
+ //
+ // add the head
+ //
+ head.hModel = ci->headModel;
+ if (!head.hModel) {
+ return;
+ }
+ head.customSkin = ci->headSkin;
+
+ VectorCopy( cent->lerpOrigin, head.lightingOrigin );
+
+ CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head");
+
+ head.shadowPlane = shadowPlane;
+ head.renderfx = renderfx;
+
+ CG_AddRefEntityWithPowerups( &head, &cent->currentState, ci->team );
+
+#ifdef MISSIONPACK
+ CG_BreathPuffs(cent, &head);
+
+ CG_DustTrail(cent);
+#endif
+
+ //
+ // add the gun / barrel / flash
+ //
+ CG_AddPlayerWeapon( &torso, NULL, cent, ci->team );
+
+ // add powerups floating behind the player
+ CG_PlayerPowerups( cent, &torso );
+}
+
+
+//=====================================================================
+
+/*
+===============
+CG_ResetPlayerEntity
+
+A player just came into view or teleported, so reset all animation info
+===============
+*/
+void CG_ResetPlayerEntity( centity_t *cent ) {
+ cent->errorTime = -99999; // guarantee no error decay added
+ cent->extrapolated = qfalse;
+
+ CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], &cent->pe.legs, cent->currentState.legsAnim );
+ CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], &cent->pe.torso, cent->currentState.torsoAnim );
+
+ BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
+ BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
+
+ VectorCopy( cent->lerpOrigin, cent->rawOrigin );
+ VectorCopy( cent->lerpAngles, cent->rawAngles );
+
+ memset( &cent->pe.legs, 0, sizeof( cent->pe.legs ) );
+ cent->pe.legs.yawAngle = cent->rawAngles[YAW];
+ cent->pe.legs.yawing = qfalse;
+ cent->pe.legs.pitchAngle = 0;
+ cent->pe.legs.pitching = qfalse;
+
+ memset( &cent->pe.torso, 0, sizeof( cent->pe.legs ) );
+ cent->pe.torso.yawAngle = cent->rawAngles[YAW];
+ cent->pe.torso.yawing = qfalse;
+ cent->pe.torso.pitchAngle = cent->rawAngles[PITCH];
+ cent->pe.torso.pitching = qfalse;
+
+ if ( cg_debugPosition.integer ) {
+ CG_Printf("%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle );
+ }
+}
+
diff --git a/code/cgame/cg_playerstate.c b/code/cgame/cg_playerstate.c
index 1e0d61a..16f3608 100755
--- a/code/cgame/cg_playerstate.c
+++ b/code/cgame/cg_playerstate.c
@@ -1,526 +1,526 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_playerstate.c -- this file acts on changes in a new playerState_t
-// With normal play, this will be done after local prediction, but when
-// following another player or playing back a demo, it will be checked
-// when the snapshot transitions like all the other entities
-
-#include "cg_local.h"
-
-/*
-==============
-CG_CheckAmmo
-
-If the ammo has gone low enough to generate the warning, play a sound
-==============
-*/
-void CG_CheckAmmo( void ) {
- int i;
- int total;
- int previous;
- int weapons;
-
- // see about how many seconds of ammo we have remaining
- weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
- total = 0;
- for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
- if ( ! ( weapons & ( 1 << i ) ) ) {
- continue;
- }
- switch ( i ) {
- case WP_ROCKET_LAUNCHER:
- case WP_GRENADE_LAUNCHER:
- case WP_RAILGUN:
- case WP_SHOTGUN:
-#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
-#endif
- total += cg.snap->ps.ammo[i] * 1000;
- break;
- default:
- total += cg.snap->ps.ammo[i] * 200;
- break;
- }
- if ( total >= 5000 ) {
- cg.lowAmmoWarning = 0;
- return;
- }
- }
-
- previous = cg.lowAmmoWarning;
-
- if ( total == 0 ) {
- cg.lowAmmoWarning = 2;
- } else {
- cg.lowAmmoWarning = 1;
- }
-
- // play a sound on transitions
- if ( cg.lowAmmoWarning != previous ) {
- trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );
- }
-}
-
-/*
-==============
-CG_DamageFeedback
-==============
-*/
-void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
- float left, front, up;
- float kick;
- int health;
- float scale;
- vec3_t dir;
- vec3_t angles;
- float dist;
- float yaw, pitch;
-
- // show the attacking player's head and name in corner
- cg.attackerTime = cg.time;
-
- // the lower on health you are, the greater the view kick will be
- health = cg.snap->ps.stats[STAT_HEALTH];
- if ( health < 40 ) {
- scale = 1;
- } else {
- scale = 40.0 / health;
- }
- kick = damage * scale;
-
- if (kick < 5)
- kick = 5;
- if (kick > 10)
- kick = 10;
-
- // if yaw and pitch are both 255, make the damage always centered (falling, etc)
- if ( yawByte == 255 && pitchByte == 255 ) {
- cg.damageX = 0;
- cg.damageY = 0;
- cg.v_dmg_roll = 0;
- cg.v_dmg_pitch = -kick;
- } else {
- // positional
- pitch = pitchByte / 255.0 * 360;
- yaw = yawByte / 255.0 * 360;
-
- angles[PITCH] = pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-
- AngleVectors( angles, dir, NULL, NULL );
- VectorSubtract( vec3_origin, dir, dir );
-
- front = DotProduct (dir, cg.refdef.viewaxis[0] );
- left = DotProduct (dir, cg.refdef.viewaxis[1] );
- up = DotProduct (dir, cg.refdef.viewaxis[2] );
-
- dir[0] = front;
- dir[1] = left;
- dir[2] = 0;
- dist = VectorLength( dir );
- if ( dist < 0.1 ) {
- dist = 0.1f;
- }
-
- cg.v_dmg_roll = kick * left;
-
- cg.v_dmg_pitch = -kick * front;
-
- if ( front <= 0.1 ) {
- front = 0.1f;
- }
- cg.damageX = -left / front;
- cg.damageY = up / dist;
- }
-
- // clamp the position
- if ( cg.damageX > 1.0 ) {
- cg.damageX = 1.0;
- }
- if ( cg.damageX < - 1.0 ) {
- cg.damageX = -1.0;
- }
-
- if ( cg.damageY > 1.0 ) {
- cg.damageY = 1.0;
- }
- if ( cg.damageY < - 1.0 ) {
- cg.damageY = -1.0;
- }
-
- // don't let the screen flashes vary as much
- if ( kick > 10 ) {
- kick = 10;
- }
- cg.damageValue = kick;
- cg.v_dmg_time = cg.time + DAMAGE_TIME;
- cg.damageTime = cg.snap->serverTime;
-}
-
-
-
-
-/*
-================
-CG_Respawn
-
-A respawn happened this snapshot
-================
-*/
-void CG_Respawn( void ) {
- // no error decay on player movement
- cg.thisFrameTeleport = qtrue;
-
- // display weapons available
- cg.weaponSelectTime = cg.time;
-
- // select the weapon the server says we are using
- cg.weaponSelect = cg.snap->ps.weapon;
-}
-
-extern char *eventnames[];
-
-/*
-==============
-CG_CheckPlayerstateEvents
-==============
-*/
-void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
- int i;
- int event;
- centity_t *cent;
-
- if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
- cent = &cg_entities[ ps->clientNum ];
- cent->currentState.event = ps->externalEvent;
- cent->currentState.eventParm = ps->externalEventParm;
- CG_EntityEvent( cent, cent->lerpOrigin );
- }
-
- cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
- // go through the predictable events buffer
- for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
- // if we have a new predictable event
- if ( i >= ops->eventSequence
- // or the server told us to play another event instead of a predicted event we already issued
- // or something the server told us changed our prediction causing a different event
- || (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {
-
- event = ps->events[ i & (MAX_PS_EVENTS-1) ];
- cent->currentState.event = event;
- cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
- CG_EntityEvent( cent, cent->lerpOrigin );
-
- cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
-
- cg.eventSequence++;
- }
- }
-}
-
-/*
-==================
-CG_CheckChangedPredictableEvents
-==================
-*/
-void CG_CheckChangedPredictableEvents( playerState_t *ps ) {
- int i;
- int event;
- centity_t *cent;
-
- cent = &cg.predictedPlayerEntity;
- for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
- //
- if (i >= cg.eventSequence) {
- continue;
- }
- // if this event is not further back in than the maximum predictable events we remember
- if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {
- // if the new playerstate event is different from a previously predicted one
- if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {
-
- event = ps->events[ i & (MAX_PS_EVENTS-1) ];
- cent->currentState.event = event;
- cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
- CG_EntityEvent( cent, cent->lerpOrigin );
-
- cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
-
- if ( cg_showmiss.integer ) {
- CG_Printf("WARNING: changed predicted event\n");
- }
- }
- }
- }
-}
-
-/*
-==================
-pushReward
-==================
-*/
-static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) {
- if (cg.rewardStack < (MAX_REWARDSTACK-1)) {
- cg.rewardStack++;
- cg.rewardSound[cg.rewardStack] = sfx;
- cg.rewardShader[cg.rewardStack] = shader;
- cg.rewardCount[cg.rewardStack] = rewardCount;
- }
-}
-
-/*
-==================
-CG_CheckLocalSounds
-==================
-*/
-void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {
- int highScore, health, armor, reward;
- sfxHandle_t sfx;
-
- // don't play the sounds if the player just changed teams
- if ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) {
- return;
- }
-
- // hit changes
- if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {
- armor = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff;
- health = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8;
-#ifdef MISSIONPACK
- if (armor > 50 ) {
- trap_S_StartLocalSound( cgs.media.hitSoundHighArmor, CHAN_LOCAL_SOUND );
- } else if (armor || health > 100) {
- trap_S_StartLocalSound( cgs.media.hitSoundLowArmor, CHAN_LOCAL_SOUND );
- } else {
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
- }
-#else
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
-#endif
- } else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {
- trap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND );
- }
-
- // health changes of more than -1 should make pain sounds
- if ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) {
- if ( ps->stats[STAT_HEALTH] > 0 ) {
- CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] );
- }
- }
-
-
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- // reward sounds
- reward = qfalse;
- if (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) {
- pushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]);
- reward = qtrue;
- //Com_Printf("capture\n");
- }
- if (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) {
-#ifdef MISSIONPACK
- if (ps->persistant[PERS_IMPRESSIVE_COUNT] == 1) {
- sfx = cgs.media.firstImpressiveSound;
- } else {
- sfx = cgs.media.impressiveSound;
- }
-#else
- sfx = cgs.media.impressiveSound;
-#endif
- pushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]);
- reward = qtrue;
- //Com_Printf("impressive\n");
- }
- if (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) {
-#ifdef MISSIONPACK
- if (ps->persistant[PERS_EXCELLENT_COUNT] == 1) {
- sfx = cgs.media.firstExcellentSound;
- } else {
- sfx = cgs.media.excellentSound;
- }
-#else
- sfx = cgs.media.excellentSound;
-#endif
- pushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]);
- reward = qtrue;
- //Com_Printf("excellent\n");
- }
- if (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) {
-#ifdef MISSIONPACK
- if (ops->persistant[PERS_GAUNTLET_FRAG_COUNT] == 1) {
- sfx = cgs.media.firstHumiliationSound;
- } else {
- sfx = cgs.media.humiliationSound;
- }
-#else
- sfx = cgs.media.humiliationSound;
-#endif
- pushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]);
- reward = qtrue;
- //Com_Printf("guantlet frag\n");
- }
- if (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) {
- pushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]);
- reward = qtrue;
- //Com_Printf("defend\n");
- }
- if (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) {
- pushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]);
- reward = qtrue;
- //Com_Printf("assist\n");
- }
- // if any of the player event bits changed
- if (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) {
- if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) {
- trap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER );
- }
- else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) {
- trap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER );
- }
- else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) !=
- (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) {
- trap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER );
- }
- reward = qtrue;
- }
-
- // check for flag pickup
- if ( cgs.gametype >= GT_TEAM ) {
- if ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) ||
- (ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) ||
- (ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) )
- {
- trap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER );
- }
- }
-
- // lead changes
- if (!reward) {
- //
- if ( !cg.warmup ) {
- // never play lead changes during warmup
- if ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) {
- if ( cgs.gametype < GT_TEAM) {
- if ( ps->persistant[PERS_RANK] == 0 ) {
- CG_AddBufferedSound(cgs.media.takenLeadSound);
- } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) {
- CG_AddBufferedSound(cgs.media.tiedLeadSound);
- } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) {
- CG_AddBufferedSound(cgs.media.lostLeadSound);
- }
- }
- }
- }
- }
-
- // timelimit warnings
- if ( cgs.timelimit > 0 ) {
- int msec;
-
- msec = cg.time - cgs.levelStartTime;
- if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) {
- cg.timelimitWarnings |= 1 | 2 | 4;
- trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER );
- }
- else if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) {
- cg.timelimitWarnings |= 1 | 2;
- trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER );
- }
- else if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) {
- cg.timelimitWarnings |= 1;
- trap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER );
- }
- }
-
- // fraglimit warnings
- if ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) {
- highScore = cgs.scores1;
- if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) {
- cg.fraglimitWarnings |= 1 | 2 | 4;
- CG_AddBufferedSound(cgs.media.oneFragSound);
- }
- else if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) {
- cg.fraglimitWarnings |= 1 | 2;
- CG_AddBufferedSound(cgs.media.twoFragSound);
- }
- else if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) {
- cg.fraglimitWarnings |= 1;
- CG_AddBufferedSound(cgs.media.threeFragSound);
- }
- }
-}
-
-/*
-===============
-CG_TransitionPlayerState
-
-===============
-*/
-void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
- // check for changing follow mode
- if ( ps->clientNum != ops->clientNum ) {
- cg.thisFrameTeleport = qtrue;
- // make sure we don't get any unwanted transition effects
- *ops = *ps;
- }
-
- // damage events (player is getting wounded)
- if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
- CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
- }
-
- // respawning
- if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
- CG_Respawn();
- }
-
- if ( cg.mapRestart ) {
- CG_Respawn();
- cg.mapRestart = qfalse;
- }
-
- if ( cg.snap->ps.pm_type != PM_INTERMISSION
- && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- CG_CheckLocalSounds( ps, ops );
- }
-
- // check for going low on ammo
- CG_CheckAmmo();
-
- // run events
- CG_CheckPlayerstateEvents( ps, ops );
-
- // smooth the ducking viewheight change
- if ( ps->viewheight != ops->viewheight ) {
- cg.duckChange = ps->viewheight - ops->viewheight;
- cg.duckTime = cg.time;
- }
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_playerstate.c -- this file acts on changes in a new playerState_t
+// With normal play, this will be done after local prediction, but when
+// following another player or playing back a demo, it will be checked
+// when the snapshot transitions like all the other entities
+
+#include "cg_local.h"
+
+/*
+==============
+CG_CheckAmmo
+
+If the ammo has gone low enough to generate the warning, play a sound
+==============
+*/
+void CG_CheckAmmo( void ) {
+ int i;
+ int total;
+ int previous;
+ int weapons;
+
+ // see about how many seconds of ammo we have remaining
+ weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
+ total = 0;
+ for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
+ if ( ! ( weapons & ( 1 << i ) ) ) {
+ continue;
+ }
+ switch ( i ) {
+ case WP_ROCKET_LAUNCHER:
+ case WP_GRENADE_LAUNCHER:
+ case WP_RAILGUN:
+ case WP_SHOTGUN:
+#ifdef MISSIONPACK
+ case WP_PROX_LAUNCHER:
+#endif
+ total += cg.snap->ps.ammo[i] * 1000;
+ break;
+ default:
+ total += cg.snap->ps.ammo[i] * 200;
+ break;
+ }
+ if ( total >= 5000 ) {
+ cg.lowAmmoWarning = 0;
+ return;
+ }
+ }
+
+ previous = cg.lowAmmoWarning;
+
+ if ( total == 0 ) {
+ cg.lowAmmoWarning = 2;
+ } else {
+ cg.lowAmmoWarning = 1;
+ }
+
+ // play a sound on transitions
+ if ( cg.lowAmmoWarning != previous ) {
+ trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );
+ }
+}
+
+/*
+==============
+CG_DamageFeedback
+==============
+*/
+void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
+ float left, front, up;
+ float kick;
+ int health;
+ float scale;
+ vec3_t dir;
+ vec3_t angles;
+ float dist;
+ float yaw, pitch;
+
+ // show the attacking player's head and name in corner
+ cg.attackerTime = cg.time;
+
+ // the lower on health you are, the greater the view kick will be
+ health = cg.snap->ps.stats[STAT_HEALTH];
+ if ( health < 40 ) {
+ scale = 1;
+ } else {
+ scale = 40.0 / health;
+ }
+ kick = damage * scale;
+
+ if (kick < 5)
+ kick = 5;
+ if (kick > 10)
+ kick = 10;
+
+ // if yaw and pitch are both 255, make the damage always centered (falling, etc)
+ if ( yawByte == 255 && pitchByte == 255 ) {
+ cg.damageX = 0;
+ cg.damageY = 0;
+ cg.v_dmg_roll = 0;
+ cg.v_dmg_pitch = -kick;
+ } else {
+ // positional
+ pitch = pitchByte / 255.0 * 360;
+ yaw = yawByte / 255.0 * 360;
+
+ angles[PITCH] = pitch;
+ angles[YAW] = yaw;
+ angles[ROLL] = 0;
+
+ AngleVectors( angles, dir, NULL, NULL );
+ VectorSubtract( vec3_origin, dir, dir );
+
+ front = DotProduct (dir, cg.refdef.viewaxis[0] );
+ left = DotProduct (dir, cg.refdef.viewaxis[1] );
+ up = DotProduct (dir, cg.refdef.viewaxis[2] );
+
+ dir[0] = front;
+ dir[1] = left;
+ dir[2] = 0;
+ dist = VectorLength( dir );
+ if ( dist < 0.1 ) {
+ dist = 0.1f;
+ }
+
+ cg.v_dmg_roll = kick * left;
+
+ cg.v_dmg_pitch = -kick * front;
+
+ if ( front <= 0.1 ) {
+ front = 0.1f;
+ }
+ cg.damageX = -left / front;
+ cg.damageY = up / dist;
+ }
+
+ // clamp the position
+ if ( cg.damageX > 1.0 ) {
+ cg.damageX = 1.0;
+ }
+ if ( cg.damageX < - 1.0 ) {
+ cg.damageX = -1.0;
+ }
+
+ if ( cg.damageY > 1.0 ) {
+ cg.damageY = 1.0;
+ }
+ if ( cg.damageY < - 1.0 ) {
+ cg.damageY = -1.0;
+ }
+
+ // don't let the screen flashes vary as much
+ if ( kick > 10 ) {
+ kick = 10;
+ }
+ cg.damageValue = kick;
+ cg.v_dmg_time = cg.time + DAMAGE_TIME;
+ cg.damageTime = cg.snap->serverTime;
+}
+
+
+
+
+/*
+================
+CG_Respawn
+
+A respawn happened this snapshot
+================
+*/
+void CG_Respawn( void ) {
+ // no error decay on player movement
+ cg.thisFrameTeleport = qtrue;
+
+ // display weapons available
+ cg.weaponSelectTime = cg.time;
+
+ // select the weapon the server says we are using
+ cg.weaponSelect = cg.snap->ps.weapon;
+}
+
+extern char *eventnames[];
+
+/*
+==============
+CG_CheckPlayerstateEvents
+==============
+*/
+void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
+ int i;
+ int event;
+ centity_t *cent;
+
+ if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
+ cent = &cg_entities[ ps->clientNum ];
+ cent->currentState.event = ps->externalEvent;
+ cent->currentState.eventParm = ps->externalEventParm;
+ CG_EntityEvent( cent, cent->lerpOrigin );
+ }
+
+ cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
+ // go through the predictable events buffer
+ for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
+ // if we have a new predictable event
+ if ( i >= ops->eventSequence
+ // or the server told us to play another event instead of a predicted event we already issued
+ // or something the server told us changed our prediction causing a different event
+ || (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {
+
+ event = ps->events[ i & (MAX_PS_EVENTS-1) ];
+ cent->currentState.event = event;
+ cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
+ CG_EntityEvent( cent, cent->lerpOrigin );
+
+ cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
+
+ cg.eventSequence++;
+ }
+ }
+}
+
+/*
+==================
+CG_CheckChangedPredictableEvents
+==================
+*/
+void CG_CheckChangedPredictableEvents( playerState_t *ps ) {
+ int i;
+ int event;
+ centity_t *cent;
+
+ cent = &cg.predictedPlayerEntity;
+ for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
+ //
+ if (i >= cg.eventSequence) {
+ continue;
+ }
+ // if this event is not further back in than the maximum predictable events we remember
+ if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {
+ // if the new playerstate event is different from a previously predicted one
+ if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {
+
+ event = ps->events[ i & (MAX_PS_EVENTS-1) ];
+ cent->currentState.event = event;
+ cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
+ CG_EntityEvent( cent, cent->lerpOrigin );
+
+ cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
+
+ if ( cg_showmiss.integer ) {
+ CG_Printf("WARNING: changed predicted event\n");
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+pushReward
+==================
+*/
+static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) {
+ if (cg.rewardStack < (MAX_REWARDSTACK-1)) {
+ cg.rewardStack++;
+ cg.rewardSound[cg.rewardStack] = sfx;
+ cg.rewardShader[cg.rewardStack] = shader;
+ cg.rewardCount[cg.rewardStack] = rewardCount;
+ }
+}
+
+/*
+==================
+CG_CheckLocalSounds
+==================
+*/
+void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) {
+ int highScore, health, armor, reward;
+ sfxHandle_t sfx;
+
+ // don't play the sounds if the player just changed teams
+ if ( ps->persistant[PERS_TEAM] != ops->persistant[PERS_TEAM] ) {
+ return;
+ }
+
+ // hit changes
+ if ( ps->persistant[PERS_HITS] > ops->persistant[PERS_HITS] ) {
+ armor = ps->persistant[PERS_ATTACKEE_ARMOR] & 0xff;
+ health = ps->persistant[PERS_ATTACKEE_ARMOR] >> 8;
+#ifdef MISSIONPACK
+ if (armor > 50 ) {
+ trap_S_StartLocalSound( cgs.media.hitSoundHighArmor, CHAN_LOCAL_SOUND );
+ } else if (armor || health > 100) {
+ trap_S_StartLocalSound( cgs.media.hitSoundLowArmor, CHAN_LOCAL_SOUND );
+ } else {
+ trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
+ }
+#else
+ trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
+#endif
+ } else if ( ps->persistant[PERS_HITS] < ops->persistant[PERS_HITS] ) {
+ trap_S_StartLocalSound( cgs.media.hitTeamSound, CHAN_LOCAL_SOUND );
+ }
+
+ // health changes of more than -1 should make pain sounds
+ if ( ps->stats[STAT_HEALTH] < ops->stats[STAT_HEALTH] - 1 ) {
+ if ( ps->stats[STAT_HEALTH] > 0 ) {
+ CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[STAT_HEALTH] );
+ }
+ }
+
+
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ // reward sounds
+ reward = qfalse;
+ if (ps->persistant[PERS_CAPTURES] != ops->persistant[PERS_CAPTURES]) {
+ pushReward(cgs.media.captureAwardSound, cgs.media.medalCapture, ps->persistant[PERS_CAPTURES]);
+ reward = qtrue;
+ //Com_Printf("capture\n");
+ }
+ if (ps->persistant[PERS_IMPRESSIVE_COUNT] != ops->persistant[PERS_IMPRESSIVE_COUNT]) {
+#ifdef MISSIONPACK
+ if (ps->persistant[PERS_IMPRESSIVE_COUNT] == 1) {
+ sfx = cgs.media.firstImpressiveSound;
+ } else {
+ sfx = cgs.media.impressiveSound;
+ }
+#else
+ sfx = cgs.media.impressiveSound;
+#endif
+ pushReward(sfx, cgs.media.medalImpressive, ps->persistant[PERS_IMPRESSIVE_COUNT]);
+ reward = qtrue;
+ //Com_Printf("impressive\n");
+ }
+ if (ps->persistant[PERS_EXCELLENT_COUNT] != ops->persistant[PERS_EXCELLENT_COUNT]) {
+#ifdef MISSIONPACK
+ if (ps->persistant[PERS_EXCELLENT_COUNT] == 1) {
+ sfx = cgs.media.firstExcellentSound;
+ } else {
+ sfx = cgs.media.excellentSound;
+ }
+#else
+ sfx = cgs.media.excellentSound;
+#endif
+ pushReward(sfx, cgs.media.medalExcellent, ps->persistant[PERS_EXCELLENT_COUNT]);
+ reward = qtrue;
+ //Com_Printf("excellent\n");
+ }
+ if (ps->persistant[PERS_GAUNTLET_FRAG_COUNT] != ops->persistant[PERS_GAUNTLET_FRAG_COUNT]) {
+#ifdef MISSIONPACK
+ if (ops->persistant[PERS_GAUNTLET_FRAG_COUNT] == 1) {
+ sfx = cgs.media.firstHumiliationSound;
+ } else {
+ sfx = cgs.media.humiliationSound;
+ }
+#else
+ sfx = cgs.media.humiliationSound;
+#endif
+ pushReward(sfx, cgs.media.medalGauntlet, ps->persistant[PERS_GAUNTLET_FRAG_COUNT]);
+ reward = qtrue;
+ //Com_Printf("guantlet frag\n");
+ }
+ if (ps->persistant[PERS_DEFEND_COUNT] != ops->persistant[PERS_DEFEND_COUNT]) {
+ pushReward(cgs.media.defendSound, cgs.media.medalDefend, ps->persistant[PERS_DEFEND_COUNT]);
+ reward = qtrue;
+ //Com_Printf("defend\n");
+ }
+ if (ps->persistant[PERS_ASSIST_COUNT] != ops->persistant[PERS_ASSIST_COUNT]) {
+ pushReward(cgs.media.assistSound, cgs.media.medalAssist, ps->persistant[PERS_ASSIST_COUNT]);
+ reward = qtrue;
+ //Com_Printf("assist\n");
+ }
+ // if any of the player event bits changed
+ if (ps->persistant[PERS_PLAYEREVENTS] != ops->persistant[PERS_PLAYEREVENTS]) {
+ if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD) !=
+ (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_DENIEDREWARD)) {
+ trap_S_StartLocalSound( cgs.media.deniedSound, CHAN_ANNOUNCER );
+ }
+ else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD) !=
+ (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_GAUNTLETREWARD)) {
+ trap_S_StartLocalSound( cgs.media.humiliationSound, CHAN_ANNOUNCER );
+ }
+ else if ((ps->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT) !=
+ (ops->persistant[PERS_PLAYEREVENTS] & PLAYEREVENT_HOLYSHIT)) {
+ trap_S_StartLocalSound( cgs.media.holyShitSound, CHAN_ANNOUNCER );
+ }
+ reward = qtrue;
+ }
+
+ // check for flag pickup
+ if ( cgs.gametype >= GT_TEAM ) {
+ if ((ps->powerups[PW_REDFLAG] != ops->powerups[PW_REDFLAG] && ps->powerups[PW_REDFLAG]) ||
+ (ps->powerups[PW_BLUEFLAG] != ops->powerups[PW_BLUEFLAG] && ps->powerups[PW_BLUEFLAG]) ||
+ (ps->powerups[PW_NEUTRALFLAG] != ops->powerups[PW_NEUTRALFLAG] && ps->powerups[PW_NEUTRALFLAG]) )
+ {
+ trap_S_StartLocalSound( cgs.media.youHaveFlagSound, CHAN_ANNOUNCER );
+ }
+ }
+
+ // lead changes
+ if (!reward) {
+ //
+ if ( !cg.warmup ) {
+ // never play lead changes during warmup
+ if ( ps->persistant[PERS_RANK] != ops->persistant[PERS_RANK] ) {
+ if ( cgs.gametype < GT_TEAM) {
+ if ( ps->persistant[PERS_RANK] == 0 ) {
+ CG_AddBufferedSound(cgs.media.takenLeadSound);
+ } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) {
+ CG_AddBufferedSound(cgs.media.tiedLeadSound);
+ } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) {
+ CG_AddBufferedSound(cgs.media.lostLeadSound);
+ }
+ }
+ }
+ }
+ }
+
+ // timelimit warnings
+ if ( cgs.timelimit > 0 ) {
+ int msec;
+
+ msec = cg.time - cgs.levelStartTime;
+ if ( !( cg.timelimitWarnings & 4 ) && msec > ( cgs.timelimit * 60 + 2 ) * 1000 ) {
+ cg.timelimitWarnings |= 1 | 2 | 4;
+ trap_S_StartLocalSound( cgs.media.suddenDeathSound, CHAN_ANNOUNCER );
+ }
+ else if ( !( cg.timelimitWarnings & 2 ) && msec > (cgs.timelimit - 1) * 60 * 1000 ) {
+ cg.timelimitWarnings |= 1 | 2;
+ trap_S_StartLocalSound( cgs.media.oneMinuteSound, CHAN_ANNOUNCER );
+ }
+ else if ( cgs.timelimit > 5 && !( cg.timelimitWarnings & 1 ) && msec > (cgs.timelimit - 5) * 60 * 1000 ) {
+ cg.timelimitWarnings |= 1;
+ trap_S_StartLocalSound( cgs.media.fiveMinuteSound, CHAN_ANNOUNCER );
+ }
+ }
+
+ // fraglimit warnings
+ if ( cgs.fraglimit > 0 && cgs.gametype < GT_CTF) {
+ highScore = cgs.scores1;
+ if ( !( cg.fraglimitWarnings & 4 ) && highScore == (cgs.fraglimit - 1) ) {
+ cg.fraglimitWarnings |= 1 | 2 | 4;
+ CG_AddBufferedSound(cgs.media.oneFragSound);
+ }
+ else if ( cgs.fraglimit > 2 && !( cg.fraglimitWarnings & 2 ) && highScore == (cgs.fraglimit - 2) ) {
+ cg.fraglimitWarnings |= 1 | 2;
+ CG_AddBufferedSound(cgs.media.twoFragSound);
+ }
+ else if ( cgs.fraglimit > 3 && !( cg.fraglimitWarnings & 1 ) && highScore == (cgs.fraglimit - 3) ) {
+ cg.fraglimitWarnings |= 1;
+ CG_AddBufferedSound(cgs.media.threeFragSound);
+ }
+ }
+}
+
+/*
+===============
+CG_TransitionPlayerState
+
+===============
+*/
+void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
+ // check for changing follow mode
+ if ( ps->clientNum != ops->clientNum ) {
+ cg.thisFrameTeleport = qtrue;
+ // make sure we don't get any unwanted transition effects
+ *ops = *ps;
+ }
+
+ // damage events (player is getting wounded)
+ if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
+ CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
+ }
+
+ // respawning
+ if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
+ CG_Respawn();
+ }
+
+ if ( cg.mapRestart ) {
+ CG_Respawn();
+ cg.mapRestart = qfalse;
+ }
+
+ if ( cg.snap->ps.pm_type != PM_INTERMISSION
+ && ps->persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
+ CG_CheckLocalSounds( ps, ops );
+ }
+
+ // check for going low on ammo
+ CG_CheckAmmo();
+
+ // run events
+ CG_CheckPlayerstateEvents( ps, ops );
+
+ // smooth the ducking viewheight change
+ if ( ps->viewheight != ops->viewheight ) {
+ cg.duckChange = ps->viewheight - ops->viewheight;
+ cg.duckTime = cg.time;
+ }
+}
+
diff --git a/code/cgame/cg_predict.c b/code/cgame/cg_predict.c
index fec2cfb..893b439 100755
--- a/code/cgame/cg_predict.c
+++ b/code/cgame/cg_predict.c
@@ -1,628 +1,628 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_predict.c -- this file generates cg.predictedPlayerState by either
-// interpolating between snapshots from the server or locally predicting
-// ahead the client's movement.
-// It also handles local physics interaction, like fragments bouncing off walls
-
-#include "cg_local.h"
-
-static pmove_t cg_pmove;
-
-static int cg_numSolidEntities;
-static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
-static int cg_numTriggerEntities;
-static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
-
-/*
-====================
-CG_BuildSolidList
-
-When a new cg.snap has been set, this function builds a sublist
-of the entities that are actually solid, to make for more
-efficient collision detection
-====================
-*/
-void CG_BuildSolidList( void ) {
- int i;
- centity_t *cent;
- snapshot_t *snap;
- entityState_t *ent;
-
- cg_numSolidEntities = 0;
- cg_numTriggerEntities = 0;
-
- if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
- snap = cg.nextSnap;
- } else {
- snap = cg.snap;
- }
-
- for ( i = 0 ; i < snap->numEntities ; i++ ) {
- cent = &cg_entities[ snap->entities[ i ].number ];
- ent = &cent->currentState;
-
- if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
- cg_triggerEntities[cg_numTriggerEntities] = cent;
- cg_numTriggerEntities++;
- continue;
- }
-
- if ( cent->nextState.solid ) {
- cg_solidEntities[cg_numSolidEntities] = cent;
- cg_numSolidEntities++;
- continue;
- }
- }
-}
-
-/*
-====================
-CG_ClipMoveToEntities
-
-====================
-*/
-static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask, trace_t *tr ) {
- int i, x, zd, zu;
- trace_t trace;
- entityState_t *ent;
- clipHandle_t cmodel;
- vec3_t bmins, bmaxs;
- vec3_t origin, angles;
- centity_t *cent;
-
- for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
- cent = cg_solidEntities[ i ];
- ent = &cent->currentState;
-
- if ( ent->number == skipNumber ) {
- continue;
- }
-
- if ( ent->solid == SOLID_BMODEL ) {
- // special value for bmodel
- cmodel = trap_CM_InlineModel( ent->modelindex );
- VectorCopy( cent->lerpAngles, angles );
- BG_EvaluateTrajectory( &cent->currentState.pos, cg.physicsTime, origin );
- } else {
- // encoded bbox
- x = (ent->solid & 255);
- zd = ((ent->solid>>8) & 255);
- zu = ((ent->solid>>16) & 255) - 32;
-
- bmins[0] = bmins[1] = -x;
- bmaxs[0] = bmaxs[1] = x;
- bmins[2] = -zd;
- bmaxs[2] = zu;
-
- cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
- VectorCopy( vec3_origin, angles );
- VectorCopy( cent->lerpOrigin, origin );
- }
-
-
- trap_CM_TransformedBoxTrace ( &trace, start, end,
- mins, maxs, cmodel, mask, origin, angles);
-
- if (trace.allsolid || trace.fraction < tr->fraction) {
- trace.entityNum = ent->number;
- *tr = trace;
- } else if (trace.startsolid) {
- tr->startsolid = qtrue;
- }
- if ( tr->allsolid ) {
- return;
- }
- }
-}
-
-/*
-================
-CG_Trace
-================
-*/
-void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
- int skipNumber, int mask ) {
- trace_t t;
-
- trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
- t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
- // check all other solid models
- CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
-
- *result = t;
-}
-
-/*
-================
-CG_PointContents
-================
-*/
-int CG_PointContents( const vec3_t point, int passEntityNum ) {
- int i;
- entityState_t *ent;
- centity_t *cent;
- clipHandle_t cmodel;
- int contents;
-
- contents = trap_CM_PointContents (point, 0);
-
- for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
- cent = cg_solidEntities[ i ];
-
- ent = &cent->currentState;
-
- if ( ent->number == passEntityNum ) {
- continue;
- }
-
- if (ent->solid != SOLID_BMODEL) { // special value for bmodel
- continue;
- }
-
- cmodel = trap_CM_InlineModel( ent->modelindex );
- if ( !cmodel ) {
- continue;
- }
-
- contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
- }
-
- return contents;
-}
-
-
-/*
-========================
-CG_InterpolatePlayerState
-
-Generates cg.predictedPlayerState by interpolating between
-cg.snap->player_state and cg.nextFrame->player_state
-========================
-*/
-static void CG_InterpolatePlayerState( qboolean grabAngles ) {
- float f;
- int i;
- playerState_t *out;
- snapshot_t *prev, *next;
-
- out = &cg.predictedPlayerState;
- prev = cg.snap;
- next = cg.nextSnap;
-
- *out = cg.snap->ps;
-
- // if we are still allowing local input, short circuit the view angles
- if ( grabAngles ) {
- usercmd_t cmd;
- int cmdNum;
-
- cmdNum = trap_GetCurrentCmdNumber();
- trap_GetUserCmd( cmdNum, &cmd );
-
- PM_UpdateViewAngles( out, &cmd );
- }
-
- // if the next frame is a teleport, we can't lerp to it
- if ( cg.nextFrameTeleport ) {
- return;
- }
-
- if ( !next || next->serverTime <= prev->serverTime ) {
- return;
- }
-
- f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
-
- i = next->ps.bobCycle;
- if ( i < prev->ps.bobCycle ) {
- i += 256; // handle wraparound
- }
- out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
-
- for ( i = 0 ; i < 3 ; i++ ) {
- out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
- if ( !grabAngles ) {
- out->viewangles[i] = LerpAngle(
- prev->ps.viewangles[i], next->ps.viewangles[i], f );
- }
- out->velocity[i] = prev->ps.velocity[i] +
- f * (next->ps.velocity[i] - prev->ps.velocity[i] );
- }
-
-}
-
-/*
-===================
-CG_TouchItem
-===================
-*/
-static void CG_TouchItem( centity_t *cent ) {
- gitem_t *item;
-
- if ( !cg_predictItems.integer ) {
- return;
- }
- if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, &cent->currentState, cg.time ) ) {
- return;
- }
-
- // never pick an item up twice in a prediction
- if ( cent->miscTime == cg.time ) {
- return;
- }
-
- if ( !BG_CanItemBeGrabbed( cgs.gametype, &cent->currentState, &cg.predictedPlayerState ) ) {
- return; // can't hold it
- }
-
- item = &bg_itemlist[ cent->currentState.modelindex ];
-
- // Special case for flags.
- // We don't predict touching our own flag
-#ifdef MISSIONPACK
- if( cgs.gametype == GT_1FCTF ) {
- if( item->giTag != PW_NEUTRALFLAG ) {
- return;
- }
- }
- if( cgs.gametype == GT_CTF || cgs.gametype == GT_HARVESTER ) {
-#else
- if( cgs.gametype == GT_CTF ) {
-#endif
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
- item->giTag == PW_REDFLAG)
- return;
- if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
- item->giTag == PW_BLUEFLAG)
- return;
- }
-
- // grab it
- BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);
-
- // remove it from the frame so it won't be drawn
- cent->currentState.eFlags |= EF_NODRAW;
-
- // don't touch it again this prediction
- cent->miscTime = cg.time;
-
- // if its a weapon, give them some predicted ammo so the autoswitch will work
- if ( item->giType == IT_WEAPON ) {
- cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
- if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
- cg.predictedPlayerState.ammo[ item->giTag ] = 1;
- }
- }
-}
-
-
-/*
-=========================
-CG_TouchTriggerPrediction
-
-Predict push triggers and items
-=========================
-*/
-static void CG_TouchTriggerPrediction( void ) {
- int i;
- trace_t trace;
- entityState_t *ent;
- clipHandle_t cmodel;
- centity_t *cent;
- qboolean spectator;
-
- // dead clients don't activate triggers
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
-
- if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
- return;
- }
-
- for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
- cent = cg_triggerEntities[ i ];
- ent = &cent->currentState;
-
- if ( ent->eType == ET_ITEM && !spectator ) {
- CG_TouchItem( cent );
- continue;
- }
-
- if ( ent->solid != SOLID_BMODEL ) {
- continue;
- }
-
- cmodel = trap_CM_InlineModel( ent->modelindex );
- if ( !cmodel ) {
- continue;
- }
-
- trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
- cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
-
- if ( !trace.startsolid ) {
- continue;
- }
-
- if ( ent->eType == ET_TELEPORT_TRIGGER ) {
- cg.hyperspace = qtrue;
- } else if ( ent->eType == ET_PUSH_TRIGGER ) {
- BG_TouchJumpPad( &cg.predictedPlayerState, ent );
- }
- }
-
- // if we didn't touch a jump pad this pmove frame
- if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {
- cg.predictedPlayerState.jumppad_frame = 0;
- cg.predictedPlayerState.jumppad_ent = 0;
- }
-}
-
-
-
-/*
-=================
-CG_PredictPlayerState
-
-Generates cg.predictedPlayerState for the current cg.time
-cg.predictedPlayerState is guaranteed to be valid after exiting.
-
-For demo playback, this will be an interpolation between two valid
-playerState_t.
-
-For normal gameplay, it will be the result of predicted usercmd_t on
-top of the most recent playerState_t received from the server.
-
-Each new snapshot will usually have one or more new usercmd over the last,
-but we simulate all unacknowledged commands each time, not just the new ones.
-This means that on an internet connection, quite a few pmoves may be issued
-each frame.
-
-OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
-differs from the predicted one. Would require saving all intermediate
-playerState_t during prediction.
-
-We detect prediction errors and allow them to be decayed off over several frames
-to ease the jerk.
-=================
-*/
-void CG_PredictPlayerState( void ) {
- int cmdNum, current;
- playerState_t oldPlayerState;
- qboolean moved;
- usercmd_t oldestCmd;
- usercmd_t latestCmd;
-
- cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
-
- // if this is the first frame we must guarantee
- // predictedPlayerState is valid even if there is some
- // other error condition
- if ( !cg.validPPS ) {
- cg.validPPS = qtrue;
- cg.predictedPlayerState = cg.snap->ps;
- }
-
-
- // demo playback just copies the moves
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
- CG_InterpolatePlayerState( qfalse );
- return;
- }
-
- // non-predicting local movement will grab the latest angles
- if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_InterpolatePlayerState( qtrue );
- return;
- }
-
- // prepare for pmove
- cg_pmove.ps = &cg.predictedPlayerState;
- cg_pmove.trace = CG_Trace;
- cg_pmove.pointcontents = CG_PointContents;
- if ( cg_pmove.ps->pm_type == PM_DEAD ) {
- cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
- }
- else {
- cg_pmove.tracemask = MASK_PLAYERSOLID;
- }
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
- }
- cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
-
- // save the state before the pmove so we can detect transitions
- oldPlayerState = cg.predictedPlayerState;
-
- current = trap_GetCurrentCmdNumber();
-
- // if we don't have the commands right after the snapshot, we
- // can't accurately predict a current position, so just freeze at
- // the last good position we had
- cmdNum = current - CMD_BACKUP + 1;
- trap_GetUserCmd( cmdNum, &oldestCmd );
- if ( oldestCmd.serverTime > cg.snap->ps.commandTime
- && oldestCmd.serverTime < cg.time ) { // special check for map_restart
- if ( cg_showmiss.integer ) {
- CG_Printf ("exceeded PACKET_BACKUP on commands\n");
- }
- return;
- }
-
- // get the latest command so we can know which commands are from previous map_restarts
- trap_GetUserCmd( current, &latestCmd );
-
- // get the most recent information we have, even if
- // the server time is beyond our current cg.time,
- // because predicted player positions are going to
- // be ahead of everything else anyway
- if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
- cg.predictedPlayerState = cg.nextSnap->ps;
- cg.physicsTime = cg.nextSnap->serverTime;
- } else {
- cg.predictedPlayerState = cg.snap->ps;
- cg.physicsTime = cg.snap->serverTime;
- }
-
- if ( pmove_msec.integer < 8 ) {
- trap_Cvar_Set("pmove_msec", "8");
- }
- else if (pmove_msec.integer > 33) {
- trap_Cvar_Set("pmove_msec", "33");
- }
-
- cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
- cg_pmove.pmove_msec = pmove_msec.integer;
-
- // run cmds
- moved = qfalse;
- for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
- // get the command
- trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
-
- if ( cg_pmove.pmove_fixed ) {
- PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
- }
-
- // don't do anything if the time is before the snapshot player time
- if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
- continue;
- }
-
- // don't do anything if the command was from a previous map_restart
- if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
- continue;
- }
-
- // check for a prediction error from last frame
- // on a lan, this will often be the exact value
- // from the snapshot, but on a wan we will have
- // to predict several commands to get to the point
- // we want to compare
- if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
- vec3_t delta;
- float len;
-
- if ( cg.thisFrameTeleport ) {
- // a teleport will not cause an error decay
- VectorClear( cg.predictedError );
- if ( cg_showmiss.integer ) {
- CG_Printf( "PredictionTeleport\n" );
- }
- cg.thisFrameTeleport = qfalse;
- } else {
- vec3_t adjusted;
- CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
- cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
-
- if ( cg_showmiss.integer ) {
- if (!VectorCompare( oldPlayerState.origin, adjusted )) {
- CG_Printf("prediction error\n");
- }
- }
- VectorSubtract( oldPlayerState.origin, adjusted, delta );
- len = VectorLength( delta );
- if ( len > 0.1 ) {
- if ( cg_showmiss.integer ) {
- CG_Printf("Prediction miss: %f\n", len);
- }
- if ( cg_errorDecay.integer ) {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f < 0 ) {
- f = 0;
- }
- if ( f > 0 && cg_showmiss.integer ) {
- CG_Printf("Double prediction decay: %f\n", f);
- }
- VectorScale( cg.predictedError, f, cg.predictedError );
- } else {
- VectorClear( cg.predictedError );
- }
- VectorAdd( delta, cg.predictedError, cg.predictedError );
- cg.predictedErrorTime = cg.oldTime;
- }
- }
- }
-
- // don't predict gauntlet firing, which is only supposed to happen
- // when it actually inflicts damage
- cg_pmove.gauntletHit = qfalse;
-
- if ( cg_pmove.pmove_fixed ) {
- cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
- }
-
- Pmove (&cg_pmove);
-
- moved = qtrue;
-
- // add push trigger movement effects
- CG_TouchTriggerPrediction();
-
- // check for predictable events that changed from previous predictions
- //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
- }
-
- if ( cg_showmiss.integer > 1 ) {
- CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
- }
-
- if ( !moved ) {
- if ( cg_showmiss.integer ) {
- CG_Printf( "not moved\n" );
- }
- return;
- }
-
- // adjust for the movement of the groundentity
- CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
- cg.predictedPlayerState.groundEntityNum,
- cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
-
- if ( cg_showmiss.integer ) {
- if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {
- CG_Printf("WARNING: dropped event\n");
- }
- }
-
- // fire events and other transition triggered things
- CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
-
- if ( cg_showmiss.integer ) {
- if (cg.eventSequence > cg.predictedPlayerState.eventSequence) {
- CG_Printf("WARNING: double event\n");
- cg.eventSequence = cg.predictedPlayerState.eventSequence;
- }
- }
-}
-
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_predict.c -- this file generates cg.predictedPlayerState by either
+// interpolating between snapshots from the server or locally predicting
+// ahead the client's movement.
+// It also handles local physics interaction, like fragments bouncing off walls
+
+#include "cg_local.h"
+
+static pmove_t cg_pmove;
+
+static int cg_numSolidEntities;
+static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
+static int cg_numTriggerEntities;
+static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
+
+/*
+====================
+CG_BuildSolidList
+
+When a new cg.snap has been set, this function builds a sublist
+of the entities that are actually solid, to make for more
+efficient collision detection
+====================
+*/
+void CG_BuildSolidList( void ) {
+ int i;
+ centity_t *cent;
+ snapshot_t *snap;
+ entityState_t *ent;
+
+ cg_numSolidEntities = 0;
+ cg_numTriggerEntities = 0;
+
+ if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
+ snap = cg.nextSnap;
+ } else {
+ snap = cg.snap;
+ }
+
+ for ( i = 0 ; i < snap->numEntities ; i++ ) {
+ cent = &cg_entities[ snap->entities[ i ].number ];
+ ent = &cent->currentState;
+
+ if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
+ cg_triggerEntities[cg_numTriggerEntities] = cent;
+ cg_numTriggerEntities++;
+ continue;
+ }
+
+ if ( cent->nextState.solid ) {
+ cg_solidEntities[cg_numSolidEntities] = cent;
+ cg_numSolidEntities++;
+ continue;
+ }
+ }
+}
+
+/*
+====================
+CG_ClipMoveToEntities
+
+====================
+*/
+static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int skipNumber, int mask, trace_t *tr ) {
+ int i, x, zd, zu;
+ trace_t trace;
+ entityState_t *ent;
+ clipHandle_t cmodel;
+ vec3_t bmins, bmaxs;
+ vec3_t origin, angles;
+ centity_t *cent;
+
+ for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
+ cent = cg_solidEntities[ i ];
+ ent = &cent->currentState;
+
+ if ( ent->number == skipNumber ) {
+ continue;
+ }
+
+ if ( ent->solid == SOLID_BMODEL ) {
+ // special value for bmodel
+ cmodel = trap_CM_InlineModel( ent->modelindex );
+ VectorCopy( cent->lerpAngles, angles );
+ BG_EvaluateTrajectory( &cent->currentState.pos, cg.physicsTime, origin );
+ } else {
+ // encoded bbox
+ x = (ent->solid & 255);
+ zd = ((ent->solid>>8) & 255);
+ zu = ((ent->solid>>16) & 255) - 32;
+
+ bmins[0] = bmins[1] = -x;
+ bmaxs[0] = bmaxs[1] = x;
+ bmins[2] = -zd;
+ bmaxs[2] = zu;
+
+ cmodel = trap_CM_TempBoxModel( bmins, bmaxs );
+ VectorCopy( vec3_origin, angles );
+ VectorCopy( cent->lerpOrigin, origin );
+ }
+
+
+ trap_CM_TransformedBoxTrace ( &trace, start, end,
+ mins, maxs, cmodel, mask, origin, angles);
+
+ if (trace.allsolid || trace.fraction < tr->fraction) {
+ trace.entityNum = ent->number;
+ *tr = trace;
+ } else if (trace.startsolid) {
+ tr->startsolid = qtrue;
+ }
+ if ( tr->allsolid ) {
+ return;
+ }
+ }
+}
+
+/*
+================
+CG_Trace
+================
+*/
+void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
+ int skipNumber, int mask ) {
+ trace_t t;
+
+ trap_CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask);
+ t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
+ // check all other solid models
+ CG_ClipMoveToEntities (start, mins, maxs, end, skipNumber, mask, &t);
+
+ *result = t;
+}
+
+/*
+================
+CG_PointContents
+================
+*/
+int CG_PointContents( const vec3_t point, int passEntityNum ) {
+ int i;
+ entityState_t *ent;
+ centity_t *cent;
+ clipHandle_t cmodel;
+ int contents;
+
+ contents = trap_CM_PointContents (point, 0);
+
+ for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
+ cent = cg_solidEntities[ i ];
+
+ ent = &cent->currentState;
+
+ if ( ent->number == passEntityNum ) {
+ continue;
+ }
+
+ if (ent->solid != SOLID_BMODEL) { // special value for bmodel
+ continue;
+ }
+
+ cmodel = trap_CM_InlineModel( ent->modelindex );
+ if ( !cmodel ) {
+ continue;
+ }
+
+ contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
+ }
+
+ return contents;
+}
+
+
+/*
+========================
+CG_InterpolatePlayerState
+
+Generates cg.predictedPlayerState by interpolating between
+cg.snap->player_state and cg.nextFrame->player_state
+========================
+*/
+static void CG_InterpolatePlayerState( qboolean grabAngles ) {
+ float f;
+ int i;
+ playerState_t *out;
+ snapshot_t *prev, *next;
+
+ out = &cg.predictedPlayerState;
+ prev = cg.snap;
+ next = cg.nextSnap;
+
+ *out = cg.snap->ps;
+
+ // if we are still allowing local input, short circuit the view angles
+ if ( grabAngles ) {
+ usercmd_t cmd;
+ int cmdNum;
+
+ cmdNum = trap_GetCurrentCmdNumber();
+ trap_GetUserCmd( cmdNum, &cmd );
+
+ PM_UpdateViewAngles( out, &cmd );
+ }
+
+ // if the next frame is a teleport, we can't lerp to it
+ if ( cg.nextFrameTeleport ) {
+ return;
+ }
+
+ if ( !next || next->serverTime <= prev->serverTime ) {
+ return;
+ }
+
+ f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
+
+ i = next->ps.bobCycle;
+ if ( i < prev->ps.bobCycle ) {
+ i += 256; // handle wraparound
+ }
+ out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
+ if ( !grabAngles ) {
+ out->viewangles[i] = LerpAngle(
+ prev->ps.viewangles[i], next->ps.viewangles[i], f );
+ }
+ out->velocity[i] = prev->ps.velocity[i] +
+ f * (next->ps.velocity[i] - prev->ps.velocity[i] );
+ }
+
+}
+
+/*
+===================
+CG_TouchItem
+===================
+*/
+static void CG_TouchItem( centity_t *cent ) {
+ gitem_t *item;
+
+ if ( !cg_predictItems.integer ) {
+ return;
+ }
+ if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, &cent->currentState, cg.time ) ) {
+ return;
+ }
+
+ // never pick an item up twice in a prediction
+ if ( cent->miscTime == cg.time ) {
+ return;
+ }
+
+ if ( !BG_CanItemBeGrabbed( cgs.gametype, &cent->currentState, &cg.predictedPlayerState ) ) {
+ return; // can't hold it
+ }
+
+ item = &bg_itemlist[ cent->currentState.modelindex ];
+
+ // Special case for flags.
+ // We don't predict touching our own flag
+#ifdef MISSIONPACK
+ if( cgs.gametype == GT_1FCTF ) {
+ if( item->giTag != PW_NEUTRALFLAG ) {
+ return;
+ }
+ }
+ if( cgs.gametype == GT_CTF || cgs.gametype == GT_HARVESTER ) {
+#else
+ if( cgs.gametype == GT_CTF ) {
+#endif
+ if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_RED &&
+ item->giTag == PW_REDFLAG)
+ return;
+ if (cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_BLUE &&
+ item->giTag == PW_BLUEFLAG)
+ return;
+ }
+
+ // grab it
+ BG_AddPredictableEventToPlayerstate( EV_ITEM_PICKUP, cent->currentState.modelindex , &cg.predictedPlayerState);
+
+ // remove it from the frame so it won't be drawn
+ cent->currentState.eFlags |= EF_NODRAW;
+
+ // don't touch it again this prediction
+ cent->miscTime = cg.time;
+
+ // if its a weapon, give them some predicted ammo so the autoswitch will work
+ if ( item->giType == IT_WEAPON ) {
+ cg.predictedPlayerState.stats[ STAT_WEAPONS ] |= 1 << item->giTag;
+ if ( !cg.predictedPlayerState.ammo[ item->giTag ] ) {
+ cg.predictedPlayerState.ammo[ item->giTag ] = 1;
+ }
+ }
+}
+
+
+/*
+=========================
+CG_TouchTriggerPrediction
+
+Predict push triggers and items
+=========================
+*/
+static void CG_TouchTriggerPrediction( void ) {
+ int i;
+ trace_t trace;
+ entityState_t *ent;
+ clipHandle_t cmodel;
+ centity_t *cent;
+ qboolean spectator;
+
+ // dead clients don't activate triggers
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ return;
+ }
+
+ spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR );
+
+ if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
+ return;
+ }
+
+ for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
+ cent = cg_triggerEntities[ i ];
+ ent = &cent->currentState;
+
+ if ( ent->eType == ET_ITEM && !spectator ) {
+ CG_TouchItem( cent );
+ continue;
+ }
+
+ if ( ent->solid != SOLID_BMODEL ) {
+ continue;
+ }
+
+ cmodel = trap_CM_InlineModel( ent->modelindex );
+ if ( !cmodel ) {
+ continue;
+ }
+
+ trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
+ cg_pmove.mins, cg_pmove.maxs, cmodel, -1 );
+
+ if ( !trace.startsolid ) {
+ continue;
+ }
+
+ if ( ent->eType == ET_TELEPORT_TRIGGER ) {
+ cg.hyperspace = qtrue;
+ } else if ( ent->eType == ET_PUSH_TRIGGER ) {
+ BG_TouchJumpPad( &cg.predictedPlayerState, ent );
+ }
+ }
+
+ // if we didn't touch a jump pad this pmove frame
+ if ( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) {
+ cg.predictedPlayerState.jumppad_frame = 0;
+ cg.predictedPlayerState.jumppad_ent = 0;
+ }
+}
+
+
+
+/*
+=================
+CG_PredictPlayerState
+
+Generates cg.predictedPlayerState for the current cg.time
+cg.predictedPlayerState is guaranteed to be valid after exiting.
+
+For demo playback, this will be an interpolation between two valid
+playerState_t.
+
+For normal gameplay, it will be the result of predicted usercmd_t on
+top of the most recent playerState_t received from the server.
+
+Each new snapshot will usually have one or more new usercmd over the last,
+but we simulate all unacknowledged commands each time, not just the new ones.
+This means that on an internet connection, quite a few pmoves may be issued
+each frame.
+
+OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t
+differs from the predicted one. Would require saving all intermediate
+playerState_t during prediction.
+
+We detect prediction errors and allow them to be decayed off over several frames
+to ease the jerk.
+=================
+*/
+void CG_PredictPlayerState( void ) {
+ int cmdNum, current;
+ playerState_t oldPlayerState;
+ qboolean moved;
+ usercmd_t oldestCmd;
+ usercmd_t latestCmd;
+
+ cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
+
+ // if this is the first frame we must guarantee
+ // predictedPlayerState is valid even if there is some
+ // other error condition
+ if ( !cg.validPPS ) {
+ cg.validPPS = qtrue;
+ cg.predictedPlayerState = cg.snap->ps;
+ }
+
+
+ // demo playback just copies the moves
+ if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
+ CG_InterpolatePlayerState( qfalse );
+ return;
+ }
+
+ // non-predicting local movement will grab the latest angles
+ if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
+ CG_InterpolatePlayerState( qtrue );
+ return;
+ }
+
+ // prepare for pmove
+ cg_pmove.ps = &cg.predictedPlayerState;
+ cg_pmove.trace = CG_Trace;
+ cg_pmove.pointcontents = CG_PointContents;
+ if ( cg_pmove.ps->pm_type == PM_DEAD ) {
+ cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
+ }
+ else {
+ cg_pmove.tracemask = MASK_PLAYERSOLID;
+ }
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
+ cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
+ }
+ cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
+
+ // save the state before the pmove so we can detect transitions
+ oldPlayerState = cg.predictedPlayerState;
+
+ current = trap_GetCurrentCmdNumber();
+
+ // if we don't have the commands right after the snapshot, we
+ // can't accurately predict a current position, so just freeze at
+ // the last good position we had
+ cmdNum = current - CMD_BACKUP + 1;
+ trap_GetUserCmd( cmdNum, &oldestCmd );
+ if ( oldestCmd.serverTime > cg.snap->ps.commandTime
+ && oldestCmd.serverTime < cg.time ) { // special check for map_restart
+ if ( cg_showmiss.integer ) {
+ CG_Printf ("exceeded PACKET_BACKUP on commands\n");
+ }
+ return;
+ }
+
+ // get the latest command so we can know which commands are from previous map_restarts
+ trap_GetUserCmd( current, &latestCmd );
+
+ // get the most recent information we have, even if
+ // the server time is beyond our current cg.time,
+ // because predicted player positions are going to
+ // be ahead of everything else anyway
+ if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
+ cg.predictedPlayerState = cg.nextSnap->ps;
+ cg.physicsTime = cg.nextSnap->serverTime;
+ } else {
+ cg.predictedPlayerState = cg.snap->ps;
+ cg.physicsTime = cg.snap->serverTime;
+ }
+
+ if ( pmove_msec.integer < 8 ) {
+ trap_Cvar_Set("pmove_msec", "8");
+ }
+ else if (pmove_msec.integer > 33) {
+ trap_Cvar_Set("pmove_msec", "33");
+ }
+
+ cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer;
+ cg_pmove.pmove_msec = pmove_msec.integer;
+
+ // run cmds
+ moved = qfalse;
+ for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
+ // get the command
+ trap_GetUserCmd( cmdNum, &cg_pmove.cmd );
+
+ if ( cg_pmove.pmove_fixed ) {
+ PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
+ }
+
+ // don't do anything if the time is before the snapshot player time
+ if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
+ continue;
+ }
+
+ // don't do anything if the command was from a previous map_restart
+ if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
+ continue;
+ }
+
+ // check for a prediction error from last frame
+ // on a lan, this will often be the exact value
+ // from the snapshot, but on a wan we will have
+ // to predict several commands to get to the point
+ // we want to compare
+ if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
+ vec3_t delta;
+ float len;
+
+ if ( cg.thisFrameTeleport ) {
+ // a teleport will not cause an error decay
+ VectorClear( cg.predictedError );
+ if ( cg_showmiss.integer ) {
+ CG_Printf( "PredictionTeleport\n" );
+ }
+ cg.thisFrameTeleport = qfalse;
+ } else {
+ vec3_t adjusted;
+ CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
+ cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
+
+ if ( cg_showmiss.integer ) {
+ if (!VectorCompare( oldPlayerState.origin, adjusted )) {
+ CG_Printf("prediction error\n");
+ }
+ }
+ VectorSubtract( oldPlayerState.origin, adjusted, delta );
+ len = VectorLength( delta );
+ if ( len > 0.1 ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf("Prediction miss: %f\n", len);
+ }
+ if ( cg_errorDecay.integer ) {
+ int t;
+ float f;
+
+ t = cg.time - cg.predictedErrorTime;
+ f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
+ if ( f < 0 ) {
+ f = 0;
+ }
+ if ( f > 0 && cg_showmiss.integer ) {
+ CG_Printf("Double prediction decay: %f\n", f);
+ }
+ VectorScale( cg.predictedError, f, cg.predictedError );
+ } else {
+ VectorClear( cg.predictedError );
+ }
+ VectorAdd( delta, cg.predictedError, cg.predictedError );
+ cg.predictedErrorTime = cg.oldTime;
+ }
+ }
+ }
+
+ // don't predict gauntlet firing, which is only supposed to happen
+ // when it actually inflicts damage
+ cg_pmove.gauntletHit = qfalse;
+
+ if ( cg_pmove.pmove_fixed ) {
+ cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
+ }
+
+ Pmove (&cg_pmove);
+
+ moved = qtrue;
+
+ // add push trigger movement effects
+ CG_TouchTriggerPrediction();
+
+ // check for predictable events that changed from previous predictions
+ //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
+ }
+
+ if ( cg_showmiss.integer > 1 ) {
+ CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
+ }
+
+ if ( !moved ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf( "not moved\n" );
+ }
+ return;
+ }
+
+ // adjust for the movement of the groundentity
+ CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
+ cg.predictedPlayerState.groundEntityNum,
+ cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
+
+ if ( cg_showmiss.integer ) {
+ if (cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS) {
+ CG_Printf("WARNING: dropped event\n");
+ }
+ }
+
+ // fire events and other transition triggered things
+ CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
+
+ if ( cg_showmiss.integer ) {
+ if (cg.eventSequence > cg.predictedPlayerState.eventSequence) {
+ CG_Printf("WARNING: double event\n");
+ cg.eventSequence = cg.predictedPlayerState.eventSequence;
+ }
+ }
+}
+
+
diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h
index 8514143..8f8ea6d 100755
--- a/code/cgame/cg_public.h
+++ b/code/cgame/cg_public.h
@@ -1,238 +1,238 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-
-
-#define CMD_BACKUP 64
-#define CMD_MASK (CMD_BACKUP - 1)
-// allow a lot of command backups for very fast systems
-// multiple commands may be combined into a single packet, so this
-// needs to be larger than PACKET_BACKUP
-
-
-#define MAX_ENTITIES_IN_SNAPSHOT 256
-
-// snapshots are a view of the server at a given time
-
-// Snapshots are generated at regular time intervals by the server,
-// but they may not be sent if a client's rate level is exceeded, or
-// they may be dropped by the network.
-typedef struct {
- int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
- int ping;
-
- int serverTime; // server time the message is valid for (in msec)
-
- byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
-
- playerState_t ps; // complete information about the current player at this time
-
- int numEntities; // all of the entities that need to be presented
- entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
-
- int numServerCommands; // text based server commands to execute when this
- int serverCommandSequence; // snapshot becomes current
-} snapshot_t;
-
-enum {
- CGAME_EVENT_NONE,
- CGAME_EVENT_TEAMMENU,
- CGAME_EVENT_SCOREBOARD,
- CGAME_EVENT_EDITHUD
-};
-
-
-/*
-==================================================================
-
-functions imported from the main executable
-
-==================================================================
-*/
-
-#define CGAME_IMPORT_API_VERSION 4
-
-typedef enum {
- CG_PRINT,
- CG_ERROR,
- CG_MILLISECONDS,
- CG_CVAR_REGISTER,
- CG_CVAR_UPDATE,
- CG_CVAR_SET,
- CG_CVAR_VARIABLESTRINGBUFFER,
- CG_ARGC,
- CG_ARGV,
- CG_ARGS,
- CG_FS_FOPENFILE,
- CG_FS_READ,
- CG_FS_WRITE,
- CG_FS_FCLOSEFILE,
- CG_SENDCONSOLECOMMAND,
- CG_ADDCOMMAND,
- CG_SENDCLIENTCOMMAND,
- CG_UPDATESCREEN,
- CG_CM_LOADMAP,
- CG_CM_NUMINLINEMODELS,
- CG_CM_INLINEMODEL,
- CG_CM_LOADMODEL,
- CG_CM_TEMPBOXMODEL,
- CG_CM_POINTCONTENTS,
- CG_CM_TRANSFORMEDPOINTCONTENTS,
- CG_CM_BOXTRACE,
- CG_CM_TRANSFORMEDBOXTRACE,
- CG_CM_MARKFRAGMENTS,
- CG_S_STARTSOUND,
- CG_S_STARTLOCALSOUND,
- CG_S_CLEARLOOPINGSOUNDS,
- CG_S_ADDLOOPINGSOUND,
- CG_S_UPDATEENTITYPOSITION,
- CG_S_RESPATIALIZE,
- CG_S_REGISTERSOUND,
- CG_S_STARTBACKGROUNDTRACK,
- CG_R_LOADWORLDMAP,
- CG_R_REGISTERMODEL,
- CG_R_REGISTERSKIN,
- CG_R_REGISTERSHADER,
- CG_R_CLEARSCENE,
- CG_R_ADDREFENTITYTOSCENE,
- CG_R_ADDPOLYTOSCENE,
- CG_R_ADDLIGHTTOSCENE,
- CG_R_RENDERSCENE,
- CG_R_SETCOLOR,
- CG_R_DRAWSTRETCHPIC,
- CG_R_MODELBOUNDS,
- CG_R_LERPTAG,
- CG_GETGLCONFIG,
- CG_GETGAMESTATE,
- CG_GETCURRENTSNAPSHOTNUMBER,
- CG_GETSNAPSHOT,
- CG_GETSERVERCOMMAND,
- CG_GETCURRENTCMDNUMBER,
- CG_GETUSERCMD,
- CG_SETUSERCMDVALUE,
- CG_R_REGISTERSHADERNOMIP,
- CG_MEMORY_REMAINING,
- CG_R_REGISTERFONT,
- CG_KEY_ISDOWN,
- CG_KEY_GETCATCHER,
- CG_KEY_SETCATCHER,
- CG_KEY_GETKEY,
- CG_PC_ADD_GLOBAL_DEFINE,
- CG_PC_LOAD_SOURCE,
- CG_PC_FREE_SOURCE,
- CG_PC_READ_TOKEN,
- CG_PC_SOURCE_FILE_AND_LINE,
- CG_S_STOPBACKGROUNDTRACK,
- CG_REAL_TIME,
- CG_SNAPVECTOR,
- CG_REMOVECOMMAND,
- CG_R_LIGHTFORPOINT,
- CG_CIN_PLAYCINEMATIC,
- CG_CIN_STOPCINEMATIC,
- CG_CIN_RUNCINEMATIC,
- CG_CIN_DRAWCINEMATIC,
- CG_CIN_SETEXTENTS,
- CG_R_REMAP_SHADER,
- CG_S_ADDREALLOOPINGSOUND,
- CG_S_STOPLOOPINGSOUND,
-
- CG_CM_TEMPCAPSULEMODEL,
- CG_CM_CAPSULETRACE,
- CG_CM_TRANSFORMEDCAPSULETRACE,
- CG_R_ADDADDITIVELIGHTTOSCENE,
- CG_GET_ENTITY_TOKEN,
- CG_R_ADDPOLYSTOSCENE,
- CG_R_INPVS,
- // 1.32
- CG_FS_SEEK,
-
-/*
- CG_LOADCAMERA,
- CG_STARTCAMERA,
- CG_GETCAMERAINFO,
-*/
-
- CG_MEMSET = 100,
- CG_MEMCPY,
- CG_STRNCPY,
- CG_SIN,
- CG_COS,
- CG_ATAN2,
- CG_SQRT,
- CG_FLOOR,
- CG_CEIL,
- CG_TESTPRINTINT,
- CG_TESTPRINTFLOAT,
- CG_ACOS
-} cgameImport_t;
-
-
-/*
-==================================================================
-
-functions exported to the main executable
-
-==================================================================
-*/
-
-typedef enum {
- CG_INIT,
-// void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
- // called when the level loads or when the renderer is restarted
- // all media should be registered at this time
- // cgame will display loading status by calling SCR_Update, which
- // will call CG_DrawInformation during the loading process
- // reliableCommandSequence will be 0 on fresh loads, but higher for
- // demos, tourney restarts, or vid_restarts
-
- CG_SHUTDOWN,
-// void (*CG_Shutdown)( void );
- // oportunity to flush and close any open files
-
- CG_CONSOLE_COMMAND,
-// qboolean (*CG_ConsoleCommand)( void );
- // a console command has been issued locally that is not recognized by the
- // main game system.
- // use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
- // command is not known to the game
-
- CG_DRAW_ACTIVE_FRAME,
-// void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
- // Generates and draws a game scene and status information at the given time.
- // If demoPlayback is set, local movement prediction will not be enabled
-
- CG_CROSSHAIR_PLAYER,
-// int (*CG_CrosshairPlayer)( void );
-
- CG_LAST_ATTACKER,
-// int (*CG_LastAttacker)( void );
-
- CG_KEY_EVENT,
-// void (*CG_KeyEvent)( int key, qboolean down );
-
- CG_MOUSE_EVENT,
-// void (*CG_MouseEvent)( int dx, int dy );
- CG_EVENT_HANDLING
-// void (*CG_EventHandling)(int type);
-} cgameExport_t;
-
-//----------------------------------------------
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+
+
+#define CMD_BACKUP 64
+#define CMD_MASK (CMD_BACKUP - 1)
+// allow a lot of command backups for very fast systems
+// multiple commands may be combined into a single packet, so this
+// needs to be larger than PACKET_BACKUP
+
+
+#define MAX_ENTITIES_IN_SNAPSHOT 256
+
+// snapshots are a view of the server at a given time
+
+// Snapshots are generated at regular time intervals by the server,
+// but they may not be sent if a client's rate level is exceeded, or
+// they may be dropped by the network.
+typedef struct {
+ int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
+ int ping;
+
+ int serverTime; // server time the message is valid for (in msec)
+
+ byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
+
+ playerState_t ps; // complete information about the current player at this time
+
+ int numEntities; // all of the entities that need to be presented
+ entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
+
+ int numServerCommands; // text based server commands to execute when this
+ int serverCommandSequence; // snapshot becomes current
+} snapshot_t;
+
+enum {
+ CGAME_EVENT_NONE,
+ CGAME_EVENT_TEAMMENU,
+ CGAME_EVENT_SCOREBOARD,
+ CGAME_EVENT_EDITHUD
+};
+
+
+/*
+==================================================================
+
+functions imported from the main executable
+
+==================================================================
+*/
+
+#define CGAME_IMPORT_API_VERSION 4
+
+typedef enum {
+ CG_PRINT,
+ CG_ERROR,
+ CG_MILLISECONDS,
+ CG_CVAR_REGISTER,
+ CG_CVAR_UPDATE,
+ CG_CVAR_SET,
+ CG_CVAR_VARIABLESTRINGBUFFER,
+ CG_ARGC,
+ CG_ARGV,
+ CG_ARGS,
+ CG_FS_FOPENFILE,
+ CG_FS_READ,
+ CG_FS_WRITE,
+ CG_FS_FCLOSEFILE,
+ CG_SENDCONSOLECOMMAND,
+ CG_ADDCOMMAND,
+ CG_SENDCLIENTCOMMAND,
+ CG_UPDATESCREEN,
+ CG_CM_LOADMAP,
+ CG_CM_NUMINLINEMODELS,
+ CG_CM_INLINEMODEL,
+ CG_CM_LOADMODEL,
+ CG_CM_TEMPBOXMODEL,
+ CG_CM_POINTCONTENTS,
+ CG_CM_TRANSFORMEDPOINTCONTENTS,
+ CG_CM_BOXTRACE,
+ CG_CM_TRANSFORMEDBOXTRACE,
+ CG_CM_MARKFRAGMENTS,
+ CG_S_STARTSOUND,
+ CG_S_STARTLOCALSOUND,
+ CG_S_CLEARLOOPINGSOUNDS,
+ CG_S_ADDLOOPINGSOUND,
+ CG_S_UPDATEENTITYPOSITION,
+ CG_S_RESPATIALIZE,
+ CG_S_REGISTERSOUND,
+ CG_S_STARTBACKGROUNDTRACK,
+ CG_R_LOADWORLDMAP,
+ CG_R_REGISTERMODEL,
+ CG_R_REGISTERSKIN,
+ CG_R_REGISTERSHADER,
+ CG_R_CLEARSCENE,
+ CG_R_ADDREFENTITYTOSCENE,
+ CG_R_ADDPOLYTOSCENE,
+ CG_R_ADDLIGHTTOSCENE,
+ CG_R_RENDERSCENE,
+ CG_R_SETCOLOR,
+ CG_R_DRAWSTRETCHPIC,
+ CG_R_MODELBOUNDS,
+ CG_R_LERPTAG,
+ CG_GETGLCONFIG,
+ CG_GETGAMESTATE,
+ CG_GETCURRENTSNAPSHOTNUMBER,
+ CG_GETSNAPSHOT,
+ CG_GETSERVERCOMMAND,
+ CG_GETCURRENTCMDNUMBER,
+ CG_GETUSERCMD,
+ CG_SETUSERCMDVALUE,
+ CG_R_REGISTERSHADERNOMIP,
+ CG_MEMORY_REMAINING,
+ CG_R_REGISTERFONT,
+ CG_KEY_ISDOWN,
+ CG_KEY_GETCATCHER,
+ CG_KEY_SETCATCHER,
+ CG_KEY_GETKEY,
+ CG_PC_ADD_GLOBAL_DEFINE,
+ CG_PC_LOAD_SOURCE,
+ CG_PC_FREE_SOURCE,
+ CG_PC_READ_TOKEN,
+ CG_PC_SOURCE_FILE_AND_LINE,
+ CG_S_STOPBACKGROUNDTRACK,
+ CG_REAL_TIME,
+ CG_SNAPVECTOR,
+ CG_REMOVECOMMAND,
+ CG_R_LIGHTFORPOINT,
+ CG_CIN_PLAYCINEMATIC,
+ CG_CIN_STOPCINEMATIC,
+ CG_CIN_RUNCINEMATIC,
+ CG_CIN_DRAWCINEMATIC,
+ CG_CIN_SETEXTENTS,
+ CG_R_REMAP_SHADER,
+ CG_S_ADDREALLOOPINGSOUND,
+ CG_S_STOPLOOPINGSOUND,
+
+ CG_CM_TEMPCAPSULEMODEL,
+ CG_CM_CAPSULETRACE,
+ CG_CM_TRANSFORMEDCAPSULETRACE,
+ CG_R_ADDADDITIVELIGHTTOSCENE,
+ CG_GET_ENTITY_TOKEN,
+ CG_R_ADDPOLYSTOSCENE,
+ CG_R_INPVS,
+ // 1.32
+ CG_FS_SEEK,
+
+/*
+ CG_LOADCAMERA,
+ CG_STARTCAMERA,
+ CG_GETCAMERAINFO,
+*/
+
+ CG_MEMSET = 100,
+ CG_MEMCPY,
+ CG_STRNCPY,
+ CG_SIN,
+ CG_COS,
+ CG_ATAN2,
+ CG_SQRT,
+ CG_FLOOR,
+ CG_CEIL,
+ CG_TESTPRINTINT,
+ CG_TESTPRINTFLOAT,
+ CG_ACOS
+} cgameImport_t;
+
+
+/*
+==================================================================
+
+functions exported to the main executable
+
+==================================================================
+*/
+
+typedef enum {
+ CG_INIT,
+// void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
+ // called when the level loads or when the renderer is restarted
+ // all media should be registered at this time
+ // cgame will display loading status by calling SCR_Update, which
+ // will call CG_DrawInformation during the loading process
+ // reliableCommandSequence will be 0 on fresh loads, but higher for
+ // demos, tourney restarts, or vid_restarts
+
+ CG_SHUTDOWN,
+// void (*CG_Shutdown)( void );
+ // oportunity to flush and close any open files
+
+ CG_CONSOLE_COMMAND,
+// qboolean (*CG_ConsoleCommand)( void );
+ // a console command has been issued locally that is not recognized by the
+ // main game system.
+ // use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
+ // command is not known to the game
+
+ CG_DRAW_ACTIVE_FRAME,
+// void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
+ // Generates and draws a game scene and status information at the given time.
+ // If demoPlayback is set, local movement prediction will not be enabled
+
+ CG_CROSSHAIR_PLAYER,
+// int (*CG_CrosshairPlayer)( void );
+
+ CG_LAST_ATTACKER,
+// int (*CG_LastAttacker)( void );
+
+ CG_KEY_EVENT,
+// void (*CG_KeyEvent)( int key, qboolean down );
+
+ CG_MOUSE_EVENT,
+// void (*CG_MouseEvent)( int dx, int dy );
+ CG_EVENT_HANDLING
+// void (*CG_EventHandling)(int type);
+} cgameExport_t;
+
+//----------------------------------------------
diff --git a/code/cgame/cg_scoreboard.c b/code/cgame/cg_scoreboard.c
index 25966c9..eb9d40b 100755
--- a/code/cgame/cg_scoreboard.c
+++ b/code/cgame/cg_scoreboard.c
@@ -1,534 +1,534 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_scoreboard -- draw the scoreboard on top of the game screen
-#include "cg_local.h"
-
-
-#define SCOREBOARD_X (0)
-
-#define SB_HEADER 86
-#define SB_TOP (SB_HEADER+32)
-
-// Where the status bar starts, so we don't overwrite it
-#define SB_STATUSBAR 420
-
-#define SB_NORMAL_HEIGHT 40
-#define SB_INTER_HEIGHT 16 // interleaved height
-
-#define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
-#define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
-
-// Used when interleaved
-
-
-
-#define SB_LEFT_BOTICON_X (SCOREBOARD_X+0)
-#define SB_LEFT_HEAD_X (SCOREBOARD_X+32)
-#define SB_RIGHT_BOTICON_X (SCOREBOARD_X+64)
-#define SB_RIGHT_HEAD_X (SCOREBOARD_X+96)
-// Normal
-#define SB_BOTICON_X (SCOREBOARD_X+32)
-#define SB_HEAD_X (SCOREBOARD_X+64)
-
-#define SB_SCORELINE_X 112
-
-#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6
-#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
-#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6
-#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5
-#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5
-#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15
-
-// The new and improved score board
-//
-// In cases where the number of clients is high, the score board heads are interleaved
-// here's the layout
-
-//
-// 0 32 80 112 144 240 320 400 <-- pixel position
-// bot head bot head score ping time name
-//
-// wins/losses are drawn on bot icon now
-
-static qboolean localClient; // true if local client has been displayed
-
-
- /*
-=================
-CG_DrawScoreboard
-=================
-*/
-static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
- char string[1024];
- vec3_t headAngles;
- clientInfo_t *ci;
- int iconx, headx;
-
- if ( score->client < 0 || score->client >= cgs.maxclients ) {
- Com_Printf( "Bad score->client: %i\n", score->client );
- return;
- }
-
- ci = &cgs.clientinfo[score->client];
-
- iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
- headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);
-
- // draw the handicap or bot skill marker (unless player has flag)
- if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
- }
- } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
- }
- } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
- if( largeFormat ) {
- CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
- }
- else {
- CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
- }
- } else {
- if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
- if ( cg_drawIcons.integer ) {
- if( largeFormat ) {
- CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
- }
- else {
- CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
- }
- }
- } else if ( ci->handicap < 100 ) {
- Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
- if ( cgs.gametype == GT_TOURNAMENT )
- CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
- else
- CG_DrawSmallStringColor( iconx, y, string, color );
- }
-
- // draw the wins / losses
- if ( cgs.gametype == GT_TOURNAMENT ) {
- Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
- if( ci->handicap < 100 && !ci->botSkill ) {
- CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
- }
- else {
- CG_DrawSmallStringColor( iconx, y, string, color );
- }
- }
- }
-
- // draw the face
- VectorClear( headAngles );
- headAngles[YAW] = 180;
- if( largeFormat ) {
- CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE,
- score->client, headAngles );
- }
- else {
- CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
- }
-
-#ifdef MISSIONPACK
- // draw the team task
- if ( ci->teamTask != TEAMTASK_NONE ) {
- if ( ci->teamTask == TEAMTASK_OFFENSE ) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
- }
- else if ( ci->teamTask == TEAMTASK_DEFENSE ) {
- CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
- }
- }
-#endif
- // draw the score line
- if ( score->ping == -1 ) {
- Com_sprintf(string, sizeof(string),
- " connecting %s", ci->name);
- } else if ( ci->team == TEAM_SPECTATOR ) {
- Com_sprintf(string, sizeof(string),
- " SPECT %3i %4i %s", score->ping, score->time, ci->name);
- } else {
- Com_sprintf(string, sizeof(string),
- "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
- }
-
- // highlight your position
- if ( score->client == cg.snap->ps.clientNum ) {
- float hcolor[4];
- int rank;
-
- localClient = qtrue;
-
- if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR
- || cgs.gametype >= GT_TEAM ) {
- rank = -1;
- } else {
- rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
- }
- if ( rank == 0 ) {
- hcolor[0] = 0;
- hcolor[1] = 0;
- hcolor[2] = 0.7f;
- } else if ( rank == 1 ) {
- hcolor[0] = 0.7f;
- hcolor[1] = 0;
- hcolor[2] = 0;
- } else if ( rank == 2 ) {
- hcolor[0] = 0.7f;
- hcolor[1] = 0.7f;
- hcolor[2] = 0;
- } else {
- hcolor[0] = 0.7f;
- hcolor[1] = 0.7f;
- hcolor[2] = 0.7f;
- }
-
- hcolor[3] = fade * 0.7;
- CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y,
- 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
- }
-
- CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );
-
- // add the "ready" marker for intermission exiting
- if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
- CG_DrawBigStringColor( iconx, y, "READY", color );
- }
-}
-
-/*
-=================
-CG_TeamScoreboard
-=================
-*/
-static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
- int i;
- score_t *score;
- float color[4];
- int count;
- clientInfo_t *ci;
-
- color[0] = color[1] = color[2] = 1.0;
- color[3] = fade;
-
- count = 0;
- for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
- score = &cg.scores[i];
- ci = &cgs.clientinfo[ score->client ];
-
- if ( team != ci->team ) {
- continue;
- }
-
- CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
-
- count++;
- }
-
- return count;
-}
-
-/*
-=================
-CG_DrawScoreboard
-
-Draw the normal in-game scoreboard
-=================
-*/
-qboolean CG_DrawOldScoreboard( void ) {
- int x, y, w, i, n1, n2;
- float fade;
- float *fadeColor;
- char *s;
- int maxClients;
- int lineHeight;
- int topBorderSize, bottomBorderSize;
-
- // don't draw amuthing if the menu or console is up
- if ( cg_paused.integer ) {
- cg.deferredPlayerLoading = 0;
- return qfalse;
- }
-
- if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- cg.deferredPlayerLoading = 0;
- return qfalse;
- }
-
- // don't draw scoreboard during death while warmup up
- if ( cg.warmup && !cg.showScores ) {
- return qfalse;
- }
-
- if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
- cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- fade = 1.0;
- fadeColor = colorWhite;
- } else {
- fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
-
- if ( !fadeColor ) {
- // next time scoreboard comes up, don't print killer
- cg.deferredPlayerLoading = 0;
- cg.killerName[0] = 0;
- return qfalse;
- }
- fade = *fadeColor;
- }
-
-
- // fragged by ... line
- if ( cg.killerName[0] ) {
- s = va("Fragged by %s", cg.killerName );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 40;
- CG_DrawBigString( x, y, s, fade );
- }
-
- // current rank
- if ( cgs.gametype < GT_TEAM) {
- if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
- s = va("%s place with %i",
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- cg.snap->ps.persistant[PERS_SCORE] );
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 60;
- CG_DrawBigString( x, y, s, fade );
- }
- } else {
- if ( cg.teamScores[0] == cg.teamScores[1] ) {
- s = va("Teams are tied at %i", cg.teamScores[0] );
- } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
- } else {
- s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
- }
-
- w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- y = 60;
- CG_DrawBigString( x, y, s, fade );
- }
-
- // scoreboard
- y = SB_HEADER;
-
- CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );
- CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );
- CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );
- CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );
-
- y = SB_TOP;
-
- // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
- if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
- maxClients = SB_MAXCLIENTS_INTER;
- lineHeight = SB_INTER_HEIGHT;
- topBorderSize = 8;
- bottomBorderSize = 16;
- } else {
- maxClients = SB_MAXCLIENTS_NORMAL;
- lineHeight = SB_NORMAL_HEIGHT;
- topBorderSize = 16;
- bottomBorderSize = 16;
- }
-
- localClient = qfalse;
-
- if ( cgs.gametype >= GT_TEAM ) {
- //
- // teamplay scoreboard
- //
- y += lineHeight/2;
-
- if ( cg.teamScores[0] >= cg.teamScores[1] ) {
- n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n1;
- n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n2;
- } else {
- n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n1;
- n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
- CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- maxClients -= n2;
- }
- n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
-
- } else {
- //
- // free for all scoreboard
- //
- n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
- y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
- n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
- y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
- }
-
- if (!localClient) {
- // draw local client at the bottom
- for ( i = 0 ; i < cg.numScores ; i++ ) {
- if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
- CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
- break;
- }
- }
- }
-
- // load any models that have been deferred
- if ( ++cg.deferredPlayerLoading > 10 ) {
- CG_LoadDeferredPlayers();
- }
-
- return qtrue;
-}
-
-//================================================================================
-
-/*
-================
-CG_CenterGiantLine
-================
-*/
-static void CG_CenterGiantLine( float y, const char *string ) {
- float x;
- vec4_t color;
-
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
- x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
-
- CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-}
-
-/*
-=================
-CG_DrawTourneyScoreboard
-
-Draw the oversize scoreboard for tournements
-=================
-*/
-void CG_DrawOldTourneyScoreboard( void ) {
- const char *s;
- vec4_t color;
- int min, tens, ones;
- clientInfo_t *ci;
- int y;
- int i;
-
- // request more scores regularly
- if ( cg.scoresRequestTime + 2000 < cg.time ) {
- cg.scoresRequestTime = cg.time;
- trap_SendClientCommand( "score" );
- }
-
- color[0] = 1;
- color[1] = 1;
- color[2] = 1;
- color[3] = 1;
-
- // draw the dialog background
- color[0] = color[1] = color[2] = 0;
- color[3] = 1;
- CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
-
- // print the mesage of the day
- s = CG_ConfigString( CS_MOTD );
- if ( !s[0] ) {
- s = "Scoreboard";
- }
-
- // print optional title
- CG_CenterGiantLine( 8, s );
-
- // print server time
- ones = cg.time / 1000;
- min = ones / 60;
- ones %= 60;
- tens = ones / 10;
- ones %= 10;
- s = va("%i:%i%i", min, tens, ones );
-
- CG_CenterGiantLine( 64, s );
-
-
- // print the two scores
-
- y = 160;
- if ( cgs.gametype >= GT_TEAM ) {
- //
- // teamplay scoreboard
- //
- CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", cg.teamScores[0] );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
-
- y += 64;
-
- CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", cg.teamScores[1] );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- } else {
- //
- // free for all scoreboard
- //
- for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
- ci = &cgs.clientinfo[i];
- if ( !ci->infoValid ) {
- continue;
- }
- if ( ci->team != TEAM_FREE ) {
- continue;
- }
-
- CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- s = va("%i", ci->score );
- CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
- y += 64;
- }
- }
-
-
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_scoreboard -- draw the scoreboard on top of the game screen
+#include "cg_local.h"
+
+
+#define SCOREBOARD_X (0)
+
+#define SB_HEADER 86
+#define SB_TOP (SB_HEADER+32)
+
+// Where the status bar starts, so we don't overwrite it
+#define SB_STATUSBAR 420
+
+#define SB_NORMAL_HEIGHT 40
+#define SB_INTER_HEIGHT 16 // interleaved height
+
+#define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
+#define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
+
+// Used when interleaved
+
+
+
+#define SB_LEFT_BOTICON_X (SCOREBOARD_X+0)
+#define SB_LEFT_HEAD_X (SCOREBOARD_X+32)
+#define SB_RIGHT_BOTICON_X (SCOREBOARD_X+64)
+#define SB_RIGHT_HEAD_X (SCOREBOARD_X+96)
+// Normal
+#define SB_BOTICON_X (SCOREBOARD_X+32)
+#define SB_HEAD_X (SCOREBOARD_X+64)
+
+#define SB_SCORELINE_X 112
+
+#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6
+#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
+#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6
+#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5
+#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5
+#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15
+
+// The new and improved score board
+//
+// In cases where the number of clients is high, the score board heads are interleaved
+// here's the layout
+
+//
+// 0 32 80 112 144 240 320 400 <-- pixel position
+// bot head bot head score ping time name
+//
+// wins/losses are drawn on bot icon now
+
+static qboolean localClient; // true if local client has been displayed
+
+
+ /*
+=================
+CG_DrawScoreboard
+=================
+*/
+static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
+ char string[1024];
+ vec3_t headAngles;
+ clientInfo_t *ci;
+ int iconx, headx;
+
+ if ( score->client < 0 || score->client >= cgs.maxclients ) {
+ Com_Printf( "Bad score->client: %i\n", score->client );
+ return;
+ }
+
+ ci = &cgs.clientinfo[score->client];
+
+ iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
+ headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);
+
+ // draw the handicap or bot skill marker (unless player has flag)
+ if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
+ if( largeFormat ) {
+ CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
+ }
+ else {
+ CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
+ }
+ } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
+ if( largeFormat ) {
+ CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
+ }
+ else {
+ CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
+ }
+ } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
+ if( largeFormat ) {
+ CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
+ }
+ else {
+ CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
+ }
+ } else {
+ if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
+ if ( cg_drawIcons.integer ) {
+ if( largeFormat ) {
+ CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
+ }
+ else {
+ CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
+ }
+ }
+ } else if ( ci->handicap < 100 ) {
+ Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
+ if ( cgs.gametype == GT_TOURNAMENT )
+ CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
+ else
+ CG_DrawSmallStringColor( iconx, y, string, color );
+ }
+
+ // draw the wins / losses
+ if ( cgs.gametype == GT_TOURNAMENT ) {
+ Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
+ if( ci->handicap < 100 && !ci->botSkill ) {
+ CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
+ }
+ else {
+ CG_DrawSmallStringColor( iconx, y, string, color );
+ }
+ }
+ }
+
+ // draw the face
+ VectorClear( headAngles );
+ headAngles[YAW] = 180;
+ if( largeFormat ) {
+ CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE,
+ score->client, headAngles );
+ }
+ else {
+ CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
+ }
+
+#ifdef MISSIONPACK
+ // draw the team task
+ if ( ci->teamTask != TEAMTASK_NONE ) {
+ if ( ci->teamTask == TEAMTASK_OFFENSE ) {
+ CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
+ }
+ else if ( ci->teamTask == TEAMTASK_DEFENSE ) {
+ CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
+ }
+ }
+#endif
+ // draw the score line
+ if ( score->ping == -1 ) {
+ Com_sprintf(string, sizeof(string),
+ " connecting %s", ci->name);
+ } else if ( ci->team == TEAM_SPECTATOR ) {
+ Com_sprintf(string, sizeof(string),
+ " SPECT %3i %4i %s", score->ping, score->time, ci->name);
+ } else {
+ Com_sprintf(string, sizeof(string),
+ "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
+ }
+
+ // highlight your position
+ if ( score->client == cg.snap->ps.clientNum ) {
+ float hcolor[4];
+ int rank;
+
+ localClient = qtrue;
+
+ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR
+ || cgs.gametype >= GT_TEAM ) {
+ rank = -1;
+ } else {
+ rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
+ }
+ if ( rank == 0 ) {
+ hcolor[0] = 0;
+ hcolor[1] = 0;
+ hcolor[2] = 0.7f;
+ } else if ( rank == 1 ) {
+ hcolor[0] = 0.7f;
+ hcolor[1] = 0;
+ hcolor[2] = 0;
+ } else if ( rank == 2 ) {
+ hcolor[0] = 0.7f;
+ hcolor[1] = 0.7f;
+ hcolor[2] = 0;
+ } else {
+ hcolor[0] = 0.7f;
+ hcolor[1] = 0.7f;
+ hcolor[2] = 0.7f;
+ }
+
+ hcolor[3] = fade * 0.7;
+ CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y,
+ 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
+ }
+
+ CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );
+
+ // add the "ready" marker for intermission exiting
+ if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
+ CG_DrawBigStringColor( iconx, y, "READY", color );
+ }
+}
+
+/*
+=================
+CG_TeamScoreboard
+=================
+*/
+static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
+ int i;
+ score_t *score;
+ float color[4];
+ int count;
+ clientInfo_t *ci;
+
+ color[0] = color[1] = color[2] = 1.0;
+ color[3] = fade;
+
+ count = 0;
+ for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
+ score = &cg.scores[i];
+ ci = &cgs.clientinfo[ score->client ];
+
+ if ( team != ci->team ) {
+ continue;
+ }
+
+ CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
+
+ count++;
+ }
+
+ return count;
+}
+
+/*
+=================
+CG_DrawScoreboard
+
+Draw the normal in-game scoreboard
+=================
+*/
+qboolean CG_DrawOldScoreboard( void ) {
+ int x, y, w, i, n1, n2;
+ float fade;
+ float *fadeColor;
+ char *s;
+ int maxClients;
+ int lineHeight;
+ int topBorderSize, bottomBorderSize;
+
+ // don't draw amuthing if the menu or console is up
+ if ( cg_paused.integer ) {
+ cg.deferredPlayerLoading = 0;
+ return qfalse;
+ }
+
+ if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ cg.deferredPlayerLoading = 0;
+ return qfalse;
+ }
+
+ // don't draw scoreboard during death while warmup up
+ if ( cg.warmup && !cg.showScores ) {
+ return qfalse;
+ }
+
+ if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
+ cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ fade = 1.0;
+ fadeColor = colorWhite;
+ } else {
+ fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
+
+ if ( !fadeColor ) {
+ // next time scoreboard comes up, don't print killer
+ cg.deferredPlayerLoading = 0;
+ cg.killerName[0] = 0;
+ return qfalse;
+ }
+ fade = *fadeColor;
+ }
+
+
+ // fragged by ... line
+ if ( cg.killerName[0] ) {
+ s = va("Fragged by %s", cg.killerName );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ y = 40;
+ CG_DrawBigString( x, y, s, fade );
+ }
+
+ // current rank
+ if ( cgs.gametype < GT_TEAM) {
+ if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
+ s = va("%s place with %i",
+ CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
+ cg.snap->ps.persistant[PERS_SCORE] );
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ y = 60;
+ CG_DrawBigString( x, y, s, fade );
+ }
+ } else {
+ if ( cg.teamScores[0] == cg.teamScores[1] ) {
+ s = va("Teams are tied at %i", cg.teamScores[0] );
+ } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
+ s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
+ } else {
+ s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
+ }
+
+ w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ y = 60;
+ CG_DrawBigString( x, y, s, fade );
+ }
+
+ // scoreboard
+ y = SB_HEADER;
+
+ CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );
+ CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );
+ CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );
+ CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );
+
+ y = SB_TOP;
+
+ // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
+ if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
+ maxClients = SB_MAXCLIENTS_INTER;
+ lineHeight = SB_INTER_HEIGHT;
+ topBorderSize = 8;
+ bottomBorderSize = 16;
+ } else {
+ maxClients = SB_MAXCLIENTS_NORMAL;
+ lineHeight = SB_NORMAL_HEIGHT;
+ topBorderSize = 16;
+ bottomBorderSize = 16;
+ }
+
+ localClient = qfalse;
+
+ if ( cgs.gametype >= GT_TEAM ) {
+ //
+ // teamplay scoreboard
+ //
+ y += lineHeight/2;
+
+ if ( cg.teamScores[0] >= cg.teamScores[1] ) {
+ n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n1;
+ n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
+ y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n2;
+ } else {
+ n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n1;
+ n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
+ CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
+ y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
+ maxClients -= n2;
+ }
+ n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+
+ } else {
+ //
+ // free for all scoreboard
+ //
+ n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
+ y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
+ n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
+ y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
+ }
+
+ if (!localClient) {
+ // draw local client at the bottom
+ for ( i = 0 ; i < cg.numScores ; i++ ) {
+ if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
+ CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
+ break;
+ }
+ }
+ }
+
+ // load any models that have been deferred
+ if ( ++cg.deferredPlayerLoading > 10 ) {
+ CG_LoadDeferredPlayers();
+ }
+
+ return qtrue;
+}
+
+//================================================================================
+
+/*
+================
+CG_CenterGiantLine
+================
+*/
+static void CG_CenterGiantLine( float y, const char *string ) {
+ float x;
+ vec4_t color;
+
+ color[0] = 1;
+ color[1] = 1;
+ color[2] = 1;
+ color[3] = 1;
+
+ x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
+
+ CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+}
+
+/*
+=================
+CG_DrawTourneyScoreboard
+
+Draw the oversize scoreboard for tournements
+=================
+*/
+void CG_DrawOldTourneyScoreboard( void ) {
+ const char *s;
+ vec4_t color;
+ int min, tens, ones;
+ clientInfo_t *ci;
+ int y;
+ int i;
+
+ // request more scores regularly
+ if ( cg.scoresRequestTime + 2000 < cg.time ) {
+ cg.scoresRequestTime = cg.time;
+ trap_SendClientCommand( "score" );
+ }
+
+ color[0] = 1;
+ color[1] = 1;
+ color[2] = 1;
+ color[3] = 1;
+
+ // draw the dialog background
+ color[0] = color[1] = color[2] = 0;
+ color[3] = 1;
+ CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
+
+ // print the mesage of the day
+ s = CG_ConfigString( CS_MOTD );
+ if ( !s[0] ) {
+ s = "Scoreboard";
+ }
+
+ // print optional title
+ CG_CenterGiantLine( 8, s );
+
+ // print server time
+ ones = cg.time / 1000;
+ min = ones / 60;
+ ones %= 60;
+ tens = ones / 10;
+ ones %= 10;
+ s = va("%i:%i%i", min, tens, ones );
+
+ CG_CenterGiantLine( 64, s );
+
+
+ // print the two scores
+
+ y = 160;
+ if ( cgs.gametype >= GT_TEAM ) {
+ //
+ // teamplay scoreboard
+ //
+ CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ s = va("%i", cg.teamScores[0] );
+ CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+
+ y += 64;
+
+ CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ s = va("%i", cg.teamScores[1] );
+ CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ } else {
+ //
+ // free for all scoreboard
+ //
+ for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
+ ci = &cgs.clientinfo[i];
+ if ( !ci->infoValid ) {
+ continue;
+ }
+ if ( ci->team != TEAM_FREE ) {
+ continue;
+ }
+
+ CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ s = va("%i", ci->score );
+ CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
+ y += 64;
+ }
+ }
+
+
+}
+
diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c
index d12cd97..6558d2f 100755
--- a/code/cgame/cg_servercmds.c
+++ b/code/cgame/cg_servercmds.c
@@ -1,1098 +1,1098 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_servercmds.c -- reliably sequenced text commands sent by the server
-// these are processed at snapshot transition time, so there will definately
-// be a valid snapshot this frame
-
-#include "cg_local.h"
-#include "../../ui/menudef.h" // bk001205 - for Q3_ui as well
-
-typedef struct {
- const char *order;
- int taskNum;
-} orderTask_t;
-
-static const orderTask_t validOrders[] = {
- { VOICECHAT_GETFLAG, TEAMTASK_OFFENSE },
- { VOICECHAT_OFFENSE, TEAMTASK_OFFENSE },
- { VOICECHAT_DEFEND, TEAMTASK_DEFENSE },
- { VOICECHAT_DEFENDFLAG, TEAMTASK_DEFENSE },
- { VOICECHAT_PATROL, TEAMTASK_PATROL },
- { VOICECHAT_CAMP, TEAMTASK_CAMP },
- { VOICECHAT_FOLLOWME, TEAMTASK_FOLLOW },
- { VOICECHAT_RETURNFLAG, TEAMTASK_RETRIEVE },
- { VOICECHAT_FOLLOWFLAGCARRIER, TEAMTASK_ESCORT }
-};
-
-static const int numValidOrders = sizeof(validOrders) / sizeof(orderTask_t);
-
-#ifdef MISSIONPACK // bk001204
-static int CG_ValidOrder(const char *p) {
- int i;
- for (i = 0; i < numValidOrders; i++) {
- if (Q_stricmp(p, validOrders[i].order) == 0) {
- return validOrders[i].taskNum;
- }
- }
- return -1;
-}
-#endif
-
-/*
-=================
-CG_ParseScores
-
-=================
-*/
-static void CG_ParseScores( void ) {
- int i, powerups;
-
- cg.numScores = atoi( CG_Argv( 1 ) );
- if ( cg.numScores > MAX_CLIENTS ) {
- cg.numScores = MAX_CLIENTS;
- }
-
- cg.teamScores[0] = atoi( CG_Argv( 2 ) );
- cg.teamScores[1] = atoi( CG_Argv( 3 ) );
-
- memset( cg.scores, 0, sizeof( cg.scores ) );
- for ( i = 0 ; i < cg.numScores ; i++ ) {
- //
- cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) );
- cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) );
- cg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) );
- cg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) );
- cg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) );
- powerups = atoi( CG_Argv( i * 14 + 9 ) );
- cg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10));
- cg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11));
- cg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12));
- cg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13));
- cg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14));
- cg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15));
- cg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16));
- cg.scores[i].captures = atoi(CG_Argv(i * 14 + 17));
-
- if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
- cg.scores[i].client = 0;
- }
- cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
- cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
-
- cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;
- }
-#ifdef MISSIONPACK
- CG_SetScoreSelection(NULL);
-#endif
-
-}
-
-/*
-=================
-CG_ParseTeamInfo
-
-=================
-*/
-static void CG_ParseTeamInfo( void ) {
- int i;
- int client;
-
- numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
-
- for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
- client = atoi( CG_Argv( i * 6 + 2 ) );
-
- sortedTeamPlayers[i] = client;
-
- cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
- cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
- cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
- cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
- cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
- }
-}
-
-
-/*
-================
-CG_ParseServerinfo
-
-This is called explicitly when the gamestate is first received,
-and whenever the server updates any serverinfo flagged cvars
-================
-*/
-void CG_ParseServerinfo( void ) {
- const char *info;
- char *mapname;
-
- info = CG_ConfigString( CS_SERVERINFO );
- cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
- trap_Cvar_Set("g_gametype", va("%i", cgs.gametype));
- cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
- cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
- cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
- cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
- cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
- cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- mapname = Info_ValueForKey( info, "mapname" );
- Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
- Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) );
- trap_Cvar_Set("g_redTeam", cgs.redTeam);
- Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) );
- trap_Cvar_Set("g_blueTeam", cgs.blueTeam);
-}
-
-/*
-==================
-CG_ParseWarmup
-==================
-*/
-static void CG_ParseWarmup( void ) {
- const char *info;
- int warmup;
-
- info = CG_ConfigString( CS_WARMUP );
-
- warmup = atoi( info );
- cg.warmupCount = -1;
-
- if ( warmup == 0 && cg.warmup ) {
-
- } else if ( warmup > 0 && cg.warmup <= 0 ) {
-#ifdef MISSIONPACK
- if (cgs.gametype >= GT_CTF && cgs.gametype <= GT_HARVESTER) {
- trap_S_StartLocalSound( cgs.media.countPrepareTeamSound, CHAN_ANNOUNCER );
- } else
-#endif
- {
- trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
- }
- }
-
- cg.warmup = warmup;
-}
-
-/*
-================
-CG_SetConfigValues
-
-Called on load to set the initial values from configure strings
-================
-*/
-void CG_SetConfigValues( void ) {
- const char *s;
-
- cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
- cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
- cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
- if( cgs.gametype == GT_CTF ) {
- s = CG_ConfigString( CS_FLAGSTATUS );
- cgs.redflag = s[0] - '0';
- cgs.blueflag = s[1] - '0';
- }
-#ifdef MISSIONPACK
- else if( cgs.gametype == GT_1FCTF ) {
- s = CG_ConfigString( CS_FLAGSTATUS );
- cgs.flagStatus = s[0] - '0';
- }
-#endif
- cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
-}
-
-/*
-=====================
-CG_ShaderStateChanged
-=====================
-*/
-void CG_ShaderStateChanged(void) {
- char originalShader[MAX_QPATH];
- char newShader[MAX_QPATH];
- char timeOffset[16];
- const char *o;
- char *n,*t;
-
- o = CG_ConfigString( CS_SHADERSTATE );
- while (o && *o) {
- n = strstr(o, "=");
- if (n && *n) {
- strncpy(originalShader, o, n-o);
- originalShader[n-o] = 0;
- n++;
- t = strstr(n, ":");
- if (t && *t) {
- strncpy(newShader, n, t-n);
- newShader[t-n] = 0;
- } else {
- break;
- }
- t++;
- o = strstr(t, "@");
- if (o) {
- strncpy(timeOffset, t, o-t);
- timeOffset[o-t] = 0;
- o++;
- trap_R_RemapShader( originalShader, newShader, timeOffset );
- }
- } else {
- break;
- }
- }
-}
-
-/*
-================
-CG_ConfigStringModified
-
-================
-*/
-static void CG_ConfigStringModified( void ) {
- const char *str;
- int num;
-
- num = atoi( CG_Argv( 1 ) );
-
- // get the gamestate from the client system, which will have the
- // new configstring already integrated
- trap_GetGameState( &cgs.gameState );
-
- // look up the individual string that was modified
- str = CG_ConfigString( num );
-
- // do something with it if necessary
- if ( num == CS_MUSIC ) {
- CG_StartMusic();
- } else if ( num == CS_SERVERINFO ) {
- CG_ParseServerinfo();
- } else if ( num == CS_WARMUP ) {
- CG_ParseWarmup();
- } else if ( num == CS_SCORES1 ) {
- cgs.scores1 = atoi( str );
- } else if ( num == CS_SCORES2 ) {
- cgs.scores2 = atoi( str );
- } else if ( num == CS_LEVEL_START_TIME ) {
- cgs.levelStartTime = atoi( str );
- } else if ( num == CS_VOTE_TIME ) {
- cgs.voteTime = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_YES ) {
- cgs.voteYes = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_NO ) {
- cgs.voteNo = atoi( str );
- cgs.voteModified = qtrue;
- } else if ( num == CS_VOTE_STRING ) {
- Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
-#ifdef MISSIONPACK
- trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
-#endif //MISSIONPACK
- } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {
- cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;
- } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {
- cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;
- } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {
- cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );
- cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;
- } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {
- Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );
-#ifdef MISSIONPACK
- trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
-#endif
- } else if ( num == CS_INTERMISSION ) {
- cg.intermissionStarted = atoi( str );
- } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
- cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
- } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_MODELS ) {
- if ( str[0] != '*' ) { // player specific sounds don't register here
- cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse );
- }
- } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
- CG_NewClientInfo( num - CS_PLAYERS );
- CG_BuildSpectatorString();
- } else if ( num == CS_FLAGSTATUS ) {
- if( cgs.gametype == GT_CTF ) {
- // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
- cgs.redflag = str[0] - '0';
- cgs.blueflag = str[1] - '0';
- }
-#ifdef MISSIONPACK
- else if( cgs.gametype == GT_1FCTF ) {
- cgs.flagStatus = str[0] - '0';
- }
-#endif
- }
- else if ( num == CS_SHADERSTATE ) {
- CG_ShaderStateChanged();
- }
-
-}
-
-
-/*
-=======================
-CG_AddToTeamChat
-
-=======================
-*/
-static void CG_AddToTeamChat( const char *str ) {
- int len;
- char *p, *ls;
- int lastcolor;
- int chatHeight;
-
- if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
- chatHeight = cg_teamChatHeight.integer;
- } else {
- chatHeight = TEAMCHAT_HEIGHT;
- }
-
- if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
- // team chat disabled, dump into normal chat
- cgs.teamChatPos = cgs.teamLastChatPos = 0;
- return;
- }
-
- len = 0;
-
- p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
- *p = 0;
-
- lastcolor = '7';
-
- ls = NULL;
- while (*str) {
- if (len > TEAMCHAT_WIDTH - 1) {
- if (ls) {
- str -= (p - ls);
- str++;
- p -= (p - ls);
- }
- *p = 0;
-
- cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
-
- cgs.teamChatPos++;
- p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
- *p = 0;
- *p++ = Q_COLOR_ESCAPE;
- *p++ = lastcolor;
- len = 0;
- ls = NULL;
- }
-
- if ( Q_IsColorString( str ) ) {
- *p++ = *str++;
- lastcolor = *str;
- *p++ = *str++;
- continue;
- }
- if (*str == ' ') {
- ls = p;
- }
- *p++ = *str++;
- len++;
- }
- *p = 0;
-
- cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
- cgs.teamChatPos++;
-
- if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
- cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
-}
-
-/*
-===============
-CG_MapRestart
-
-The server has issued a map_restart, so the next snapshot
-is completely new and should not be interpolated to.
-
-A tournement restart will clear everything, but doesn't
-require a reload of all the media
-===============
-*/
-static void CG_MapRestart( void ) {
- if ( cg_showmiss.integer ) {
- CG_Printf( "CG_MapRestart\n" );
- }
-
- CG_InitLocalEntities();
- CG_InitMarkPolys();
- CG_ClearParticles ();
-
- // make sure the "3 frags left" warnings play again
- cg.fraglimitWarnings = 0;
-
- cg.timelimitWarnings = 0;
-
- cg.intermissionStarted = qfalse;
-
- cgs.voteTime = 0;
-
- cg.mapRestart = qtrue;
-
- CG_StartMusic();
-
- trap_S_ClearLoopingSounds(qtrue);
-
- // we really should clear more parts of cg here and stop sounds
-
- // play the "fight" sound if this is a restart without warmup
- if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
- trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
- CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
- }
-#ifdef MISSIONPACK
- if (cg_singlePlayerActive.integer) {
- trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time));
- if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) {
- trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string));
- }
- }
-#endif
- trap_Cvar_Set("cg_thirdPerson", "0");
-}
-
-#define MAX_VOICEFILESIZE 16384
-#define MAX_VOICEFILES 8
-#define MAX_VOICECHATS 64
-#define MAX_VOICESOUNDS 64
-#define MAX_CHATSIZE 64
-#define MAX_HEADMODELS 64
-
-typedef struct voiceChat_s
-{
- char id[64];
- int numSounds;
- sfxHandle_t sounds[MAX_VOICESOUNDS];
- char chats[MAX_VOICESOUNDS][MAX_CHATSIZE];
-} voiceChat_t;
-
-typedef struct voiceChatList_s
-{
- char name[64];
- int gender;
- int numVoiceChats;
- voiceChat_t voiceChats[MAX_VOICECHATS];
-} voiceChatList_t;
-
-typedef struct headModelVoiceChat_s
-{
- char headmodel[64];
- int voiceChatNum;
-} headModelVoiceChat_t;
-
-voiceChatList_t voiceChatLists[MAX_VOICEFILES];
-headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS];
-
-/*
-=================
-CG_ParseVoiceChats
-=================
-*/
-int CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) {
- int len, i;
- fileHandle_t f;
- char buf[MAX_VOICEFILESIZE];
- char **p, *ptr;
- char *token;
- voiceChat_t *voiceChats;
- qboolean compress;
- sfxHandle_t sound;
-
- compress = qtrue;
- if (cg_buildScript.integer) {
- compress = qfalse;
- }
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- trap_Print( va( S_COLOR_RED "voice chat file not found: %s\n", filename ) );
- return qfalse;
- }
- if ( len >= MAX_VOICEFILESIZE ) {
- trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
- trap_FS_FCloseFile( f );
- return qfalse;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ptr = buf;
- p = &ptr;
-
- Com_sprintf(voiceChatList->name, sizeof(voiceChatList->name), "%s", filename);
- voiceChats = voiceChatList->voiceChats;
- for ( i = 0; i < maxVoiceChats; i++ ) {
- voiceChats[i].id[0] = 0;
- }
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- if (!Q_stricmp(token, "female")) {
- voiceChatList->gender = GENDER_FEMALE;
- }
- else if (!Q_stricmp(token, "male")) {
- voiceChatList->gender = GENDER_MALE;
- }
- else if (!Q_stricmp(token, "neuter")) {
- voiceChatList->gender = GENDER_NEUTER;
- }
- else {
- trap_Print( va( S_COLOR_RED "expected gender not found in voice chat file: %s\n", filename ) );
- return qfalse;
- }
-
- voiceChatList->numVoiceChats = 0;
- while ( 1 ) {
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), "%s", token);
- token = COM_ParseExt(p, qtrue);
- if (Q_stricmp(token, "{")) {
- trap_Print( va( S_COLOR_RED "expected { found %s in voice chat file: %s\n", token, filename ) );
- return qfalse;
- }
- voiceChats[voiceChatList->numVoiceChats].numSounds = 0;
- while(1) {
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- if (!Q_stricmp(token, "}"))
- break;
- sound = trap_S_RegisterSound( token, compress );
- voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound;
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return qtrue;
- }
- Com_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[
- voiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, "%s", token);
- if (sound)
- voiceChats[voiceChatList->numVoiceChats].numSounds++;
- if (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS)
- break;
- }
- voiceChatList->numVoiceChats++;
- if (voiceChatList->numVoiceChats >= maxVoiceChats)
- return qtrue;
- }
- return qtrue;
-}
-
-/*
-=================
-CG_LoadVoiceChats
-=================
-*/
-void CG_LoadVoiceChats( void ) {
- int size;
-
- size = trap_MemoryRemaining();
- CG_ParseVoiceChats( "scripts/female1.voice", &voiceChatLists[0], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/female2.voice", &voiceChatLists[1], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/female3.voice", &voiceChatLists[2], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male1.voice", &voiceChatLists[3], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male2.voice", &voiceChatLists[4], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male3.voice", &voiceChatLists[5], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male4.voice", &voiceChatLists[6], MAX_VOICECHATS );
- CG_ParseVoiceChats( "scripts/male5.voice", &voiceChatLists[7], MAX_VOICECHATS );
- CG_Printf("voice chat memory size = %d\n", size - trap_MemoryRemaining());
-}
-
-/*
-=================
-CG_HeadModelVoiceChats
-=================
-*/
-int CG_HeadModelVoiceChats( char *filename ) {
- int len, i;
- fileHandle_t f;
- char buf[MAX_VOICEFILESIZE];
- char **p, *ptr;
- char *token;
-
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( !f ) {
- //trap_Print( va( "voice chat file not found: %s\n", filename ) );
- return -1;
- }
- if ( len >= MAX_VOICEFILESIZE ) {
- trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
- trap_FS_FCloseFile( f );
- return -1;
- }
-
- trap_FS_Read( buf, len, f );
- buf[len] = 0;
- trap_FS_FCloseFile( f );
-
- ptr = buf;
- p = &ptr;
-
- token = COM_ParseExt(p, qtrue);
- if (!token || token[0] == 0) {
- return -1;
- }
-
- for ( i = 0; i < MAX_VOICEFILES; i++ ) {
- if ( !Q_stricmp(token, voiceChatLists[i].name) ) {
- return i;
- }
- }
-
- //FIXME: maybe try to load the .voice file which name is stored in token?
-
- return -1;
-}
-
-
-/*
-=================
-CG_GetVoiceChat
-=================
-*/
-int CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) {
- int i, rnd;
-
- for ( i = 0; i < voiceChatList->numVoiceChats; i++ ) {
- if ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) {
- rnd = random() * voiceChatList->voiceChats[i].numSounds;
- *snd = voiceChatList->voiceChats[i].sounds[rnd];
- *chat = voiceChatList->voiceChats[i].chats[rnd];
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-CG_VoiceChatListForClient
-=================
-*/
-voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) {
- clientInfo_t *ci;
- int voiceChatNum, i, j, k, gender;
- char filename[MAX_QPATH], headModelName[MAX_QPATH];
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- for ( k = 0; k < 2; k++ ) {
- if ( k == 0 ) {
- if (ci->headModelName[0] == '*') {
- Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName+1, ci->headSkinName );
- }
- else {
- Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName, ci->headSkinName );
- }
- }
- else {
- if (ci->headModelName[0] == '*') {
- Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName+1 );
- }
- else {
- Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName );
- }
- }
- // find the voice file for the head model the client uses
- for ( i = 0; i < MAX_HEADMODELS; i++ ) {
- if (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) {
- break;
- }
- }
- if (i < MAX_HEADMODELS) {
- return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
- }
- // find a <headmodelname>.vc file
- for ( i = 0; i < MAX_HEADMODELS; i++ ) {
- if (!strlen(headModelVoiceChat[i].headmodel)) {
- Com_sprintf(filename, sizeof(filename), "scripts/%s.vc", headModelName);
- voiceChatNum = CG_HeadModelVoiceChats(filename);
- if (voiceChatNum == -1)
- break;
- Com_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[i].voiceChatNum = voiceChatNum;
- return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
- }
- }
- }
- gender = ci->gender;
- for (k = 0; k < 2; k++) {
- // just pick the first with the right gender
- for ( i = 0; i < MAX_VOICEFILES; i++ ) {
- if (strlen(voiceChatLists[i].name)) {
- if (voiceChatLists[i].gender == gender) {
- // store this head model with voice chat for future reference
- for ( j = 0; j < MAX_HEADMODELS; j++ ) {
- if (!strlen(headModelVoiceChat[j].headmodel)) {
- Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[j].voiceChatNum = i;
- break;
- }
- }
- return &voiceChatLists[i];
- }
- }
- }
- // fall back to male gender because we don't have neuter in the mission pack
- if (gender == GENDER_MALE)
- break;
- gender = GENDER_MALE;
- }
- // store this head model with voice chat for future reference
- for ( j = 0; j < MAX_HEADMODELS; j++ ) {
- if (!strlen(headModelVoiceChat[j].headmodel)) {
- Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
- "%s", headModelName);
- headModelVoiceChat[j].voiceChatNum = 0;
- break;
- }
- }
- // just return the first voice chat list
- return &voiceChatLists[0];
-}
-
-#define MAX_VOICECHATBUFFER 32
-
-typedef struct bufferedVoiceChat_s
-{
- int clientNum;
- sfxHandle_t snd;
- int voiceOnly;
- char cmd[MAX_SAY_TEXT];
- char message[MAX_SAY_TEXT];
-} bufferedVoiceChat_t;
-
-bufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER];
-
-/*
-=================
-CG_PlayVoiceChat
-=================
-*/
-void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) {
-#ifdef MISSIONPACK
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- if ( !cg_noVoiceChats.integer ) {
- trap_S_StartLocalSound( vchat->snd, CHAN_VOICE);
- if (vchat->clientNum != cg.snap->ps.clientNum) {
- int orderTask = CG_ValidOrder(vchat->cmd);
- if (orderTask > 0) {
- cgs.acceptOrderTime = cg.time + 5000;
- Q_strncpyz(cgs.acceptVoice, vchat->cmd, sizeof(cgs.acceptVoice));
- cgs.acceptTask = orderTask;
- cgs.acceptLeader = vchat->clientNum;
- }
- // see if this was an order
- CG_ShowResponseHead();
- }
- }
- if (!vchat->voiceOnly && !cg_noVoiceText.integer) {
- CG_AddToTeamChat( vchat->message );
- CG_Printf( "%s\n", vchat->message );
- }
- voiceChatBuffer[cg.voiceChatBufferOut].snd = 0;
-#endif
-}
-
-/*
-=====================
-CG_PlayBufferedVoieChats
-=====================
-*/
-void CG_PlayBufferedVoiceChats( void ) {
-#ifdef MISSIONPACK
- if ( cg.voiceChatTime < cg.time ) {
- if (cg.voiceChatBufferOut != cg.voiceChatBufferIn && voiceChatBuffer[cg.voiceChatBufferOut].snd) {
- //
- CG_PlayVoiceChat(&voiceChatBuffer[cg.voiceChatBufferOut]);
- //
- cg.voiceChatBufferOut = (cg.voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER;
- cg.voiceChatTime = cg.time + 1000;
- }
- }
-#endif
-}
-
-/*
-=====================
-CG_AddBufferedVoiceChat
-=====================
-*/
-void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) {
-#ifdef MISSIONPACK
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- memcpy(&voiceChatBuffer[cg.voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t));
- cg.voiceChatBufferIn = (cg.voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER;
- if (cg.voiceChatBufferIn == cg.voiceChatBufferOut) {
- CG_PlayVoiceChat( &voiceChatBuffer[cg.voiceChatBufferOut] );
- cg.voiceChatBufferOut++;
- }
-#endif
-}
-
-/*
-=================
-CG_VoiceChatLocal
-=================
-*/
-void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) {
-#ifdef MISSIONPACK
- char *chat;
- voiceChatList_t *voiceChatList;
- clientInfo_t *ci;
- sfxHandle_t snd;
- bufferedVoiceChat_t vchat;
-
- // if we are going into the intermission, don't start any voices
- if ( cg.intermissionStarted ) {
- return;
- }
-
- if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
- clientNum = 0;
- }
- ci = &cgs.clientinfo[ clientNum ];
-
- cgs.currentVoiceClient = clientNum;
-
- voiceChatList = CG_VoiceChatListForClient( clientNum );
-
- if ( CG_GetVoiceChat( voiceChatList, cmd, &snd, &chat ) ) {
- //
- if ( mode == SAY_TEAM || !cg_teamChatsOnly.integer ) {
- vchat.clientNum = clientNum;
- vchat.snd = snd;
- vchat.voiceOnly = voiceOnly;
- Q_strncpyz(vchat.cmd, cmd, sizeof(vchat.cmd));
- if ( mode == SAY_TELL ) {
- Com_sprintf(vchat.message, sizeof(vchat.message), "[%s]: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- else if ( mode == SAY_TEAM ) {
- Com_sprintf(vchat.message, sizeof(vchat.message), "(%s): %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- else {
- Com_sprintf(vchat.message, sizeof(vchat.message), "%s: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
- }
- CG_AddBufferedVoiceChat(&vchat);
- }
- }
-#endif
-}
-
-/*
-=================
-CG_VoiceChat
-=================
-*/
-void CG_VoiceChat( int mode ) {
-#ifdef MISSIONPACK
- const char *cmd;
- int clientNum, color;
- qboolean voiceOnly;
-
- voiceOnly = atoi(CG_Argv(1));
- clientNum = atoi(CG_Argv(2));
- color = atoi(CG_Argv(3));
- cmd = CG_Argv(4);
-
- if (cg_noTaunt.integer != 0) {
- if (!strcmp(cmd, VOICECHAT_KILLINSULT) || !strcmp(cmd, VOICECHAT_TAUNT) || \
- !strcmp(cmd, VOICECHAT_DEATHINSULT) || !strcmp(cmd, VOICECHAT_KILLGAUNTLET) || \
- !strcmp(cmd, VOICECHAT_PRAISE)) {
- return;
- }
- }
-
- CG_VoiceChatLocal( mode, voiceOnly, clientNum, color, cmd );
-#endif
-}
-
-/*
-=================
-CG_RemoveChatEscapeChar
-=================
-*/
-static void CG_RemoveChatEscapeChar( char *text ) {
- int i, l;
-
- l = 0;
- for ( i = 0; text[i]; i++ ) {
- if (text[i] == '\x19')
- continue;
- text[l++] = text[i];
- }
- text[l] = '\0';
-}
-
-/*
-=================
-CG_ServerCommand
-
-The string has been tokenized and can be retrieved with
-Cmd_Argc() / Cmd_Argv()
-=================
-*/
-static void CG_ServerCommand( void ) {
- const char *cmd;
- char text[MAX_SAY_TEXT];
-
- cmd = CG_Argv(0);
-
- if ( !cmd[0] ) {
- // server claimed the command
- return;
- }
-
- if ( !strcmp( cmd, "cp" ) ) {
- CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- return;
- }
-
- if ( !strcmp( cmd, "cs" ) ) {
- CG_ConfigStringModified();
- return;
- }
-
- if ( !strcmp( cmd, "print" ) ) {
- CG_Printf( "%s", CG_Argv(1) );
-#ifdef MISSIONPACK
- cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about
- // votes passing or failing
- if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) {
- trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER );
- } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) {
- trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER );
- }
-#endif
- return;
- }
-
- if ( !strcmp( cmd, "chat" ) ) {
- if ( !cg_teamChatsOnly.integer ) {
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
- CG_RemoveChatEscapeChar( text );
- CG_Printf( "%s\n", text );
- }
- return;
- }
-
- if ( !strcmp( cmd, "tchat" ) ) {
- trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
- Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
- CG_RemoveChatEscapeChar( text );
- CG_AddToTeamChat( text );
- CG_Printf( "%s\n", text );
- return;
- }
- if ( !strcmp( cmd, "vchat" ) ) {
- CG_VoiceChat( SAY_ALL );
- return;
- }
-
- if ( !strcmp( cmd, "vtchat" ) ) {
- CG_VoiceChat( SAY_TEAM );
- return;
- }
-
- if ( !strcmp( cmd, "vtell" ) ) {
- CG_VoiceChat( SAY_TELL );
- return;
- }
-
- if ( !strcmp( cmd, "scores" ) ) {
- CG_ParseScores();
- return;
- }
-
- if ( !strcmp( cmd, "tinfo" ) ) {
- CG_ParseTeamInfo();
- return;
- }
-
- if ( !strcmp( cmd, "map_restart" ) ) {
- CG_MapRestart();
- return;
- }
-
- if ( Q_stricmp (cmd, "remapShader") == 0 ) {
- if (trap_Argc() == 4) {
- trap_R_RemapShader(CG_Argv(1), CG_Argv(2), CG_Argv(3));
- }
- }
-
- // loaddeferred can be both a servercmd and a consolecmd
- if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo
- CG_LoadDeferredPlayers();
- return;
- }
-
- // clientLevelShot is sent before taking a special screenshot for
- // the menu system during development
- if ( !strcmp( cmd, "clientLevelShot" ) ) {
- cg.levelShot = qtrue;
- return;
- }
-
- CG_Printf( "Unknown client game command: %s\n", cmd );
-}
-
-
-/*
-====================
-CG_ExecuteNewServerCommands
-
-Execute all of the server commands that were received along
-with this this snapshot.
-====================
-*/
-void CG_ExecuteNewServerCommands( int latestSequence ) {
- while ( cgs.serverCommandSequence < latestSequence ) {
- if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
- CG_ServerCommand();
- }
- }
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_servercmds.c -- reliably sequenced text commands sent by the server
+// these are processed at snapshot transition time, so there will definately
+// be a valid snapshot this frame
+
+#include "cg_local.h"
+#include "../../ui/menudef.h" // bk001205 - for Q3_ui as well
+
+typedef struct {
+ const char *order;
+ int taskNum;
+} orderTask_t;
+
+static const orderTask_t validOrders[] = {
+ { VOICECHAT_GETFLAG, TEAMTASK_OFFENSE },
+ { VOICECHAT_OFFENSE, TEAMTASK_OFFENSE },
+ { VOICECHAT_DEFEND, TEAMTASK_DEFENSE },
+ { VOICECHAT_DEFENDFLAG, TEAMTASK_DEFENSE },
+ { VOICECHAT_PATROL, TEAMTASK_PATROL },
+ { VOICECHAT_CAMP, TEAMTASK_CAMP },
+ { VOICECHAT_FOLLOWME, TEAMTASK_FOLLOW },
+ { VOICECHAT_RETURNFLAG, TEAMTASK_RETRIEVE },
+ { VOICECHAT_FOLLOWFLAGCARRIER, TEAMTASK_ESCORT }
+};
+
+static const int numValidOrders = sizeof(validOrders) / sizeof(orderTask_t);
+
+#ifdef MISSIONPACK // bk001204
+static int CG_ValidOrder(const char *p) {
+ int i;
+ for (i = 0; i < numValidOrders; i++) {
+ if (Q_stricmp(p, validOrders[i].order) == 0) {
+ return validOrders[i].taskNum;
+ }
+ }
+ return -1;
+}
+#endif
+
+/*
+=================
+CG_ParseScores
+
+=================
+*/
+static void CG_ParseScores( void ) {
+ int i, powerups;
+
+ cg.numScores = atoi( CG_Argv( 1 ) );
+ if ( cg.numScores > MAX_CLIENTS ) {
+ cg.numScores = MAX_CLIENTS;
+ }
+
+ cg.teamScores[0] = atoi( CG_Argv( 2 ) );
+ cg.teamScores[1] = atoi( CG_Argv( 3 ) );
+
+ memset( cg.scores, 0, sizeof( cg.scores ) );
+ for ( i = 0 ; i < cg.numScores ; i++ ) {
+ //
+ cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) );
+ cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) );
+ cg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) );
+ cg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) );
+ cg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) );
+ powerups = atoi( CG_Argv( i * 14 + 9 ) );
+ cg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10));
+ cg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11));
+ cg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12));
+ cg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13));
+ cg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14));
+ cg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15));
+ cg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16));
+ cg.scores[i].captures = atoi(CG_Argv(i * 14 + 17));
+
+ if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
+ cg.scores[i].client = 0;
+ }
+ cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
+ cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
+
+ cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;
+ }
+#ifdef MISSIONPACK
+ CG_SetScoreSelection(NULL);
+#endif
+
+}
+
+/*
+=================
+CG_ParseTeamInfo
+
+=================
+*/
+static void CG_ParseTeamInfo( void ) {
+ int i;
+ int client;
+
+ numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
+
+ for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
+ client = atoi( CG_Argv( i * 6 + 2 ) );
+
+ sortedTeamPlayers[i] = client;
+
+ cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
+ cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
+ cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
+ cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
+ cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
+ }
+}
+
+
+/*
+================
+CG_ParseServerinfo
+
+This is called explicitly when the gamestate is first received,
+and whenever the server updates any serverinfo flagged cvars
+================
+*/
+void CG_ParseServerinfo( void ) {
+ const char *info;
+ char *mapname;
+
+ info = CG_ConfigString( CS_SERVERINFO );
+ cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
+ trap_Cvar_Set("g_gametype", va("%i", cgs.gametype));
+ cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
+ cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
+ cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
+ cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
+ cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
+ cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+ mapname = Info_ValueForKey( info, "mapname" );
+ Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
+ Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) );
+ trap_Cvar_Set("g_redTeam", cgs.redTeam);
+ Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) );
+ trap_Cvar_Set("g_blueTeam", cgs.blueTeam);
+}
+
+/*
+==================
+CG_ParseWarmup
+==================
+*/
+static void CG_ParseWarmup( void ) {
+ const char *info;
+ int warmup;
+
+ info = CG_ConfigString( CS_WARMUP );
+
+ warmup = atoi( info );
+ cg.warmupCount = -1;
+
+ if ( warmup == 0 && cg.warmup ) {
+
+ } else if ( warmup > 0 && cg.warmup <= 0 ) {
+#ifdef MISSIONPACK
+ if (cgs.gametype >= GT_CTF && cgs.gametype <= GT_HARVESTER) {
+ trap_S_StartLocalSound( cgs.media.countPrepareTeamSound, CHAN_ANNOUNCER );
+ } else
+#endif
+ {
+ trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
+ }
+ }
+
+ cg.warmup = warmup;
+}
+
+/*
+================
+CG_SetConfigValues
+
+Called on load to set the initial values from configure strings
+================
+*/
+void CG_SetConfigValues( void ) {
+ const char *s;
+
+ cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
+ cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
+ cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
+ if( cgs.gametype == GT_CTF ) {
+ s = CG_ConfigString( CS_FLAGSTATUS );
+ cgs.redflag = s[0] - '0';
+ cgs.blueflag = s[1] - '0';
+ }
+#ifdef MISSIONPACK
+ else if( cgs.gametype == GT_1FCTF ) {
+ s = CG_ConfigString( CS_FLAGSTATUS );
+ cgs.flagStatus = s[0] - '0';
+ }
+#endif
+ cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
+}
+
+/*
+=====================
+CG_ShaderStateChanged
+=====================
+*/
+void CG_ShaderStateChanged(void) {
+ char originalShader[MAX_QPATH];
+ char newShader[MAX_QPATH];
+ char timeOffset[16];
+ const char *o;
+ char *n,*t;
+
+ o = CG_ConfigString( CS_SHADERSTATE );
+ while (o && *o) {
+ n = strstr(o, "=");
+ if (n && *n) {
+ strncpy(originalShader, o, n-o);
+ originalShader[n-o] = 0;
+ n++;
+ t = strstr(n, ":");
+ if (t && *t) {
+ strncpy(newShader, n, t-n);
+ newShader[t-n] = 0;
+ } else {
+ break;
+ }
+ t++;
+ o = strstr(t, "@");
+ if (o) {
+ strncpy(timeOffset, t, o-t);
+ timeOffset[o-t] = 0;
+ o++;
+ trap_R_RemapShader( originalShader, newShader, timeOffset );
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+/*
+================
+CG_ConfigStringModified
+
+================
+*/
+static void CG_ConfigStringModified( void ) {
+ const char *str;
+ int num;
+
+ num = atoi( CG_Argv( 1 ) );
+
+ // get the gamestate from the client system, which will have the
+ // new configstring already integrated
+ trap_GetGameState( &cgs.gameState );
+
+ // look up the individual string that was modified
+ str = CG_ConfigString( num );
+
+ // do something with it if necessary
+ if ( num == CS_MUSIC ) {
+ CG_StartMusic();
+ } else if ( num == CS_SERVERINFO ) {
+ CG_ParseServerinfo();
+ } else if ( num == CS_WARMUP ) {
+ CG_ParseWarmup();
+ } else if ( num == CS_SCORES1 ) {
+ cgs.scores1 = atoi( str );
+ } else if ( num == CS_SCORES2 ) {
+ cgs.scores2 = atoi( str );
+ } else if ( num == CS_LEVEL_START_TIME ) {
+ cgs.levelStartTime = atoi( str );
+ } else if ( num == CS_VOTE_TIME ) {
+ cgs.voteTime = atoi( str );
+ cgs.voteModified = qtrue;
+ } else if ( num == CS_VOTE_YES ) {
+ cgs.voteYes = atoi( str );
+ cgs.voteModified = qtrue;
+ } else if ( num == CS_VOTE_NO ) {
+ cgs.voteNo = atoi( str );
+ cgs.voteModified = qtrue;
+ } else if ( num == CS_VOTE_STRING ) {
+ Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
+#ifdef MISSIONPACK
+ trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
+#endif //MISSIONPACK
+ } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {
+ cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );
+ cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;
+ } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {
+ cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );
+ cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;
+ } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {
+ cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );
+ cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;
+ } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {
+ Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );
+#ifdef MISSIONPACK
+ trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER );
+#endif
+ } else if ( num == CS_INTERMISSION ) {
+ cg.intermissionStarted = atoi( str );
+ } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
+ cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
+ } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_MODELS ) {
+ if ( str[0] != '*' ) { // player specific sounds don't register here
+ cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse );
+ }
+ } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
+ CG_NewClientInfo( num - CS_PLAYERS );
+ CG_BuildSpectatorString();
+ } else if ( num == CS_FLAGSTATUS ) {
+ if( cgs.gametype == GT_CTF ) {
+ // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
+ cgs.redflag = str[0] - '0';
+ cgs.blueflag = str[1] - '0';
+ }
+#ifdef MISSIONPACK
+ else if( cgs.gametype == GT_1FCTF ) {
+ cgs.flagStatus = str[0] - '0';
+ }
+#endif
+ }
+ else if ( num == CS_SHADERSTATE ) {
+ CG_ShaderStateChanged();
+ }
+
+}
+
+
+/*
+=======================
+CG_AddToTeamChat
+
+=======================
+*/
+static void CG_AddToTeamChat( const char *str ) {
+ int len;
+ char *p, *ls;
+ int lastcolor;
+ int chatHeight;
+
+ if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
+ chatHeight = cg_teamChatHeight.integer;
+ } else {
+ chatHeight = TEAMCHAT_HEIGHT;
+ }
+
+ if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
+ // team chat disabled, dump into normal chat
+ cgs.teamChatPos = cgs.teamLastChatPos = 0;
+ return;
+ }
+
+ len = 0;
+
+ p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
+ *p = 0;
+
+ lastcolor = '7';
+
+ ls = NULL;
+ while (*str) {
+ if (len > TEAMCHAT_WIDTH - 1) {
+ if (ls) {
+ str -= (p - ls);
+ str++;
+ p -= (p - ls);
+ }
+ *p = 0;
+
+ cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
+
+ cgs.teamChatPos++;
+ p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
+ *p = 0;
+ *p++ = Q_COLOR_ESCAPE;
+ *p++ = lastcolor;
+ len = 0;
+ ls = NULL;
+ }
+
+ if ( Q_IsColorString( str ) ) {
+ *p++ = *str++;
+ lastcolor = *str;
+ *p++ = *str++;
+ continue;
+ }
+ if (*str == ' ') {
+ ls = p;
+ }
+ *p++ = *str++;
+ len++;
+ }
+ *p = 0;
+
+ cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
+ cgs.teamChatPos++;
+
+ if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
+ cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
+}
+
+/*
+===============
+CG_MapRestart
+
+The server has issued a map_restart, so the next snapshot
+is completely new and should not be interpolated to.
+
+A tournement restart will clear everything, but doesn't
+require a reload of all the media
+===============
+*/
+static void CG_MapRestart( void ) {
+ if ( cg_showmiss.integer ) {
+ CG_Printf( "CG_MapRestart\n" );
+ }
+
+ CG_InitLocalEntities();
+ CG_InitMarkPolys();
+ CG_ClearParticles ();
+
+ // make sure the "3 frags left" warnings play again
+ cg.fraglimitWarnings = 0;
+
+ cg.timelimitWarnings = 0;
+
+ cg.intermissionStarted = qfalse;
+
+ cgs.voteTime = 0;
+
+ cg.mapRestart = qtrue;
+
+ CG_StartMusic();
+
+ trap_S_ClearLoopingSounds(qtrue);
+
+ // we really should clear more parts of cg here and stop sounds
+
+ // play the "fight" sound if this is a restart without warmup
+ if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
+ trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
+ CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
+ }
+#ifdef MISSIONPACK
+ if (cg_singlePlayerActive.integer) {
+ trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time));
+ if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) {
+ trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string));
+ }
+ }
+#endif
+ trap_Cvar_Set("cg_thirdPerson", "0");
+}
+
+#define MAX_VOICEFILESIZE 16384
+#define MAX_VOICEFILES 8
+#define MAX_VOICECHATS 64
+#define MAX_VOICESOUNDS 64
+#define MAX_CHATSIZE 64
+#define MAX_HEADMODELS 64
+
+typedef struct voiceChat_s
+{
+ char id[64];
+ int numSounds;
+ sfxHandle_t sounds[MAX_VOICESOUNDS];
+ char chats[MAX_VOICESOUNDS][MAX_CHATSIZE];
+} voiceChat_t;
+
+typedef struct voiceChatList_s
+{
+ char name[64];
+ int gender;
+ int numVoiceChats;
+ voiceChat_t voiceChats[MAX_VOICECHATS];
+} voiceChatList_t;
+
+typedef struct headModelVoiceChat_s
+{
+ char headmodel[64];
+ int voiceChatNum;
+} headModelVoiceChat_t;
+
+voiceChatList_t voiceChatLists[MAX_VOICEFILES];
+headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS];
+
+/*
+=================
+CG_ParseVoiceChats
+=================
+*/
+int CG_ParseVoiceChats( const char *filename, voiceChatList_t *voiceChatList, int maxVoiceChats ) {
+ int len, i;
+ fileHandle_t f;
+ char buf[MAX_VOICEFILESIZE];
+ char **p, *ptr;
+ char *token;
+ voiceChat_t *voiceChats;
+ qboolean compress;
+ sfxHandle_t sound;
+
+ compress = qtrue;
+ if (cg_buildScript.integer) {
+ compress = qfalse;
+ }
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ trap_Print( va( S_COLOR_RED "voice chat file not found: %s\n", filename ) );
+ return qfalse;
+ }
+ if ( len >= MAX_VOICEFILESIZE ) {
+ trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
+ trap_FS_FCloseFile( f );
+ return qfalse;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ptr = buf;
+ p = &ptr;
+
+ Com_sprintf(voiceChatList->name, sizeof(voiceChatList->name), "%s", filename);
+ voiceChats = voiceChatList->voiceChats;
+ for ( i = 0; i < maxVoiceChats; i++ ) {
+ voiceChats[i].id[0] = 0;
+ }
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ if (!Q_stricmp(token, "female")) {
+ voiceChatList->gender = GENDER_FEMALE;
+ }
+ else if (!Q_stricmp(token, "male")) {
+ voiceChatList->gender = GENDER_MALE;
+ }
+ else if (!Q_stricmp(token, "neuter")) {
+ voiceChatList->gender = GENDER_NEUTER;
+ }
+ else {
+ trap_Print( va( S_COLOR_RED "expected gender not found in voice chat file: %s\n", filename ) );
+ return qfalse;
+ }
+
+ voiceChatList->numVoiceChats = 0;
+ while ( 1 ) {
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id, sizeof( voiceChats[voiceChatList->numVoiceChats].id ), "%s", token);
+ token = COM_ParseExt(p, qtrue);
+ if (Q_stricmp(token, "{")) {
+ trap_Print( va( S_COLOR_RED "expected { found %s in voice chat file: %s\n", token, filename ) );
+ return qfalse;
+ }
+ voiceChats[voiceChatList->numVoiceChats].numSounds = 0;
+ while(1) {
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ if (!Q_stricmp(token, "}"))
+ break;
+ sound = trap_S_RegisterSound( token, compress );
+ voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = sound;
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return qtrue;
+ }
+ Com_sprintf(voiceChats[voiceChatList->numVoiceChats].chats[
+ voiceChats[voiceChatList->numVoiceChats].numSounds], MAX_CHATSIZE, "%s", token);
+ if (sound)
+ voiceChats[voiceChatList->numVoiceChats].numSounds++;
+ if (voiceChats[voiceChatList->numVoiceChats].numSounds >= MAX_VOICESOUNDS)
+ break;
+ }
+ voiceChatList->numVoiceChats++;
+ if (voiceChatList->numVoiceChats >= maxVoiceChats)
+ return qtrue;
+ }
+ return qtrue;
+}
+
+/*
+=================
+CG_LoadVoiceChats
+=================
+*/
+void CG_LoadVoiceChats( void ) {
+ int size;
+
+ size = trap_MemoryRemaining();
+ CG_ParseVoiceChats( "scripts/female1.voice", &voiceChatLists[0], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/female2.voice", &voiceChatLists[1], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/female3.voice", &voiceChatLists[2], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male1.voice", &voiceChatLists[3], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male2.voice", &voiceChatLists[4], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male3.voice", &voiceChatLists[5], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male4.voice", &voiceChatLists[6], MAX_VOICECHATS );
+ CG_ParseVoiceChats( "scripts/male5.voice", &voiceChatLists[7], MAX_VOICECHATS );
+ CG_Printf("voice chat memory size = %d\n", size - trap_MemoryRemaining());
+}
+
+/*
+=================
+CG_HeadModelVoiceChats
+=================
+*/
+int CG_HeadModelVoiceChats( char *filename ) {
+ int len, i;
+ fileHandle_t f;
+ char buf[MAX_VOICEFILESIZE];
+ char **p, *ptr;
+ char *token;
+
+ len = trap_FS_FOpenFile( filename, &f, FS_READ );
+ if ( !f ) {
+ //trap_Print( va( "voice chat file not found: %s\n", filename ) );
+ return -1;
+ }
+ if ( len >= MAX_VOICEFILESIZE ) {
+ trap_Print( va( S_COLOR_RED "voice chat file too large: %s is %i, max allowed is %i", filename, len, MAX_VOICEFILESIZE ) );
+ trap_FS_FCloseFile( f );
+ return -1;
+ }
+
+ trap_FS_Read( buf, len, f );
+ buf[len] = 0;
+ trap_FS_FCloseFile( f );
+
+ ptr = buf;
+ p = &ptr;
+
+ token = COM_ParseExt(p, qtrue);
+ if (!token || token[0] == 0) {
+ return -1;
+ }
+
+ for ( i = 0; i < MAX_VOICEFILES; i++ ) {
+ if ( !Q_stricmp(token, voiceChatLists[i].name) ) {
+ return i;
+ }
+ }
+
+ //FIXME: maybe try to load the .voice file which name is stored in token?
+
+ return -1;
+}
+
+
+/*
+=================
+CG_GetVoiceChat
+=================
+*/
+int CG_GetVoiceChat( voiceChatList_t *voiceChatList, const char *id, sfxHandle_t *snd, char **chat) {
+ int i, rnd;
+
+ for ( i = 0; i < voiceChatList->numVoiceChats; i++ ) {
+ if ( !Q_stricmp( id, voiceChatList->voiceChats[i].id ) ) {
+ rnd = random() * voiceChatList->voiceChats[i].numSounds;
+ *snd = voiceChatList->voiceChats[i].sounds[rnd];
+ *chat = voiceChatList->voiceChats[i].chats[rnd];
+ return qtrue;
+ }
+ }
+ return qfalse;
+}
+
+/*
+=================
+CG_VoiceChatListForClient
+=================
+*/
+voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) {
+ clientInfo_t *ci;
+ int voiceChatNum, i, j, k, gender;
+ char filename[MAX_QPATH], headModelName[MAX_QPATH];
+
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ for ( k = 0; k < 2; k++ ) {
+ if ( k == 0 ) {
+ if (ci->headModelName[0] == '*') {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName+1, ci->headSkinName );
+ }
+ else {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s/%s", ci->headModelName, ci->headSkinName );
+ }
+ }
+ else {
+ if (ci->headModelName[0] == '*') {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName+1 );
+ }
+ else {
+ Com_sprintf( headModelName, sizeof(headModelName), "%s", ci->headModelName );
+ }
+ }
+ // find the voice file for the head model the client uses
+ for ( i = 0; i < MAX_HEADMODELS; i++ ) {
+ if (!Q_stricmp(headModelVoiceChat[i].headmodel, headModelName)) {
+ break;
+ }
+ }
+ if (i < MAX_HEADMODELS) {
+ return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
+ }
+ // find a <headmodelname>.vc file
+ for ( i = 0; i < MAX_HEADMODELS; i++ ) {
+ if (!strlen(headModelVoiceChat[i].headmodel)) {
+ Com_sprintf(filename, sizeof(filename), "scripts/%s.vc", headModelName);
+ voiceChatNum = CG_HeadModelVoiceChats(filename);
+ if (voiceChatNum == -1)
+ break;
+ Com_sprintf(headModelVoiceChat[i].headmodel, sizeof ( headModelVoiceChat[i].headmodel ),
+ "%s", headModelName);
+ headModelVoiceChat[i].voiceChatNum = voiceChatNum;
+ return &voiceChatLists[headModelVoiceChat[i].voiceChatNum];
+ }
+ }
+ }
+ gender = ci->gender;
+ for (k = 0; k < 2; k++) {
+ // just pick the first with the right gender
+ for ( i = 0; i < MAX_VOICEFILES; i++ ) {
+ if (strlen(voiceChatLists[i].name)) {
+ if (voiceChatLists[i].gender == gender) {
+ // store this head model with voice chat for future reference
+ for ( j = 0; j < MAX_HEADMODELS; j++ ) {
+ if (!strlen(headModelVoiceChat[j].headmodel)) {
+ Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
+ "%s", headModelName);
+ headModelVoiceChat[j].voiceChatNum = i;
+ break;
+ }
+ }
+ return &voiceChatLists[i];
+ }
+ }
+ }
+ // fall back to male gender because we don't have neuter in the mission pack
+ if (gender == GENDER_MALE)
+ break;
+ gender = GENDER_MALE;
+ }
+ // store this head model with voice chat for future reference
+ for ( j = 0; j < MAX_HEADMODELS; j++ ) {
+ if (!strlen(headModelVoiceChat[j].headmodel)) {
+ Com_sprintf(headModelVoiceChat[j].headmodel, sizeof ( headModelVoiceChat[j].headmodel ),
+ "%s", headModelName);
+ headModelVoiceChat[j].voiceChatNum = 0;
+ break;
+ }
+ }
+ // just return the first voice chat list
+ return &voiceChatLists[0];
+}
+
+#define MAX_VOICECHATBUFFER 32
+
+typedef struct bufferedVoiceChat_s
+{
+ int clientNum;
+ sfxHandle_t snd;
+ int voiceOnly;
+ char cmd[MAX_SAY_TEXT];
+ char message[MAX_SAY_TEXT];
+} bufferedVoiceChat_t;
+
+bufferedVoiceChat_t voiceChatBuffer[MAX_VOICECHATBUFFER];
+
+/*
+=================
+CG_PlayVoiceChat
+=================
+*/
+void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) {
+#ifdef MISSIONPACK
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ if ( !cg_noVoiceChats.integer ) {
+ trap_S_StartLocalSound( vchat->snd, CHAN_VOICE);
+ if (vchat->clientNum != cg.snap->ps.clientNum) {
+ int orderTask = CG_ValidOrder(vchat->cmd);
+ if (orderTask > 0) {
+ cgs.acceptOrderTime = cg.time + 5000;
+ Q_strncpyz(cgs.acceptVoice, vchat->cmd, sizeof(cgs.acceptVoice));
+ cgs.acceptTask = orderTask;
+ cgs.acceptLeader = vchat->clientNum;
+ }
+ // see if this was an order
+ CG_ShowResponseHead();
+ }
+ }
+ if (!vchat->voiceOnly && !cg_noVoiceText.integer) {
+ CG_AddToTeamChat( vchat->message );
+ CG_Printf( "%s\n", vchat->message );
+ }
+ voiceChatBuffer[cg.voiceChatBufferOut].snd = 0;
+#endif
+}
+
+/*
+=====================
+CG_PlayBufferedVoieChats
+=====================
+*/
+void CG_PlayBufferedVoiceChats( void ) {
+#ifdef MISSIONPACK
+ if ( cg.voiceChatTime < cg.time ) {
+ if (cg.voiceChatBufferOut != cg.voiceChatBufferIn && voiceChatBuffer[cg.voiceChatBufferOut].snd) {
+ //
+ CG_PlayVoiceChat(&voiceChatBuffer[cg.voiceChatBufferOut]);
+ //
+ cg.voiceChatBufferOut = (cg.voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER;
+ cg.voiceChatTime = cg.time + 1000;
+ }
+ }
+#endif
+}
+
+/*
+=====================
+CG_AddBufferedVoiceChat
+=====================
+*/
+void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) {
+#ifdef MISSIONPACK
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ memcpy(&voiceChatBuffer[cg.voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t));
+ cg.voiceChatBufferIn = (cg.voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER;
+ if (cg.voiceChatBufferIn == cg.voiceChatBufferOut) {
+ CG_PlayVoiceChat( &voiceChatBuffer[cg.voiceChatBufferOut] );
+ cg.voiceChatBufferOut++;
+ }
+#endif
+}
+
+/*
+=================
+CG_VoiceChatLocal
+=================
+*/
+void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) {
+#ifdef MISSIONPACK
+ char *chat;
+ voiceChatList_t *voiceChatList;
+ clientInfo_t *ci;
+ sfxHandle_t snd;
+ bufferedVoiceChat_t vchat;
+
+ // if we are going into the intermission, don't start any voices
+ if ( cg.intermissionStarted ) {
+ return;
+ }
+
+ if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
+ clientNum = 0;
+ }
+ ci = &cgs.clientinfo[ clientNum ];
+
+ cgs.currentVoiceClient = clientNum;
+
+ voiceChatList = CG_VoiceChatListForClient( clientNum );
+
+ if ( CG_GetVoiceChat( voiceChatList, cmd, &snd, &chat ) ) {
+ //
+ if ( mode == SAY_TEAM || !cg_teamChatsOnly.integer ) {
+ vchat.clientNum = clientNum;
+ vchat.snd = snd;
+ vchat.voiceOnly = voiceOnly;
+ Q_strncpyz(vchat.cmd, cmd, sizeof(vchat.cmd));
+ if ( mode == SAY_TELL ) {
+ Com_sprintf(vchat.message, sizeof(vchat.message), "[%s]: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
+ }
+ else if ( mode == SAY_TEAM ) {
+ Com_sprintf(vchat.message, sizeof(vchat.message), "(%s): %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
+ }
+ else {
+ Com_sprintf(vchat.message, sizeof(vchat.message), "%s: %c%c%s", ci->name, Q_COLOR_ESCAPE, color, chat);
+ }
+ CG_AddBufferedVoiceChat(&vchat);
+ }
+ }
+#endif
+}
+
+/*
+=================
+CG_VoiceChat
+=================
+*/
+void CG_VoiceChat( int mode ) {
+#ifdef MISSIONPACK
+ const char *cmd;
+ int clientNum, color;
+ qboolean voiceOnly;
+
+ voiceOnly = atoi(CG_Argv(1));
+ clientNum = atoi(CG_Argv(2));
+ color = atoi(CG_Argv(3));
+ cmd = CG_Argv(4);
+
+ if (cg_noTaunt.integer != 0) {
+ if (!strcmp(cmd, VOICECHAT_KILLINSULT) || !strcmp(cmd, VOICECHAT_TAUNT) || \
+ !strcmp(cmd, VOICECHAT_DEATHINSULT) || !strcmp(cmd, VOICECHAT_KILLGAUNTLET) || \
+ !strcmp(cmd, VOICECHAT_PRAISE)) {
+ return;
+ }
+ }
+
+ CG_VoiceChatLocal( mode, voiceOnly, clientNum, color, cmd );
+#endif
+}
+
+/*
+=================
+CG_RemoveChatEscapeChar
+=================
+*/
+static void CG_RemoveChatEscapeChar( char *text ) {
+ int i, l;
+
+ l = 0;
+ for ( i = 0; text[i]; i++ ) {
+ if (text[i] == '\x19')
+ continue;
+ text[l++] = text[i];
+ }
+ text[l] = '\0';
+}
+
+/*
+=================
+CG_ServerCommand
+
+The string has been tokenized and can be retrieved with
+Cmd_Argc() / Cmd_Argv()
+=================
+*/
+static void CG_ServerCommand( void ) {
+ const char *cmd;
+ char text[MAX_SAY_TEXT];
+
+ cmd = CG_Argv(0);
+
+ if ( !cmd[0] ) {
+ // server claimed the command
+ return;
+ }
+
+ if ( !strcmp( cmd, "cp" ) ) {
+ CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
+ return;
+ }
+
+ if ( !strcmp( cmd, "cs" ) ) {
+ CG_ConfigStringModified();
+ return;
+ }
+
+ if ( !strcmp( cmd, "print" ) ) {
+ CG_Printf( "%s", CG_Argv(1) );
+#ifdef MISSIONPACK
+ cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about
+ // votes passing or failing
+ if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) {
+ trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER );
+ } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) {
+ trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER );
+ }
+#endif
+ return;
+ }
+
+ if ( !strcmp( cmd, "chat" ) ) {
+ if ( !cg_teamChatsOnly.integer ) {
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
+ CG_RemoveChatEscapeChar( text );
+ CG_Printf( "%s\n", text );
+ }
+ return;
+ }
+
+ if ( !strcmp( cmd, "tchat" ) ) {
+ trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
+ Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
+ CG_RemoveChatEscapeChar( text );
+ CG_AddToTeamChat( text );
+ CG_Printf( "%s\n", text );
+ return;
+ }
+ if ( !strcmp( cmd, "vchat" ) ) {
+ CG_VoiceChat( SAY_ALL );
+ return;
+ }
+
+ if ( !strcmp( cmd, "vtchat" ) ) {
+ CG_VoiceChat( SAY_TEAM );
+ return;
+ }
+
+ if ( !strcmp( cmd, "vtell" ) ) {
+ CG_VoiceChat( SAY_TELL );
+ return;
+ }
+
+ if ( !strcmp( cmd, "scores" ) ) {
+ CG_ParseScores();
+ return;
+ }
+
+ if ( !strcmp( cmd, "tinfo" ) ) {
+ CG_ParseTeamInfo();
+ return;
+ }
+
+ if ( !strcmp( cmd, "map_restart" ) ) {
+ CG_MapRestart();
+ return;
+ }
+
+ if ( Q_stricmp (cmd, "remapShader") == 0 ) {
+ if (trap_Argc() == 4) {
+ trap_R_RemapShader(CG_Argv(1), CG_Argv(2), CG_Argv(3));
+ }
+ }
+
+ // loaddeferred can be both a servercmd and a consolecmd
+ if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo
+ CG_LoadDeferredPlayers();
+ return;
+ }
+
+ // clientLevelShot is sent before taking a special screenshot for
+ // the menu system during development
+ if ( !strcmp( cmd, "clientLevelShot" ) ) {
+ cg.levelShot = qtrue;
+ return;
+ }
+
+ CG_Printf( "Unknown client game command: %s\n", cmd );
+}
+
+
+/*
+====================
+CG_ExecuteNewServerCommands
+
+Execute all of the server commands that were received along
+with this this snapshot.
+====================
+*/
+void CG_ExecuteNewServerCommands( int latestSequence ) {
+ while ( cgs.serverCommandSequence < latestSequence ) {
+ if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
+ CG_ServerCommand();
+ }
+ }
+}
diff --git a/code/cgame/cg_snapshot.c b/code/cgame/cg_snapshot.c
index add49f0..f337e08 100755
--- a/code/cgame/cg_snapshot.c
+++ b/code/cgame/cg_snapshot.c
@@ -1,403 +1,403 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_snapshot.c -- things that happen on snapshot transition,
-// not necessarily every single rendered frame
-
-#include "cg_local.h"
-
-
-
-/*
-==================
-CG_ResetEntity
-==================
-*/
-static void CG_ResetEntity( centity_t *cent ) {
- // if the previous snapshot this entity was updated in is at least
- // an event window back in time then we can reset the previous event
- if ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) {
- cent->previousEvent = 0;
- }
-
- cent->trailTime = cg.snap->serverTime;
-
- VectorCopy (cent->currentState.origin, cent->lerpOrigin);
- VectorCopy (cent->currentState.angles, cent->lerpAngles);
- if ( cent->currentState.eType == ET_PLAYER ) {
- CG_ResetPlayerEntity( cent );
- }
-}
-
-/*
-===============
-CG_TransitionEntity
-
-cent->nextState is moved to cent->currentState and events are fired
-===============
-*/
-static void CG_TransitionEntity( centity_t *cent ) {
- cent->currentState = cent->nextState;
- cent->currentValid = qtrue;
-
- // reset if the entity wasn't in the last frame or was teleported
- if ( !cent->interpolate ) {
- CG_ResetEntity( cent );
- }
-
- // clear the next state. if will be set by the next CG_SetNextSnap
- cent->interpolate = qfalse;
-
- // check for events
- CG_CheckEvents( cent );
-}
-
-
-/*
-==================
-CG_SetInitialSnapshot
-
-This will only happen on the very first snapshot, or
-on tourney restarts. All other times will use
-CG_TransitionSnapshot instead.
-
-FIXME: Also called by map_restart?
-==================
-*/
-void CG_SetInitialSnapshot( snapshot_t *snap ) {
- int i;
- centity_t *cent;
- entityState_t *state;
-
- cg.snap = snap;
-
- BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
-
- // sort out solid entities
- CG_BuildSolidList();
-
- CG_ExecuteNewServerCommands( snap->serverCommandSequence );
-
- // set our local weapon selection pointer to
- // what the server has indicated the current weapon is
- CG_Respawn();
-
- for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
- state = &cg.snap->entities[ i ];
- cent = &cg_entities[ state->number ];
-
- memcpy(&cent->currentState, state, sizeof(entityState_t));
- //cent->currentState = *state;
- cent->interpolate = qfalse;
- cent->currentValid = qtrue;
-
- CG_ResetEntity( cent );
-
- // check for events
- CG_CheckEvents( cent );
- }
-}
-
-
-/*
-===================
-CG_TransitionSnapshot
-
-The transition point from snap to nextSnap has passed
-===================
-*/
-static void CG_TransitionSnapshot( void ) {
- centity_t *cent;
- snapshot_t *oldFrame;
- int i;
-
- if ( !cg.snap ) {
- CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
- }
- if ( !cg.nextSnap ) {
- CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
- }
-
- // execute any server string commands before transitioning entities
- CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
-
- // if we had a map_restart, set everthing with initial
- if ( !cg.snap ) {
- }
-
- // clear the currentValid flag for all entities in the existing snapshot
- for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
- cent = &cg_entities[ cg.snap->entities[ i ].number ];
- cent->currentValid = qfalse;
- }
-
- // move nextSnap to snap and do the transitions
- oldFrame = cg.snap;
- cg.snap = cg.nextSnap;
-
- BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
- cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
-
- for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
- cent = &cg_entities[ cg.snap->entities[ i ].number ];
- CG_TransitionEntity( cent );
-
- // remember time of snapshot this entity was last updated in
- cent->snapShotTime = cg.snap->serverTime;
- }
-
- cg.nextSnap = NULL;
-
- // check for playerstate transition events
- if ( oldFrame ) {
- playerState_t *ops, *ps;
-
- ops = &oldFrame->ps;
- ps = &cg.snap->ps;
- // teleporting checks are irrespective of prediction
- if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
- cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
- }
-
- // if we are not doing client side movement prediction for any
- // reason, then the client events and view changes will be issued now
- if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW)
- || cg_nopredict.integer || cg_synchronousClients.integer ) {
- CG_TransitionPlayerState( ps, ops );
- }
- }
-
-}
-
-
-/*
-===================
-CG_SetNextSnap
-
-A new snapshot has just been read in from the client system.
-===================
-*/
-static void CG_SetNextSnap( snapshot_t *snap ) {
- int num;
- entityState_t *es;
- centity_t *cent;
-
- cg.nextSnap = snap;
-
- BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
- cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
-
- // check for extrapolation errors
- for ( num = 0 ; num < snap->numEntities ; num++ ) {
- es = &snap->entities[num];
- cent = &cg_entities[ es->number ];
-
- memcpy(&cent->nextState, es, sizeof(entityState_t));
- //cent->nextState = *es;
-
- // if this frame is a teleport, or the entity wasn't in the
- // previous frame, don't interpolate
- if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) {
- cent->interpolate = qfalse;
- } else {
- cent->interpolate = qtrue;
- }
- }
-
- // if the next frame is a teleport for the playerstate, we
- // can't interpolate during demos
- if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
- cg.nextFrameTeleport = qtrue;
- } else {
- cg.nextFrameTeleport = qfalse;
- }
-
- // if changing follow mode, don't interpolate
- if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
- cg.nextFrameTeleport = qtrue;
- }
-
- // if changing server restarts, don't interpolate
- if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
- cg.nextFrameTeleport = qtrue;
- }
-
- // sort out solid entities
- CG_BuildSolidList();
-}
-
-
-/*
-========================
-CG_ReadNextSnapshot
-
-This is the only place new snapshots are requested
-This may increment cgs.processedSnapshotNum multiple
-times if the client system fails to return a
-valid snapshot.
-========================
-*/
-static snapshot_t *CG_ReadNextSnapshot( void ) {
- qboolean r;
- snapshot_t *dest;
-
- if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
- CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
- cg.latestSnapshotNum, cgs.processedSnapshotNum );
- }
-
- while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
- // decide which of the two slots to load it into
- if ( cg.snap == &cg.activeSnapshots[0] ) {
- dest = &cg.activeSnapshots[1];
- } else {
- dest = &cg.activeSnapshots[0];
- }
-
- // try to read the snapshot from the client system
- cgs.processedSnapshotNum++;
- r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
-
- // FIXME: why would trap_GetSnapshot return a snapshot with the same server time
- if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
- //continue;
- }
-
- // if it succeeded, return
- if ( r ) {
- CG_AddLagometerSnapshotInfo( dest );
- return dest;
- }
-
- // a GetSnapshot will return failure if the snapshot
- // never arrived, or is so old that its entities
- // have been shoved off the end of the circular
- // buffer in the client system.
-
- // record as a dropped packet
- CG_AddLagometerSnapshotInfo( NULL );
-
- // If there are additional snapshots, continue trying to
- // read them.
- }
-
- // nothing left to read
- return NULL;
-}
-
-
-/*
-============
-CG_ProcessSnapshots
-
-We are trying to set up a renderable view, so determine
-what the simulated time is, and try to get snapshots
-both before and after that time if available.
-
-If we don't have a valid cg.snap after exiting this function,
-then a 3D game view cannot be rendered. This should only happen
-right after the initial connection. After cg.snap has been valid
-once, it will never turn invalid.
-
-Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
-hasn't arrived yet (it becomes an extrapolating situation instead
-of an interpolating one)
-
-============
-*/
-void CG_ProcessSnapshots( void ) {
- snapshot_t *snap;
- int n;
-
- // see what the latest snapshot the client system has is
- trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
- if ( n != cg.latestSnapshotNum ) {
- if ( n < cg.latestSnapshotNum ) {
- // this should never happen
- CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
- }
- cg.latestSnapshotNum = n;
- }
-
- // If we have yet to receive a snapshot, check for it.
- // Once we have gotten the first snapshot, cg.snap will
- // always have valid data for the rest of the game
- while ( !cg.snap ) {
- snap = CG_ReadNextSnapshot();
- if ( !snap ) {
- // we can't continue until we get a snapshot
- return;
- }
-
- // set our weapon selection to what
- // the playerstate is currently using
- if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
- CG_SetInitialSnapshot( snap );
- }
- }
-
- // loop until we either have a valid nextSnap with a serverTime
- // greater than cg.time to interpolate towards, or we run
- // out of available snapshots
- do {
- // if we don't have a nextframe, try and read a new one in
- if ( !cg.nextSnap ) {
- snap = CG_ReadNextSnapshot();
-
- // if we still don't have a nextframe, we will just have to
- // extrapolate
- if ( !snap ) {
- break;
- }
-
- CG_SetNextSnap( snap );
-
-
- // if time went backwards, we have a level restart
- if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
- CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
- }
- }
-
- // if our time is < nextFrame's, we have a nice interpolating state
- if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
- break;
- }
-
- // we have passed the transition from nextFrame to frame
- CG_TransitionSnapshot();
- } while ( 1 );
-
- // assert our valid conditions upon exiting
- if ( cg.snap == NULL ) {
- CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
- }
- if ( cg.time < cg.snap->serverTime ) {
- // this can happen right after a vid_restart
- cg.time = cg.snap->serverTime;
- }
- if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
- CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
- }
-
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_snapshot.c -- things that happen on snapshot transition,
+// not necessarily every single rendered frame
+
+#include "cg_local.h"
+
+
+
+/*
+==================
+CG_ResetEntity
+==================
+*/
+static void CG_ResetEntity( centity_t *cent ) {
+ // if the previous snapshot this entity was updated in is at least
+ // an event window back in time then we can reset the previous event
+ if ( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) {
+ cent->previousEvent = 0;
+ }
+
+ cent->trailTime = cg.snap->serverTime;
+
+ VectorCopy (cent->currentState.origin, cent->lerpOrigin);
+ VectorCopy (cent->currentState.angles, cent->lerpAngles);
+ if ( cent->currentState.eType == ET_PLAYER ) {
+ CG_ResetPlayerEntity( cent );
+ }
+}
+
+/*
+===============
+CG_TransitionEntity
+
+cent->nextState is moved to cent->currentState and events are fired
+===============
+*/
+static void CG_TransitionEntity( centity_t *cent ) {
+ cent->currentState = cent->nextState;
+ cent->currentValid = qtrue;
+
+ // reset if the entity wasn't in the last frame or was teleported
+ if ( !cent->interpolate ) {
+ CG_ResetEntity( cent );
+ }
+
+ // clear the next state. if will be set by the next CG_SetNextSnap
+ cent->interpolate = qfalse;
+
+ // check for events
+ CG_CheckEvents( cent );
+}
+
+
+/*
+==================
+CG_SetInitialSnapshot
+
+This will only happen on the very first snapshot, or
+on tourney restarts. All other times will use
+CG_TransitionSnapshot instead.
+
+FIXME: Also called by map_restart?
+==================
+*/
+void CG_SetInitialSnapshot( snapshot_t *snap ) {
+ int i;
+ centity_t *cent;
+ entityState_t *state;
+
+ cg.snap = snap;
+
+ BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
+
+ // sort out solid entities
+ CG_BuildSolidList();
+
+ CG_ExecuteNewServerCommands( snap->serverCommandSequence );
+
+ // set our local weapon selection pointer to
+ // what the server has indicated the current weapon is
+ CG_Respawn();
+
+ for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
+ state = &cg.snap->entities[ i ];
+ cent = &cg_entities[ state->number ];
+
+ memcpy(&cent->currentState, state, sizeof(entityState_t));
+ //cent->currentState = *state;
+ cent->interpolate = qfalse;
+ cent->currentValid = qtrue;
+
+ CG_ResetEntity( cent );
+
+ // check for events
+ CG_CheckEvents( cent );
+ }
+}
+
+
+/*
+===================
+CG_TransitionSnapshot
+
+The transition point from snap to nextSnap has passed
+===================
+*/
+static void CG_TransitionSnapshot( void ) {
+ centity_t *cent;
+ snapshot_t *oldFrame;
+ int i;
+
+ if ( !cg.snap ) {
+ CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
+ }
+ if ( !cg.nextSnap ) {
+ CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
+ }
+
+ // execute any server string commands before transitioning entities
+ CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
+
+ // if we had a map_restart, set everthing with initial
+ if ( !cg.snap ) {
+ }
+
+ // clear the currentValid flag for all entities in the existing snapshot
+ for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
+ cent = &cg_entities[ cg.snap->entities[ i ].number ];
+ cent->currentValid = qfalse;
+ }
+
+ // move nextSnap to snap and do the transitions
+ oldFrame = cg.snap;
+ cg.snap = cg.nextSnap;
+
+ BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
+ cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
+
+ for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
+ cent = &cg_entities[ cg.snap->entities[ i ].number ];
+ CG_TransitionEntity( cent );
+
+ // remember time of snapshot this entity was last updated in
+ cent->snapShotTime = cg.snap->serverTime;
+ }
+
+ cg.nextSnap = NULL;
+
+ // check for playerstate transition events
+ if ( oldFrame ) {
+ playerState_t *ops, *ps;
+
+ ops = &oldFrame->ps;
+ ps = &cg.snap->ps;
+ // teleporting checks are irrespective of prediction
+ if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
+ cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
+ }
+
+ // if we are not doing client side movement prediction for any
+ // reason, then the client events and view changes will be issued now
+ if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW)
+ || cg_nopredict.integer || cg_synchronousClients.integer ) {
+ CG_TransitionPlayerState( ps, ops );
+ }
+ }
+
+}
+
+
+/*
+===================
+CG_SetNextSnap
+
+A new snapshot has just been read in from the client system.
+===================
+*/
+static void CG_SetNextSnap( snapshot_t *snap ) {
+ int num;
+ entityState_t *es;
+ centity_t *cent;
+
+ cg.nextSnap = snap;
+
+ BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
+ cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
+
+ // check for extrapolation errors
+ for ( num = 0 ; num < snap->numEntities ; num++ ) {
+ es = &snap->entities[num];
+ cent = &cg_entities[ es->number ];
+
+ memcpy(&cent->nextState, es, sizeof(entityState_t));
+ //cent->nextState = *es;
+
+ // if this frame is a teleport, or the entity wasn't in the
+ // previous frame, don't interpolate
+ if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) {
+ cent->interpolate = qfalse;
+ } else {
+ cent->interpolate = qtrue;
+ }
+ }
+
+ // if the next frame is a teleport for the playerstate, we
+ // can't interpolate during demos
+ if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
+ cg.nextFrameTeleport = qtrue;
+ } else {
+ cg.nextFrameTeleport = qfalse;
+ }
+
+ // if changing follow mode, don't interpolate
+ if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
+ cg.nextFrameTeleport = qtrue;
+ }
+
+ // if changing server restarts, don't interpolate
+ if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
+ cg.nextFrameTeleport = qtrue;
+ }
+
+ // sort out solid entities
+ CG_BuildSolidList();
+}
+
+
+/*
+========================
+CG_ReadNextSnapshot
+
+This is the only place new snapshots are requested
+This may increment cgs.processedSnapshotNum multiple
+times if the client system fails to return a
+valid snapshot.
+========================
+*/
+static snapshot_t *CG_ReadNextSnapshot( void ) {
+ qboolean r;
+ snapshot_t *dest;
+
+ if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
+ CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
+ cg.latestSnapshotNum, cgs.processedSnapshotNum );
+ }
+
+ while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
+ // decide which of the two slots to load it into
+ if ( cg.snap == &cg.activeSnapshots[0] ) {
+ dest = &cg.activeSnapshots[1];
+ } else {
+ dest = &cg.activeSnapshots[0];
+ }
+
+ // try to read the snapshot from the client system
+ cgs.processedSnapshotNum++;
+ r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
+
+ // FIXME: why would trap_GetSnapshot return a snapshot with the same server time
+ if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
+ //continue;
+ }
+
+ // if it succeeded, return
+ if ( r ) {
+ CG_AddLagometerSnapshotInfo( dest );
+ return dest;
+ }
+
+ // a GetSnapshot will return failure if the snapshot
+ // never arrived, or is so old that its entities
+ // have been shoved off the end of the circular
+ // buffer in the client system.
+
+ // record as a dropped packet
+ CG_AddLagometerSnapshotInfo( NULL );
+
+ // If there are additional snapshots, continue trying to
+ // read them.
+ }
+
+ // nothing left to read
+ return NULL;
+}
+
+
+/*
+============
+CG_ProcessSnapshots
+
+We are trying to set up a renderable view, so determine
+what the simulated time is, and try to get snapshots
+both before and after that time if available.
+
+If we don't have a valid cg.snap after exiting this function,
+then a 3D game view cannot be rendered. This should only happen
+right after the initial connection. After cg.snap has been valid
+once, it will never turn invalid.
+
+Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
+hasn't arrived yet (it becomes an extrapolating situation instead
+of an interpolating one)
+
+============
+*/
+void CG_ProcessSnapshots( void ) {
+ snapshot_t *snap;
+ int n;
+
+ // see what the latest snapshot the client system has is
+ trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
+ if ( n != cg.latestSnapshotNum ) {
+ if ( n < cg.latestSnapshotNum ) {
+ // this should never happen
+ CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
+ }
+ cg.latestSnapshotNum = n;
+ }
+
+ // If we have yet to receive a snapshot, check for it.
+ // Once we have gotten the first snapshot, cg.snap will
+ // always have valid data for the rest of the game
+ while ( !cg.snap ) {
+ snap = CG_ReadNextSnapshot();
+ if ( !snap ) {
+ // we can't continue until we get a snapshot
+ return;
+ }
+
+ // set our weapon selection to what
+ // the playerstate is currently using
+ if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
+ CG_SetInitialSnapshot( snap );
+ }
+ }
+
+ // loop until we either have a valid nextSnap with a serverTime
+ // greater than cg.time to interpolate towards, or we run
+ // out of available snapshots
+ do {
+ // if we don't have a nextframe, try and read a new one in
+ if ( !cg.nextSnap ) {
+ snap = CG_ReadNextSnapshot();
+
+ // if we still don't have a nextframe, we will just have to
+ // extrapolate
+ if ( !snap ) {
+ break;
+ }
+
+ CG_SetNextSnap( snap );
+
+
+ // if time went backwards, we have a level restart
+ if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
+ CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
+ }
+ }
+
+ // if our time is < nextFrame's, we have a nice interpolating state
+ if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
+ break;
+ }
+
+ // we have passed the transition from nextFrame to frame
+ CG_TransitionSnapshot();
+ } while ( 1 );
+
+ // assert our valid conditions upon exiting
+ if ( cg.snap == NULL ) {
+ CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
+ }
+ if ( cg.time < cg.snap->serverTime ) {
+ // this can happen right after a vid_restart
+ cg.time = cg.snap->serverTime;
+ }
+ if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
+ CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
+ }
+
+}
+
diff --git a/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm
index 8363fe3..0874b47 100755
--- a/code/cgame/cg_syscalls.asm
+++ b/code/cgame/cg_syscalls.asm
@@ -1,106 +1,106 @@
-code
-
-equ trap_Print -1
-equ trap_Error -2
-equ trap_Milliseconds -3
-equ trap_Cvar_Register -4
-equ trap_Cvar_Update -5
-equ trap_Cvar_Set -6
-equ trap_Cvar_VariableStringBuffer -7
-equ trap_Argc -8
-equ trap_Argv -9
-equ trap_Args -10
-equ trap_FS_FOpenFile -11
-equ trap_FS_Read -12
-equ trap_FS_Write -13
-equ trap_FS_FCloseFile -14
-equ trap_SendConsoleCommand -15
-equ trap_AddCommand -16
-equ trap_SendClientCommand -17
-equ trap_UpdateScreen -18
-equ trap_CM_LoadMap -19
-equ trap_CM_NumInlineModels -20
-equ trap_CM_InlineModel -21
-equ trap_CM_LoadModel -22
-equ trap_CM_TempBoxModel -23
-equ trap_CM_PointContents -24
-equ trap_CM_TransformedPointContents -25
-equ trap_CM_BoxTrace -26
-equ trap_CM_TransformedBoxTrace -27
-equ trap_CM_MarkFragments -28
-equ trap_S_StartSound -29
-equ trap_S_StartLocalSound -30
-equ trap_S_ClearLoopingSounds -31
-equ trap_S_AddLoopingSound -32
-equ trap_S_UpdateEntityPosition -33
-equ trap_S_Respatialize -34
-equ trap_S_RegisterSound -35
-equ trap_S_StartBackgroundTrack -36
-equ trap_R_LoadWorldMap -37
-equ trap_R_RegisterModel -38
-equ trap_R_RegisterSkin -39
-equ trap_R_RegisterShader -40
-equ trap_R_ClearScene -41
-equ trap_R_AddRefEntityToScene -42
-equ trap_R_AddPolyToScene -43
-equ trap_R_AddLightToScene -44
-equ trap_R_RenderScene -45
-equ trap_R_SetColor -46
-equ trap_R_DrawStretchPic -47
-equ trap_R_ModelBounds -48
-equ trap_R_LerpTag -49
-equ trap_GetGlconfig -50
-equ trap_GetGameState -51
-equ trap_GetCurrentSnapshotNumber -52
-equ trap_GetSnapshot -53
-equ trap_GetServerCommand -54
-equ trap_GetCurrentCmdNumber -55
-equ trap_GetUserCmd -56
-equ trap_SetUserCmdValue -57
-equ trap_R_RegisterShaderNoMip -58
-equ trap_MemoryRemaining -59
-equ trap_R_RegisterFont -60
-equ trap_Key_IsDown -61
-equ trap_Key_GetCatcher -62
-equ trap_Key_SetCatcher -63
-equ trap_Key_GetKey -64
-equ trap_PC_AddGlobalDefine -65
-equ trap_PC_LoadSource -66
-equ trap_PC_FreeSource -67
-equ trap_PC_ReadToken -68
-equ trap_PC_SourceFileAndLine -69
-equ trap_S_StopBackgroundTrack -70
-equ trap_RealTime -71
-equ trap_SnapVector -72
-equ trap_RemoveCommand -73
-equ trap_R_LightForPoint -74
-equ trap_CIN_PlayCinematic -75
-equ trap_CIN_StopCinematic -76
-equ trap_CIN_RunCinematic -77
-equ trap_CIN_DrawCinematic -78
-equ trap_CIN_SetExtents -79
-equ trap_R_RemapShader -80
-equ trap_S_AddRealLoopingSound -81
-equ trap_S_StopLoopingSound -82
-equ trap_CM_TempCapsuleModel -83
-equ trap_CM_CapsuleTrace -84
-equ trap_CM_TransformedCapsuleTrace -85
-equ trap_R_AddAdditiveLightToScene -86
-equ trap_GetEntityToken -87
-equ trap_R_AddPolysToScene -88
-equ trap_R_inPVS -89
-equ trap_FS_Seek -90
-
-equ memset -101
-equ memcpy -102
-equ strncpy -103
-equ sin -104
-equ cos -105
-equ atan2 -106
-equ sqrt -107
-equ floor -108
-equ ceil -109
-equ testPrintInt -110
-equ testPrintFloat -111
-equ acos -112
-
+code
+
+equ trap_Print -1
+equ trap_Error -2
+equ trap_Milliseconds -3
+equ trap_Cvar_Register -4
+equ trap_Cvar_Update -5
+equ trap_Cvar_Set -6
+equ trap_Cvar_VariableStringBuffer -7
+equ trap_Argc -8
+equ trap_Argv -9
+equ trap_Args -10
+equ trap_FS_FOpenFile -11
+equ trap_FS_Read -12
+equ trap_FS_Write -13
+equ trap_FS_FCloseFile -14
+equ trap_SendConsoleCommand -15
+equ trap_AddCommand -16
+equ trap_SendClientCommand -17
+equ trap_UpdateScreen -18
+equ trap_CM_LoadMap -19
+equ trap_CM_NumInlineModels -20
+equ trap_CM_InlineModel -21
+equ trap_CM_LoadModel -22
+equ trap_CM_TempBoxModel -23
+equ trap_CM_PointContents -24
+equ trap_CM_TransformedPointContents -25
+equ trap_CM_BoxTrace -26
+equ trap_CM_TransformedBoxTrace -27
+equ trap_CM_MarkFragments -28
+equ trap_S_StartSound -29
+equ trap_S_StartLocalSound -30
+equ trap_S_ClearLoopingSounds -31
+equ trap_S_AddLoopingSound -32
+equ trap_S_UpdateEntityPosition -33
+equ trap_S_Respatialize -34
+equ trap_S_RegisterSound -35
+equ trap_S_StartBackgroundTrack -36
+equ trap_R_LoadWorldMap -37
+equ trap_R_RegisterModel -38
+equ trap_R_RegisterSkin -39
+equ trap_R_RegisterShader -40
+equ trap_R_ClearScene -41
+equ trap_R_AddRefEntityToScene -42
+equ trap_R_AddPolyToScene -43
+equ trap_R_AddLightToScene -44
+equ trap_R_RenderScene -45
+equ trap_R_SetColor -46
+equ trap_R_DrawStretchPic -47
+equ trap_R_ModelBounds -48
+equ trap_R_LerpTag -49
+equ trap_GetGlconfig -50
+equ trap_GetGameState -51
+equ trap_GetCurrentSnapshotNumber -52
+equ trap_GetSnapshot -53
+equ trap_GetServerCommand -54
+equ trap_GetCurrentCmdNumber -55
+equ trap_GetUserCmd -56
+equ trap_SetUserCmdValue -57
+equ trap_R_RegisterShaderNoMip -58
+equ trap_MemoryRemaining -59
+equ trap_R_RegisterFont -60
+equ trap_Key_IsDown -61
+equ trap_Key_GetCatcher -62
+equ trap_Key_SetCatcher -63
+equ trap_Key_GetKey -64
+equ trap_PC_AddGlobalDefine -65
+equ trap_PC_LoadSource -66
+equ trap_PC_FreeSource -67
+equ trap_PC_ReadToken -68
+equ trap_PC_SourceFileAndLine -69
+equ trap_S_StopBackgroundTrack -70
+equ trap_RealTime -71
+equ trap_SnapVector -72
+equ trap_RemoveCommand -73
+equ trap_R_LightForPoint -74
+equ trap_CIN_PlayCinematic -75
+equ trap_CIN_StopCinematic -76
+equ trap_CIN_RunCinematic -77
+equ trap_CIN_DrawCinematic -78
+equ trap_CIN_SetExtents -79
+equ trap_R_RemapShader -80
+equ trap_S_AddRealLoopingSound -81
+equ trap_S_StopLoopingSound -82
+equ trap_CM_TempCapsuleModel -83
+equ trap_CM_CapsuleTrace -84
+equ trap_CM_TransformedCapsuleTrace -85
+equ trap_R_AddAdditiveLightToScene -86
+equ trap_GetEntityToken -87
+equ trap_R_AddPolysToScene -88
+equ trap_R_inPVS -89
+equ trap_FS_Seek -90
+
+equ memset -101
+equ memcpy -102
+equ strncpy -103
+equ sin -104
+equ cos -105
+equ atan2 -106
+equ sqrt -107
+equ floor -108
+equ ceil -109
+equ testPrintInt -110
+equ testPrintFloat -111
+equ acos -112
+
diff --git a/code/cgame/cg_syscalls.c b/code/cgame/cg_syscalls.c
index a7bf659..c7ad938 100755
--- a/code/cgame/cg_syscalls.c
+++ b/code/cgame/cg_syscalls.c
@@ -1,445 +1,445 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_syscalls.c -- this file is only included when building a dll
-// cg_syscalls.asm is included instead when building a qvm
-#ifdef Q3_VM
-#error "Do not use in VM build"
-#endif
-
-#include "cg_local.h"
-
-static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1;
-
-
-void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) {
- syscall = syscallptr;
-}
-
-
-int PASSFLOAT( float x ) {
- float floatTemp;
- floatTemp = x;
- return *(int *)&floatTemp;
-}
-
-void trap_Print( const char *fmt ) {
- syscall( CG_PRINT, fmt );
-}
-
-void trap_Error( const char *fmt ) {
- syscall( CG_ERROR, fmt );
-}
-
-int trap_Milliseconds( void ) {
- return syscall( CG_MILLISECONDS );
-}
-
-void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
- syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );
-}
-
-void trap_Cvar_Update( vmCvar_t *vmCvar ) {
- syscall( CG_CVAR_UPDATE, vmCvar );
-}
-
-void trap_Cvar_Set( const char *var_name, const char *value ) {
- syscall( CG_CVAR_SET, var_name, value );
-}
-
-void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
- syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
-}
-
-int trap_Argc( void ) {
- return syscall( CG_ARGC );
-}
-
-void trap_Argv( int n, char *buffer, int bufferLength ) {
- syscall( CG_ARGV, n, buffer, bufferLength );
-}
-
-void trap_Args( char *buffer, int bufferLength ) {
- syscall( CG_ARGS, buffer, bufferLength );
-}
-
-int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
- return syscall( CG_FS_FOPENFILE, qpath, f, mode );
-}
-
-void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
- syscall( CG_FS_READ, buffer, len, f );
-}
-
-void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
- syscall( CG_FS_WRITE, buffer, len, f );
-}
-
-void trap_FS_FCloseFile( fileHandle_t f ) {
- syscall( CG_FS_FCLOSEFILE, f );
-}
-
-int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
- return syscall( CG_FS_SEEK, f, offset, origin );
-}
-
-void trap_SendConsoleCommand( const char *text ) {
- syscall( CG_SENDCONSOLECOMMAND, text );
-}
-
-void trap_AddCommand( const char *cmdName ) {
- syscall( CG_ADDCOMMAND, cmdName );
-}
-
-void trap_RemoveCommand( const char *cmdName ) {
- syscall( CG_REMOVECOMMAND, cmdName );
-}
-
-void trap_SendClientCommand( const char *s ) {
- syscall( CG_SENDCLIENTCOMMAND, s );
-}
-
-void trap_UpdateScreen( void ) {
- syscall( CG_UPDATESCREEN );
-}
-
-void trap_CM_LoadMap( const char *mapname ) {
- syscall( CG_CM_LOADMAP, mapname );
-}
-
-int trap_CM_NumInlineModels( void ) {
- return syscall( CG_CM_NUMINLINEMODELS );
-}
-
-clipHandle_t trap_CM_InlineModel( int index ) {
- return syscall( CG_CM_INLINEMODEL, index );
-}
-
-clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {
- return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );
-}
-
-clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) {
- return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs );
-}
-
-int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) {
- return syscall( CG_CM_POINTCONTENTS, p, model );
-}
-
-int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {
- return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );
-}
-
-void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask ) {
- syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );
-}
-
-void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask ) {
- syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask );
-}
-
-void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles ) {
- syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
-}
-
-void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
- const vec3_t mins, const vec3_t maxs,
- clipHandle_t model, int brushmask,
- const vec3_t origin, const vec3_t angles ) {
- syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
-}
-
-int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
- const vec3_t projection,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer ) {
- return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
-}
-
-void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {
- syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );
-}
-
-void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
- syscall( CG_S_STARTLOCALSOUND, sfx, channelNum );
-}
-
-void trap_S_ClearLoopingSounds( qboolean killall ) {
- syscall( CG_S_CLEARLOOPINGSOUNDS, killall );
-}
-
-void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
- syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx );
-}
-
-void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
- syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx );
-}
-
-void trap_S_StopLoopingSound( int entityNum ) {
- syscall( CG_S_STOPLOOPINGSOUND, entityNum );
-}
-
-void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
- syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );
-}
-
-void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) {
- syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );
-}
-
-sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
- return syscall( CG_S_REGISTERSOUND, sample, compressed );
-}
-
-void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) {
- syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );
-}
-
-void trap_R_LoadWorldMap( const char *mapname ) {
- syscall( CG_R_LOADWORLDMAP, mapname );
-}
-
-qhandle_t trap_R_RegisterModel( const char *name ) {
- return syscall( CG_R_REGISTERMODEL, name );
-}
-
-qhandle_t trap_R_RegisterSkin( const char *name ) {
- return syscall( CG_R_REGISTERSKIN, name );
-}
-
-qhandle_t trap_R_RegisterShader( const char *name ) {
- return syscall( CG_R_REGISTERSHADER, name );
-}
-
-qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
- return syscall( CG_R_REGISTERSHADERNOMIP, name );
-}
-
-void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
- syscall(CG_R_REGISTERFONT, fontName, pointSize, font );
-}
-
-void trap_R_ClearScene( void ) {
- syscall( CG_R_CLEARSCENE );
-}
-
-void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
- syscall( CG_R_ADDREFENTITYTOSCENE, re );
-}
-
-void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
- syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
-}
-
-void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {
- syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );
-}
-
-int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {
- return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir );
-}
-
-void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
-}
-
-void trap_R_RenderScene( const refdef_t *fd ) {
- syscall( CG_R_RENDERSCENE, fd );
-}
-
-void trap_R_SetColor( const float *rgba ) {
- syscall( CG_R_SETCOLOR, rgba );
-}
-
-void trap_R_DrawStretchPic( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
-}
-
-void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
- syscall( CG_R_MODELBOUNDS, model, mins, maxs );
-}
-
-int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
- float frac, const char *tagName ) {
- return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
-}
-
-void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
- syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset );
-}
-
-void trap_GetGlconfig( glconfig_t *glconfig ) {
- syscall( CG_GETGLCONFIG, glconfig );
-}
-
-void trap_GetGameState( gameState_t *gamestate ) {
- syscall( CG_GETGAMESTATE, gamestate );
-}
-
-void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
- syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );
-}
-
-qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
- return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );
-}
-
-qboolean trap_GetServerCommand( int serverCommandNumber ) {
- return syscall( CG_GETSERVERCOMMAND, serverCommandNumber );
-}
-
-int trap_GetCurrentCmdNumber( void ) {
- return syscall( CG_GETCURRENTCMDNUMBER );
-}
-
-qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
- return syscall( CG_GETUSERCMD, cmdNumber, ucmd );
-}
-
-void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) {
- syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) );
-}
-
-void testPrintInt( char *string, int i ) {
- syscall( CG_TESTPRINTINT, string, i );
-}
-
-void testPrintFloat( char *string, float f ) {
- syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) );
-}
-
-int trap_MemoryRemaining( void ) {
- return syscall( CG_MEMORY_REMAINING );
-}
-
-qboolean trap_Key_IsDown( int keynum ) {
- return syscall( CG_KEY_ISDOWN, keynum );
-}
-
-int trap_Key_GetCatcher( void ) {
- return syscall( CG_KEY_GETCATCHER );
-}
-
-void trap_Key_SetCatcher( int catcher ) {
- syscall( CG_KEY_SETCATCHER, catcher );
-}
-
-int trap_Key_GetKey( const char *binding ) {
- return syscall( CG_KEY_GETKEY, binding );
-}
-
-int trap_PC_AddGlobalDefine( char *define ) {
- return syscall( CG_PC_ADD_GLOBAL_DEFINE, define );
-}
-
-int trap_PC_LoadSource( const char *filename ) {
- return syscall( CG_PC_LOAD_SOURCE, filename );
-}
-
-int trap_PC_FreeSource( int handle ) {
- return syscall( CG_PC_FREE_SOURCE, handle );
-}
-
-int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
- return syscall( CG_PC_READ_TOKEN, handle, pc_token );
-}
-
-int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
- return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
-}
-
-void trap_S_StopBackgroundTrack( void ) {
- syscall( CG_S_STOPBACKGROUNDTRACK );
-}
-
-int trap_RealTime(qtime_t *qtime) {
- return syscall( CG_REAL_TIME, qtime );
-}
-
-void trap_SnapVector( float *v ) {
- syscall( CG_SNAPVECTOR, v );
-}
-
-// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
-int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
- return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
-}
-
-// stops playing the cinematic and ends it. should always return FMV_EOF
-// cinematics must be stopped in reverse order of when they are started
-e_status trap_CIN_StopCinematic(int handle) {
- return syscall(CG_CIN_STOPCINEMATIC, handle);
-}
-
-
-// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
-e_status trap_CIN_RunCinematic (int handle) {
- return syscall(CG_CIN_RUNCINEMATIC, handle);
-}
-
-
-// draws the current frame
-void trap_CIN_DrawCinematic (int handle) {
- syscall(CG_CIN_DRAWCINEMATIC, handle);
-}
-
-
-// allows you to resize the animation dynamically
-void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
- syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);
-}
-
-/*
-qboolean trap_loadCamera( const char *name ) {
- return syscall( CG_LOADCAMERA, name );
-}
-
-void trap_startCamera(int time) {
- syscall(CG_STARTCAMERA, time);
-}
-
-qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) {
- return syscall( CG_GETCAMERAINFO, time, origin, angles );
-}
-*/
-
-qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
- return syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize );
-}
-
-qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) {
- return syscall( CG_R_INPVS, p1, p2 );
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_syscalls.c -- this file is only included when building a dll
+// cg_syscalls.asm is included instead when building a qvm
+#ifdef Q3_VM
+#error "Do not use in VM build"
+#endif
+
+#include "cg_local.h"
+
+static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1;
+
+
+void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) {
+ syscall = syscallptr;
+}
+
+
+int PASSFLOAT( float x ) {
+ float floatTemp;
+ floatTemp = x;
+ return *(int *)&floatTemp;
+}
+
+void trap_Print( const char *fmt ) {
+ syscall( CG_PRINT, fmt );
+}
+
+void trap_Error( const char *fmt ) {
+ syscall( CG_ERROR, fmt );
+}
+
+int trap_Milliseconds( void ) {
+ return syscall( CG_MILLISECONDS );
+}
+
+void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
+ syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags );
+}
+
+void trap_Cvar_Update( vmCvar_t *vmCvar ) {
+ syscall( CG_CVAR_UPDATE, vmCvar );
+}
+
+void trap_Cvar_Set( const char *var_name, const char *value ) {
+ syscall( CG_CVAR_SET, var_name, value );
+}
+
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
+ syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize );
+}
+
+int trap_Argc( void ) {
+ return syscall( CG_ARGC );
+}
+
+void trap_Argv( int n, char *buffer, int bufferLength ) {
+ syscall( CG_ARGV, n, buffer, bufferLength );
+}
+
+void trap_Args( char *buffer, int bufferLength ) {
+ syscall( CG_ARGS, buffer, bufferLength );
+}
+
+int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
+ return syscall( CG_FS_FOPENFILE, qpath, f, mode );
+}
+
+void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
+ syscall( CG_FS_READ, buffer, len, f );
+}
+
+void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
+ syscall( CG_FS_WRITE, buffer, len, f );
+}
+
+void trap_FS_FCloseFile( fileHandle_t f ) {
+ syscall( CG_FS_FCLOSEFILE, f );
+}
+
+int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
+ return syscall( CG_FS_SEEK, f, offset, origin );
+}
+
+void trap_SendConsoleCommand( const char *text ) {
+ syscall( CG_SENDCONSOLECOMMAND, text );
+}
+
+void trap_AddCommand( const char *cmdName ) {
+ syscall( CG_ADDCOMMAND, cmdName );
+}
+
+void trap_RemoveCommand( const char *cmdName ) {
+ syscall( CG_REMOVECOMMAND, cmdName );
+}
+
+void trap_SendClientCommand( const char *s ) {
+ syscall( CG_SENDCLIENTCOMMAND, s );
+}
+
+void trap_UpdateScreen( void ) {
+ syscall( CG_UPDATESCREEN );
+}
+
+void trap_CM_LoadMap( const char *mapname ) {
+ syscall( CG_CM_LOADMAP, mapname );
+}
+
+int trap_CM_NumInlineModels( void ) {
+ return syscall( CG_CM_NUMINLINEMODELS );
+}
+
+clipHandle_t trap_CM_InlineModel( int index ) {
+ return syscall( CG_CM_INLINEMODEL, index );
+}
+
+clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) {
+ return syscall( CG_CM_TEMPBOXMODEL, mins, maxs );
+}
+
+clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) {
+ return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs );
+}
+
+int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) {
+ return syscall( CG_CM_POINTCONTENTS, p, model );
+}
+
+int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) {
+ return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles );
+}
+
+void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask ) {
+ syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask );
+}
+
+void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask ) {
+ syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask );
+}
+
+void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles ) {
+ syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
+}
+
+void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end,
+ const vec3_t mins, const vec3_t maxs,
+ clipHandle_t model, int brushmask,
+ const vec3_t origin, const vec3_t angles ) {
+ syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles );
+}
+
+int trap_CM_MarkFragments( int numPoints, const vec3_t *points,
+ const vec3_t projection,
+ int maxPoints, vec3_t pointBuffer,
+ int maxFragments, markFragment_t *fragmentBuffer ) {
+ return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
+}
+
+void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) {
+ syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx );
+}
+
+void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) {
+ syscall( CG_S_STARTLOCALSOUND, sfx, channelNum );
+}
+
+void trap_S_ClearLoopingSounds( qboolean killall ) {
+ syscall( CG_S_CLEARLOOPINGSOUNDS, killall );
+}
+
+void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
+ syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx );
+}
+
+void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) {
+ syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx );
+}
+
+void trap_S_StopLoopingSound( int entityNum ) {
+ syscall( CG_S_STOPLOOPINGSOUND, entityNum );
+}
+
+void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
+ syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin );
+}
+
+void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) {
+ syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater );
+}
+
+sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) {
+ return syscall( CG_S_REGISTERSOUND, sample, compressed );
+}
+
+void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) {
+ syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop );
+}
+
+void trap_R_LoadWorldMap( const char *mapname ) {
+ syscall( CG_R_LOADWORLDMAP, mapname );
+}
+
+qhandle_t trap_R_RegisterModel( const char *name ) {
+ return syscall( CG_R_REGISTERMODEL, name );
+}
+
+qhandle_t trap_R_RegisterSkin( const char *name ) {
+ return syscall( CG_R_REGISTERSKIN, name );
+}
+
+qhandle_t trap_R_RegisterShader( const char *name ) {
+ return syscall( CG_R_REGISTERSHADER, name );
+}
+
+qhandle_t trap_R_RegisterShaderNoMip( const char *name ) {
+ return syscall( CG_R_REGISTERSHADERNOMIP, name );
+}
+
+void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
+ syscall(CG_R_REGISTERFONT, fontName, pointSize, font );
+}
+
+void trap_R_ClearScene( void ) {
+ syscall( CG_R_CLEARSCENE );
+}
+
+void trap_R_AddRefEntityToScene( const refEntity_t *re ) {
+ syscall( CG_R_ADDREFENTITYTOSCENE, re );
+}
+
+void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) {
+ syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts );
+}
+
+void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) {
+ syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num );
+}
+
+int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) {
+ return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir );
+}
+
+void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
+}
+
+void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
+ syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) );
+}
+
+void trap_R_RenderScene( const refdef_t *fd ) {
+ syscall( CG_R_RENDERSCENE, fd );
+}
+
+void trap_R_SetColor( const float *rgba ) {
+ syscall( CG_R_SETCOLOR, rgba );
+}
+
+void trap_R_DrawStretchPic( float x, float y, float w, float h,
+ float s1, float t1, float s2, float t2, qhandle_t hShader ) {
+ syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader );
+}
+
+void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
+ syscall( CG_R_MODELBOUNDS, model, mins, maxs );
+}
+
+int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
+ float frac, const char *tagName ) {
+ return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName );
+}
+
+void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) {
+ syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset );
+}
+
+void trap_GetGlconfig( glconfig_t *glconfig ) {
+ syscall( CG_GETGLCONFIG, glconfig );
+}
+
+void trap_GetGameState( gameState_t *gamestate ) {
+ syscall( CG_GETGAMESTATE, gamestate );
+}
+
+void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
+ syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime );
+}
+
+qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
+ return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot );
+}
+
+qboolean trap_GetServerCommand( int serverCommandNumber ) {
+ return syscall( CG_GETSERVERCOMMAND, serverCommandNumber );
+}
+
+int trap_GetCurrentCmdNumber( void ) {
+ return syscall( CG_GETCURRENTCMDNUMBER );
+}
+
+qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
+ return syscall( CG_GETUSERCMD, cmdNumber, ucmd );
+}
+
+void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) {
+ syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) );
+}
+
+void testPrintInt( char *string, int i ) {
+ syscall( CG_TESTPRINTINT, string, i );
+}
+
+void testPrintFloat( char *string, float f ) {
+ syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) );
+}
+
+int trap_MemoryRemaining( void ) {
+ return syscall( CG_MEMORY_REMAINING );
+}
+
+qboolean trap_Key_IsDown( int keynum ) {
+ return syscall( CG_KEY_ISDOWN, keynum );
+}
+
+int trap_Key_GetCatcher( void ) {
+ return syscall( CG_KEY_GETCATCHER );
+}
+
+void trap_Key_SetCatcher( int catcher ) {
+ syscall( CG_KEY_SETCATCHER, catcher );
+}
+
+int trap_Key_GetKey( const char *binding ) {
+ return syscall( CG_KEY_GETKEY, binding );
+}
+
+int trap_PC_AddGlobalDefine( char *define ) {
+ return syscall( CG_PC_ADD_GLOBAL_DEFINE, define );
+}
+
+int trap_PC_LoadSource( const char *filename ) {
+ return syscall( CG_PC_LOAD_SOURCE, filename );
+}
+
+int trap_PC_FreeSource( int handle ) {
+ return syscall( CG_PC_FREE_SOURCE, handle );
+}
+
+int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
+ return syscall( CG_PC_READ_TOKEN, handle, pc_token );
+}
+
+int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
+ return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
+}
+
+void trap_S_StopBackgroundTrack( void ) {
+ syscall( CG_S_STOPBACKGROUNDTRACK );
+}
+
+int trap_RealTime(qtime_t *qtime) {
+ return syscall( CG_REAL_TIME, qtime );
+}
+
+void trap_SnapVector( float *v ) {
+ syscall( CG_SNAPVECTOR, v );
+}
+
+// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate)
+int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits) {
+ return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits);
+}
+
+// stops playing the cinematic and ends it. should always return FMV_EOF
+// cinematics must be stopped in reverse order of when they are started
+e_status trap_CIN_StopCinematic(int handle) {
+ return syscall(CG_CIN_STOPCINEMATIC, handle);
+}
+
+
+// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached.
+e_status trap_CIN_RunCinematic (int handle) {
+ return syscall(CG_CIN_RUNCINEMATIC, handle);
+}
+
+
+// draws the current frame
+void trap_CIN_DrawCinematic (int handle) {
+ syscall(CG_CIN_DRAWCINEMATIC, handle);
+}
+
+
+// allows you to resize the animation dynamically
+void trap_CIN_SetExtents (int handle, int x, int y, int w, int h) {
+ syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h);
+}
+
+/*
+qboolean trap_loadCamera( const char *name ) {
+ return syscall( CG_LOADCAMERA, name );
+}
+
+void trap_startCamera(int time) {
+ syscall(CG_STARTCAMERA, time);
+}
+
+qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles) {
+ return syscall( CG_GETCAMERAINFO, time, origin, angles );
+}
+*/
+
+qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
+ return syscall( CG_GET_ENTITY_TOKEN, buffer, bufferSize );
+}
+
+qboolean trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) {
+ return syscall( CG_R_INPVS, p1, p2 );
+}
diff --git a/code/cgame/cg_view.c b/code/cgame/cg_view.c
index 83d5141..49c9ddd 100755
--- a/code/cgame/cg_view.c
+++ b/code/cgame/cg_view.c
@@ -1,876 +1,876 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_view.c -- setup all the parameters (position, angle, etc)
-// for a 3D rendering
-#include "cg_local.h"
-
-
-/*
-=============================================================================
-
- MODEL TESTING
-
-The viewthing and gun positioning tools from Q2 have been integrated and
-enhanced into a single model testing facility.
-
-Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
-
-The names must be the full pathname after the basedir, like
-"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
-
-Testmodel will create a fake entity 100 units in front of the current view
-position, directly facing the viewer. It will remain immobile, so you can
-move around it to view it from different angles.
-
-Testgun will cause the model to follow the player around and supress the real
-view weapon model. The default frame 0 of most guns is completely off screen,
-so you will probably have to cycle a couple frames to see it.
-
-"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
-frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
-q3default.cfg.
-
-If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
-you adjust the positioning.
-
-Note that none of the model testing features update while the game is paused, so
-it may be convenient to test with deathmatch set to 1 so that bringing down the
-console doesn't pause the game.
-
-=============================================================================
-*/
-
-/*
-=================
-CG_TestModel_f
-
-Creates an entity in front of the current position, which
-can then be moved around
-=================
-*/
-void CG_TestModel_f (void) {
- vec3_t angles;
-
- memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
- if ( trap_Argc() < 2 ) {
- return;
- }
-
- Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
-
- if ( trap_Argc() == 3 ) {
- cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
- cg.testModelEntity.frame = 1;
- cg.testModelEntity.oldframe = 0;
- }
- if (! cg.testModelEntity.hModel ) {
- CG_Printf( "Can't register model\n" );
- return;
- }
-
- VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
-
- angles[PITCH] = 0;
- angles[YAW] = 180 + cg.refdefViewAngles[1];
- angles[ROLL] = 0;
-
- AnglesToAxis( angles, cg.testModelEntity.axis );
- cg.testGun = qfalse;
-}
-
-/*
-=================
-CG_TestGun_f
-
-Replaces the current view weapon with the given model
-=================
-*/
-void CG_TestGun_f (void) {
- CG_TestModel_f();
- cg.testGun = qtrue;
- cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
-}
-
-
-void CG_TestModelNextFrame_f (void) {
- cg.testModelEntity.frame++;
- CG_Printf( "frame %i\n", cg.testModelEntity.frame );
-}
-
-void CG_TestModelPrevFrame_f (void) {
- cg.testModelEntity.frame--;
- if ( cg.testModelEntity.frame < 0 ) {
- cg.testModelEntity.frame = 0;
- }
- CG_Printf( "frame %i\n", cg.testModelEntity.frame );
-}
-
-void CG_TestModelNextSkin_f (void) {
- cg.testModelEntity.skinNum++;
- CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
-}
-
-void CG_TestModelPrevSkin_f (void) {
- cg.testModelEntity.skinNum--;
- if ( cg.testModelEntity.skinNum < 0 ) {
- cg.testModelEntity.skinNum = 0;
- }
- CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
-}
-
-static void CG_AddTestModel (void) {
- int i;
-
- // re-register the model, because the level may have changed
- cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
- if (! cg.testModelEntity.hModel ) {
- CG_Printf ("Can't register model\n");
- return;
- }
-
- // if testing a gun, set the origin reletive to the view origin
- if ( cg.testGun ) {
- VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
- VectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );
- VectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );
- VectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );
-
- // allow the position to be adjusted
- for (i=0 ; i<3 ; i++) {
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;
- cg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;
- }
- }
-
- trap_R_AddRefEntityToScene( &cg.testModelEntity );
-}
-
-
-
-//============================================================================
-
-
-/*
-=================
-CG_CalcVrect
-
-Sets the coordinates of the rendered window
-=================
-*/
-static void CG_CalcVrect (void) {
- int size;
-
- // the intermission should allways be full screen
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- size = 100;
- } else {
- // bound normal viewsize
- if (cg_viewsize.integer < 30) {
- trap_Cvar_Set ("cg_viewsize","30");
- size = 30;
- } else if (cg_viewsize.integer > 100) {
- trap_Cvar_Set ("cg_viewsize","100");
- size = 100;
- } else {
- size = cg_viewsize.integer;
- }
-
- }
- cg.refdef.width = cgs.glconfig.vidWidth*size/100;
- cg.refdef.width &= ~1;
-
- cg.refdef.height = cgs.glconfig.vidHeight*size/100;
- cg.refdef.height &= ~1;
-
- cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
- cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
-}
-
-//==============================================================================
-
-
-/*
-===============
-CG_OffsetThirdPersonView
-
-===============
-*/
-#define FOCUS_DISTANCE 512
-static void CG_OffsetThirdPersonView( void ) {
- vec3_t forward, right, up;
- vec3_t view;
- vec3_t focusAngles;
- trace_t trace;
- static vec3_t mins = { -4, -4, -4 };
- static vec3_t maxs = { 4, 4, 4 };
- vec3_t focusPoint;
- float focusDist;
- float forwardScale, sideScale;
-
- cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
-
- VectorCopy( cg.refdefViewAngles, focusAngles );
-
- // if dead, look at killer
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
- }
-
- if ( focusAngles[PITCH] > 45 ) {
- focusAngles[PITCH] = 45; // don't go too far overhead
- }
- AngleVectors( focusAngles, forward, NULL, NULL );
-
- VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
-
- VectorCopy( cg.refdef.vieworg, view );
-
- view[2] += 8;
-
- cg.refdefViewAngles[PITCH] *= 0.5;
-
- AngleVectors( cg.refdefViewAngles, forward, right, up );
-
- forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
- sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
- VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
- VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
-
- // trace a ray from the origin to the viewpoint to make sure the view isn't
- // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
-
- if (!cg_cameraMode.integer) {
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
-
- if ( trace.fraction != 1.0 ) {
- VectorCopy( trace.endpos, view );
- view[2] += (1.0 - trace.fraction) * 32;
- // try another trace to this position, because a tunnel may have the ceiling
- // close enogh that this is poking out
-
- CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
- VectorCopy( trace.endpos, view );
- }
- }
-
-
- VectorCopy( view, cg.refdef.vieworg );
-
- // select pitch to look at focus point from vieword
- VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
- focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
- if ( focusDist < 1 ) {
- focusDist = 1; // should never happen
- }
- cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
- cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
-}
-
-
-// this causes a compiler bug on mac MrC compiler
-static void CG_StepOffset( void ) {
- int timeDelta;
-
- // smooth out stair climbing
- timeDelta = cg.time - cg.stepTime;
- if ( timeDelta < STEP_TIME ) {
- cg.refdef.vieworg[2] -= cg.stepChange
- * (STEP_TIME - timeDelta) / STEP_TIME;
- }
-}
-
-/*
-===============
-CG_OffsetFirstPersonView
-
-===============
-*/
-static void CG_OffsetFirstPersonView( void ) {
- float *origin;
- float *angles;
- float bob;
- float ratio;
- float delta;
- float speed;
- float f;
- vec3_t predictedVelocity;
- int timeDelta;
-
- if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
- return;
- }
-
- origin = cg.refdef.vieworg;
- angles = cg.refdefViewAngles;
-
- // if dead, fix the angle and don't add any kick
- if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
- angles[ROLL] = 40;
- angles[PITCH] = -15;
- angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
- origin[2] += cg.predictedPlayerState.viewheight;
- return;
- }
-
- // add angles based on weapon kick
- VectorAdd (angles, cg.kick_angles, angles);
-
- // add angles based on damage kick
- if ( cg.damageTime ) {
- ratio = cg.time - cg.damageTime;
- if ( ratio < DAMAGE_DEFLECT_TIME ) {
- ratio /= DAMAGE_DEFLECT_TIME;
- angles[PITCH] += ratio * cg.v_dmg_pitch;
- angles[ROLL] += ratio * cg.v_dmg_roll;
- } else {
- ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
- if ( ratio > 0 ) {
- angles[PITCH] += ratio * cg.v_dmg_pitch;
- angles[ROLL] += ratio * cg.v_dmg_roll;
- }
- }
- }
-
- // add pitch based on fall kick
-#if 0
- ratio = ( cg.time - cg.landTime) / FALL_TIME;
- if (ratio < 0)
- ratio = 0;
- angles[PITCH] += ratio * cg.fall_value;
-#endif
-
- // add angles based on velocity
- VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
- angles[PITCH] += delta * cg_runpitch.value;
-
- delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
- angles[ROLL] -= delta * cg_runroll.value;
-
- // add angles based on bob
-
- // make sure the bob is visible even at low speeds
- speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
-
- delta = cg.bobfracsin * cg_bobpitch.value * speed;
- if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
- delta *= 3; // crouching
- angles[PITCH] += delta;
- delta = cg.bobfracsin * cg_bobroll.value * speed;
- if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
- delta *= 3; // crouching accentuates roll
- if (cg.bobcycle & 1)
- delta = -delta;
- angles[ROLL] += delta;
-
-//===================================
-
- // add view height
- origin[2] += cg.predictedPlayerState.viewheight;
-
- // smooth out duck height changes
- timeDelta = cg.time - cg.duckTime;
- if ( timeDelta < DUCK_TIME) {
- cg.refdef.vieworg[2] -= cg.duckChange
- * (DUCK_TIME - timeDelta) / DUCK_TIME;
- }
-
- // add bob height
- bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
- if (bob > 6) {
- bob = 6;
- }
-
- origin[2] += bob;
-
-
- // add fall height
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- f = delta / LAND_DEFLECT_TIME;
- cg.refdef.vieworg[2] += cg.landChange * f;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- delta -= LAND_DEFLECT_TIME;
- f = 1.0 - ( delta / LAND_RETURN_TIME );
- cg.refdef.vieworg[2] += cg.landChange * f;
- }
-
- // add step offset
- CG_StepOffset();
-
- // add kick offset
-
- VectorAdd (origin, cg.kick_origin, origin);
-
- // pivot the eye based on a neck length
-#if 0
- {
-#define NECK_LENGTH 8
- vec3_t forward, up;
-
- cg.refdef.vieworg[2] -= NECK_LENGTH;
- AngleVectors( cg.refdefViewAngles, forward, NULL, up );
- VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );
- VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
- }
-#endif
-}
-
-//======================================================================
-
-void CG_ZoomDown_f( void ) {
- if ( cg.zoomed ) {
- return;
- }
- cg.zoomed = qtrue;
- cg.zoomTime = cg.time;
-}
-
-void CG_ZoomUp_f( void ) {
- if ( !cg.zoomed ) {
- return;
- }
- cg.zoomed = qfalse;
- cg.zoomTime = cg.time;
-}
-
-
-/*
-====================
-CG_CalcFov
-
-Fixed fov at intermissions, otherwise account for fov variable and zooms.
-====================
-*/
-#define WAVE_AMPLITUDE 1
-#define WAVE_FREQUENCY 0.4
-
-static int CG_CalcFov( void ) {
- float x;
- float phase;
- float v;
- int contents;
- float fov_x, fov_y;
- float zoomFov;
- float f;
- int inwater;
-
- if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
- // if in intermission, use a fixed value
- fov_x = 90;
- } else {
- // user selectable
- if ( cgs.dmflags & DF_FIXED_FOV ) {
- // dmflag to prevent wide fov for all clients
- fov_x = 90;
- } else {
- fov_x = cg_fov.value;
- if ( fov_x < 1 ) {
- fov_x = 1;
- } else if ( fov_x > 160 ) {
- fov_x = 160;
- }
- }
-
- // account for zooms
- zoomFov = cg_zoomFov.value;
- if ( zoomFov < 1 ) {
- zoomFov = 1;
- } else if ( zoomFov > 160 ) {
- zoomFov = 160;
- }
-
- if ( cg.zoomed ) {
- f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 ) {
- fov_x = zoomFov;
- } else {
- fov_x = fov_x + f * ( zoomFov - fov_x );
- }
- } else {
- f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
- if ( f > 1.0 ) {
- fov_x = fov_x;
- } else {
- fov_x = zoomFov + f * ( fov_x - zoomFov );
- }
- }
- }
-
- x = cg.refdef.width / tan( fov_x / 360 * M_PI );
- fov_y = atan2( cg.refdef.height, x );
- fov_y = fov_y * 360 / M_PI;
-
- // warp if underwater
- contents = CG_PointContents( cg.refdef.vieworg, -1 );
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
- phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
- v = WAVE_AMPLITUDE * sin( phase );
- fov_x += v;
- fov_y -= v;
- inwater = qtrue;
- }
- else {
- inwater = qfalse;
- }
-
-
- // set it
- cg.refdef.fov_x = fov_x;
- cg.refdef.fov_y = fov_y;
-
- if ( !cg.zoomed ) {
- cg.zoomSensitivity = 1;
- } else {
- cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
- }
-
- return inwater;
-}
-
-
-
-/*
-===============
-CG_DamageBlendBlob
-
-===============
-*/
-static void CG_DamageBlendBlob( void ) {
- int t;
- int maxTime;
- refEntity_t ent;
-
- if ( !cg.damageValue ) {
- return;
- }
-
- //if (cg.cameraMode) {
- // return;
- //}
-
- // ragePro systems can't fade blends, so don't obscure the screen
- if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
- return;
- }
-
- maxTime = DAMAGE_TIME;
- t = cg.time - cg.damageTime;
- if ( t <= 0 || t >= maxTime ) {
- return;
- }
-
-
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_SPRITE;
- ent.renderfx = RF_FIRST_PERSON;
-
- VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
- VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
- VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
-
- ent.radius = cg.damageValue * 3;
- ent.customShader = cgs.media.viewBloodShader;
- ent.shaderRGBA[0] = 255;
- ent.shaderRGBA[1] = 255;
- ent.shaderRGBA[2] = 255;
- ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );
- trap_R_AddRefEntityToScene( &ent );
-}
-
-
-/*
-===============
-CG_CalcViewValues
-
-Sets cg.refdef view values
-===============
-*/
-static int CG_CalcViewValues( void ) {
- playerState_t *ps;
-
- memset( &cg.refdef, 0, sizeof( cg.refdef ) );
-
- // strings for in game rendering
- // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
- // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
-
- // calculate size of 3D view
- CG_CalcVrect();
-
- ps = &cg.predictedPlayerState;
-/*
- if (cg.cameraMode) {
- vec3_t origin, angles;
- if (trap_getCameraInfo(cg.time, &origin, &angles)) {
- VectorCopy(origin, cg.refdef.vieworg);
- angles[ROLL] = 0;
- VectorCopy(angles, cg.refdefViewAngles);
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
- return CG_CalcFov();
- } else {
- cg.cameraMode = qfalse;
- }
- }
-*/
- // intermission view
- if ( ps->pm_type == PM_INTERMISSION ) {
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdefViewAngles );
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
- return CG_CalcFov();
- }
-
- cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
- cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
- cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
- ps->velocity[1] * ps->velocity[1] );
-
-
- VectorCopy( ps->origin, cg.refdef.vieworg );
- VectorCopy( ps->viewangles, cg.refdefViewAngles );
-
- if (cg_cameraOrbit.integer) {
- if (cg.time > cg.nextOrbitTime) {
- cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
- cg_thirdPersonAngle.value += cg_cameraOrbit.value;
- }
- }
- // add error decay
- if ( cg_errorDecay.value > 0 ) {
- int t;
- float f;
-
- t = cg.time - cg.predictedErrorTime;
- f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
- if ( f > 0 && f < 1 ) {
- VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
- } else {
- cg.predictedErrorTime = 0;
- }
- }
-
- if ( cg.renderingThirdPerson ) {
- // back away from character
- CG_OffsetThirdPersonView();
- } else {
- // offset for local bobbing and kicks
- CG_OffsetFirstPersonView();
- }
-
- // position eye reletive to origin
- AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
-
- if ( cg.hyperspace ) {
- cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
- }
-
- // field of view
- return CG_CalcFov();
-}
-
-
-/*
-=====================
-CG_PowerupTimerSounds
-=====================
-*/
-static void CG_PowerupTimerSounds( void ) {
- int i;
- int t;
-
- // powerup timers going away
- for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
- t = cg.snap->ps.powerups[i];
- if ( t <= cg.time ) {
- continue;
- }
- if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
- continue;
- }
- if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {
- trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );
- }
- }
-}
-
-/*
-=====================
-CG_AddBufferedSound
-=====================
-*/
-void CG_AddBufferedSound( sfxHandle_t sfx ) {
- if ( !sfx )
- return;
- cg.soundBuffer[cg.soundBufferIn] = sfx;
- cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
- if (cg.soundBufferIn == cg.soundBufferOut) {
- cg.soundBufferOut++;
- }
-}
-
-/*
-=====================
-CG_PlayBufferedSounds
-=====================
-*/
-static void CG_PlayBufferedSounds( void ) {
- if ( cg.soundTime < cg.time ) {
- if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
- trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
- cg.soundBuffer[cg.soundBufferOut] = 0;
- cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
- cg.soundTime = cg.time + 750;
- }
- }
-}
-
-//=========================================================================
-
-/*
-=================
-CG_DrawActiveFrame
-
-Generates and draws a game scene and status information at the given time.
-=================
-*/
-void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
- int inwater;
-
- cg.time = serverTime;
- cg.demoPlayback = demoPlayback;
-
- // update cvars
- CG_UpdateCvars();
-
- // if we are only updating the screen as a loading
- // pacifier, don't even try to read snapshots
- if ( cg.infoScreenText[0] != 0 ) {
- CG_DrawInformation();
- return;
- }
-
- // any looped sounds will be respecified as entities
- // are added to the render list
- trap_S_ClearLoopingSounds(qfalse);
-
- // clear all the render lists
- trap_R_ClearScene();
-
- // set up cg.snap and possibly cg.nextSnap
- CG_ProcessSnapshots();
-
- // if we haven't received any snapshots yet, all
- // we can draw is the information screen
- if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
- CG_DrawInformation();
- return;
- }
-
- // let the client system know what our weapon and zoom settings are
- trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
-
- // this counter will be bumped for every valid scene we generate
- cg.clientFrame++;
-
- // update cg.predictedPlayerState
- CG_PredictPlayerState();
-
- // decide on third person view
- cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
-
- // build cg.refdef
- inwater = CG_CalcViewValues();
-
- // first person blend blobs, done after AnglesToAxis
- if ( !cg.renderingThirdPerson ) {
- CG_DamageBlendBlob();
- }
-
- // build the render lists
- if ( !cg.hyperspace ) {
- CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct
- CG_AddMarks();
- CG_AddParticles ();
- CG_AddLocalEntities();
- }
- CG_AddViewWeapon( &cg.predictedPlayerState );
-
- // add buffered sounds
- CG_PlayBufferedSounds();
-
- // play buffered voice chats
- CG_PlayBufferedVoiceChats();
-
- // finish up the rest of the refdef
- if ( cg.testModelEntity.hModel ) {
- CG_AddTestModel();
- }
- cg.refdef.time = cg.time;
- memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
-
- // warning sounds when powerup is wearing off
- CG_PowerupTimerSounds();
-
- // update audio positions
- trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
-
- // make sure the lagometerSample and frame timing isn't done twice when in stereo
- if ( stereoView != STEREO_RIGHT ) {
- cg.frametime = cg.time - cg.oldTime;
- if ( cg.frametime < 0 ) {
- cg.frametime = 0;
- }
- cg.oldTime = cg.time;
- CG_AddLagometerFrameInfo();
- }
- if (cg_timescale.value != cg_timescaleFadeEnd.value) {
- if (cg_timescale.value < cg_timescaleFadeEnd.value) {
- cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
- if (cg_timescale.value > cg_timescaleFadeEnd.value)
- cg_timescale.value = cg_timescaleFadeEnd.value;
- }
- else {
- cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
- if (cg_timescale.value < cg_timescaleFadeEnd.value)
- cg_timescale.value = cg_timescaleFadeEnd.value;
- }
- if (cg_timescaleFadeSpeed.value) {
- trap_Cvar_Set("timescale", va("%f", cg_timescale.value));
- }
- }
-
- // actually issue the rendering calls
- CG_DrawActive( stereoView );
-
- if ( cg_stats.integer ) {
- CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
- }
-
-
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_view.c -- setup all the parameters (position, angle, etc)
+// for a 3D rendering
+#include "cg_local.h"
+
+
+/*
+=============================================================================
+
+ MODEL TESTING
+
+The viewthing and gun positioning tools from Q2 have been integrated and
+enhanced into a single model testing facility.
+
+Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
+
+The names must be the full pathname after the basedir, like
+"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
+
+Testmodel will create a fake entity 100 units in front of the current view
+position, directly facing the viewer. It will remain immobile, so you can
+move around it to view it from different angles.
+
+Testgun will cause the model to follow the player around and supress the real
+view weapon model. The default frame 0 of most guns is completely off screen,
+so you will probably have to cycle a couple frames to see it.
+
+"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
+frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
+q3default.cfg.
+
+If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let
+you adjust the positioning.
+
+Note that none of the model testing features update while the game is paused, so
+it may be convenient to test with deathmatch set to 1 so that bringing down the
+console doesn't pause the game.
+
+=============================================================================
+*/
+
+/*
+=================
+CG_TestModel_f
+
+Creates an entity in front of the current position, which
+can then be moved around
+=================
+*/
+void CG_TestModel_f (void) {
+ vec3_t angles;
+
+ memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
+ if ( trap_Argc() < 2 ) {
+ return;
+ }
+
+ Q_strncpyz (cg.testModelName, CG_Argv( 1 ), MAX_QPATH );
+ cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
+
+ if ( trap_Argc() == 3 ) {
+ cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) );
+ cg.testModelEntity.frame = 1;
+ cg.testModelEntity.oldframe = 0;
+ }
+ if (! cg.testModelEntity.hModel ) {
+ CG_Printf( "Can't register model\n" );
+ return;
+ }
+
+ VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
+
+ angles[PITCH] = 0;
+ angles[YAW] = 180 + cg.refdefViewAngles[1];
+ angles[ROLL] = 0;
+
+ AnglesToAxis( angles, cg.testModelEntity.axis );
+ cg.testGun = qfalse;
+}
+
+/*
+=================
+CG_TestGun_f
+
+Replaces the current view weapon with the given model
+=================
+*/
+void CG_TestGun_f (void) {
+ CG_TestModel_f();
+ cg.testGun = qtrue;
+ cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
+}
+
+
+void CG_TestModelNextFrame_f (void) {
+ cg.testModelEntity.frame++;
+ CG_Printf( "frame %i\n", cg.testModelEntity.frame );
+}
+
+void CG_TestModelPrevFrame_f (void) {
+ cg.testModelEntity.frame--;
+ if ( cg.testModelEntity.frame < 0 ) {
+ cg.testModelEntity.frame = 0;
+ }
+ CG_Printf( "frame %i\n", cg.testModelEntity.frame );
+}
+
+void CG_TestModelNextSkin_f (void) {
+ cg.testModelEntity.skinNum++;
+ CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
+}
+
+void CG_TestModelPrevSkin_f (void) {
+ cg.testModelEntity.skinNum--;
+ if ( cg.testModelEntity.skinNum < 0 ) {
+ cg.testModelEntity.skinNum = 0;
+ }
+ CG_Printf( "skin %i\n", cg.testModelEntity.skinNum );
+}
+
+static void CG_AddTestModel (void) {
+ int i;
+
+ // re-register the model, because the level may have changed
+ cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName );
+ if (! cg.testModelEntity.hModel ) {
+ CG_Printf ("Can't register model\n");
+ return;
+ }
+
+ // if testing a gun, set the origin reletive to the view origin
+ if ( cg.testGun ) {
+ VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin );
+ VectorCopy( cg.refdef.viewaxis[0], cg.testModelEntity.axis[0] );
+ VectorCopy( cg.refdef.viewaxis[1], cg.testModelEntity.axis[1] );
+ VectorCopy( cg.refdef.viewaxis[2], cg.testModelEntity.axis[2] );
+
+ // allow the position to be adjusted
+ for (i=0 ; i<3 ; i++) {
+ cg.testModelEntity.origin[i] += cg.refdef.viewaxis[0][i] * cg_gun_x.value;
+ cg.testModelEntity.origin[i] += cg.refdef.viewaxis[1][i] * cg_gun_y.value;
+ cg.testModelEntity.origin[i] += cg.refdef.viewaxis[2][i] * cg_gun_z.value;
+ }
+ }
+
+ trap_R_AddRefEntityToScene( &cg.testModelEntity );
+}
+
+
+
+//============================================================================
+
+
+/*
+=================
+CG_CalcVrect
+
+Sets the coordinates of the rendered window
+=================
+*/
+static void CG_CalcVrect (void) {
+ int size;
+
+ // the intermission should allways be full screen
+ if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
+ size = 100;
+ } else {
+ // bound normal viewsize
+ if (cg_viewsize.integer < 30) {
+ trap_Cvar_Set ("cg_viewsize","30");
+ size = 30;
+ } else if (cg_viewsize.integer > 100) {
+ trap_Cvar_Set ("cg_viewsize","100");
+ size = 100;
+ } else {
+ size = cg_viewsize.integer;
+ }
+
+ }
+ cg.refdef.width = cgs.glconfig.vidWidth*size/100;
+ cg.refdef.width &= ~1;
+
+ cg.refdef.height = cgs.glconfig.vidHeight*size/100;
+ cg.refdef.height &= ~1;
+
+ cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2;
+ cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2;
+}
+
+//==============================================================================
+
+
+/*
+===============
+CG_OffsetThirdPersonView
+
+===============
+*/
+#define FOCUS_DISTANCE 512
+static void CG_OffsetThirdPersonView( void ) {
+ vec3_t forward, right, up;
+ vec3_t view;
+ vec3_t focusAngles;
+ trace_t trace;
+ static vec3_t mins = { -4, -4, -4 };
+ static vec3_t maxs = { 4, 4, 4 };
+ vec3_t focusPoint;
+ float focusDist;
+ float forwardScale, sideScale;
+
+ cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;
+
+ VectorCopy( cg.refdefViewAngles, focusAngles );
+
+ // if dead, look at killer
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
+ cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
+ }
+
+ if ( focusAngles[PITCH] > 45 ) {
+ focusAngles[PITCH] = 45; // don't go too far overhead
+ }
+ AngleVectors( focusAngles, forward, NULL, NULL );
+
+ VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );
+
+ VectorCopy( cg.refdef.vieworg, view );
+
+ view[2] += 8;
+
+ cg.refdefViewAngles[PITCH] *= 0.5;
+
+ AngleVectors( cg.refdefViewAngles, forward, right, up );
+
+ forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
+ sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
+ VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
+ VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );
+
+ // trace a ray from the origin to the viewpoint to make sure the view isn't
+ // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
+
+ if (!cg_cameraMode.integer) {
+ CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
+
+ if ( trace.fraction != 1.0 ) {
+ VectorCopy( trace.endpos, view );
+ view[2] += (1.0 - trace.fraction) * 32;
+ // try another trace to this position, because a tunnel may have the ceiling
+ // close enogh that this is poking out
+
+ CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
+ VectorCopy( trace.endpos, view );
+ }
+ }
+
+
+ VectorCopy( view, cg.refdef.vieworg );
+
+ // select pitch to look at focus point from vieword
+ VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
+ focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
+ if ( focusDist < 1 ) {
+ focusDist = 1; // should never happen
+ }
+ cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
+ cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
+}
+
+
+// this causes a compiler bug on mac MrC compiler
+static void CG_StepOffset( void ) {
+ int timeDelta;
+
+ // smooth out stair climbing
+ timeDelta = cg.time - cg.stepTime;
+ if ( timeDelta < STEP_TIME ) {
+ cg.refdef.vieworg[2] -= cg.stepChange
+ * (STEP_TIME - timeDelta) / STEP_TIME;
+ }
+}
+
+/*
+===============
+CG_OffsetFirstPersonView
+
+===============
+*/
+static void CG_OffsetFirstPersonView( void ) {
+ float *origin;
+ float *angles;
+ float bob;
+ float ratio;
+ float delta;
+ float speed;
+ float f;
+ vec3_t predictedVelocity;
+ int timeDelta;
+
+ if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
+ return;
+ }
+
+ origin = cg.refdef.vieworg;
+ angles = cg.refdefViewAngles;
+
+ // if dead, fix the angle and don't add any kick
+ if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
+ angles[ROLL] = 40;
+ angles[PITCH] = -15;
+ angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
+ origin[2] += cg.predictedPlayerState.viewheight;
+ return;
+ }
+
+ // add angles based on weapon kick
+ VectorAdd (angles, cg.kick_angles, angles);
+
+ // add angles based on damage kick
+ if ( cg.damageTime ) {
+ ratio = cg.time - cg.damageTime;
+ if ( ratio < DAMAGE_DEFLECT_TIME ) {
+ ratio /= DAMAGE_DEFLECT_TIME;
+ angles[PITCH] += ratio * cg.v_dmg_pitch;
+ angles[ROLL] += ratio * cg.v_dmg_roll;
+ } else {
+ ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
+ if ( ratio > 0 ) {
+ angles[PITCH] += ratio * cg.v_dmg_pitch;
+ angles[ROLL] += ratio * cg.v_dmg_roll;
+ }
+ }
+ }
+
+ // add pitch based on fall kick
+#if 0
+ ratio = ( cg.time - cg.landTime) / FALL_TIME;
+ if (ratio < 0)
+ ratio = 0;
+ angles[PITCH] += ratio * cg.fall_value;
+#endif
+
+ // add angles based on velocity
+ VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );
+
+ delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
+ angles[PITCH] += delta * cg_runpitch.value;
+
+ delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
+ angles[ROLL] -= delta * cg_runroll.value;
+
+ // add angles based on bob
+
+ // make sure the bob is visible even at low speeds
+ speed = cg.xyspeed > 200 ? cg.xyspeed : 200;
+
+ delta = cg.bobfracsin * cg_bobpitch.value * speed;
+ if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
+ delta *= 3; // crouching
+ angles[PITCH] += delta;
+ delta = cg.bobfracsin * cg_bobroll.value * speed;
+ if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
+ delta *= 3; // crouching accentuates roll
+ if (cg.bobcycle & 1)
+ delta = -delta;
+ angles[ROLL] += delta;
+
+//===================================
+
+ // add view height
+ origin[2] += cg.predictedPlayerState.viewheight;
+
+ // smooth out duck height changes
+ timeDelta = cg.time - cg.duckTime;
+ if ( timeDelta < DUCK_TIME) {
+ cg.refdef.vieworg[2] -= cg.duckChange
+ * (DUCK_TIME - timeDelta) / DUCK_TIME;
+ }
+
+ // add bob height
+ bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
+ if (bob > 6) {
+ bob = 6;
+ }
+
+ origin[2] += bob;
+
+
+ // add fall height
+ delta = cg.time - cg.landTime;
+ if ( delta < LAND_DEFLECT_TIME ) {
+ f = delta / LAND_DEFLECT_TIME;
+ cg.refdef.vieworg[2] += cg.landChange * f;
+ } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
+ delta -= LAND_DEFLECT_TIME;
+ f = 1.0 - ( delta / LAND_RETURN_TIME );
+ cg.refdef.vieworg[2] += cg.landChange * f;
+ }
+
+ // add step offset
+ CG_StepOffset();
+
+ // add kick offset
+
+ VectorAdd (origin, cg.kick_origin, origin);
+
+ // pivot the eye based on a neck length
+#if 0
+ {
+#define NECK_LENGTH 8
+ vec3_t forward, up;
+
+ cg.refdef.vieworg[2] -= NECK_LENGTH;
+ AngleVectors( cg.refdefViewAngles, forward, NULL, up );
+ VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg );
+ VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
+ }
+#endif
+}
+
+//======================================================================
+
+void CG_ZoomDown_f( void ) {
+ if ( cg.zoomed ) {
+ return;
+ }
+ cg.zoomed = qtrue;
+ cg.zoomTime = cg.time;
+}
+
+void CG_ZoomUp_f( void ) {
+ if ( !cg.zoomed ) {
+ return;
+ }
+ cg.zoomed = qfalse;
+ cg.zoomTime = cg.time;
+}
+
+
+/*
+====================
+CG_CalcFov
+
+Fixed fov at intermissions, otherwise account for fov variable and zooms.
+====================
+*/
+#define WAVE_AMPLITUDE 1
+#define WAVE_FREQUENCY 0.4
+
+static int CG_CalcFov( void ) {
+ float x;
+ float phase;
+ float v;
+ int contents;
+ float fov_x, fov_y;
+ float zoomFov;
+ float f;
+ int inwater;
+
+ if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
+ // if in intermission, use a fixed value
+ fov_x = 90;
+ } else {
+ // user selectable
+ if ( cgs.dmflags & DF_FIXED_FOV ) {
+ // dmflag to prevent wide fov for all clients
+ fov_x = 90;
+ } else {
+ fov_x = cg_fov.value;
+ if ( fov_x < 1 ) {
+ fov_x = 1;
+ } else if ( fov_x > 160 ) {
+ fov_x = 160;
+ }
+ }
+
+ // account for zooms
+ zoomFov = cg_zoomFov.value;
+ if ( zoomFov < 1 ) {
+ zoomFov = 1;
+ } else if ( zoomFov > 160 ) {
+ zoomFov = 160;
+ }
+
+ if ( cg.zoomed ) {
+ f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
+ if ( f > 1.0 ) {
+ fov_x = zoomFov;
+ } else {
+ fov_x = fov_x + f * ( zoomFov - fov_x );
+ }
+ } else {
+ f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;
+ if ( f > 1.0 ) {
+ fov_x = fov_x;
+ } else {
+ fov_x = zoomFov + f * ( fov_x - zoomFov );
+ }
+ }
+ }
+
+ x = cg.refdef.width / tan( fov_x / 360 * M_PI );
+ fov_y = atan2( cg.refdef.height, x );
+ fov_y = fov_y * 360 / M_PI;
+
+ // warp if underwater
+ contents = CG_PointContents( cg.refdef.vieworg, -1 );
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){
+ phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
+ v = WAVE_AMPLITUDE * sin( phase );
+ fov_x += v;
+ fov_y -= v;
+ inwater = qtrue;
+ }
+ else {
+ inwater = qfalse;
+ }
+
+
+ // set it
+ cg.refdef.fov_x = fov_x;
+ cg.refdef.fov_y = fov_y;
+
+ if ( !cg.zoomed ) {
+ cg.zoomSensitivity = 1;
+ } else {
+ cg.zoomSensitivity = cg.refdef.fov_y / 75.0;
+ }
+
+ return inwater;
+}
+
+
+
+/*
+===============
+CG_DamageBlendBlob
+
+===============
+*/
+static void CG_DamageBlendBlob( void ) {
+ int t;
+ int maxTime;
+ refEntity_t ent;
+
+ if ( !cg.damageValue ) {
+ return;
+ }
+
+ //if (cg.cameraMode) {
+ // return;
+ //}
+
+ // ragePro systems can't fade blends, so don't obscure the screen
+ if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
+ return;
+ }
+
+ maxTime = DAMAGE_TIME;
+ t = cg.time - cg.damageTime;
+ if ( t <= 0 || t >= maxTime ) {
+ return;
+ }
+
+
+ memset( &ent, 0, sizeof( ent ) );
+ ent.reType = RT_SPRITE;
+ ent.renderfx = RF_FIRST_PERSON;
+
+ VectorMA( cg.refdef.vieworg, 8, cg.refdef.viewaxis[0], ent.origin );
+ VectorMA( ent.origin, cg.damageX * -8, cg.refdef.viewaxis[1], ent.origin );
+ VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin );
+
+ ent.radius = cg.damageValue * 3;
+ ent.customShader = cgs.media.viewBloodShader;
+ ent.shaderRGBA[0] = 255;
+ ent.shaderRGBA[1] = 255;
+ ent.shaderRGBA[2] = 255;
+ ent.shaderRGBA[3] = 200 * ( 1.0 - ((float)t / maxTime) );
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+===============
+CG_CalcViewValues
+
+Sets cg.refdef view values
+===============
+*/
+static int CG_CalcViewValues( void ) {
+ playerState_t *ps;
+
+ memset( &cg.refdef, 0, sizeof( cg.refdef ) );
+
+ // strings for in game rendering
+ // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) );
+ // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) );
+
+ // calculate size of 3D view
+ CG_CalcVrect();
+
+ ps = &cg.predictedPlayerState;
+/*
+ if (cg.cameraMode) {
+ vec3_t origin, angles;
+ if (trap_getCameraInfo(cg.time, &origin, &angles)) {
+ VectorCopy(origin, cg.refdef.vieworg);
+ angles[ROLL] = 0;
+ VectorCopy(angles, cg.refdefViewAngles);
+ AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
+ return CG_CalcFov();
+ } else {
+ cg.cameraMode = qfalse;
+ }
+ }
+*/
+ // intermission view
+ if ( ps->pm_type == PM_INTERMISSION ) {
+ VectorCopy( ps->origin, cg.refdef.vieworg );
+ VectorCopy( ps->viewangles, cg.refdefViewAngles );
+ AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
+ return CG_CalcFov();
+ }
+
+ cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
+ cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
+ cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] +
+ ps->velocity[1] * ps->velocity[1] );
+
+
+ VectorCopy( ps->origin, cg.refdef.vieworg );
+ VectorCopy( ps->viewangles, cg.refdefViewAngles );
+
+ if (cg_cameraOrbit.integer) {
+ if (cg.time > cg.nextOrbitTime) {
+ cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer;
+ cg_thirdPersonAngle.value += cg_cameraOrbit.value;
+ }
+ }
+ // add error decay
+ if ( cg_errorDecay.value > 0 ) {
+ int t;
+ float f;
+
+ t = cg.time - cg.predictedErrorTime;
+ f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;
+ if ( f > 0 && f < 1 ) {
+ VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
+ } else {
+ cg.predictedErrorTime = 0;
+ }
+ }
+
+ if ( cg.renderingThirdPerson ) {
+ // back away from character
+ CG_OffsetThirdPersonView();
+ } else {
+ // offset for local bobbing and kicks
+ CG_OffsetFirstPersonView();
+ }
+
+ // position eye reletive to origin
+ AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
+
+ if ( cg.hyperspace ) {
+ cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
+ }
+
+ // field of view
+ return CG_CalcFov();
+}
+
+
+/*
+=====================
+CG_PowerupTimerSounds
+=====================
+*/
+static void CG_PowerupTimerSounds( void ) {
+ int i;
+ int t;
+
+ // powerup timers going away
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ t = cg.snap->ps.powerups[i];
+ if ( t <= cg.time ) {
+ continue;
+ }
+ if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
+ continue;
+ }
+ if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) {
+ trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound );
+ }
+ }
+}
+
+/*
+=====================
+CG_AddBufferedSound
+=====================
+*/
+void CG_AddBufferedSound( sfxHandle_t sfx ) {
+ if ( !sfx )
+ return;
+ cg.soundBuffer[cg.soundBufferIn] = sfx;
+ cg.soundBufferIn = (cg.soundBufferIn + 1) % MAX_SOUNDBUFFER;
+ if (cg.soundBufferIn == cg.soundBufferOut) {
+ cg.soundBufferOut++;
+ }
+}
+
+/*
+=====================
+CG_PlayBufferedSounds
+=====================
+*/
+static void CG_PlayBufferedSounds( void ) {
+ if ( cg.soundTime < cg.time ) {
+ if (cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[cg.soundBufferOut]) {
+ trap_S_StartLocalSound(cg.soundBuffer[cg.soundBufferOut], CHAN_ANNOUNCER);
+ cg.soundBuffer[cg.soundBufferOut] = 0;
+ cg.soundBufferOut = (cg.soundBufferOut + 1) % MAX_SOUNDBUFFER;
+ cg.soundTime = cg.time + 750;
+ }
+ }
+}
+
+//=========================================================================
+
+/*
+=================
+CG_DrawActiveFrame
+
+Generates and draws a game scene and status information at the given time.
+=================
+*/
+void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) {
+ int inwater;
+
+ cg.time = serverTime;
+ cg.demoPlayback = demoPlayback;
+
+ // update cvars
+ CG_UpdateCvars();
+
+ // if we are only updating the screen as a loading
+ // pacifier, don't even try to read snapshots
+ if ( cg.infoScreenText[0] != 0 ) {
+ CG_DrawInformation();
+ return;
+ }
+
+ // any looped sounds will be respecified as entities
+ // are added to the render list
+ trap_S_ClearLoopingSounds(qfalse);
+
+ // clear all the render lists
+ trap_R_ClearScene();
+
+ // set up cg.snap and possibly cg.nextSnap
+ CG_ProcessSnapshots();
+
+ // if we haven't received any snapshots yet, all
+ // we can draw is the information screen
+ if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
+ CG_DrawInformation();
+ return;
+ }
+
+ // let the client system know what our weapon and zoom settings are
+ trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity );
+
+ // this counter will be bumped for every valid scene we generate
+ cg.clientFrame++;
+
+ // update cg.predictedPlayerState
+ CG_PredictPlayerState();
+
+ // decide on third person view
+ cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0);
+
+ // build cg.refdef
+ inwater = CG_CalcViewValues();
+
+ // first person blend blobs, done after AnglesToAxis
+ if ( !cg.renderingThirdPerson ) {
+ CG_DamageBlendBlob();
+ }
+
+ // build the render lists
+ if ( !cg.hyperspace ) {
+ CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct
+ CG_AddMarks();
+ CG_AddParticles ();
+ CG_AddLocalEntities();
+ }
+ CG_AddViewWeapon( &cg.predictedPlayerState );
+
+ // add buffered sounds
+ CG_PlayBufferedSounds();
+
+ // play buffered voice chats
+ CG_PlayBufferedVoiceChats();
+
+ // finish up the rest of the refdef
+ if ( cg.testModelEntity.hModel ) {
+ CG_AddTestModel();
+ }
+ cg.refdef.time = cg.time;
+ memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) );
+
+ // warning sounds when powerup is wearing off
+ CG_PowerupTimerSounds();
+
+ // update audio positions
+ trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater );
+
+ // make sure the lagometerSample and frame timing isn't done twice when in stereo
+ if ( stereoView != STEREO_RIGHT ) {
+ cg.frametime = cg.time - cg.oldTime;
+ if ( cg.frametime < 0 ) {
+ cg.frametime = 0;
+ }
+ cg.oldTime = cg.time;
+ CG_AddLagometerFrameInfo();
+ }
+ if (cg_timescale.value != cg_timescaleFadeEnd.value) {
+ if (cg_timescale.value < cg_timescaleFadeEnd.value) {
+ cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
+ if (cg_timescale.value > cg_timescaleFadeEnd.value)
+ cg_timescale.value = cg_timescaleFadeEnd.value;
+ }
+ else {
+ cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000;
+ if (cg_timescale.value < cg_timescaleFadeEnd.value)
+ cg_timescale.value = cg_timescaleFadeEnd.value;
+ }
+ if (cg_timescaleFadeSpeed.value) {
+ trap_Cvar_Set("timescale", va("%f", cg_timescale.value));
+ }
+ }
+
+ // actually issue the rendering calls
+ CG_DrawActive( stereoView );
+
+ if ( cg_stats.integer ) {
+ CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame );
+ }
+
+
+}
+
diff --git a/code/cgame/cg_weapons.c b/code/cgame/cg_weapons.c
index 9ac1ca9..c4a1753 100755
--- a/code/cgame/cg_weapons.c
+++ b/code/cgame/cg_weapons.c
@@ -1,2277 +1,2277 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-// cg_weapons.c -- events and effects dealing with weapons
-#include "cg_local.h"
-
-/*
-==========================
-CG_MachineGunEjectBrass
-==========================
-*/
-static void CG_MachineGunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- float waterScale = 1.0f;
- vec3_t v[3];
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 0;
- velocity[1] = -50 + 40 * crandom();
- velocity[2] = 100 + 50 * crandom();
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time - (rand()&15);
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = -4;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
-
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.machinegunBrassModel;
-
- le->bounceFactor = 0.4 * waterScale;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 2;
- le->angles.trDelta[1] = 1;
- le->angles.trDelta[2] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
-}
-
-/*
-==========================
-CG_ShotgunEjectBrass
-==========================
-*/
-static void CG_ShotgunEjectBrass( centity_t *cent ) {
- localEntity_t *le;
- refEntity_t *re;
- vec3_t velocity, xvelocity;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int i;
-
- if ( cg_brassTime.integer <= 0 ) {
- return;
- }
-
- for ( i = 0; i < 2; i++ ) {
- float waterScale = 1.0f;
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 60 + 60 * crandom();
- if ( i == 0 ) {
- velocity[1] = 40 + 10 * crandom();
- } else {
- velocity[1] = -40 + 10 * crandom();
- }
- velocity[2] = 100 + 50 * crandom();
-
- le->leType = LE_FRAGMENT;
- le->startTime = cg.time;
- le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 8;
- offset[1] = 0;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->hModel = cgs.media.shotgunBrassModel;
- le->bounceFactor = 0.3f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
-
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_BRASS;
- le->leMarkType = LEMT_NONE;
- }
-}
-
-
-#ifdef MISSIONPACK
-/*
-==========================
-CG_NailgunEjectBrass
-==========================
-*/
-static void CG_NailgunEjectBrass( centity_t *cent ) {
- localEntity_t *smoke;
- vec3_t origin;
- vec3_t v[3];
- vec3_t offset;
- vec3_t xoffset;
- vec3_t up;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 0;
- offset[1] = -12;
- offset[2] = 24;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
- VectorAdd( cent->lerpOrigin, xoffset, origin );
-
- VectorSet( up, 0, 0, 64 );
-
- smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
-}
-#endif
-
-
-/*
-==========================
-CG_RailTrail
-==========================
-*/
-void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
- vec3_t axis[36], move, move2, next_move, vec, temp;
- float len;
- int i, j, skip;
-
- localEntity_t *le;
- refEntity_t *re;
-
-#define RADIUS 4
-#define ROTATION 1
-#define SPACING 5
-
- start[2] -= 4;
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
- PerpendicularVector(temp, vec);
- for (i = 0 ; i < 36; i++) {
- RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
- }
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_FADE_RGB;
- le->startTime = cg.time;
- le->endTime = cg.time + cg_railTrailTime.value;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_RAIL_CORE;
- re->customShader = cgs.media.railCoreShader;
-
- VectorCopy(start, re->origin);
- VectorCopy(end, re->oldorigin);
-
- re->shaderRGBA[0] = ci->color1[0] * 255;
- re->shaderRGBA[1] = ci->color1[1] * 255;
- re->shaderRGBA[2] = ci->color1[2] * 255;
- re->shaderRGBA[3] = 255;
-
- le->color[0] = ci->color1[0] * 0.75;
- le->color[1] = ci->color1[1] * 0.75;
- le->color[2] = ci->color1[2] * 0.75;
- le->color[3] = 1.0f;
-
- AxisClear( re->axis );
-
- VectorMA(move, 20, vec, move);
- VectorCopy(move, next_move);
- VectorScale (vec, SPACING, vec);
-
- if (cg_oldRail.integer != 0) {
- // nudge down a bit so it isn't exactly in center
- re->origin[2] -= 8;
- re->oldorigin[2] -= 8;
- return;
- }
- skip = -1;
-
- j = 18;
- for (i = 0; i < len; i += SPACING) {
- if (i != skip) {
- skip = i + SPACING;
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
- le->leFlags = LEF_PUFF_DONT_SCALE;
- le->leType = LE_MOVE_SCALE_FADE;
- le->startTime = cg.time;
- le->endTime = cg.time + (i>>1) + 600;
- le->lifeRate = 1.0 / (le->endTime - le->startTime);
-
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 1.1f;
- re->customShader = cgs.media.railRingsShader;
-
- re->shaderRGBA[0] = ci->color2[0] * 255;
- re->shaderRGBA[1] = ci->color2[1] * 255;
- re->shaderRGBA[2] = ci->color2[2] * 255;
- re->shaderRGBA[3] = 255;
-
- le->color[0] = ci->color2[0] * 0.75;
- le->color[1] = ci->color2[1] * 0.75;
- le->color[2] = ci->color2[2] * 0.75;
- le->color[3] = 1.0f;
-
- le->pos.trType = TR_LINEAR;
- le->pos.trTime = cg.time;
-
- VectorCopy( move, move2);
- VectorMA(move2, RADIUS , axis[j], move2);
- VectorCopy(move2, le->pos.trBase);
-
- le->pos.trDelta[0] = axis[j][0]*6;
- le->pos.trDelta[1] = axis[j][1]*6;
- le->pos.trDelta[2] = axis[j][2]*6;
- }
-
- VectorAdd (move, vec, move);
-
- j = j + ROTATION < 36 ? j + ROTATION : (j + ROTATION) % 36;
- }
-}
-
-/*
-==========================
-CG_RocketTrail
-==========================
-*/
-static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 50;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.smokePuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
-
-}
-
-#ifdef MISSIONPACK
-/*
-==========================
-CG_NailTrail
-==========================
-*/
-static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
- int step;
- vec3_t origin, lastPos;
- int t;
- int startTime, contents;
- int lastContents;
- entityState_t *es;
- vec3_t up;
- localEntity_t *smoke;
-
- if ( cg_noProjectileTrail.integer ) {
- return;
- }
-
- up[0] = 0;
- up[1] = 0;
- up[2] = 0;
-
- step = 50;
-
- es = &ent->currentState;
- startTime = ent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- contents = CG_PointContents( origin, -1 );
-
- // if object (e.g. grenade) is stationary, don't toss up smoke
- if ( es->pos.trType == TR_STATIONARY ) {
- ent->trailTime = cg.time;
- return;
- }
-
- BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
- lastContents = CG_PointContents( lastPos, -1 );
-
- ent->trailTime = cg.time;
-
- if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
- if ( contents & lastContents & CONTENTS_WATER ) {
- CG_BubbleTrail( lastPos, origin, 8 );
- }
- return;
- }
-
- for ( ; t <= ent->trailTime ; t += step ) {
- BG_EvaluateTrajectory( &es->pos, t, lastPos );
-
- smoke = CG_SmokePuff( lastPos, up,
- wi->trailRadius,
- 1, 1, 1, 0.33f,
- wi->wiTrailTime,
- t,
- 0,
- 0,
- cgs.media.nailPuffShader );
- // use the optimized local entity add
- smoke->leType = LE_SCALE_FADE;
- }
-
-}
-#endif
-
-/*
-==========================
-CG_NailTrail
-==========================
-*/
-static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
- localEntity_t *le;
- refEntity_t *re;
- entityState_t *es;
- vec3_t velocity, xvelocity, origin;
- vec3_t offset, xoffset;
- vec3_t v[3];
- int t, startTime, step;
-
- float waterScale = 1.0f;
-
- if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
- return;
- }
-
- step = 50;
-
- es = &cent->currentState;
- startTime = cent->trailTime;
- t = step * ( (startTime + step) / step );
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
-
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- velocity[0] = 60 - 120 * crandom();
- velocity[1] = 40 - 80 * crandom();
- velocity[2] = 100 - 200 * crandom();
-
- le->leType = LE_MOVE_SCALE_FADE;
- le->leFlags = LEF_TUMBLE;
- le->leBounceSoundType = LEBS_NONE;
- le->leMarkType = LEMT_NONE;
-
- le->startTime = cg.time;
- le->endTime = le->startTime + 600;
-
- le->pos.trType = TR_GRAVITY;
- le->pos.trTime = cg.time;
-
- AnglesToAxis( cent->lerpAngles, v );
-
- offset[0] = 2;
- offset[1] = 2;
- offset[2] = 2;
-
- xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
- xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
- xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
-
- VectorAdd( origin, xoffset, re->origin );
- VectorCopy( re->origin, le->pos.trBase );
-
- if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
- waterScale = 0.10f;
- }
-
- xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
- xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
- xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
- VectorScale( xvelocity, waterScale, le->pos.trDelta );
-
- AxisCopy( axisDefault, re->axis );
- re->shaderTime = cg.time / 1000.0f;
- re->reType = RT_SPRITE;
- re->radius = 0.25f;
- re->customShader = cgs.media.railRingsShader;
- le->bounceFactor = 0.3f;
-
- re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
- re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
- re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
- re->shaderRGBA[3] = 63;
-
- le->color[0] = wi->flashDlightColor[0] * 0.2;
- le->color[1] = wi->flashDlightColor[1] * 0.2;
- le->color[2] = wi->flashDlightColor[2] * 0.2;
- le->color[3] = 0.25f;
-
- le->angles.trType = TR_LINEAR;
- le->angles.trTime = cg.time;
- le->angles.trBase[0] = rand()&31;
- le->angles.trBase[1] = rand()&31;
- le->angles.trBase[2] = rand()&31;
- le->angles.trDelta[0] = 1;
- le->angles.trDelta[1] = 0.5;
- le->angles.trDelta[2] = 0;
-
-}
-/*
-==========================
-CG_GrappleTrail
-==========================
-*/
-void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {
- vec3_t origin;
- entityState_t *es;
- vec3_t forward, up;
- refEntity_t beam;
-
- es = &ent->currentState;
-
- BG_EvaluateTrajectory( &es->pos, cg.time, origin );
- ent->trailTime = cg.time;
-
- memset( &beam, 0, sizeof( beam ) );
- //FIXME adjust for muzzle position
- VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );
- beam.origin[2] += 26;
- AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );
- VectorMA( beam.origin, -6, up, beam.origin );
- VectorCopy( origin, beam.oldorigin );
-
- if (Distance( beam.origin, beam.oldorigin ) < 64 )
- return; // Don't draw if close
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
-
- AxisClear( beam.axis );
- beam.shaderRGBA[0] = 0xff;
- beam.shaderRGBA[1] = 0xff;
- beam.shaderRGBA[2] = 0xff;
- beam.shaderRGBA[3] = 0xff;
- trap_R_AddRefEntityToScene( &beam );
-}
-
-/*
-==========================
-CG_GrenadeTrail
-==========================
-*/
-static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {
- CG_RocketTrail( ent, wi );
-}
-
-
-/*
-=================
-CG_RegisterWeapon
-
-The server says this item is used on this level
-=================
-*/
-void CG_RegisterWeapon( int weaponNum ) {
- weaponInfo_t *weaponInfo;
- gitem_t *item, *ammo;
- char path[MAX_QPATH];
- vec3_t mins, maxs;
- int i;
-
- weaponInfo = &cg_weapons[weaponNum];
-
- if ( weaponNum == 0 ) {
- return;
- }
-
- if ( weaponInfo->registered ) {
- return;
- }
-
- memset( weaponInfo, 0, sizeof( *weaponInfo ) );
- weaponInfo->registered = qtrue;
-
- for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
- if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
- weaponInfo->item = item;
- break;
- }
- }
- if ( !item->classname ) {
- CG_Error( "Couldn't find weapon %i", weaponNum );
- }
- CG_RegisterItemVisuals( item - bg_itemlist );
-
- // load cmodel before model so filecache works
- weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );
-
- // calc midpoint for rotation
- trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
- for ( i = 0 ; i < 3 ; i++ ) {
- weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
- }
-
- weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
- weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon );
-
- for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
- if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {
- break;
- }
- }
- if ( ammo->classname && ammo->world_model[0] ) {
- weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );
- }
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_flash.md3" );
- weaponInfo->flashModel = trap_R_RegisterModel( path );
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_barrel.md3" );
- weaponInfo->barrelModel = trap_R_RegisterModel( path );
-
- strcpy( path, item->world_model[0] );
- COM_StripExtension( path, path );
- strcat( path, "_hand.md3" );
- weaponInfo->handsModel = trap_R_RegisterModel( path );
-
- if ( !weaponInfo->handsModel ) {
- weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
- }
-
- weaponInfo->loopFireSound = qfalse;
-
- switch ( weaponNum ) {
- case WP_GAUNTLET:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse );
- break;
-
- case WP_LIGHTNING:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse );
-
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
- cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
- cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
- cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse );
- cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse );
- cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse );
-
- break;
-
- case WP_GRAPPLING_HOOK:
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileTrailFunc = CG_GrappleTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
- break;
-
-#ifdef MISSIONPACK
- case WP_CHAINGUN:
- weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse );
- weaponInfo->loopFireSound = qtrue;
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
-#endif
-
- case WP_MACHINEGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse );
- weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse );
- weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse );
- weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- break;
-
- case WP_SHOTGUN:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse );
- weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
- break;
-
- case WP_ROCKET_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- weaponInfo->missileTrailFunc = CG_RocketTrail;
- weaponInfo->missileDlight = 200;
- weaponInfo->wiTrailTime = 2000;
- weaponInfo->trailRadius = 64;
-
- MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
-
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" );
- break;
-
-#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
-#endif
-
- case WP_GRENADE_LAUNCHER:
- weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" );
- weaponInfo->missileTrailFunc = CG_GrenadeTrail;
- weaponInfo->wiTrailTime = 700;
- weaponInfo->trailRadius = 32;
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse );
- cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
- break;
-
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass;
- weaponInfo->missileTrailFunc = CG_NailTrail;
-// weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse );
- weaponInfo->trailRadius = 16;
- weaponInfo->wiTrailTime = 250;
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse );
- break;
-#endif
-
- case WP_PLASMAGUN:
-// weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;
- weaponInfo->missileTrailFunc = CG_PlasmaTrail;
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse );
- cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- break;
-
- case WP_RAILGUN:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse );
- cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" );
- cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
- cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" );
- break;
-
- case WP_BFG:
- weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse );
- MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse );
- cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
- weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" );
- weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
- break;
-
- default:
- MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
- weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
- break;
- }
-}
-
-/*
-=================
-CG_RegisterItemVisuals
-
-The server says this item is used on this level
-=================
-*/
-void CG_RegisterItemVisuals( int itemNum ) {
- itemInfo_t *itemInfo;
- gitem_t *item;
-
- if ( itemNum < 0 || itemNum >= bg_numItems ) {
- CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
- }
-
- itemInfo = &cg_items[ itemNum ];
- if ( itemInfo->registered ) {
- return;
- }
-
- item = &bg_itemlist[ itemNum ];
-
- memset( itemInfo, 0, sizeof( &itemInfo ) );
- itemInfo->registered = qtrue;
-
- itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
-
- itemInfo->icon = trap_R_RegisterShader( item->icon );
-
- if ( item->giType == IT_WEAPON ) {
- CG_RegisterWeapon( item->giTag );
- }
-
- //
- // powerups have an accompanying ring or sphere
- //
- if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH ||
- item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
- if ( item->world_model[1] ) {
- itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
- }
- }
-}
-
-
-/*
-========================================================================================
-
-VIEW WEAPON
-
-========================================================================================
-*/
-
-/*
-=================
-CG_MapTorsoToWeaponFrame
-
-=================
-*/
-static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
-
- // change weapon
- if ( frame >= ci->animations[TORSO_DROP].firstFrame
- && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {
- return frame - ci->animations[TORSO_DROP].firstFrame + 6;
- }
-
- // stand attack
- if ( frame >= ci->animations[TORSO_ATTACK].firstFrame
- && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;
- }
-
- // stand attack 2
- if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame
- && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {
- return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;
- }
-
- return 0;
-}
-
-
-/*
-==============
-CG_CalculateWeaponPosition
-==============
-*/
-static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
- float scale;
- int delta;
- float fracsin;
-
- VectorCopy( cg.refdef.vieworg, origin );
- VectorCopy( cg.refdefViewAngles, angles );
-
- // on odd legs, invert some angles
- if ( cg.bobcycle & 1 ) {
- scale = -cg.xyspeed;
- } else {
- scale = cg.xyspeed;
- }
-
- // gun angles from bobbing
- angles[ROLL] += scale * cg.bobfracsin * 0.005;
- angles[YAW] += scale * cg.bobfracsin * 0.01;
- angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
-
- // drop the weapon when landing
- delta = cg.time - cg.landTime;
- if ( delta < LAND_DEFLECT_TIME ) {
- origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
- } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
- origin[2] += cg.landChange*0.25 *
- (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
- }
-
-#if 0
- // drop the weapon when stair climbing
- delta = cg.time - cg.stepTime;
- if ( delta < STEP_TIME/2 ) {
- origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
- } else if ( delta < STEP_TIME ) {
- origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
- }
-#endif
-
- // idle drift
- scale = cg.xyspeed + 40;
- fracsin = sin( cg.time * 0.001 );
- angles[ROLL] += scale * fracsin * 0.01;
- angles[YAW] += scale * fracsin * 0.01;
- angles[PITCH] += scale * fracsin * 0.01;
-}
-
-
-/*
-===============
-CG_LightningBolt
-
-Origin will be the exact tag point, which is slightly
-different than the muzzle point used for determining hits.
-The cent should be the non-predicted cent if it is from the player,
-so the endpoint will reflect the simulated strike (lagging the predicted
-angle)
-===============
-*/
-static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
-
- if (cent->currentState.weapon != WP_LIGHTNING) {
- return;
- }
-
- memset( &beam, 0, sizeof( beam ) );
-
- // CPMA "true" lightning
- if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
- vec3_t angle;
- int i;
-
- for (i = 0; i < 3; i++) {
- float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
- if (a > 180) {
- a -= 360;
- }
- if (a < -180) {
- a += 360;
- }
-
- angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);
- if (angle[i] < 0) {
- angle[i] += 360;
- }
- if (angle[i] > 360) {
- angle[i] -= 360;
- }
- }
-
- AngleVectors(angle, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
-// VectorCopy(cg.refdef.vieworg, muzzlePoint );
- } else {
- // !CPMA
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
- VectorCopy(cent->lerpOrigin, muzzlePoint );
- }
-
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
-
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
-
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
-
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
-
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
-
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
-
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
-
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
-
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
-
- VectorMA( trace.endpos, -16, dir, beam.origin );
-
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
-}
-/*
-
-static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
- trace_t trace;
- refEntity_t beam;
- vec3_t forward;
- vec3_t muzzlePoint, endPoint;
-
- if ( cent->currentState.weapon != WP_LIGHTNING ) {
- return;
- }
-
- memset( &beam, 0, sizeof( beam ) );
-
- // find muzzle point for this frame
- VectorCopy( cent->lerpOrigin, muzzlePoint );
- AngleVectors( cent->lerpAngles, forward, NULL, NULL );
-
- // FIXME: crouch
- muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
-
- VectorMA( muzzlePoint, 14, forward, muzzlePoint );
-
- // project forward by the lightning range
- VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
-
- // see if it hit a wall
- CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
- cent->currentState.number, MASK_SHOT );
-
- // this is the endpoint
- VectorCopy( trace.endpos, beam.oldorigin );
-
- // use the provided origin, even though it may be slightly
- // different than the muzzle origin
- VectorCopy( origin, beam.origin );
-
- beam.reType = RT_LIGHTNING;
- beam.customShader = cgs.media.lightningShader;
- trap_R_AddRefEntityToScene( &beam );
-
- // add the impact flare if it hit something
- if ( trace.fraction < 1.0 ) {
- vec3_t angles;
- vec3_t dir;
-
- VectorSubtract( beam.oldorigin, beam.origin, dir );
- VectorNormalize( dir );
-
- memset( &beam, 0, sizeof( beam ) );
- beam.hModel = cgs.media.lightningExplosionModel;
-
- VectorMA( trace.endpos, -16, dir, beam.origin );
-
- // make a random orientation
- angles[0] = rand() % 360;
- angles[1] = rand() % 360;
- angles[2] = rand() % 360;
- AnglesToAxis( angles, beam.axis );
- trap_R_AddRefEntityToScene( &beam );
- }
-}
-*/
-
-/*
-===============
-CG_SpawnRailTrail
-
-Origin will be the exact tag point, which is slightly
-different than the muzzle point used for determining hits.
-===============
-*/
-static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {
- clientInfo_t *ci;
-
- if ( cent->currentState.weapon != WP_RAILGUN ) {
- return;
- }
- if ( !cent->pe.railgunFlash ) {
- return;
- }
- cent->pe.railgunFlash = qtrue;
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- CG_RailTrail( ci, origin, cent->pe.railgunImpact );
-}
-
-
-/*
-======================
-CG_MachinegunSpinAngle
-======================
-*/
-#define SPIN_SPEED 0.9
-#define COAST_TIME 1000
-static float CG_MachinegunSpinAngle( centity_t *cent ) {
- int delta;
- float angle;
- float speed;
-
- delta = cg.time - cent->pe.barrelTime;
- if ( cent->pe.barrelSpinning ) {
- angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
- } else {
- if ( delta > COAST_TIME ) {
- delta = COAST_TIME;
- }
-
- speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
- angle = cent->pe.barrelAngle + delta * speed;
- }
-
- if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
- cent->pe.barrelTime = cg.time;
- cent->pe.barrelAngle = AngleMod( angle );
- cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
-#ifdef MISSIONPACK
- if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) {
- trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) );
- }
-#endif
- }
-
- return angle;
-}
-
-
-/*
-========================
-CG_AddWeaponWithPowerups
-========================
-*/
-static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
- // add powerup effects
- if ( powerups & ( 1 << PW_INVIS ) ) {
- gun->customShader = cgs.media.invisShader;
- trap_R_AddRefEntityToScene( gun );
- } else {
- trap_R_AddRefEntityToScene( gun );
-
- if ( powerups & ( 1 << PW_BATTLESUIT ) ) {
- gun->customShader = cgs.media.battleWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- if ( powerups & ( 1 << PW_QUAD ) ) {
- gun->customShader = cgs.media.quadWeaponShader;
- trap_R_AddRefEntityToScene( gun );
- }
- }
-}
-
-
-/*
-=============
-CG_AddPlayerWeapon
-
-Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
-The main player will have this called for BOTH cases, so effects like light and
-sound should only be done on the world model case.
-=============
-*/
-void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) {
- refEntity_t gun;
- refEntity_t barrel;
- refEntity_t flash;
- vec3_t angles;
- weapon_t weaponNum;
- weaponInfo_t *weapon;
- centity_t *nonPredictedCent;
-// int col;
-
- weaponNum = cent->currentState.weapon;
-
- CG_RegisterWeapon( weaponNum );
- weapon = &cg_weapons[weaponNum];
-
- // add the weapon
- memset( &gun, 0, sizeof( gun ) );
- VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
- gun.shadowPlane = parent->shadowPlane;
- gun.renderfx = parent->renderfx;
-
- // set custom shading for railgun refire rate
- if ( ps ) {
- if ( cg.predictedPlayerState.weapon == WP_RAILGUN
- && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
- float f;
-
- f = (float)cg.predictedPlayerState.weaponTime / 1500;
- gun.shaderRGBA[1] = 0;
- gun.shaderRGBA[0] =
- gun.shaderRGBA[2] = 255 * ( 1.0 - f );
- } else {
- gun.shaderRGBA[0] = 255;
- gun.shaderRGBA[1] = 255;
- gun.shaderRGBA[2] = 255;
- gun.shaderRGBA[3] = 255;
- }
- }
-
- gun.hModel = weapon->weaponModel;
- if (!gun.hModel) {
- return;
- }
-
- if ( !ps ) {
- // add weapon ready sound
- cent->pe.lightningFiring = qfalse;
- if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
- // lightning gun and guantlet make a different sound when fire is held down
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
- cent->pe.lightningFiring = qtrue;
- } else if ( weapon->readySound ) {
- trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
- }
- }
-
- CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
-
- CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
-
- // add the spinning barrel
- if ( weapon->barrelModel ) {
- memset( &barrel, 0, sizeof( barrel ) );
- VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
- barrel.shadowPlane = parent->shadowPlane;
- barrel.renderfx = parent->renderfx;
-
- barrel.hModel = weapon->barrelModel;
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = CG_MachinegunSpinAngle( cent );
- AnglesToAxis( angles, barrel.axis );
-
- CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
-
- CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
- }
-
- // make sure we aren't looking at cg.predictedPlayerEntity for LG
- nonPredictedCent = &cg_entities[cent->currentState.clientNum];
-
- // if the index of the nonPredictedCent is not the same as the clientNum
- // then this is a fake player (like on teh single player podiums), so
- // go ahead and use the cent
- if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
- nonPredictedCent = cent;
- }
-
- // add the flash
- if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
- && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
- {
- // continuous flash
- } else {
- // impulse flash
- if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
- return;
- }
- }
-
- memset( &flash, 0, sizeof( flash ) );
- VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
- flash.shadowPlane = parent->shadowPlane;
- flash.renderfx = parent->renderfx;
-
- flash.hModel = weapon->flashModel;
- if (!flash.hModel) {
- return;
- }
- angles[YAW] = 0;
- angles[PITCH] = 0;
- angles[ROLL] = crandom() * 10;
- AnglesToAxis( angles, flash.axis );
-
- // colorize the railgun blast
- if ( weaponNum == WP_RAILGUN ) {
- clientInfo_t *ci;
-
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- flash.shaderRGBA[0] = 255 * ci->color1[0];
- flash.shaderRGBA[1] = 255 * ci->color1[1];
- flash.shaderRGBA[2] = 255 * ci->color1[2];
- }
-
- CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
- trap_R_AddRefEntityToScene( &flash );
-
- if ( ps || cg.renderingThirdPerson ||
- cent->currentState.number != cg.predictedPlayerState.clientNum ) {
- // add lightning bolt
- CG_LightningBolt( nonPredictedCent, flash.origin );
-
- // add rail trail
- CG_SpawnRailTrail( cent, flash.origin );
-
- if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
- trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0],
- weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
- }
- }
-}
-
-/*
-==============
-CG_AddViewWeapon
-
-Add the weapon, and flash for the player's view
-==============
-*/
-void CG_AddViewWeapon( playerState_t *ps ) {
- refEntity_t hand;
- centity_t *cent;
- clientInfo_t *ci;
- float fovOffset;
- vec3_t angles;
- weaponInfo_t *weapon;
-
- if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
- return;
- }
-
- if ( ps->pm_type == PM_INTERMISSION ) {
- return;
- }
-
- // no gun if in third person view or a camera is active
- //if ( cg.renderingThirdPerson || cg.cameraMode) {
- if ( cg.renderingThirdPerson ) {
- return;
- }
-
-
- // allow the gun to be completely removed
- if ( !cg_drawGun.integer ) {
- vec3_t origin;
-
- if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
- // special hack for lightning gun...
- VectorCopy( cg.refdef.vieworg, origin );
- VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
- CG_LightningBolt( &cg_entities[ps->clientNum], origin );
- }
- return;
- }
-
- // don't draw if testing a gun model
- if ( cg.testGun ) {
- return;
- }
-
- // drop gun lower at higher fov
- if ( cg_fov.integer > 90 ) {
- fovOffset = -0.2 * ( cg_fov.integer - 90 );
- } else {
- fovOffset = 0;
- }
-
- cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
- CG_RegisterWeapon( ps->weapon );
- weapon = &cg_weapons[ ps->weapon ];
-
- memset (&hand, 0, sizeof(hand));
-
- // set up gun position
- CG_CalculateWeaponPosition( hand.origin, angles );
-
- VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
- VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
- VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
-
- AnglesToAxis( angles, hand.axis );
-
- // map torso animations to weapon animations
- if ( cg_gun_frame.integer ) {
- // development tool
- hand.frame = hand.oldframe = cg_gun_frame.integer;
- hand.backlerp = 0;
- } else {
- // get clientinfo for animation map
- ci = &cgs.clientinfo[ cent->currentState.clientNum ];
- hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
- hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
- hand.backlerp = cent->pe.torso.backlerp;
- }
-
- hand.hModel = weapon->handsModel;
- hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
-
- // add everything onto the hand
- CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
-}
-
-/*
-==============================================================================
-
-WEAPON SELECTION
-
-==============================================================================
-*/
-
-/*
-===================
-CG_DrawWeaponSelect
-===================
-*/
-void CG_DrawWeaponSelect( void ) {
- int i;
- int bits;
- int count;
- int x, y, w;
- char *name;
- float *color;
-
- // don't display if dead
- if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
- return;
- }
-
- color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
- if ( !color ) {
- return;
- }
- trap_R_SetColor( color );
-
- // showing weapon select clears pickup item display, but not the blend blob
- cg.itemPickupTime = 0;
-
- // count the number of weapons owned
- bits = cg.snap->ps.stats[ STAT_WEAPONS ];
- count = 0;
- for ( i = 1 ; i < 16 ; i++ ) {
- if ( bits & ( 1 << i ) ) {
- count++;
- }
- }
-
- x = 320 - count * 20;
- y = 380;
-
- for ( i = 1 ; i < 16 ; i++ ) {
- if ( !( bits & ( 1 << i ) ) ) {
- continue;
- }
-
- CG_RegisterWeapon( i );
-
- // draw weapon icon
- CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
-
- // draw selection marker
- if ( i == cg.weaponSelect ) {
- CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
- }
-
- // no ammo cross on top
- if ( !cg.snap->ps.ammo[ i ] ) {
- CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
- }
-
- x += 40;
- }
-
- // draw the selected name
- if ( cg_weapons[ cg.weaponSelect ].item ) {
- name = cg_weapons[ cg.weaponSelect ].item->pickup_name;
- if ( name ) {
- w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
- x = ( SCREEN_WIDTH - w ) / 2;
- CG_DrawBigStringColor(x, y - 22, name, color);
- }
- }
-
- trap_R_SetColor( NULL );
-}
-
-
-/*
-===============
-CG_WeaponSelectable
-===============
-*/
-static qboolean CG_WeaponSelectable( int i ) {
- if ( !cg.snap->ps.ammo[i] ) {
- return qfalse;
- }
- if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-===============
-CG_NextWeapon_f
-===============
-*/
-void CG_NextWeapon_f( void ) {
- int i;
- int original;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
-
- for ( i = 0 ; i < 16 ; i++ ) {
- cg.weaponSelect++;
- if ( cg.weaponSelect == 16 ) {
- cg.weaponSelect = 0;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- }
- if ( i == 16 ) {
- cg.weaponSelect = original;
- }
-}
-
-/*
-===============
-CG_PrevWeapon_f
-===============
-*/
-void CG_PrevWeapon_f( void ) {
- int i;
- int original;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
- original = cg.weaponSelect;
-
- for ( i = 0 ; i < 16 ; i++ ) {
- cg.weaponSelect--;
- if ( cg.weaponSelect == -1 ) {
- cg.weaponSelect = 15;
- }
- if ( cg.weaponSelect == WP_GAUNTLET ) {
- continue; // never cycle to gauntlet
- }
- if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
- break;
- }
- }
- if ( i == 16 ) {
- cg.weaponSelect = original;
- }
-}
-
-/*
-===============
-CG_Weapon_f
-===============
-*/
-void CG_Weapon_f( void ) {
- int num;
-
- if ( !cg.snap ) {
- return;
- }
- if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
- return;
- }
-
- num = atoi( CG_Argv( 1 ) );
-
- if ( num < 1 || num > 15 ) {
- return;
- }
-
- cg.weaponSelectTime = cg.time;
-
- if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
- return; // don't have the weapon
- }
-
- cg.weaponSelect = num;
-}
-
-/*
-===================
-CG_OutOfAmmoChange
-
-The current weapon has just run out of ammo
-===================
-*/
-void CG_OutOfAmmoChange( void ) {
- int i;
-
- cg.weaponSelectTime = cg.time;
-
- for ( i = 15 ; i > 0 ; i-- ) {
- if ( CG_WeaponSelectable( i ) ) {
- cg.weaponSelect = i;
- break;
- }
- }
-}
-
-
-
-/*
-===================================================================================================
-
-WEAPON EVENTS
-
-===================================================================================================
-*/
-
-/*
-================
-CG_FireWeapon
-
-Caused by an EV_FIRE_WEAPON event
-================
-*/
-void CG_FireWeapon( centity_t *cent ) {
- entityState_t *ent;
- int c;
- weaponInfo_t *weap;
-
- ent = &cent->currentState;
- if ( ent->weapon == WP_NONE ) {
- return;
- }
- if ( ent->weapon >= WP_NUM_WEAPONS ) {
- CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
- return;
- }
- weap = &cg_weapons[ ent->weapon ];
-
- // mark the entity as muzzle flashing, so when it is added it will
- // append the flash to the weapon model
- cent->muzzleFlashTime = cg.time;
-
- // lightning gun only does this this on initial press
- if ( ent->weapon == WP_LIGHTNING ) {
- if ( cent->pe.lightningFiring ) {
- return;
- }
- }
-
- // play quad sound if needed
- if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
- trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
- }
-
- // play a sound
- for ( c = 0 ; c < 4 ; c++ ) {
- if ( !weap->flashSound[c] ) {
- break;
- }
- }
- if ( c > 0 ) {
- c = rand() % c;
- if ( weap->flashSound[c] )
- {
- trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
- }
- }
-
- // do brass ejection
- if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {
- weap->ejectBrassFunc( cent );
- }
-}
-
-
-/*
-=================
-CG_MissileHitWall
-
-Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
-=================
-*/
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {
- qhandle_t mod;
- qhandle_t mark;
- qhandle_t shader;
- sfxHandle_t sfx;
- float radius;
- float light;
- vec3_t lightColor;
- localEntity_t *le;
- int r;
- qboolean alphaFade;
- qboolean isSprite;
- int duration;
- vec3_t sprOrg;
- vec3_t sprVel;
-
- mark = 0;
- radius = 32;
- sfx = 0;
- mod = 0;
- shader = 0;
- light = 0;
- lightColor[0] = 1;
- lightColor[1] = 1;
- lightColor[2] = 0;
-
- // set defaults
- isSprite = qfalse;
- duration = 600;
-
- switch ( weapon ) {
- default:
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_nghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_nghitmetal;
- } else {
- sfx = cgs.media.sfx_nghit;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
-#endif
- case WP_LIGHTNING:
- // no explosion at LG impact, it is added with the beam
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_lghit2;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_lghit1;
- } else {
- sfx = cgs.media.sfx_lghit3;
- }
- mark = cgs.media.holeMarkShader;
- radius = 12;
- break;
-#ifdef MISSIONPACK
- case WP_PROX_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_proxexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
-#endif
- case WP_GRENADE_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.grenadeExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- break;
- case WP_ROCKET_LAUNCHER:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.rocketExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 64;
- light = 300;
- isSprite = qtrue;
- duration = 1000;
- lightColor[0] = 1;
- lightColor[1] = 0.75;
- lightColor[2] = 0.0;
- if (cg_oldRocket.integer == 0) {
- // explosion sprite animation
- VectorMA( origin, 24, dir, sprOrg );
- VectorScale( dir, 64, sprVel );
-
- CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
- }
- break;
- case WP_RAILGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.railExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 24;
- break;
- case WP_PLASMAGUN:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.plasmaExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 16;
- break;
- case WP_BFG:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.bfgExplosionShader;
- sfx = cgs.media.sfx_rockexp;
- mark = cgs.media.burnMarkShader;
- radius = 32;
- isSprite = qtrue;
- break;
- case WP_SHOTGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
- sfx = 0;
- radius = 4;
- break;
-
-#ifdef MISSIONPACK
- case WP_CHAINGUN:
- mod = cgs.media.bulletFlashModel;
- if( soundType == IMPACTSOUND_FLESH ) {
- sfx = cgs.media.sfx_chghitflesh;
- } else if( soundType == IMPACTSOUND_METAL ) {
- sfx = cgs.media.sfx_chghitmetal;
- } else {
- sfx = cgs.media.sfx_chghit;
- }
- mark = cgs.media.bulletMarkShader;
-
- r = rand() & 3;
- if ( r < 2 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 2 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
-
- radius = 8;
- break;
-#endif
-
- case WP_MACHINEGUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
-
- r = rand() & 3;
- if ( r == 0 ) {
- sfx = cgs.media.sfx_ric1;
- } else if ( r == 1 ) {
- sfx = cgs.media.sfx_ric2;
- } else {
- sfx = cgs.media.sfx_ric3;
- }
-
- radius = 8;
- break;
- }
-
- if ( sfx ) {
- trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
- }
-
- //
- // create the explosion
- //
- if ( mod ) {
- le = CG_MakeExplosion( origin, dir,
- mod, shader,
- duration, isSprite );
- le->light = light;
- VectorCopy( lightColor, le->lightColor );
- if ( weapon == WP_RAILGUN ) {
- // colorize with client color
- VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
- }
- }
-
- //
- // impact mark
- //
- alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
- if ( weapon == WP_RAILGUN ) {
- float *color;
-
- // colorize with client color
- color = cgs.clientinfo[clientNum].color2;
- CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
- } else {
- CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
- }
-}
-
-
-/*
-=================
-CG_MissileHitPlayer
-=================
-*/
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
- CG_Bleed( origin, entityNum );
-
- // some weapons will make an explosion with the blood, while
- // others will just make the blood
- switch ( weapon ) {
- case WP_GRENADE_LAUNCHER:
- case WP_ROCKET_LAUNCHER:
-#ifdef MISSIONPACK
- case WP_NAILGUN:
- case WP_CHAINGUN:
- case WP_PROX_LAUNCHER:
-#endif
- CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
- break;
- default:
- break;
- }
-}
-
-
-
-/*
-============================================================================
-
-SHOTGUN TRACING
-
-============================================================================
-*/
-
-/*
-================
-CG_ShotgunPellet
-================
-*/
-static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
- trace_t tr;
- int sourceContentType, destContentType;
-
- CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
-
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( tr.endpos, 0 );
-
- // FIXME: should probably move this cruft into CG_BubbleTrail
- if ( sourceContentType == destContentType ) {
- if ( sourceContentType & CONTENTS_WATER ) {
- CG_BubbleTrail( start, tr.endpos, 32 );
- }
- } else if ( sourceContentType & CONTENTS_WATER ) {
- trace_t trace;
-
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
- } else if ( destContentType & CONTENTS_WATER ) {
- trace_t trace;
-
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
- }
-
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- return;
- }
-
- if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
- CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
- } else {
- if ( tr.surfaceFlags & SURF_NOIMPACT ) {
- // SURF_NOIMPACT will not make a flame puff or a mark
- return;
- }
- if ( tr.surfaceFlags & SURF_METALSTEPS ) {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
- } else {
- CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
- }
- }
-}
-
-/*
-================
-CG_ShotgunPattern
-
-Perform the same traces the server did to locate the
-hit splashes
-================
-*/
-static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
- int i;
- float r, u;
- vec3_t end;
- vec3_t forward, right, up;
-
- // derive the right and up vectors from the forward vector, because
- // the client won't have any other information
- VectorNormalize2( origin2, forward );
- PerpendicularVector( right, forward );
- CrossProduct( forward, right, up );
-
- // generate the "random" spread pattern
- for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
- r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
- VectorMA( origin, 8192 * 16, forward, end);
- VectorMA (end, r, right, end);
- VectorMA (end, u, up, end);
-
- CG_ShotgunPellet( origin, end, otherEntNum );
- }
-}
-
-/*
-==============
-CG_ShotgunFire
-==============
-*/
-void CG_ShotgunFire( entityState_t *es ) {
- vec3_t v;
- int contents;
-
- VectorSubtract( es->origin2, es->pos.trBase, v );
- VectorNormalize( v );
- VectorScale( v, 32, v );
- VectorAdd( es->pos.trBase, v, v );
- if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
- // ragepro can't alpha fade, so don't even bother with smoke
- vec3_t up;
-
- contents = trap_CM_PointContents( es->pos.trBase, 0 );
- if ( !( contents & CONTENTS_WATER ) ) {
- VectorSet( up, 0, 0, 8 );
- CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
- }
- }
- CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
-}
-
-/*
-============================================================================
-
-BULLETS
-
-============================================================================
-*/
-
-
-/*
-===============
-CG_Tracer
-===============
-*/
-void CG_Tracer( vec3_t source, vec3_t dest ) {
- vec3_t forward, right;
- polyVert_t verts[4];
- vec3_t line;
- float len, begin, end;
- vec3_t start, finish;
- vec3_t midpoint;
-
- // tracer
- VectorSubtract( dest, source, forward );
- len = VectorNormalize( forward );
-
- // start at least a little ways from the muzzle
- if ( len < 100 ) {
- return;
- }
- begin = 50 + random() * (len - 60);
- end = begin + cg_tracerLength.value;
- if ( end > len ) {
- end = len;
- }
- VectorMA( source, begin, forward, start );
- VectorMA( source, end, forward, finish );
-
- line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
- line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
-
- VectorScale( cg.refdef.viewaxis[1], line[1], right );
- VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
- VectorNormalize( right );
-
- VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
- verts[0].st[0] = 0;
- verts[0].st[1] = 1;
- verts[0].modulate[0] = 255;
- verts[0].modulate[1] = 255;
- verts[0].modulate[2] = 255;
- verts[0].modulate[3] = 255;
-
- VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
- verts[1].st[0] = 1;
- verts[1].st[1] = 0;
- verts[1].modulate[0] = 255;
- verts[1].modulate[1] = 255;
- verts[1].modulate[2] = 255;
- verts[1].modulate[3] = 255;
-
- VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
- verts[2].st[0] = 1;
- verts[2].st[1] = 1;
- verts[2].modulate[0] = 255;
- verts[2].modulate[1] = 255;
- verts[2].modulate[2] = 255;
- verts[2].modulate[3] = 255;
-
- VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
- verts[3].st[0] = 0;
- verts[3].st[1] = 0;
- verts[3].modulate[0] = 255;
- verts[3].modulate[1] = 255;
- verts[3].modulate[2] = 255;
- verts[3].modulate[3] = 255;
-
- trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
-
- midpoint[0] = ( start[0] + finish[0] ) * 0.5;
- midpoint[1] = ( start[1] + finish[1] ) * 0.5;
- midpoint[2] = ( start[2] + finish[2] ) * 0.5;
-
- // add the tracer sound
- trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
-
-}
-
-
-/*
-======================
-CG_CalcMuzzlePoint
-======================
-*/
-static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
- vec3_t forward;
- centity_t *cent;
- int anim;
-
- if ( entityNum == cg.snap->ps.clientNum ) {
- VectorCopy( cg.snap->ps.origin, muzzle );
- muzzle[2] += cg.snap->ps.viewheight;
- AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
- VectorMA( muzzle, 14, forward, muzzle );
- return qtrue;
- }
-
- cent = &cg_entities[entityNum];
- if ( !cent->currentValid ) {
- return qfalse;
- }
-
- VectorCopy( cent->currentState.pos.trBase, muzzle );
-
- AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
- anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
- if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
- muzzle[2] += CROUCH_VIEWHEIGHT;
- } else {
- muzzle[2] += DEFAULT_VIEWHEIGHT;
- }
-
- VectorMA( muzzle, 14, forward, muzzle );
-
- return qtrue;
-
-}
-
-/*
-======================
-CG_Bullet
-
-Renders bullet effects.
-======================
-*/
-void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
- trace_t trace;
- int sourceContentType, destContentType;
- vec3_t start;
-
- // if the shooter is currently valid, calc a source point and possibly
- // do trail effects
- if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
- if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
- sourceContentType = trap_CM_PointContents( start, 0 );
- destContentType = trap_CM_PointContents( end, 0 );
-
- // do a complete bubble trail if necessary
- if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
- CG_BubbleTrail( start, end, 32 );
- }
- // bubble trail from water into air
- else if ( ( sourceContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( start, trace.endpos, 32 );
- }
- // bubble trail from air into water
- else if ( ( destContentType & CONTENTS_WATER ) ) {
- trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
- CG_BubbleTrail( trace.endpos, end, 32 );
- }
-
- // draw a tracer
- if ( random() < cg_tracerChance.value ) {
- CG_Tracer( start, end );
- }
- }
- }
-
- // impact splash and mark
- if ( flesh ) {
- CG_Bleed( end, fleshEntityNum );
- } else {
- CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
- }
-
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+// cg_weapons.c -- events and effects dealing with weapons
+#include "cg_local.h"
+
+/*
+==========================
+CG_MachineGunEjectBrass
+==========================
+*/
+static void CG_MachineGunEjectBrass( centity_t *cent ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t velocity, xvelocity;
+ vec3_t offset, xoffset;
+ float waterScale = 1.0f;
+ vec3_t v[3];
+
+ if ( cg_brassTime.integer <= 0 ) {
+ return;
+ }
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ velocity[0] = 0;
+ velocity[1] = -50 + 40 * crandom();
+ velocity[2] = 100 + 50 * crandom();
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
+
+ le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time - (rand()&15);
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 8;
+ offset[1] = -4;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, re->origin );
+
+ VectorCopy( re->origin, le->pos.trBase );
+
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = cgs.media.machinegunBrassModel;
+
+ le->bounceFactor = 0.4 * waterScale;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 2;
+ le->angles.trDelta[1] = 1;
+ le->angles.trDelta[2] = 0;
+
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_BRASS;
+ le->leMarkType = LEMT_NONE;
+}
+
+/*
+==========================
+CG_ShotgunEjectBrass
+==========================
+*/
+static void CG_ShotgunEjectBrass( centity_t *cent ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ vec3_t velocity, xvelocity;
+ vec3_t offset, xoffset;
+ vec3_t v[3];
+ int i;
+
+ if ( cg_brassTime.integer <= 0 ) {
+ return;
+ }
+
+ for ( i = 0; i < 2; i++ ) {
+ float waterScale = 1.0f;
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ velocity[0] = 60 + 60 * crandom();
+ if ( i == 0 ) {
+ velocity[1] = 40 + 10 * crandom();
+ } else {
+ velocity[1] = -40 + 10 * crandom();
+ }
+ velocity[2] = 100 + 50 * crandom();
+
+ le->leType = LE_FRAGMENT;
+ le->startTime = cg.time;
+ le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
+
+ le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time;
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 8;
+ offset[1] = 0;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, re->origin );
+ VectorCopy( re->origin, le->pos.trBase );
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ AxisCopy( axisDefault, re->axis );
+ re->hModel = cgs.media.shotgunBrassModel;
+ le->bounceFactor = 0.3f;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 1;
+ le->angles.trDelta[1] = 0.5;
+ le->angles.trDelta[2] = 0;
+
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_BRASS;
+ le->leMarkType = LEMT_NONE;
+ }
+}
+
+
+#ifdef MISSIONPACK
+/*
+==========================
+CG_NailgunEjectBrass
+==========================
+*/
+static void CG_NailgunEjectBrass( centity_t *cent ) {
+ localEntity_t *smoke;
+ vec3_t origin;
+ vec3_t v[3];
+ vec3_t offset;
+ vec3_t xoffset;
+ vec3_t up;
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 0;
+ offset[1] = -12;
+ offset[2] = 24;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+ VectorAdd( cent->lerpOrigin, xoffset, origin );
+
+ VectorSet( up, 0, 0, 64 );
+
+ smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+}
+#endif
+
+
+/*
+==========================
+CG_RailTrail
+==========================
+*/
+void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
+ vec3_t axis[36], move, move2, next_move, vec, temp;
+ float len;
+ int i, j, skip;
+
+ localEntity_t *le;
+ refEntity_t *re;
+
+#define RADIUS 4
+#define ROTATION 1
+#define SPACING 5
+
+ start[2] -= 4;
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+ PerpendicularVector(temp, vec);
+ for (i = 0 ; i < 36; i++) {
+ RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
+ }
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ le->leType = LE_FADE_RGB;
+ le->startTime = cg.time;
+ le->endTime = cg.time + cg_railTrailTime.value;
+ le->lifeRate = 1.0 / (le->endTime - le->startTime);
+
+ re->shaderTime = cg.time / 1000.0f;
+ re->reType = RT_RAIL_CORE;
+ re->customShader = cgs.media.railCoreShader;
+
+ VectorCopy(start, re->origin);
+ VectorCopy(end, re->oldorigin);
+
+ re->shaderRGBA[0] = ci->color1[0] * 255;
+ re->shaderRGBA[1] = ci->color1[1] * 255;
+ re->shaderRGBA[2] = ci->color1[2] * 255;
+ re->shaderRGBA[3] = 255;
+
+ le->color[0] = ci->color1[0] * 0.75;
+ le->color[1] = ci->color1[1] * 0.75;
+ le->color[2] = ci->color1[2] * 0.75;
+ le->color[3] = 1.0f;
+
+ AxisClear( re->axis );
+
+ VectorMA(move, 20, vec, move);
+ VectorCopy(move, next_move);
+ VectorScale (vec, SPACING, vec);
+
+ if (cg_oldRail.integer != 0) {
+ // nudge down a bit so it isn't exactly in center
+ re->origin[2] -= 8;
+ re->oldorigin[2] -= 8;
+ return;
+ }
+ skip = -1;
+
+ j = 18;
+ for (i = 0; i < len; i += SPACING) {
+ if (i != skip) {
+ skip = i + SPACING;
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+ le->leFlags = LEF_PUFF_DONT_SCALE;
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->startTime = cg.time;
+ le->endTime = cg.time + (i>>1) + 600;
+ le->lifeRate = 1.0 / (le->endTime - le->startTime);
+
+ re->shaderTime = cg.time / 1000.0f;
+ re->reType = RT_SPRITE;
+ re->radius = 1.1f;
+ re->customShader = cgs.media.railRingsShader;
+
+ re->shaderRGBA[0] = ci->color2[0] * 255;
+ re->shaderRGBA[1] = ci->color2[1] * 255;
+ re->shaderRGBA[2] = ci->color2[2] * 255;
+ re->shaderRGBA[3] = 255;
+
+ le->color[0] = ci->color2[0] * 0.75;
+ le->color[1] = ci->color2[1] * 0.75;
+ le->color[2] = ci->color2[2] * 0.75;
+ le->color[3] = 1.0f;
+
+ le->pos.trType = TR_LINEAR;
+ le->pos.trTime = cg.time;
+
+ VectorCopy( move, move2);
+ VectorMA(move2, RADIUS , axis[j], move2);
+ VectorCopy(move2, le->pos.trBase);
+
+ le->pos.trDelta[0] = axis[j][0]*6;
+ le->pos.trDelta[1] = axis[j][1]*6;
+ le->pos.trDelta[2] = axis[j][2]*6;
+ }
+
+ VectorAdd (move, vec, move);
+
+ j = j + ROTATION < 36 ? j + ROTATION : (j + ROTATION) % 36;
+ }
+}
+
+/*
+==========================
+CG_RocketTrail
+==========================
+*/
+static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ int step;
+ vec3_t origin, lastPos;
+ int t;
+ int startTime, contents;
+ int lastContents;
+ entityState_t *es;
+ vec3_t up;
+ localEntity_t *smoke;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 0;
+
+ step = 50;
+
+ es = &ent->currentState;
+ startTime = ent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ contents = CG_PointContents( origin, -1 );
+
+ // if object (e.g. grenade) is stationary, don't toss up smoke
+ if ( es->pos.trType == TR_STATIONARY ) {
+ ent->trailTime = cg.time;
+ return;
+ }
+
+ BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
+ lastContents = CG_PointContents( lastPos, -1 );
+
+ ent->trailTime = cg.time;
+
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ if ( contents & lastContents & CONTENTS_WATER ) {
+ CG_BubbleTrail( lastPos, origin, 8 );
+ }
+ return;
+ }
+
+ for ( ; t <= ent->trailTime ; t += step ) {
+ BG_EvaluateTrajectory( &es->pos, t, lastPos );
+
+ smoke = CG_SmokePuff( lastPos, up,
+ wi->trailRadius,
+ 1, 1, 1, 0.33f,
+ wi->wiTrailTime,
+ t,
+ 0,
+ 0,
+ cgs.media.smokePuffShader );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+ }
+
+}
+
+#ifdef MISSIONPACK
+/*
+==========================
+CG_NailTrail
+==========================
+*/
+static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ int step;
+ vec3_t origin, lastPos;
+ int t;
+ int startTime, contents;
+ int lastContents;
+ entityState_t *es;
+ vec3_t up;
+ localEntity_t *smoke;
+
+ if ( cg_noProjectileTrail.integer ) {
+ return;
+ }
+
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 0;
+
+ step = 50;
+
+ es = &ent->currentState;
+ startTime = ent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ contents = CG_PointContents( origin, -1 );
+
+ // if object (e.g. grenade) is stationary, don't toss up smoke
+ if ( es->pos.trType == TR_STATIONARY ) {
+ ent->trailTime = cg.time;
+ return;
+ }
+
+ BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
+ lastContents = CG_PointContents( lastPos, -1 );
+
+ ent->trailTime = cg.time;
+
+ if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
+ if ( contents & lastContents & CONTENTS_WATER ) {
+ CG_BubbleTrail( lastPos, origin, 8 );
+ }
+ return;
+ }
+
+ for ( ; t <= ent->trailTime ; t += step ) {
+ BG_EvaluateTrajectory( &es->pos, t, lastPos );
+
+ smoke = CG_SmokePuff( lastPos, up,
+ wi->trailRadius,
+ 1, 1, 1, 0.33f,
+ wi->wiTrailTime,
+ t,
+ 0,
+ 0,
+ cgs.media.nailPuffShader );
+ // use the optimized local entity add
+ smoke->leType = LE_SCALE_FADE;
+ }
+
+}
+#endif
+
+/*
+==========================
+CG_NailTrail
+==========================
+*/
+static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) {
+ localEntity_t *le;
+ refEntity_t *re;
+ entityState_t *es;
+ vec3_t velocity, xvelocity, origin;
+ vec3_t offset, xoffset;
+ vec3_t v[3];
+ int t, startTime, step;
+
+ float waterScale = 1.0f;
+
+ if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) {
+ return;
+ }
+
+ step = 50;
+
+ es = &cent->currentState;
+ startTime = cent->trailTime;
+ t = step * ( (startTime + step) / step );
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+
+ le = CG_AllocLocalEntity();
+ re = &le->refEntity;
+
+ velocity[0] = 60 - 120 * crandom();
+ velocity[1] = 40 - 80 * crandom();
+ velocity[2] = 100 - 200 * crandom();
+
+ le->leType = LE_MOVE_SCALE_FADE;
+ le->leFlags = LEF_TUMBLE;
+ le->leBounceSoundType = LEBS_NONE;
+ le->leMarkType = LEMT_NONE;
+
+ le->startTime = cg.time;
+ le->endTime = le->startTime + 600;
+
+ le->pos.trType = TR_GRAVITY;
+ le->pos.trTime = cg.time;
+
+ AnglesToAxis( cent->lerpAngles, v );
+
+ offset[0] = 2;
+ offset[1] = 2;
+ offset[2] = 2;
+
+ xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
+ xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
+ xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
+
+ VectorAdd( origin, xoffset, re->origin );
+ VectorCopy( re->origin, le->pos.trBase );
+
+ if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
+ waterScale = 0.10f;
+ }
+
+ xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
+ xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
+ xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
+ VectorScale( xvelocity, waterScale, le->pos.trDelta );
+
+ AxisCopy( axisDefault, re->axis );
+ re->shaderTime = cg.time / 1000.0f;
+ re->reType = RT_SPRITE;
+ re->radius = 0.25f;
+ re->customShader = cgs.media.railRingsShader;
+ le->bounceFactor = 0.3f;
+
+ re->shaderRGBA[0] = wi->flashDlightColor[0] * 63;
+ re->shaderRGBA[1] = wi->flashDlightColor[1] * 63;
+ re->shaderRGBA[2] = wi->flashDlightColor[2] * 63;
+ re->shaderRGBA[3] = 63;
+
+ le->color[0] = wi->flashDlightColor[0] * 0.2;
+ le->color[1] = wi->flashDlightColor[1] * 0.2;
+ le->color[2] = wi->flashDlightColor[2] * 0.2;
+ le->color[3] = 0.25f;
+
+ le->angles.trType = TR_LINEAR;
+ le->angles.trTime = cg.time;
+ le->angles.trBase[0] = rand()&31;
+ le->angles.trBase[1] = rand()&31;
+ le->angles.trBase[2] = rand()&31;
+ le->angles.trDelta[0] = 1;
+ le->angles.trDelta[1] = 0.5;
+ le->angles.trDelta[2] = 0;
+
+}
+/*
+==========================
+CG_GrappleTrail
+==========================
+*/
+void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ vec3_t origin;
+ entityState_t *es;
+ vec3_t forward, up;
+ refEntity_t beam;
+
+ es = &ent->currentState;
+
+ BG_EvaluateTrajectory( &es->pos, cg.time, origin );
+ ent->trailTime = cg.time;
+
+ memset( &beam, 0, sizeof( beam ) );
+ //FIXME adjust for muzzle position
+ VectorCopy ( cg_entities[ ent->currentState.otherEntityNum ].lerpOrigin, beam.origin );
+ beam.origin[2] += 26;
+ AngleVectors( cg_entities[ ent->currentState.otherEntityNum ].lerpAngles, forward, NULL, up );
+ VectorMA( beam.origin, -6, up, beam.origin );
+ VectorCopy( origin, beam.oldorigin );
+
+ if (Distance( beam.origin, beam.oldorigin ) < 64 )
+ return; // Don't draw if close
+
+ beam.reType = RT_LIGHTNING;
+ beam.customShader = cgs.media.lightningShader;
+
+ AxisClear( beam.axis );
+ beam.shaderRGBA[0] = 0xff;
+ beam.shaderRGBA[1] = 0xff;
+ beam.shaderRGBA[2] = 0xff;
+ beam.shaderRGBA[3] = 0xff;
+ trap_R_AddRefEntityToScene( &beam );
+}
+
+/*
+==========================
+CG_GrenadeTrail
+==========================
+*/
+static void CG_GrenadeTrail( centity_t *ent, const weaponInfo_t *wi ) {
+ CG_RocketTrail( ent, wi );
+}
+
+
+/*
+=================
+CG_RegisterWeapon
+
+The server says this item is used on this level
+=================
+*/
+void CG_RegisterWeapon( int weaponNum ) {
+ weaponInfo_t *weaponInfo;
+ gitem_t *item, *ammo;
+ char path[MAX_QPATH];
+ vec3_t mins, maxs;
+ int i;
+
+ weaponInfo = &cg_weapons[weaponNum];
+
+ if ( weaponNum == 0 ) {
+ return;
+ }
+
+ if ( weaponInfo->registered ) {
+ return;
+ }
+
+ memset( weaponInfo, 0, sizeof( *weaponInfo ) );
+ weaponInfo->registered = qtrue;
+
+ for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
+ if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
+ weaponInfo->item = item;
+ break;
+ }
+ }
+ if ( !item->classname ) {
+ CG_Error( "Couldn't find weapon %i", weaponNum );
+ }
+ CG_RegisterItemVisuals( item - bg_itemlist );
+
+ // load cmodel before model so filecache works
+ weaponInfo->weaponModel = trap_R_RegisterModel( item->world_model[0] );
+
+ // calc midpoint for rotation
+ trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
+ for ( i = 0 ; i < 3 ; i++ ) {
+ weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
+ }
+
+ weaponInfo->weaponIcon = trap_R_RegisterShader( item->icon );
+ weaponInfo->ammoIcon = trap_R_RegisterShader( item->icon );
+
+ for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
+ if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) {
+ break;
+ }
+ }
+ if ( ammo->classname && ammo->world_model[0] ) {
+ weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] );
+ }
+
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension( path, path );
+ strcat( path, "_flash.md3" );
+ weaponInfo->flashModel = trap_R_RegisterModel( path );
+
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension( path, path );
+ strcat( path, "_barrel.md3" );
+ weaponInfo->barrelModel = trap_R_RegisterModel( path );
+
+ strcpy( path, item->world_model[0] );
+ COM_StripExtension( path, path );
+ strcat( path, "_hand.md3" );
+ weaponInfo->handsModel = trap_R_RegisterModel( path );
+
+ if ( !weaponInfo->handsModel ) {
+ weaponInfo->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" );
+ }
+
+ weaponInfo->loopFireSound = qfalse;
+
+ switch ( weaponNum ) {
+ case WP_GAUNTLET:
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse );
+ break;
+
+ case WP_LIGHTNING:
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/lightning/lg_hum.wav", qfalse );
+
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
+ cgs.media.lightningShader = trap_R_RegisterShader( "lightningBoltNew");
+ cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
+ cgs.media.sfx_lghit1 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit.wav", qfalse );
+ cgs.media.sfx_lghit2 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit2.wav", qfalse );
+ cgs.media.sfx_lghit3 = trap_S_RegisterSound( "sound/weapons/lightning/lg_hit3.wav", qfalse );
+
+ break;
+
+ case WP_GRAPPLING_HOOK:
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
+ weaponInfo->missileTrailFunc = CG_GrappleTrail;
+ weaponInfo->missileDlight = 200;
+ weaponInfo->wiTrailTime = 2000;
+ weaponInfo->trailRadius = 64;
+ MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/melee/fsthum.wav", qfalse );
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/melee/fstrun.wav", qfalse );
+ break;
+
+#ifdef MISSIONPACK
+ case WP_CHAINGUN:
+ weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/vulcan/wvulfire.wav", qfalse );
+ weaponInfo->loopFireSound = qtrue;
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf1b.wav", qfalse );
+ weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf2b.wav", qfalse );
+ weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf3b.wav", qfalse );
+ weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/vulcan/vulcanf4b.wav", qfalse );
+ weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
+ cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
+ break;
+#endif
+
+ case WP_MACHINEGUN:
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf1b.wav", qfalse );
+ weaponInfo->flashSound[1] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf2b.wav", qfalse );
+ weaponInfo->flashSound[2] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf3b.wav", qfalse );
+ weaponInfo->flashSound[3] = trap_S_RegisterSound( "sound/weapons/machinegun/machgf4b.wav", qfalse );
+ weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;
+ cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
+ break;
+
+ case WP_SHOTGUN:
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/shotgun/sshotf1b.wav", qfalse );
+ weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass;
+ break;
+
+ case WP_ROCKET_LAUNCHER:
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/rocket/rocket.md3" );
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
+ weaponInfo->missileTrailFunc = CG_RocketTrail;
+ weaponInfo->missileDlight = 200;
+ weaponInfo->wiTrailTime = 2000;
+ weaponInfo->trailRadius = 64;
+
+ MAKERGB( weaponInfo->missileDlightColor, 1, 0.75f, 0 );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
+
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
+ cgs.media.rocketExplosionShader = trap_R_RegisterShader( "rocketExplosion" );
+ break;
+
+#ifdef MISSIONPACK
+ case WP_PROX_LAUNCHER:
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/proxmine.md3" );
+ weaponInfo->missileTrailFunc = CG_GrenadeTrail;
+ weaponInfo->wiTrailTime = 700;
+ weaponInfo->trailRadius = 32;
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/proxmine/wstbfire.wav", qfalse );
+ cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
+ break;
+#endif
+
+ case WP_GRENADE_LAUNCHER:
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/ammo/grenade1.md3" );
+ weaponInfo->missileTrailFunc = CG_GrenadeTrail;
+ weaponInfo->wiTrailTime = 700;
+ weaponInfo->trailRadius = 32;
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.70f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/grenade/grenlf1a.wav", qfalse );
+ cgs.media.grenadeExplosionShader = trap_R_RegisterShader( "grenadeExplosion" );
+ break;
+
+#ifdef MISSIONPACK
+ case WP_NAILGUN:
+ weaponInfo->ejectBrassFunc = CG_NailgunEjectBrass;
+ weaponInfo->missileTrailFunc = CG_NailTrail;
+// weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/nailgun/wnalflit.wav", qfalse );
+ weaponInfo->trailRadius = 16;
+ weaponInfo->wiTrailTime = 250;
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/nail.md3" );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.75f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/nailgun/wnalfire.wav", qfalse );
+ break;
+#endif
+
+ case WP_PLASMAGUN:
+// weaponInfo->missileModel = cgs.media.invulnerabilityPowerupModel;
+ weaponInfo->missileTrailFunc = CG_PlasmaTrail;
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse );
+ MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/hyprbf1a.wav", qfalse );
+ cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
+ cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
+ break;
+
+ case WP_RAILGUN:
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/railgun/rg_hum.wav", qfalse );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.5f, 0 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/railgun/railgf1a.wav", qfalse );
+ cgs.media.railExplosionShader = trap_R_RegisterShader( "railExplosion" );
+ cgs.media.railRingsShader = trap_R_RegisterShader( "railDisc" );
+ cgs.media.railCoreShader = trap_R_RegisterShader( "railCore" );
+ break;
+
+ case WP_BFG:
+ weaponInfo->readySound = trap_S_RegisterSound( "sound/weapons/bfg/bfg_hum.wav", qfalse );
+ MAKERGB( weaponInfo->flashDlightColor, 1, 0.7f, 1 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/bfg/bfg_fire.wav", qfalse );
+ cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
+ weaponInfo->missileModel = trap_R_RegisterModel( "models/weaphits/bfg.md3" );
+ weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/rocket/rockfly.wav", qfalse );
+ break;
+
+ default:
+ MAKERGB( weaponInfo->flashDlightColor, 1, 1, 1 );
+ weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/rocket/rocklf1a.wav", qfalse );
+ break;
+ }
+}
+
+/*
+=================
+CG_RegisterItemVisuals
+
+The server says this item is used on this level
+=================
+*/
+void CG_RegisterItemVisuals( int itemNum ) {
+ itemInfo_t *itemInfo;
+ gitem_t *item;
+
+ if ( itemNum < 0 || itemNum >= bg_numItems ) {
+ CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
+ }
+
+ itemInfo = &cg_items[ itemNum ];
+ if ( itemInfo->registered ) {
+ return;
+ }
+
+ item = &bg_itemlist[ itemNum ];
+
+ memset( itemInfo, 0, sizeof( &itemInfo ) );
+ itemInfo->registered = qtrue;
+
+ itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
+
+ itemInfo->icon = trap_R_RegisterShader( item->icon );
+
+ if ( item->giType == IT_WEAPON ) {
+ CG_RegisterWeapon( item->giTag );
+ }
+
+ //
+ // powerups have an accompanying ring or sphere
+ //
+ if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH ||
+ item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
+ if ( item->world_model[1] ) {
+ itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
+ }
+ }
+}
+
+
+/*
+========================================================================================
+
+VIEW WEAPON
+
+========================================================================================
+*/
+
+/*
+=================
+CG_MapTorsoToWeaponFrame
+
+=================
+*/
+static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) {
+
+ // change weapon
+ if ( frame >= ci->animations[TORSO_DROP].firstFrame
+ && frame < ci->animations[TORSO_DROP].firstFrame + 9 ) {
+ return frame - ci->animations[TORSO_DROP].firstFrame + 6;
+ }
+
+ // stand attack
+ if ( frame >= ci->animations[TORSO_ATTACK].firstFrame
+ && frame < ci->animations[TORSO_ATTACK].firstFrame + 6 ) {
+ return 1 + frame - ci->animations[TORSO_ATTACK].firstFrame;
+ }
+
+ // stand attack 2
+ if ( frame >= ci->animations[TORSO_ATTACK2].firstFrame
+ && frame < ci->animations[TORSO_ATTACK2].firstFrame + 6 ) {
+ return 1 + frame - ci->animations[TORSO_ATTACK2].firstFrame;
+ }
+
+ return 0;
+}
+
+
+/*
+==============
+CG_CalculateWeaponPosition
+==============
+*/
+static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
+ float scale;
+ int delta;
+ float fracsin;
+
+ VectorCopy( cg.refdef.vieworg, origin );
+ VectorCopy( cg.refdefViewAngles, angles );
+
+ // on odd legs, invert some angles
+ if ( cg.bobcycle & 1 ) {
+ scale = -cg.xyspeed;
+ } else {
+ scale = cg.xyspeed;
+ }
+
+ // gun angles from bobbing
+ angles[ROLL] += scale * cg.bobfracsin * 0.005;
+ angles[YAW] += scale * cg.bobfracsin * 0.01;
+ angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
+
+ // drop the weapon when landing
+ delta = cg.time - cg.landTime;
+ if ( delta < LAND_DEFLECT_TIME ) {
+ origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
+ } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
+ origin[2] += cg.landChange*0.25 *
+ (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
+ }
+
+#if 0
+ // drop the weapon when stair climbing
+ delta = cg.time - cg.stepTime;
+ if ( delta < STEP_TIME/2 ) {
+ origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
+ } else if ( delta < STEP_TIME ) {
+ origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
+ }
+#endif
+
+ // idle drift
+ scale = cg.xyspeed + 40;
+ fracsin = sin( cg.time * 0.001 );
+ angles[ROLL] += scale * fracsin * 0.01;
+ angles[YAW] += scale * fracsin * 0.01;
+ angles[PITCH] += scale * fracsin * 0.01;
+}
+
+
+/*
+===============
+CG_LightningBolt
+
+Origin will be the exact tag point, which is slightly
+different than the muzzle point used for determining hits.
+The cent should be the non-predicted cent if it is from the player,
+so the endpoint will reflect the simulated strike (lagging the predicted
+angle)
+===============
+*/
+static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
+ trace_t trace;
+ refEntity_t beam;
+ vec3_t forward;
+ vec3_t muzzlePoint, endPoint;
+
+ if (cent->currentState.weapon != WP_LIGHTNING) {
+ return;
+ }
+
+ memset( &beam, 0, sizeof( beam ) );
+
+ // CPMA "true" lightning
+ if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
+ vec3_t angle;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
+ if (a > 180) {
+ a -= 360;
+ }
+ if (a < -180) {
+ a += 360;
+ }
+
+ angle[i] = cg.refdefViewAngles[i] + a * (1.0 - cg_trueLightning.value);
+ if (angle[i] < 0) {
+ angle[i] += 360;
+ }
+ if (angle[i] > 360) {
+ angle[i] -= 360;
+ }
+ }
+
+ AngleVectors(angle, forward, NULL, NULL );
+ VectorCopy(cent->lerpOrigin, muzzlePoint );
+// VectorCopy(cg.refdef.vieworg, muzzlePoint );
+ } else {
+ // !CPMA
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
+ VectorCopy(cent->lerpOrigin, muzzlePoint );
+ }
+
+ // FIXME: crouch
+ muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
+
+ VectorMA( muzzlePoint, 14, forward, muzzlePoint );
+
+ // project forward by the lightning range
+ VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
+
+ // see if it hit a wall
+ CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
+ cent->currentState.number, MASK_SHOT );
+
+ // this is the endpoint
+ VectorCopy( trace.endpos, beam.oldorigin );
+
+ // use the provided origin, even though it may be slightly
+ // different than the muzzle origin
+ VectorCopy( origin, beam.origin );
+
+ beam.reType = RT_LIGHTNING;
+ beam.customShader = cgs.media.lightningShader;
+ trap_R_AddRefEntityToScene( &beam );
+
+ // add the impact flare if it hit something
+ if ( trace.fraction < 1.0 ) {
+ vec3_t angles;
+ vec3_t dir;
+
+ VectorSubtract( beam.oldorigin, beam.origin, dir );
+ VectorNormalize( dir );
+
+ memset( &beam, 0, sizeof( beam ) );
+ beam.hModel = cgs.media.lightningExplosionModel;
+
+ VectorMA( trace.endpos, -16, dir, beam.origin );
+
+ // make a random orientation
+ angles[0] = rand() % 360;
+ angles[1] = rand() % 360;
+ angles[2] = rand() % 360;
+ AnglesToAxis( angles, beam.axis );
+ trap_R_AddRefEntityToScene( &beam );
+ }
+}
+/*
+
+static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
+ trace_t trace;
+ refEntity_t beam;
+ vec3_t forward;
+ vec3_t muzzlePoint, endPoint;
+
+ if ( cent->currentState.weapon != WP_LIGHTNING ) {
+ return;
+ }
+
+ memset( &beam, 0, sizeof( beam ) );
+
+ // find muzzle point for this frame
+ VectorCopy( cent->lerpOrigin, muzzlePoint );
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
+
+ // FIXME: crouch
+ muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
+
+ VectorMA( muzzlePoint, 14, forward, muzzlePoint );
+
+ // project forward by the lightning range
+ VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
+
+ // see if it hit a wall
+ CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint,
+ cent->currentState.number, MASK_SHOT );
+
+ // this is the endpoint
+ VectorCopy( trace.endpos, beam.oldorigin );
+
+ // use the provided origin, even though it may be slightly
+ // different than the muzzle origin
+ VectorCopy( origin, beam.origin );
+
+ beam.reType = RT_LIGHTNING;
+ beam.customShader = cgs.media.lightningShader;
+ trap_R_AddRefEntityToScene( &beam );
+
+ // add the impact flare if it hit something
+ if ( trace.fraction < 1.0 ) {
+ vec3_t angles;
+ vec3_t dir;
+
+ VectorSubtract( beam.oldorigin, beam.origin, dir );
+ VectorNormalize( dir );
+
+ memset( &beam, 0, sizeof( beam ) );
+ beam.hModel = cgs.media.lightningExplosionModel;
+
+ VectorMA( trace.endpos, -16, dir, beam.origin );
+
+ // make a random orientation
+ angles[0] = rand() % 360;
+ angles[1] = rand() % 360;
+ angles[2] = rand() % 360;
+ AnglesToAxis( angles, beam.axis );
+ trap_R_AddRefEntityToScene( &beam );
+ }
+}
+*/
+
+/*
+===============
+CG_SpawnRailTrail
+
+Origin will be the exact tag point, which is slightly
+different than the muzzle point used for determining hits.
+===============
+*/
+static void CG_SpawnRailTrail( centity_t *cent, vec3_t origin ) {
+ clientInfo_t *ci;
+
+ if ( cent->currentState.weapon != WP_RAILGUN ) {
+ return;
+ }
+ if ( !cent->pe.railgunFlash ) {
+ return;
+ }
+ cent->pe.railgunFlash = qtrue;
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ CG_RailTrail( ci, origin, cent->pe.railgunImpact );
+}
+
+
+/*
+======================
+CG_MachinegunSpinAngle
+======================
+*/
+#define SPIN_SPEED 0.9
+#define COAST_TIME 1000
+static float CG_MachinegunSpinAngle( centity_t *cent ) {
+ int delta;
+ float angle;
+ float speed;
+
+ delta = cg.time - cent->pe.barrelTime;
+ if ( cent->pe.barrelSpinning ) {
+ angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
+ } else {
+ if ( delta > COAST_TIME ) {
+ delta = COAST_TIME;
+ }
+
+ speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
+ angle = cent->pe.barrelAngle + delta * speed;
+ }
+
+ if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
+ cent->pe.barrelTime = cg.time;
+ cent->pe.barrelAngle = AngleMod( angle );
+ cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
+#ifdef MISSIONPACK
+ if ( cent->currentState.weapon == WP_CHAINGUN && !cent->pe.barrelSpinning ) {
+ trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, trap_S_RegisterSound( "sound/weapons/vulcan/wvulwind.wav", qfalse ) );
+ }
+#endif
+ }
+
+ return angle;
+}
+
+
+/*
+========================
+CG_AddWeaponWithPowerups
+========================
+*/
+static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
+ // add powerup effects
+ if ( powerups & ( 1 << PW_INVIS ) ) {
+ gun->customShader = cgs.media.invisShader;
+ trap_R_AddRefEntityToScene( gun );
+ } else {
+ trap_R_AddRefEntityToScene( gun );
+
+ if ( powerups & ( 1 << PW_BATTLESUIT ) ) {
+ gun->customShader = cgs.media.battleWeaponShader;
+ trap_R_AddRefEntityToScene( gun );
+ }
+ if ( powerups & ( 1 << PW_QUAD ) ) {
+ gun->customShader = cgs.media.quadWeaponShader;
+ trap_R_AddRefEntityToScene( gun );
+ }
+ }
+}
+
+
+/*
+=============
+CG_AddPlayerWeapon
+
+Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
+The main player will have this called for BOTH cases, so effects like light and
+sound should only be done on the world model case.
+=============
+*/
+void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team ) {
+ refEntity_t gun;
+ refEntity_t barrel;
+ refEntity_t flash;
+ vec3_t angles;
+ weapon_t weaponNum;
+ weaponInfo_t *weapon;
+ centity_t *nonPredictedCent;
+// int col;
+
+ weaponNum = cent->currentState.weapon;
+
+ CG_RegisterWeapon( weaponNum );
+ weapon = &cg_weapons[weaponNum];
+
+ // add the weapon
+ memset( &gun, 0, sizeof( gun ) );
+ VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
+ gun.shadowPlane = parent->shadowPlane;
+ gun.renderfx = parent->renderfx;
+
+ // set custom shading for railgun refire rate
+ if ( ps ) {
+ if ( cg.predictedPlayerState.weapon == WP_RAILGUN
+ && cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
+ float f;
+
+ f = (float)cg.predictedPlayerState.weaponTime / 1500;
+ gun.shaderRGBA[1] = 0;
+ gun.shaderRGBA[0] =
+ gun.shaderRGBA[2] = 255 * ( 1.0 - f );
+ } else {
+ gun.shaderRGBA[0] = 255;
+ gun.shaderRGBA[1] = 255;
+ gun.shaderRGBA[2] = 255;
+ gun.shaderRGBA[3] = 255;
+ }
+ }
+
+ gun.hModel = weapon->weaponModel;
+ if (!gun.hModel) {
+ return;
+ }
+
+ if ( !ps ) {
+ // add weapon ready sound
+ cent->pe.lightningFiring = qfalse;
+ if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
+ // lightning gun and guantlet make a different sound when fire is held down
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
+ cent->pe.lightningFiring = qtrue;
+ } else if ( weapon->readySound ) {
+ trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
+ }
+ }
+
+ CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
+
+ CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
+
+ // add the spinning barrel
+ if ( weapon->barrelModel ) {
+ memset( &barrel, 0, sizeof( barrel ) );
+ VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
+ barrel.shadowPlane = parent->shadowPlane;
+ barrel.renderfx = parent->renderfx;
+
+ barrel.hModel = weapon->barrelModel;
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = CG_MachinegunSpinAngle( cent );
+ AnglesToAxis( angles, barrel.axis );
+
+ CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
+
+ CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
+ }
+
+ // make sure we aren't looking at cg.predictedPlayerEntity for LG
+ nonPredictedCent = &cg_entities[cent->currentState.clientNum];
+
+ // if the index of the nonPredictedCent is not the same as the clientNum
+ // then this is a fake player (like on teh single player podiums), so
+ // go ahead and use the cent
+ if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
+ nonPredictedCent = cent;
+ }
+
+ // add the flash
+ if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
+ && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
+ {
+ // continuous flash
+ } else {
+ // impulse flash
+ if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
+ return;
+ }
+ }
+
+ memset( &flash, 0, sizeof( flash ) );
+ VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
+ flash.shadowPlane = parent->shadowPlane;
+ flash.renderfx = parent->renderfx;
+
+ flash.hModel = weapon->flashModel;
+ if (!flash.hModel) {
+ return;
+ }
+ angles[YAW] = 0;
+ angles[PITCH] = 0;
+ angles[ROLL] = crandom() * 10;
+ AnglesToAxis( angles, flash.axis );
+
+ // colorize the railgun blast
+ if ( weaponNum == WP_RAILGUN ) {
+ clientInfo_t *ci;
+
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ flash.shaderRGBA[0] = 255 * ci->color1[0];
+ flash.shaderRGBA[1] = 255 * ci->color1[1];
+ flash.shaderRGBA[2] = 255 * ci->color1[2];
+ }
+
+ CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
+ trap_R_AddRefEntityToScene( &flash );
+
+ if ( ps || cg.renderingThirdPerson ||
+ cent->currentState.number != cg.predictedPlayerState.clientNum ) {
+ // add lightning bolt
+ CG_LightningBolt( nonPredictedCent, flash.origin );
+
+ // add rail trail
+ CG_SpawnRailTrail( cent, flash.origin );
+
+ if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
+ trap_R_AddLightToScene( flash.origin, 300 + (rand()&31), weapon->flashDlightColor[0],
+ weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
+ }
+ }
+}
+
+/*
+==============
+CG_AddViewWeapon
+
+Add the weapon, and flash for the player's view
+==============
+*/
+void CG_AddViewWeapon( playerState_t *ps ) {
+ refEntity_t hand;
+ centity_t *cent;
+ clientInfo_t *ci;
+ float fovOffset;
+ vec3_t angles;
+ weaponInfo_t *weapon;
+
+ if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
+ return;
+ }
+
+ if ( ps->pm_type == PM_INTERMISSION ) {
+ return;
+ }
+
+ // no gun if in third person view or a camera is active
+ //if ( cg.renderingThirdPerson || cg.cameraMode) {
+ if ( cg.renderingThirdPerson ) {
+ return;
+ }
+
+
+ // allow the gun to be completely removed
+ if ( !cg_drawGun.integer ) {
+ vec3_t origin;
+
+ if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
+ // special hack for lightning gun...
+ VectorCopy( cg.refdef.vieworg, origin );
+ VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
+ CG_LightningBolt( &cg_entities[ps->clientNum], origin );
+ }
+ return;
+ }
+
+ // don't draw if testing a gun model
+ if ( cg.testGun ) {
+ return;
+ }
+
+ // drop gun lower at higher fov
+ if ( cg_fov.integer > 90 ) {
+ fovOffset = -0.2 * ( cg_fov.integer - 90 );
+ } else {
+ fovOffset = 0;
+ }
+
+ cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
+ CG_RegisterWeapon( ps->weapon );
+ weapon = &cg_weapons[ ps->weapon ];
+
+ memset (&hand, 0, sizeof(hand));
+
+ // set up gun position
+ CG_CalculateWeaponPosition( hand.origin, angles );
+
+ VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
+ VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
+ VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
+
+ AnglesToAxis( angles, hand.axis );
+
+ // map torso animations to weapon animations
+ if ( cg_gun_frame.integer ) {
+ // development tool
+ hand.frame = hand.oldframe = cg_gun_frame.integer;
+ hand.backlerp = 0;
+ } else {
+ // get clientinfo for animation map
+ ci = &cgs.clientinfo[ cent->currentState.clientNum ];
+ hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
+ hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
+ hand.backlerp = cent->pe.torso.backlerp;
+ }
+
+ hand.hModel = weapon->handsModel;
+ hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
+
+ // add everything onto the hand
+ CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
+}
+
+/*
+==============================================================================
+
+WEAPON SELECTION
+
+==============================================================================
+*/
+
+/*
+===================
+CG_DrawWeaponSelect
+===================
+*/
+void CG_DrawWeaponSelect( void ) {
+ int i;
+ int bits;
+ int count;
+ int x, y, w;
+ char *name;
+ float *color;
+
+ // don't display if dead
+ if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
+ return;
+ }
+
+ color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
+ if ( !color ) {
+ return;
+ }
+ trap_R_SetColor( color );
+
+ // showing weapon select clears pickup item display, but not the blend blob
+ cg.itemPickupTime = 0;
+
+ // count the number of weapons owned
+ bits = cg.snap->ps.stats[ STAT_WEAPONS ];
+ count = 0;
+ for ( i = 1 ; i < 16 ; i++ ) {
+ if ( bits & ( 1 << i ) ) {
+ count++;
+ }
+ }
+
+ x = 320 - count * 20;
+ y = 380;
+
+ for ( i = 1 ; i < 16 ; i++ ) {
+ if ( !( bits & ( 1 << i ) ) ) {
+ continue;
+ }
+
+ CG_RegisterWeapon( i );
+
+ // draw weapon icon
+ CG_DrawPic( x, y, 32, 32, cg_weapons[i].weaponIcon );
+
+ // draw selection marker
+ if ( i == cg.weaponSelect ) {
+ CG_DrawPic( x-4, y-4, 40, 40, cgs.media.selectShader );
+ }
+
+ // no ammo cross on top
+ if ( !cg.snap->ps.ammo[ i ] ) {
+ CG_DrawPic( x, y, 32, 32, cgs.media.noammoShader );
+ }
+
+ x += 40;
+ }
+
+ // draw the selected name
+ if ( cg_weapons[ cg.weaponSelect ].item ) {
+ name = cg_weapons[ cg.weaponSelect ].item->pickup_name;
+ if ( name ) {
+ w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
+ x = ( SCREEN_WIDTH - w ) / 2;
+ CG_DrawBigStringColor(x, y - 22, name, color);
+ }
+ }
+
+ trap_R_SetColor( NULL );
+}
+
+
+/*
+===============
+CG_WeaponSelectable
+===============
+*/
+static qboolean CG_WeaponSelectable( int i ) {
+ if ( !cg.snap->ps.ammo[i] ) {
+ return qfalse;
+ }
+ if ( ! (cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+===============
+CG_NextWeapon_f
+===============
+*/
+void CG_NextWeapon_f( void ) {
+ int i;
+ int original;
+
+ if ( !cg.snap ) {
+ return;
+ }
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
+ return;
+ }
+
+ cg.weaponSelectTime = cg.time;
+ original = cg.weaponSelect;
+
+ for ( i = 0 ; i < 16 ; i++ ) {
+ cg.weaponSelect++;
+ if ( cg.weaponSelect == 16 ) {
+ cg.weaponSelect = 0;
+ }
+ if ( cg.weaponSelect == WP_GAUNTLET ) {
+ continue; // never cycle to gauntlet
+ }
+ if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
+ break;
+ }
+ }
+ if ( i == 16 ) {
+ cg.weaponSelect = original;
+ }
+}
+
+/*
+===============
+CG_PrevWeapon_f
+===============
+*/
+void CG_PrevWeapon_f( void ) {
+ int i;
+ int original;
+
+ if ( !cg.snap ) {
+ return;
+ }
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
+ return;
+ }
+
+ cg.weaponSelectTime = cg.time;
+ original = cg.weaponSelect;
+
+ for ( i = 0 ; i < 16 ; i++ ) {
+ cg.weaponSelect--;
+ if ( cg.weaponSelect == -1 ) {
+ cg.weaponSelect = 15;
+ }
+ if ( cg.weaponSelect == WP_GAUNTLET ) {
+ continue; // never cycle to gauntlet
+ }
+ if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
+ break;
+ }
+ }
+ if ( i == 16 ) {
+ cg.weaponSelect = original;
+ }
+}
+
+/*
+===============
+CG_Weapon_f
+===============
+*/
+void CG_Weapon_f( void ) {
+ int num;
+
+ if ( !cg.snap ) {
+ return;
+ }
+ if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
+ return;
+ }
+
+ num = atoi( CG_Argv( 1 ) );
+
+ if ( num < 1 || num > 15 ) {
+ return;
+ }
+
+ cg.weaponSelectTime = cg.time;
+
+ if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
+ return; // don't have the weapon
+ }
+
+ cg.weaponSelect = num;
+}
+
+/*
+===================
+CG_OutOfAmmoChange
+
+The current weapon has just run out of ammo
+===================
+*/
+void CG_OutOfAmmoChange( void ) {
+ int i;
+
+ cg.weaponSelectTime = cg.time;
+
+ for ( i = 15 ; i > 0 ; i-- ) {
+ if ( CG_WeaponSelectable( i ) ) {
+ cg.weaponSelect = i;
+ break;
+ }
+ }
+}
+
+
+
+/*
+===================================================================================================
+
+WEAPON EVENTS
+
+===================================================================================================
+*/
+
+/*
+================
+CG_FireWeapon
+
+Caused by an EV_FIRE_WEAPON event
+================
+*/
+void CG_FireWeapon( centity_t *cent ) {
+ entityState_t *ent;
+ int c;
+ weaponInfo_t *weap;
+
+ ent = &cent->currentState;
+ if ( ent->weapon == WP_NONE ) {
+ return;
+ }
+ if ( ent->weapon >= WP_NUM_WEAPONS ) {
+ CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
+ return;
+ }
+ weap = &cg_weapons[ ent->weapon ];
+
+ // mark the entity as muzzle flashing, so when it is added it will
+ // append the flash to the weapon model
+ cent->muzzleFlashTime = cg.time;
+
+ // lightning gun only does this this on initial press
+ if ( ent->weapon == WP_LIGHTNING ) {
+ if ( cent->pe.lightningFiring ) {
+ return;
+ }
+ }
+
+ // play quad sound if needed
+ if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
+ trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
+ }
+
+ // play a sound
+ for ( c = 0 ; c < 4 ; c++ ) {
+ if ( !weap->flashSound[c] ) {
+ break;
+ }
+ }
+ if ( c > 0 ) {
+ c = rand() % c;
+ if ( weap->flashSound[c] )
+ {
+ trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
+ }
+ }
+
+ // do brass ejection
+ if ( weap->ejectBrassFunc && cg_brassTime.integer > 0 ) {
+ weap->ejectBrassFunc( cent );
+ }
+}
+
+
+/*
+=================
+CG_MissileHitWall
+
+Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
+=================
+*/
+void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) {
+ qhandle_t mod;
+ qhandle_t mark;
+ qhandle_t shader;
+ sfxHandle_t sfx;
+ float radius;
+ float light;
+ vec3_t lightColor;
+ localEntity_t *le;
+ int r;
+ qboolean alphaFade;
+ qboolean isSprite;
+ int duration;
+ vec3_t sprOrg;
+ vec3_t sprVel;
+
+ mark = 0;
+ radius = 32;
+ sfx = 0;
+ mod = 0;
+ shader = 0;
+ light = 0;
+ lightColor[0] = 1;
+ lightColor[1] = 1;
+ lightColor[2] = 0;
+
+ // set defaults
+ isSprite = qfalse;
+ duration = 600;
+
+ switch ( weapon ) {
+ default:
+#ifdef MISSIONPACK
+ case WP_NAILGUN:
+ if( soundType == IMPACTSOUND_FLESH ) {
+ sfx = cgs.media.sfx_nghitflesh;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ sfx = cgs.media.sfx_nghitmetal;
+ } else {
+ sfx = cgs.media.sfx_nghit;
+ }
+ mark = cgs.media.holeMarkShader;
+ radius = 12;
+ break;
+#endif
+ case WP_LIGHTNING:
+ // no explosion at LG impact, it is added with the beam
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.sfx_lghit2;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.sfx_lghit1;
+ } else {
+ sfx = cgs.media.sfx_lghit3;
+ }
+ mark = cgs.media.holeMarkShader;
+ radius = 12;
+ break;
+#ifdef MISSIONPACK
+ case WP_PROX_LAUNCHER:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.grenadeExplosionShader;
+ sfx = cgs.media.sfx_proxexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 64;
+ light = 300;
+ isSprite = qtrue;
+ break;
+#endif
+ case WP_GRENADE_LAUNCHER:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.grenadeExplosionShader;
+ sfx = cgs.media.sfx_rockexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 64;
+ light = 300;
+ isSprite = qtrue;
+ break;
+ case WP_ROCKET_LAUNCHER:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.rocketExplosionShader;
+ sfx = cgs.media.sfx_rockexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 64;
+ light = 300;
+ isSprite = qtrue;
+ duration = 1000;
+ lightColor[0] = 1;
+ lightColor[1] = 0.75;
+ lightColor[2] = 0.0;
+ if (cg_oldRocket.integer == 0) {
+ // explosion sprite animation
+ VectorMA( origin, 24, dir, sprOrg );
+ VectorScale( dir, 64, sprVel );
+
+ CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
+ }
+ break;
+ case WP_RAILGUN:
+ mod = cgs.media.ringFlashModel;
+ shader = cgs.media.railExplosionShader;
+ sfx = cgs.media.sfx_plasmaexp;
+ mark = cgs.media.energyMarkShader;
+ radius = 24;
+ break;
+ case WP_PLASMAGUN:
+ mod = cgs.media.ringFlashModel;
+ shader = cgs.media.plasmaExplosionShader;
+ sfx = cgs.media.sfx_plasmaexp;
+ mark = cgs.media.energyMarkShader;
+ radius = 16;
+ break;
+ case WP_BFG:
+ mod = cgs.media.dishFlashModel;
+ shader = cgs.media.bfgExplosionShader;
+ sfx = cgs.media.sfx_rockexp;
+ mark = cgs.media.burnMarkShader;
+ radius = 32;
+ isSprite = qtrue;
+ break;
+ case WP_SHOTGUN:
+ mod = cgs.media.bulletFlashModel;
+ shader = cgs.media.bulletExplosionShader;
+ mark = cgs.media.bulletMarkShader;
+ sfx = 0;
+ radius = 4;
+ break;
+
+#ifdef MISSIONPACK
+ case WP_CHAINGUN:
+ mod = cgs.media.bulletFlashModel;
+ if( soundType == IMPACTSOUND_FLESH ) {
+ sfx = cgs.media.sfx_chghitflesh;
+ } else if( soundType == IMPACTSOUND_METAL ) {
+ sfx = cgs.media.sfx_chghitmetal;
+ } else {
+ sfx = cgs.media.sfx_chghit;
+ }
+ mark = cgs.media.bulletMarkShader;
+
+ r = rand() & 3;
+ if ( r < 2 ) {
+ sfx = cgs.media.sfx_ric1;
+ } else if ( r == 2 ) {
+ sfx = cgs.media.sfx_ric2;
+ } else {
+ sfx = cgs.media.sfx_ric3;
+ }
+
+ radius = 8;
+ break;
+#endif
+
+ case WP_MACHINEGUN:
+ mod = cgs.media.bulletFlashModel;
+ shader = cgs.media.bulletExplosionShader;
+ mark = cgs.media.bulletMarkShader;
+
+ r = rand() & 3;
+ if ( r == 0 ) {
+ sfx = cgs.media.sfx_ric1;
+ } else if ( r == 1 ) {
+ sfx = cgs.media.sfx_ric2;
+ } else {
+ sfx = cgs.media.sfx_ric3;
+ }
+
+ radius = 8;
+ break;
+ }
+
+ if ( sfx ) {
+ trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
+ }
+
+ //
+ // create the explosion
+ //
+ if ( mod ) {
+ le = CG_MakeExplosion( origin, dir,
+ mod, shader,
+ duration, isSprite );
+ le->light = light;
+ VectorCopy( lightColor, le->lightColor );
+ if ( weapon == WP_RAILGUN ) {
+ // colorize with client color
+ VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
+ }
+ }
+
+ //
+ // impact mark
+ //
+ alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
+ if ( weapon == WP_RAILGUN ) {
+ float *color;
+
+ // colorize with client color
+ color = cgs.clientinfo[clientNum].color2;
+ CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
+ } else {
+ CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
+ }
+}
+
+
+/*
+=================
+CG_MissileHitPlayer
+=================
+*/
+void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
+ CG_Bleed( origin, entityNum );
+
+ // some weapons will make an explosion with the blood, while
+ // others will just make the blood
+ switch ( weapon ) {
+ case WP_GRENADE_LAUNCHER:
+ case WP_ROCKET_LAUNCHER:
+#ifdef MISSIONPACK
+ case WP_NAILGUN:
+ case WP_CHAINGUN:
+ case WP_PROX_LAUNCHER:
+#endif
+ CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+/*
+============================================================================
+
+SHOTGUN TRACING
+
+============================================================================
+*/
+
+/*
+================
+CG_ShotgunPellet
+================
+*/
+static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
+ trace_t tr;
+ int sourceContentType, destContentType;
+
+ CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
+
+ sourceContentType = trap_CM_PointContents( start, 0 );
+ destContentType = trap_CM_PointContents( tr.endpos, 0 );
+
+ // FIXME: should probably move this cruft into CG_BubbleTrail
+ if ( sourceContentType == destContentType ) {
+ if ( sourceContentType & CONTENTS_WATER ) {
+ CG_BubbleTrail( start, tr.endpos, 32 );
+ }
+ } else if ( sourceContentType & CONTENTS_WATER ) {
+ trace_t trace;
+
+ trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( start, trace.endpos, 32 );
+ } else if ( destContentType & CONTENTS_WATER ) {
+ trace_t trace;
+
+ trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
+ }
+
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ return;
+ }
+
+ if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
+ CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
+ } else {
+ if ( tr.surfaceFlags & SURF_NOIMPACT ) {
+ // SURF_NOIMPACT will not make a flame puff or a mark
+ return;
+ }
+ if ( tr.surfaceFlags & SURF_METALSTEPS ) {
+ CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
+ } else {
+ CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
+ }
+ }
+}
+
+/*
+================
+CG_ShotgunPattern
+
+Perform the same traces the server did to locate the
+hit splashes
+================
+*/
+static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
+ int i;
+ float r, u;
+ vec3_t end;
+ vec3_t forward, right, up;
+
+ // derive the right and up vectors from the forward vector, because
+ // the client won't have any other information
+ VectorNormalize2( origin2, forward );
+ PerpendicularVector( right, forward );
+ CrossProduct( forward, right, up );
+
+ // generate the "random" spread pattern
+ for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
+ r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
+ u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
+ VectorMA( origin, 8192 * 16, forward, end);
+ VectorMA (end, r, right, end);
+ VectorMA (end, u, up, end);
+
+ CG_ShotgunPellet( origin, end, otherEntNum );
+ }
+}
+
+/*
+==============
+CG_ShotgunFire
+==============
+*/
+void CG_ShotgunFire( entityState_t *es ) {
+ vec3_t v;
+ int contents;
+
+ VectorSubtract( es->origin2, es->pos.trBase, v );
+ VectorNormalize( v );
+ VectorScale( v, 32, v );
+ VectorAdd( es->pos.trBase, v, v );
+ if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
+ // ragepro can't alpha fade, so don't even bother with smoke
+ vec3_t up;
+
+ contents = trap_CM_PointContents( es->pos.trBase, 0 );
+ if ( !( contents & CONTENTS_WATER ) ) {
+ VectorSet( up, 0, 0, 8 );
+ CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
+ }
+ }
+ CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
+}
+
+/*
+============================================================================
+
+BULLETS
+
+============================================================================
+*/
+
+
+/*
+===============
+CG_Tracer
+===============
+*/
+void CG_Tracer( vec3_t source, vec3_t dest ) {
+ vec3_t forward, right;
+ polyVert_t verts[4];
+ vec3_t line;
+ float len, begin, end;
+ vec3_t start, finish;
+ vec3_t midpoint;
+
+ // tracer
+ VectorSubtract( dest, source, forward );
+ len = VectorNormalize( forward );
+
+ // start at least a little ways from the muzzle
+ if ( len < 100 ) {
+ return;
+ }
+ begin = 50 + random() * (len - 60);
+ end = begin + cg_tracerLength.value;
+ if ( end > len ) {
+ end = len;
+ }
+ VectorMA( source, begin, forward, start );
+ VectorMA( source, end, forward, finish );
+
+ line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
+ line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
+
+ VectorScale( cg.refdef.viewaxis[1], line[1], right );
+ VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
+ VectorNormalize( right );
+
+ VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
+ verts[0].st[0] = 0;
+ verts[0].st[1] = 1;
+ verts[0].modulate[0] = 255;
+ verts[0].modulate[1] = 255;
+ verts[0].modulate[2] = 255;
+ verts[0].modulate[3] = 255;
+
+ VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
+ verts[1].st[0] = 1;
+ verts[1].st[1] = 0;
+ verts[1].modulate[0] = 255;
+ verts[1].modulate[1] = 255;
+ verts[1].modulate[2] = 255;
+ verts[1].modulate[3] = 255;
+
+ VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
+ verts[2].st[0] = 1;
+ verts[2].st[1] = 1;
+ verts[2].modulate[0] = 255;
+ verts[2].modulate[1] = 255;
+ verts[2].modulate[2] = 255;
+ verts[2].modulate[3] = 255;
+
+ VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
+ verts[3].st[0] = 0;
+ verts[3].st[1] = 0;
+ verts[3].modulate[0] = 255;
+ verts[3].modulate[1] = 255;
+ verts[3].modulate[2] = 255;
+ verts[3].modulate[3] = 255;
+
+ trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
+
+ midpoint[0] = ( start[0] + finish[0] ) * 0.5;
+ midpoint[1] = ( start[1] + finish[1] ) * 0.5;
+ midpoint[2] = ( start[2] + finish[2] ) * 0.5;
+
+ // add the tracer sound
+ trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
+
+}
+
+
+/*
+======================
+CG_CalcMuzzlePoint
+======================
+*/
+static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
+ vec3_t forward;
+ centity_t *cent;
+ int anim;
+
+ if ( entityNum == cg.snap->ps.clientNum ) {
+ VectorCopy( cg.snap->ps.origin, muzzle );
+ muzzle[2] += cg.snap->ps.viewheight;
+ AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
+ VectorMA( muzzle, 14, forward, muzzle );
+ return qtrue;
+ }
+
+ cent = &cg_entities[entityNum];
+ if ( !cent->currentValid ) {
+ return qfalse;
+ }
+
+ VectorCopy( cent->currentState.pos.trBase, muzzle );
+
+ AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
+ anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
+ if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
+ muzzle[2] += CROUCH_VIEWHEIGHT;
+ } else {
+ muzzle[2] += DEFAULT_VIEWHEIGHT;
+ }
+
+ VectorMA( muzzle, 14, forward, muzzle );
+
+ return qtrue;
+
+}
+
+/*
+======================
+CG_Bullet
+
+Renders bullet effects.
+======================
+*/
+void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
+ trace_t trace;
+ int sourceContentType, destContentType;
+ vec3_t start;
+
+ // if the shooter is currently valid, calc a source point and possibly
+ // do trail effects
+ if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
+ if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
+ sourceContentType = trap_CM_PointContents( start, 0 );
+ destContentType = trap_CM_PointContents( end, 0 );
+
+ // do a complete bubble trail if necessary
+ if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
+ CG_BubbleTrail( start, end, 32 );
+ }
+ // bubble trail from water into air
+ else if ( ( sourceContentType & CONTENTS_WATER ) ) {
+ trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( start, trace.endpos, 32 );
+ }
+ // bubble trail from air into water
+ else if ( ( destContentType & CONTENTS_WATER ) ) {
+ trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
+ CG_BubbleTrail( trace.endpos, end, 32 );
+ }
+
+ // draw a tracer
+ if ( random() < cg_tracerChance.value ) {
+ CG_Tracer( start, end );
+ }
+ }
+ }
+
+ // impact splash and mark
+ if ( flesh ) {
+ CG_Bleed( end, fleshEntityNum );
+ } else {
+ CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
+ }
+
+}
diff --git a/code/cgame/cgame.bat b/code/cgame/cgame.bat
index 6e13523..a59381e 100755
--- a/code/cgame/cgame.bat
+++ b/code/cgame/cgame.bat
@@ -1,63 +1,63 @@
-rem make sure we have a safe environement
-set LIBRARY=
-set INCLUDE=
-
-mkdir vm
-cd vm
-set cc=lcc -DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
-
-%cc% ../../game/bg_misc.c
-@if errorlevel 1 goto quit
-%cc% ../../game/bg_pmove.c
-@if errorlevel 1 goto quit
-%cc% ../../game/bg_slidemove.c
-@if errorlevel 1 goto quit
-%cc% ../../game/bg_lib.c
-@if errorlevel 1 goto quit
-%cc% ../../game/q_math.c
-@if errorlevel 1 goto quit
-%cc% ../../game/q_shared.c
-@if errorlevel 1 goto quit
-%cc% ../cg_consolecmds.c
-@if errorlevel 1 goto quit
-%cc% ../cg_draw.c
-@if errorlevel 1 goto quit
-%cc% ../cg_drawtools.c
-@if errorlevel 1 goto quit
-%cc% ../cg_effects.c
-@if errorlevel 1 goto quit
-%cc% ../cg_ents.c
-@if errorlevel 1 goto quit
-%cc% ../cg_event.c
-@if errorlevel 1 goto quit
-%cc% ../cg_info.c
-@if errorlevel 1 goto quit
-%cc% ../cg_localents.c
-@if errorlevel 1 goto quit
-%cc% ../cg_main.c
-@if errorlevel 1 goto quit
-%cc% ../cg_marks.c
-@if errorlevel 1 goto quit
-%cc% ../cg_players.c
-@if errorlevel 1 goto quit
-%cc% ../cg_playerstate.c
-@if errorlevel 1 goto quit
-%cc% ../cg_predict.c
-@if errorlevel 1 goto quit
-%cc% ../cg_scoreboard.c
-@if errorlevel 1 goto quit
-%cc% ../cg_servercmds.c
-@if errorlevel 1 goto quit
-%cc% ../cg_snapshot.c
-@if errorlevel 1 goto quit
-%cc% ../cg_view.c
-@if errorlevel 1 goto quit
-%cc% ../cg_weapons.c
-@if errorlevel 1 goto quit
-
-
-
-
-q3asm -f ../cgame
-:quit
-cd ..
+rem make sure we have a safe environement
+set LIBRARY=
+set INCLUDE=
+
+mkdir vm
+cd vm
+set cc=lcc -DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
+
+%cc% ../../game/bg_misc.c
+@if errorlevel 1 goto quit
+%cc% ../../game/bg_pmove.c
+@if errorlevel 1 goto quit
+%cc% ../../game/bg_slidemove.c
+@if errorlevel 1 goto quit
+%cc% ../../game/bg_lib.c
+@if errorlevel 1 goto quit
+%cc% ../../game/q_math.c
+@if errorlevel 1 goto quit
+%cc% ../../game/q_shared.c
+@if errorlevel 1 goto quit
+%cc% ../cg_consolecmds.c
+@if errorlevel 1 goto quit
+%cc% ../cg_draw.c
+@if errorlevel 1 goto quit
+%cc% ../cg_drawtools.c
+@if errorlevel 1 goto quit
+%cc% ../cg_effects.c
+@if errorlevel 1 goto quit
+%cc% ../cg_ents.c
+@if errorlevel 1 goto quit
+%cc% ../cg_event.c
+@if errorlevel 1 goto quit
+%cc% ../cg_info.c
+@if errorlevel 1 goto quit
+%cc% ../cg_localents.c
+@if errorlevel 1 goto quit
+%cc% ../cg_main.c
+@if errorlevel 1 goto quit
+%cc% ../cg_marks.c
+@if errorlevel 1 goto quit
+%cc% ../cg_players.c
+@if errorlevel 1 goto quit
+%cc% ../cg_playerstate.c
+@if errorlevel 1 goto quit
+%cc% ../cg_predict.c
+@if errorlevel 1 goto quit
+%cc% ../cg_scoreboard.c
+@if errorlevel 1 goto quit
+%cc% ../cg_servercmds.c
+@if errorlevel 1 goto quit
+%cc% ../cg_snapshot.c
+@if errorlevel 1 goto quit
+%cc% ../cg_view.c
+@if errorlevel 1 goto quit
+%cc% ../cg_weapons.c
+@if errorlevel 1 goto quit
+
+
+
+
+q3asm -f ../cgame
+:quit
+cd ..
diff --git a/code/cgame/cgame.def b/code/cgame/cgame.def
index 01861ba..2ee748e 100755
--- a/code/cgame/cgame.def
+++ b/code/cgame/cgame.def
@@ -1,3 +1,3 @@
-EXPORTS
- vmMain
- dllEntry
+EXPORTS
+ vmMain
+ dllEntry
diff --git a/code/cgame/cgame.plg b/code/cgame/cgame.plg
index b7c80ee..781b1eb 100755
--- a/code/cgame/cgame.plg
+++ b/code/cgame/cgame.plg
@@ -1,124 +1,124 @@
-<html>
-<body>
-<pre>
-<h1>Build Log</h1>
-<h3>
---------------------Configuration: cgame - Win32 Release--------------------
-</h3>
-<h3>Command Lines</h3>
-Creating temporary file "C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BE.tmp" with contents
-[
-/nologo /G6 /ML /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/cgame.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
-"D:\quake3\MissionPack\code\game\bg_misc.c"
-"D:\quake3\MissionPack\code\game\bg_pmove.c"
-"D:\quake3\MissionPack\code\game\bg_slidemove.c"
-"D:\quake3\MissionPack\code\cgame\cg_consolecmds.c"
-"D:\quake3\MissionPack\code\cgame\cg_draw.c"
-"D:\quake3\MissionPack\code\cgame\cg_drawtools.c"
-"D:\quake3\MissionPack\code\cgame\cg_effects.c"
-"D:\quake3\MissionPack\code\cgame\cg_ents.c"
-"D:\quake3\MissionPack\code\cgame\cg_event.c"
-"D:\quake3\MissionPack\code\cgame\cg_info.c"
-"D:\quake3\MissionPack\code\cgame\cg_localents.c"
-"D:\quake3\MissionPack\code\cgame\cg_main.c"
-"D:\quake3\MissionPack\code\cgame\cg_marks.c"
-"D:\quake3\MissionPack\code\cgame\cg_players.c"
-"D:\quake3\MissionPack\code\cgame\cg_playerstate.c"
-"D:\quake3\MissionPack\code\cgame\cg_predict.c"
-"D:\quake3\MissionPack\code\cgame\cg_rankings.c"
-"D:\quake3\MissionPack\code\cgame\cg_scoreboard.c"
-"D:\quake3\MissionPack\code\cgame\cg_servercmds.c"
-"D:\quake3\MissionPack\code\cgame\cg_snapshot.c"
-"D:\quake3\MissionPack\code\cgame\cg_syscalls.c"
-"D:\quake3\MissionPack\code\cgame\cg_view.c"
-"D:\quake3\MissionPack\code\cgame\cg_weapons.c"
-"D:\quake3\MissionPack\code\game\q_math.c"
-"D:\quake3\MissionPack\code\game\q_shared.c"
-"D:\quake3\MissionPack\code\ui\ui_shared.c"
-]
-Creating command line "cl.exe @C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BE.tmp"
-Creating temporary file "C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BF.tmp" with contents
-[
-/nologo /base:"0x30000000" /subsystem:windows /dll /incremental:no /pdb:"Release/cgamex86.pdb" /map:"Release/cgamex86.map" /machine:I386 /def:".\cgame.def" /out:"../Release/cgamex86.dll" /implib:"Release/cgamex86.lib"
-.\Release\bg_misc.obj
-.\Release\bg_pmove.obj
-.\Release\bg_slidemove.obj
-.\Release\cg_consolecmds.obj
-.\Release\cg_draw.obj
-.\Release\cg_drawtools.obj
-.\Release\cg_effects.obj
-.\Release\cg_ents.obj
-.\Release\cg_event.obj
-.\Release\cg_info.obj
-.\Release\cg_localents.obj
-.\Release\cg_main.obj
-.\Release\cg_marks.obj
-.\Release\cg_players.obj
-.\Release\cg_playerstate.obj
-.\Release\cg_predict.obj
-.\Release\cg_rankings.obj
-.\Release\cg_scoreboard.obj
-.\Release\cg_servercmds.obj
-.\Release\cg_snapshot.obj
-.\Release\cg_syscalls.obj
-.\Release\cg_view.obj
-.\Release\cg_weapons.obj
-.\Release\q_math.obj
-.\Release\q_shared.obj
-.\Release\ui_shared.obj
-]
-Creating command line "link.exe @C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BF.tmp"
-<h3>Output Window</h3>
-Compiling...
-bg_misc.c
-bg_pmove.c
-D:\quake3\MissionPack\code\game\bg_pmove.c(987) : warning C4189: 'shit' : local variable is initialized but not referenced
-D:\quake3\MissionPack\code\game\bg_pmove.c(2001) : warning C4505: 'PM_InvulnerabilityMove' : unreferenced local function has been removed
- D:\quake3\MissionPack\code\game\bg_pmove.c(519) : see declaration of 'PM_InvulnerabilityMove'
-bg_slidemove.c
-cg_consolecmds.c
-cg_draw.c
-cg_drawtools.c
-cg_effects.c
-cg_ents.c
-cg_event.c
-cg_info.c
-cg_localents.c
-cg_main.c
-D:\quake3\MissionPack\code\cgame\cg_main.c(1819) : warning C4505: 'CG_Cvar_Get' : unreferenced local function has been removed
- D:\quake3\MissionPack\code\cgame\cg_main.c(1513) : see declaration of 'CG_Cvar_Get'
-cg_marks.c
-cg_players.c
-D:\quake3\MissionPack\code\cgame\cg_players.c(2209) : warning C4505: 'CG_PlayerTokens' : unreferenced local function has been removed
- D:\quake3\MissionPack\code\cgame\cg_players.c(1371) : see declaration of 'CG_PlayerTokens'
-cg_playerstate.c
-cg_predict.c
-cg_rankings.c
-cg_scoreboard.c
-cg_servercmds.c
-cg_snapshot.c
-cg_syscalls.c
-cg_view.c
-cg_weapons.c
-q_math.c
-q_shared.c
-ui_shared.c
-D:\quake3\MissionPack\code\ui\ui_shared.c(2223) : warning C4189: 'parent' : local variable is initialized but not referenced
-D:\quake3\MissionPack\code\ui\ui_shared.c(3501) : warning C4189: 'collision' : local variable is initialized but not referenced
-D:\quake3\MissionPack\code\ui\ui_shared.c(4622) : warning C4505: 'Controls_SetDefaults' : unreferenced local function has been removed
- D:\quake3\MissionPack\code\ui\ui_shared.c(2595) : see declaration of 'Controls_SetDefaults'
-D:\quake3\MissionPack\code\ui\ui_shared.c(1540) : warning C4701: local variable 'value' may be used without having been initialized
-D:\quake3\MissionPack\code\ui\ui_shared.c(1566) : warning C4701: local variable 'value' may be used without having been initialized
-D:\quake3\MissionPack\code\ui\ui_shared.c(1912) : warning C4702: unreachable code
-D:\quake3\MissionPack\code\ui\ui_shared.c(4013) : warning C4702: unreachable code
-D:\quake3\MissionPack\code\ui\ui_shared.c(4056) : warning C4702: unreachable code
-Linking...
- Creating library Release/cgamex86.lib and object Release/cgamex86.exp
-
-
-
-<h3>Results</h3>
-cgamex86.dll - 0 error(s), 12 warning(s)
-</pre>
-</body>
-</html>
+<html>
+<body>
+<pre>
+<h1>Build Log</h1>
+<h3>
+--------------------Configuration: cgame - Win32 Release--------------------
+</h3>
+<h3>Command Lines</h3>
+Creating temporary file "C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BE.tmp" with contents
+[
+/nologo /G6 /ML /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/cgame.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
+"D:\quake3\MissionPack\code\game\bg_misc.c"
+"D:\quake3\MissionPack\code\game\bg_pmove.c"
+"D:\quake3\MissionPack\code\game\bg_slidemove.c"
+"D:\quake3\MissionPack\code\cgame\cg_consolecmds.c"
+"D:\quake3\MissionPack\code\cgame\cg_draw.c"
+"D:\quake3\MissionPack\code\cgame\cg_drawtools.c"
+"D:\quake3\MissionPack\code\cgame\cg_effects.c"
+"D:\quake3\MissionPack\code\cgame\cg_ents.c"
+"D:\quake3\MissionPack\code\cgame\cg_event.c"
+"D:\quake3\MissionPack\code\cgame\cg_info.c"
+"D:\quake3\MissionPack\code\cgame\cg_localents.c"
+"D:\quake3\MissionPack\code\cgame\cg_main.c"
+"D:\quake3\MissionPack\code\cgame\cg_marks.c"
+"D:\quake3\MissionPack\code\cgame\cg_players.c"
+"D:\quake3\MissionPack\code\cgame\cg_playerstate.c"
+"D:\quake3\MissionPack\code\cgame\cg_predict.c"
+"D:\quake3\MissionPack\code\cgame\cg_rankings.c"
+"D:\quake3\MissionPack\code\cgame\cg_scoreboard.c"
+"D:\quake3\MissionPack\code\cgame\cg_servercmds.c"
+"D:\quake3\MissionPack\code\cgame\cg_snapshot.c"
+"D:\quake3\MissionPack\code\cgame\cg_syscalls.c"
+"D:\quake3\MissionPack\code\cgame\cg_view.c"
+"D:\quake3\MissionPack\code\cgame\cg_weapons.c"
+"D:\quake3\MissionPack\code\game\q_math.c"
+"D:\quake3\MissionPack\code\game\q_shared.c"
+"D:\quake3\MissionPack\code\ui\ui_shared.c"
+]
+Creating command line "cl.exe @C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BE.tmp"
+Creating temporary file "C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BF.tmp" with contents
+[
+/nologo /base:"0x30000000" /subsystem:windows /dll /incremental:no /pdb:"Release/cgamex86.pdb" /map:"Release/cgamex86.map" /machine:I386 /def:".\cgame.def" /out:"../Release/cgamex86.dll" /implib:"Release/cgamex86.lib"
+.\Release\bg_misc.obj
+.\Release\bg_pmove.obj
+.\Release\bg_slidemove.obj
+.\Release\cg_consolecmds.obj
+.\Release\cg_draw.obj
+.\Release\cg_drawtools.obj
+.\Release\cg_effects.obj
+.\Release\cg_ents.obj
+.\Release\cg_event.obj
+.\Release\cg_info.obj
+.\Release\cg_localents.obj
+.\Release\cg_main.obj
+.\Release\cg_marks.obj
+.\Release\cg_players.obj
+.\Release\cg_playerstate.obj
+.\Release\cg_predict.obj
+.\Release\cg_rankings.obj
+.\Release\cg_scoreboard.obj
+.\Release\cg_servercmds.obj
+.\Release\cg_snapshot.obj
+.\Release\cg_syscalls.obj
+.\Release\cg_view.obj
+.\Release\cg_weapons.obj
+.\Release\q_math.obj
+.\Release\q_shared.obj
+.\Release\ui_shared.obj
+]
+Creating command line "link.exe @C:\WINNT\Profiles\ADMINI~1\LOCALS~1\Temp\RSP4BF.tmp"
+<h3>Output Window</h3>
+Compiling...
+bg_misc.c
+bg_pmove.c
+D:\quake3\MissionPack\code\game\bg_pmove.c(987) : warning C4189: 'shit' : local variable is initialized but not referenced
+D:\quake3\MissionPack\code\game\bg_pmove.c(2001) : warning C4505: 'PM_InvulnerabilityMove' : unreferenced local function has been removed
+ D:\quake3\MissionPack\code\game\bg_pmove.c(519) : see declaration of 'PM_InvulnerabilityMove'
+bg_slidemove.c
+cg_consolecmds.c
+cg_draw.c
+cg_drawtools.c
+cg_effects.c
+cg_ents.c
+cg_event.c
+cg_info.c
+cg_localents.c
+cg_main.c
+D:\quake3\MissionPack\code\cgame\cg_main.c(1819) : warning C4505: 'CG_Cvar_Get' : unreferenced local function has been removed
+ D:\quake3\MissionPack\code\cgame\cg_main.c(1513) : see declaration of 'CG_Cvar_Get'
+cg_marks.c
+cg_players.c
+D:\quake3\MissionPack\code\cgame\cg_players.c(2209) : warning C4505: 'CG_PlayerTokens' : unreferenced local function has been removed
+ D:\quake3\MissionPack\code\cgame\cg_players.c(1371) : see declaration of 'CG_PlayerTokens'
+cg_playerstate.c
+cg_predict.c
+cg_rankings.c
+cg_scoreboard.c
+cg_servercmds.c
+cg_snapshot.c
+cg_syscalls.c
+cg_view.c
+cg_weapons.c
+q_math.c
+q_shared.c
+ui_shared.c
+D:\quake3\MissionPack\code\ui\ui_shared.c(2223) : warning C4189: 'parent' : local variable is initialized but not referenced
+D:\quake3\MissionPack\code\ui\ui_shared.c(3501) : warning C4189: 'collision' : local variable is initialized but not referenced
+D:\quake3\MissionPack\code\ui\ui_shared.c(4622) : warning C4505: 'Controls_SetDefaults' : unreferenced local function has been removed
+ D:\quake3\MissionPack\code\ui\ui_shared.c(2595) : see declaration of 'Controls_SetDefaults'
+D:\quake3\MissionPack\code\ui\ui_shared.c(1540) : warning C4701: local variable 'value' may be used without having been initialized
+D:\quake3\MissionPack\code\ui\ui_shared.c(1566) : warning C4701: local variable 'value' may be used without having been initialized
+D:\quake3\MissionPack\code\ui\ui_shared.c(1912) : warning C4702: unreachable code
+D:\quake3\MissionPack\code\ui\ui_shared.c(4013) : warning C4702: unreachable code
+D:\quake3\MissionPack\code\ui\ui_shared.c(4056) : warning C4702: unreachable code
+Linking...
+ Creating library Release/cgamex86.lib and object Release/cgamex86.exp
+
+
+
+<h3>Results</h3>
+cgamex86.dll - 0 error(s), 12 warning(s)
+</pre>
+</body>
+</html>
diff --git a/code/cgame/cgame.q3asm b/code/cgame/cgame.q3asm
index 7923f73..8bd1d4a 100755
--- a/code/cgame/cgame.q3asm
+++ b/code/cgame/cgame.q3asm
@@ -1,26 +1,26 @@
--o "\quake3\baseq3\vm\cgame"
-cg_main
-..\cg_syscalls
-cg_consolecmds
-cg_draw
-cg_drawtools
-cg_effects
-cg_ents
-cg_event
-cg_info
-cg_localents
-cg_marks
-cg_players
-cg_playerstate
-cg_predict
-cg_scoreboard
-cg_servercmds
-cg_snapshot
-cg_view
-cg_weapons
-bg_slidemove
-bg_pmove
-bg_lib
-bg_misc
-q_math
-q_shared
+-o "\quake3\baseq3\vm\cgame"
+cg_main
+..\cg_syscalls
+cg_consolecmds
+cg_draw
+cg_drawtools
+cg_effects
+cg_ents
+cg_event
+cg_info
+cg_localents
+cg_marks
+cg_players
+cg_playerstate
+cg_predict
+cg_scoreboard
+cg_servercmds
+cg_snapshot
+cg_view
+cg_weapons
+bg_slidemove
+bg_pmove
+bg_lib
+bg_misc
+q_math
+q_shared
diff --git a/code/cgame/cgame.sh b/code/cgame/cgame.sh
index 62f2570..cdba268 100755
--- a/code/cgame/cgame.sh
+++ b/code/cgame/cgame.sh
@@ -1,36 +1,36 @@
-#!/bin/sh
-
-mkdir -p vm
-cd vm
-
-CC="q3lcc -DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../q3_ui"
-
-$CC ../cg_syscalls.c
-$CC ../../game/bg_misc.c
-$CC ../../game/bg_pmove.c
-$CC ../../game/bg_slidemove.c
-$CC ../../game/bg_lib.c
-$CC ../../game/q_math.c
-$CC ../../game/q_shared.c
-$CC ../cg_consolecmds.c
-$CC ../cg_draw.c
-$CC ../cg_drawtools.c
-$CC ../cg_effects.c
-$CC ../cg_ents.c
-$CC ../cg_event.c
-$CC ../cg_info.c
-$CC ../cg_localents.c
-$CC ../cg_main.c
-$CC ../cg_marks.c
-$CC ../cg_players.c
-$CC ../cg_playerstate.c
-$CC ../cg_predict.c
-$CC ../cg_scoreboard.c
-$CC ../cg_servercmds.c
-$CC ../cg_snapshot.c
-$CC ../cg_view.c
-$CC ../cg_weapons.c
-
-q3asm -f ../cgame
-
-cd ..
+#!/bin/sh
+
+mkdir -p vm
+cd vm
+
+CC="q3lcc -DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../q3_ui"
+
+$CC ../cg_syscalls.c
+$CC ../../game/bg_misc.c
+$CC ../../game/bg_pmove.c
+$CC ../../game/bg_slidemove.c
+$CC ../../game/bg_lib.c
+$CC ../../game/q_math.c
+$CC ../../game/q_shared.c
+$CC ../cg_consolecmds.c
+$CC ../cg_draw.c
+$CC ../cg_drawtools.c
+$CC ../cg_effects.c
+$CC ../cg_ents.c
+$CC ../cg_event.c
+$CC ../cg_info.c
+$CC ../cg_localents.c
+$CC ../cg_main.c
+$CC ../cg_marks.c
+$CC ../cg_players.c
+$CC ../cg_playerstate.c
+$CC ../cg_predict.c
+$CC ../cg_scoreboard.c
+$CC ../cg_servercmds.c
+$CC ../cg_snapshot.c
+$CC ../cg_view.c
+$CC ../cg_weapons.c
+
+q3asm -f ../cgame
+
+cd ..
diff --git a/code/cgame/cgame.vcproj b/code/cgame/cgame.vcproj
index 4dbdfd0..fe2a212 100755
--- a/code/cgame/cgame.vcproj
+++ b/code/cgame/cgame.vcproj
@@ -1,1221 +1,1221 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="cgame"
- SccProjectName="&quot;$/MissionPack/code/cgame&quot;, NPAAAAAA"
- SccLocalPath=".">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory=".\Release_TA"
- IntermediateDirectory=".\Release_TA"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- OptimizeForProcessor="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK"
- StringPooling="TRUE"
- RuntimeLibrary="4"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Release_TA/cgame.pch"
- AssemblerListingLocation=".\Release_TA/"
- ObjectFile=".\Release_TA/"
- ProgramDataBaseFileName=".\Release_TA/"
- WarningLevel="4"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="../Release_TA/cgamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- ModuleDefinitionFile=".\cgame.def"
- ProgramDatabaseFile=".\Release_TA/cgamex86.pdb"
- GenerateMapFile="TRUE"
- MapFileName=".\Release_TA/cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary=".\Release_TA/cgamex86.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="TRUE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Release_TA/cgame.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory=".\Debug"
- IntermediateDirectory=".\Debug"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- OptimizeForProcessor="1"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Debug/cgame.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="../Debug/cgamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- ModuleDefinitionFile=".\cgame.def"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Debug/cgamex86.pdb"
- GenerateMapFile="TRUE"
- MapFileName=".\Debug/cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary=".\Debug/cgamex86.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="TRUE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/cgame.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- OptimizeForProcessor="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
- StringPooling="TRUE"
- RuntimeLibrary="4"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Release/cgame.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- WarningLevel="4"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="../Release/cgamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- ModuleDefinitionFile=".\cgame.def"
- ProgramDatabaseFile=".\Release/cgamex86.pdb"
- GenerateMapFile="TRUE"
- MapFileName=".\Release/cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary=".\Release/cgamex86.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="TRUE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/cgame.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory=".\Debug_TA"
- IntermediateDirectory=".\Debug_TA"
- ConfigurationType="2"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- OptimizeForProcessor="1"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Debug_TA/cgame.pch"
- AssemblerListingLocation=".\Debug_TA/"
- ObjectFile=".\Debug_TA/"
- ProgramDataBaseFileName=".\Debug_TA/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib"
- OutputFile="..\Debug_TA\cgamex86.dll"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- ModuleDefinitionFile=".\cgame.def"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Debug_TA/cgamex86.pdb"
- GenerateMapFile="TRUE"
- MapFileName=".\Debug_TA/cgamex86.map"
- SubSystem="2"
- BaseAddress="0x30000000"
- ImportLibrary=".\Debug_TA/cgamex86.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="TRUE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug_TA/cgame.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="c">
- <File
- RelativePath="..\game\bg_lib.c">
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\game\bg_misc.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\game\bg_pmove.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\game\bg_slidemove.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_consolecmds.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_draw.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_drawtools.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_effects.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_ents.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_event.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_info.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_localents.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_main.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_marks.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_newDraw.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_players.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_playerstate.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_predict.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_scoreboard.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_servercmds.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_snapshot.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_syscalls.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_view.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="cg_weapons.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\game\q_math.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\game\q_shared.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ui\ui_shared.c">
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
- BrowseInformation="1"/>
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h">
- <File
- RelativePath="..\game\bg_public.h">
- </File>
- <File
- RelativePath="cg_local.h">
- </File>
- <File
- RelativePath="cg_public.h">
- </File>
- <File
- RelativePath="..\game\q_shared.h">
- </File>
- <File
- RelativePath="..\game\surfaceflags.h">
- </File>
- </Filter>
- <File
- RelativePath="cgame.def">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="cgame"
+ SccProjectName="&quot;$/MissionPack/code/cgame&quot;, NPAAAAAA"
+ SccLocalPath=".">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release TA|Win32"
+ OutputDirectory=".\Release_TA"
+ IntermediateDirectory=".\Release_TA"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OptimizeForProcessor="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release_TA/cgame.pch"
+ AssemblerListingLocation=".\Release_TA/"
+ ObjectFile=".\Release_TA/"
+ ProgramDataBaseFileName=".\Release_TA/"
+ WarningLevel="4"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="odbc32.lib odbccp32.lib"
+ OutputFile="../Release_TA/cgamex86.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile=".\cgame.def"
+ ProgramDatabaseFile=".\Release_TA/cgamex86.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\Release_TA/cgamex86.map"
+ SubSystem="2"
+ BaseAddress="0x30000000"
+ ImportLibrary=".\Release_TA/cgamex86.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release_TA/cgame.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ OptimizeForProcessor="1"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/cgame.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="odbc32.lib odbccp32.lib"
+ OutputFile="../Debug/cgamex86.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile=".\cgame.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/cgamex86.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\Debug/cgamex86.map"
+ SubSystem="2"
+ BaseAddress="0x30000000"
+ ImportLibrary=".\Debug/cgamex86.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/cgame.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ OptimizeForProcessor="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/cgame.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="4"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="odbc32.lib odbccp32.lib"
+ OutputFile="../Release/cgamex86.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile=".\cgame.def"
+ ProgramDatabaseFile=".\Release/cgamex86.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\Release/cgamex86.map"
+ SubSystem="2"
+ BaseAddress="0x30000000"
+ ImportLibrary=".\Release/cgamex86.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/cgame.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug TA|Win32"
+ OutputDirectory=".\Debug_TA"
+ IntermediateDirectory=".\Debug_TA"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ OptimizeForProcessor="1"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug_TA/cgame.pch"
+ AssemblerListingLocation=".\Debug_TA/"
+ ObjectFile=".\Debug_TA/"
+ ProgramDataBaseFileName=".\Debug_TA/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="odbc32.lib odbccp32.lib"
+ OutputFile="..\Debug_TA\cgamex86.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile=".\cgame.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug_TA/cgamex86.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\Debug_TA/cgamex86.map"
+ SubSystem="2"
+ BaseAddress="0x30000000"
+ ImportLibrary=".\Debug_TA/cgamex86.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug_TA/cgame.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c">
+ <File
+ RelativePath="..\game\bg_lib.c">
+ <FileConfiguration
+ Name="Release TA|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\game\bg_misc.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\game\bg_pmove.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\game\bg_slidemove.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_consolecmds.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_draw.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_drawtools.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_effects.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_ents.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_event.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_info.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_localents.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_main.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_marks.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_newDraw.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_players.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_playerstate.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_predict.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_scoreboard.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_servercmds.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_snapshot.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_syscalls.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_view.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="cg_weapons.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\game\q_math.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\game\q_shared.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\ui\ui_shared.c">
+ <FileConfiguration
+ Name="Release TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;$(NoInherit)"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug TA|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;MISSIONPACK;$(NoInherit)"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h">
+ <File
+ RelativePath="..\game\bg_public.h">
+ </File>
+ <File
+ RelativePath="cg_local.h">
+ </File>
+ <File
+ RelativePath="cg_public.h">
+ </File>
+ <File
+ RelativePath="..\game\q_shared.h">
+ </File>
+ <File
+ RelativePath="..\game\surfaceflags.h">
+ </File>
+ </Filter>
+ <File
+ RelativePath="cgame.def">
+ <FileConfiguration
+ Name="Debug TA|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/code/cgame/cgame_ta.bat b/code/cgame/cgame_ta.bat
index 266e017..098be0e 100755
--- a/code/cgame/cgame_ta.bat
+++ b/code/cgame/cgame_ta.bat
@@ -1,65 +1,65 @@
-rem make sure we have a safe environement
-set LIBRARY=
-set INCLUDE=
-
-mkdir vm
-cd vm
-set cc=lcc -DQ3_VM -DMISSIONPACK -DCGAME -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
-
-%cc% ../../game/bg_misc.c
-@if errorlevel 1 goto quit
-%cc% ../../game/bg_pmove.c
-@if errorlevel 1 goto quit
-%cc% ../../game/bg_slidemove.c
-@if errorlevel 1 goto quit
-%cc% ../../game/bg_lib.c
-@if errorlevel 1 goto quit
-%cc% ../../game/q_math.c
-@if errorlevel 1 goto quit
-%cc% ../../game/q_shared.c
-@if errorlevel 1 goto quit
-%cc% ../cg_consolecmds.c
-@if errorlevel 1 goto quit
-%cc% ../cg_draw.c
-@if errorlevel 1 goto quit
-%cc% ../cg_drawtools.c
-@if errorlevel 1 goto quit
-%cc% ../cg_effects.c
-@if errorlevel 1 goto quit
-%cc% ../cg_ents.c
-@if errorlevel 1 goto quit
-%cc% ../cg_event.c
-@if errorlevel 1 goto quit
-%cc% ../cg_info.c
-@if errorlevel 1 goto quit
-%cc% ../cg_localents.c
-@if errorlevel 1 goto quit
-%cc% ../cg_main.c
-@if errorlevel 1 goto quit
-%cc% ../cg_marks.c
-@if errorlevel 1 goto quit
-%cc% ../cg_players.c
-@if errorlevel 1 goto quit
-%cc% ../cg_playerstate.c
-@if errorlevel 1 goto quit
-%cc% ../cg_predict.c
-@if errorlevel 1 goto quit
-%cc% ../cg_scoreboard.c
-@if errorlevel 1 goto quit
-%cc% ../cg_servercmds.c
-@if errorlevel 1 goto quit
-%cc% ../cg_snapshot.c
-@if errorlevel 1 goto quit
-%cc% ../cg_view.c
-@if errorlevel 1 goto quit
-%cc% ../cg_weapons.c
-@if errorlevel 1 goto quit
-%cc% ../../ui/ui_shared.c
-@if errorlevel 1 goto quit
-%cc% ../cg_newdraw.c
-@if errorlevel 1 goto quit
-
-
-q3asm -f ../cgame_ta
-:quit
-cd ..
+rem make sure we have a safe environement
+set LIBRARY=
+set INCLUDE=
+
+mkdir vm
+cd vm
+set cc=lcc -DQ3_VM -DMISSIONPACK -DCGAME -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
+
+%cc% ../../game/bg_misc.c
+@if errorlevel 1 goto quit
+%cc% ../../game/bg_pmove.c
+@if errorlevel 1 goto quit
+%cc% ../../game/bg_slidemove.c
+@if errorlevel 1 goto quit
+%cc% ../../game/bg_lib.c
+@if errorlevel 1 goto quit
+%cc% ../../game/q_math.c
+@if errorlevel 1 goto quit
+%cc% ../../game/q_shared.c
+@if errorlevel 1 goto quit
+%cc% ../cg_consolecmds.c
+@if errorlevel 1 goto quit
+%cc% ../cg_draw.c
+@if errorlevel 1 goto quit
+%cc% ../cg_drawtools.c
+@if errorlevel 1 goto quit
+%cc% ../cg_effects.c
+@if errorlevel 1 goto quit
+%cc% ../cg_ents.c
+@if errorlevel 1 goto quit
+%cc% ../cg_event.c
+@if errorlevel 1 goto quit
+%cc% ../cg_info.c
+@if errorlevel 1 goto quit
+%cc% ../cg_localents.c
+@if errorlevel 1 goto quit
+%cc% ../cg_main.c
+@if errorlevel 1 goto quit
+%cc% ../cg_marks.c
+@if errorlevel 1 goto quit
+%cc% ../cg_players.c
+@if errorlevel 1 goto quit
+%cc% ../cg_playerstate.c
+@if errorlevel 1 goto quit
+%cc% ../cg_predict.c
+@if errorlevel 1 goto quit
+%cc% ../cg_scoreboard.c
+@if errorlevel 1 goto quit
+%cc% ../cg_servercmds.c
+@if errorlevel 1 goto quit
+%cc% ../cg_snapshot.c
+@if errorlevel 1 goto quit
+%cc% ../cg_view.c
+@if errorlevel 1 goto quit
+%cc% ../cg_weapons.c
+@if errorlevel 1 goto quit
+%cc% ../../ui/ui_shared.c
+@if errorlevel 1 goto quit
+%cc% ../cg_newdraw.c
+@if errorlevel 1 goto quit
+
+
+q3asm -f ../cgame_ta
+:quit
+cd ..
diff --git a/code/cgame/cgame_ta.q3asm b/code/cgame/cgame_ta.q3asm
index 8b14ed9..629a778 100755
--- a/code/cgame/cgame_ta.q3asm
+++ b/code/cgame/cgame_ta.q3asm
@@ -1,28 +1,28 @@
--o "\quake3\missionpack\vm\cgame"
-cg_main
-..\cg_syscalls
-cg_consolecmds
-cg_draw
-cg_drawtools
-cg_effects
-cg_ents
-cg_event
-cg_info
-cg_localents
-cg_marks
-cg_players
-cg_playerstate
-cg_predict
-cg_scoreboard
-cg_servercmds
-cg_snapshot
-cg_view
-cg_weapons
-bg_slidemove
-bg_pmove
-bg_lib
-bg_misc
-q_math
-q_shared
-ui_shared
-cg_newdraw
+-o "\quake3\missionpack\vm\cgame"
+cg_main
+..\cg_syscalls
+cg_consolecmds
+cg_draw
+cg_drawtools
+cg_effects
+cg_ents
+cg_event
+cg_info
+cg_localents
+cg_marks
+cg_players
+cg_playerstate
+cg_predict
+cg_scoreboard
+cg_servercmds
+cg_snapshot
+cg_view
+cg_weapons
+bg_slidemove
+bg_pmove
+bg_lib
+bg_misc
+q_math
+q_shared
+ui_shared
+cg_newdraw
diff --git a/code/cgame/cgame_ta.sh b/code/cgame/cgame_ta.sh
index 5f87eb5..ce22b30 100755
--- a/code/cgame/cgame_ta.sh
+++ b/code/cgame/cgame_ta.sh
@@ -1,38 +1,38 @@
-#!/bin/sh
-
-mkdir -p vm
-cd vm
-
-CC="q3lcc -DQ3_VM -DCGAME -DMISSIONPACK -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../ui"
-
-$CC ../cg_syscalls.c
-$CC ../../game/bg_misc.c
-$CC ../../game/bg_pmove.c
-$CC ../../game/bg_slidemove.c
-$CC ../../game/bg_lib.c
-$CC ../../game/q_math.c
-$CC ../../game/q_shared.c
-$CC ../cg_consolecmds.c
-$CC ../cg_draw.c
-$CC ../cg_drawtools.c
-$CC ../cg_effects.c
-$CC ../cg_ents.c
-$CC ../cg_event.c
-$CC ../cg_info.c
-$CC ../cg_localents.c
-$CC ../cg_main.c
-$CC ../cg_marks.c
-$CC ../cg_players.c
-$CC ../cg_playerstate.c
-$CC ../cg_predict.c
-$CC ../cg_scoreboard.c
-$CC ../cg_servercmds.c
-$CC ../cg_snapshot.c
-$CC ../cg_view.c
-$CC ../cg_weapons.c
-$CC ../../ui/ui_shared.c
-$CC ../cg_newdraw.c
-
-q3asm -f ../cgame_ta
-
-cd ..
+#!/bin/sh
+
+mkdir -p vm
+cd vm
+
+CC="q3lcc -DQ3_VM -DCGAME -DMISSIONPACK -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../ui"
+
+$CC ../cg_syscalls.c
+$CC ../../game/bg_misc.c
+$CC ../../game/bg_pmove.c
+$CC ../../game/bg_slidemove.c
+$CC ../../game/bg_lib.c
+$CC ../../game/q_math.c
+$CC ../../game/q_shared.c
+$CC ../cg_consolecmds.c
+$CC ../cg_draw.c
+$CC ../cg_drawtools.c
+$CC ../cg_effects.c
+$CC ../cg_ents.c
+$CC ../cg_event.c
+$CC ../cg_info.c
+$CC ../cg_localents.c
+$CC ../cg_main.c
+$CC ../cg_marks.c
+$CC ../cg_players.c
+$CC ../cg_playerstate.c
+$CC ../cg_predict.c
+$CC ../cg_scoreboard.c
+$CC ../cg_servercmds.c
+$CC ../cg_snapshot.c
+$CC ../cg_view.c
+$CC ../cg_weapons.c
+$CC ../../ui/ui_shared.c
+$CC ../cg_newdraw.c
+
+q3asm -f ../cgame_ta
+
+cd ..
diff --git a/code/cgame/tr_types.h b/code/cgame/tr_types.h
index ec2e054..d68a174 100755
--- a/code/cgame/tr_types.h
+++ b/code/cgame/tr_types.h
@@ -1,229 +1,229 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-#ifndef __TR_TYPES_H
-#define __TR_TYPES_H
-
-
-#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
-#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
-
-// renderfx flags
-#define RF_MINLIGHT 1 // allways have some light (viewmodel, some items)
-#define RF_THIRD_PERSON 2 // don't draw through eyes, only mirrors (player bodies, chat sprites)
-#define RF_FIRST_PERSON 4 // only draw through eyes (view weapon, damage blood blob)
-#define RF_DEPTHHACK 8 // for view weapon Z crunching
-#define RF_NOSHADOW 64 // don't add stencil shadows
-
-#define RF_LIGHTING_ORIGIN 128 // use refEntity->lightingOrigin instead of refEntity->origin
- // for lighting. This allows entities to sink into the floor
- // with their origin going solid, and allows all parts of a
- // player to get the same lighting
-#define RF_SHADOW_PLANE 256 // use refEntity->shadowPlane
-#define RF_WRAP_FRAMES 512 // mod the model frames by the maxframes to allow continuous
- // animation without needing to know the frame count
-
-// refdef flags
-#define RDF_NOWORLDMODEL 1 // used for player configuration screen
-#define RDF_HYPERSPACE 4 // teleportation effect
-
-typedef struct {
- vec3_t xyz;
- float st[2];
- byte modulate[4];
-} polyVert_t;
-
-typedef struct poly_s {
- qhandle_t hShader;
- int numVerts;
- polyVert_t *verts;
-} poly_t;
-
-typedef enum {
- RT_MODEL,
- RT_POLY,
- RT_SPRITE,
- RT_BEAM,
- RT_RAIL_CORE,
- RT_RAIL_RINGS,
- RT_LIGHTNING,
- RT_PORTALSURFACE, // doesn't draw anything, just info for portals
-
- RT_MAX_REF_ENTITY_TYPE
-} refEntityType_t;
-
-typedef struct {
- refEntityType_t reType;
- int renderfx;
-
- qhandle_t hModel; // opaque type outside refresh
-
- // most recent data
- vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)
- float shadowPlane; // projection shadows go here, stencils go slightly lower
-
- vec3_t axis[3]; // rotation vectors
- qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale
- float origin[3]; // also used as MODEL_BEAM's "from"
- int frame; // also used as MODEL_BEAM's diameter
-
- // previous data for frame interpolation
- float oldorigin[3]; // also used as MODEL_BEAM's "to"
- int oldframe;
- float backlerp; // 0.0 = current, 1.0 = old
-
- // texturing
- int skinNum; // inline skin index
- qhandle_t customSkin; // NULL for default skin
- qhandle_t customShader; // use one image for the entire thing
-
- // misc
- byte shaderRGBA[4]; // colors used by rgbgen entity shaders
- float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers
- float shaderTime; // subtracted from refdef time to control effect start times
-
- // extra sprite information
- float radius;
- float rotation;
-} refEntity_t;
-
-
-#define MAX_RENDER_STRINGS 8
-#define MAX_RENDER_STRING_LENGTH 32
-
-typedef struct {
- int x, y, width, height;
- float fov_x, fov_y;
- vec3_t vieworg;
- vec3_t viewaxis[3]; // transformation matrix
-
- // time in milliseconds for shader effects and other time dependent rendering issues
- int time;
-
- int rdflags; // RDF_NOWORLDMODEL, etc
-
- // 1 bits will prevent the associated area from rendering at all
- byte areamask[MAX_MAP_AREA_BYTES];
-
- // text messages for deform text shaders
- char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
-} refdef_t;
-
-
-typedef enum {
- STEREO_CENTER,
- STEREO_LEFT,
- STEREO_RIGHT
-} stereoFrame_t;
-
-
-/*
-** glconfig_t
-**
-** Contains variables specific to the OpenGL configuration
-** being run right now. These are constant once the OpenGL
-** subsystem is initialized.
-*/
-typedef enum {
- TC_NONE,
- TC_S3TC
-} textureCompression_t;
-
-typedef enum {
- GLDRV_ICD, // driver is integrated with window system
- // WARNING: there are tests that check for
- // > GLDRV_ICD for minidriverness, so this
- // should always be the lowest value in this
- // enum set
- GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver
- GLDRV_VOODOO // driver is a 3Dfx standalone driver
-} glDriverType_t;
-
-typedef enum {
- GLHW_GENERIC, // where everthing works the way it should
- GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is
- // the hardware type then there can NOT exist a secondary
- // display adapter
- GLHW_RIVA128, // where you can't interpolate alpha
- GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures
- GLHW_PERMEDIA2 // where you don't have src*dst
-} glHardwareType_t;
-
-typedef struct {
- char renderer_string[MAX_STRING_CHARS];
- char vendor_string[MAX_STRING_CHARS];
- char version_string[MAX_STRING_CHARS];
- char extensions_string[BIG_INFO_STRING];
-
- int maxTextureSize; // queried from GL
- int maxActiveTextures; // multitexture ability
-
- int colorBits, depthBits, stencilBits;
-
- glDriverType_t driverType;
- glHardwareType_t hardwareType;
-
- qboolean deviceSupportsGamma;
- textureCompression_t textureCompression;
- qboolean textureEnvAddAvailable;
-
- int vidWidth, vidHeight;
- // aspect is the screen's physical width / height, which may be different
- // than scrWidth / scrHeight if the pixels are non-square
- // normal screens should be 4/3, but wide aspect monitors may be 16/9
- float windowAspect;
-
- int displayFrequency;
-
- // synonymous with "does rendering consume the entire screen?", therefore
- // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that
- // used CDS.
- qboolean isFullscreen;
- qboolean stereoEnabled;
- qboolean smpActive; // dual processor
-} glconfig_t;
-
-// FIXME: VM should be OS agnostic .. in theory
-
-/*
-#ifdef Q3_VM
-
-#define _3DFX_DRIVER_NAME "Voodoo"
-#define OPENGL_DRIVER_NAME "Default"
-
-#elif defined(_WIN32)
-*/
-
-#if defined(Q3_VM) || defined(_WIN32)
-
-#define _3DFX_DRIVER_NAME "3dfxvgl"
-#define OPENGL_DRIVER_NAME "opengl32"
-
-#else
-
-#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so"
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=524
-#define OPENGL_DRIVER_NAME "libGL.so.1"
-
-#endif // !defined _WIN32
-
-#endif // __TR_TYPES_H
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#ifndef __TR_TYPES_H
+#define __TR_TYPES_H
+
+
+#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
+#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
+
+// renderfx flags
+#define RF_MINLIGHT 1 // allways have some light (viewmodel, some items)
+#define RF_THIRD_PERSON 2 // don't draw through eyes, only mirrors (player bodies, chat sprites)
+#define RF_FIRST_PERSON 4 // only draw through eyes (view weapon, damage blood blob)
+#define RF_DEPTHHACK 8 // for view weapon Z crunching
+#define RF_NOSHADOW 64 // don't add stencil shadows
+
+#define RF_LIGHTING_ORIGIN 128 // use refEntity->lightingOrigin instead of refEntity->origin
+ // for lighting. This allows entities to sink into the floor
+ // with their origin going solid, and allows all parts of a
+ // player to get the same lighting
+#define RF_SHADOW_PLANE 256 // use refEntity->shadowPlane
+#define RF_WRAP_FRAMES 512 // mod the model frames by the maxframes to allow continuous
+ // animation without needing to know the frame count
+
+// refdef flags
+#define RDF_NOWORLDMODEL 1 // used for player configuration screen
+#define RDF_HYPERSPACE 4 // teleportation effect
+
+typedef struct {
+ vec3_t xyz;
+ float st[2];
+ byte modulate[4];
+} polyVert_t;
+
+typedef struct poly_s {
+ qhandle_t hShader;
+ int numVerts;
+ polyVert_t *verts;
+} poly_t;
+
+typedef enum {
+ RT_MODEL,
+ RT_POLY,
+ RT_SPRITE,
+ RT_BEAM,
+ RT_RAIL_CORE,
+ RT_RAIL_RINGS,
+ RT_LIGHTNING,
+ RT_PORTALSURFACE, // doesn't draw anything, just info for portals
+
+ RT_MAX_REF_ENTITY_TYPE
+} refEntityType_t;
+
+typedef struct {
+ refEntityType_t reType;
+ int renderfx;
+
+ qhandle_t hModel; // opaque type outside refresh
+
+ // most recent data
+ vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)
+ float shadowPlane; // projection shadows go here, stencils go slightly lower
+
+ vec3_t axis[3]; // rotation vectors
+ qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale
+ float origin[3]; // also used as MODEL_BEAM's "from"
+ int frame; // also used as MODEL_BEAM's diameter
+
+ // previous data for frame interpolation
+ float oldorigin[3]; // also used as MODEL_BEAM's "to"
+ int oldframe;
+ float backlerp; // 0.0 = current, 1.0 = old
+
+ // texturing
+ int skinNum; // inline skin index
+ qhandle_t customSkin; // NULL for default skin
+ qhandle_t customShader; // use one image for the entire thing
+
+ // misc
+ byte shaderRGBA[4]; // colors used by rgbgen entity shaders
+ float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers
+ float shaderTime; // subtracted from refdef time to control effect start times
+
+ // extra sprite information
+ float radius;
+ float rotation;
+} refEntity_t;
+
+
+#define MAX_RENDER_STRINGS 8
+#define MAX_RENDER_STRING_LENGTH 32
+
+typedef struct {
+ int x, y, width, height;
+ float fov_x, fov_y;
+ vec3_t vieworg;
+ vec3_t viewaxis[3]; // transformation matrix
+
+ // time in milliseconds for shader effects and other time dependent rendering issues
+ int time;
+
+ int rdflags; // RDF_NOWORLDMODEL, etc
+
+ // 1 bits will prevent the associated area from rendering at all
+ byte areamask[MAX_MAP_AREA_BYTES];
+
+ // text messages for deform text shaders
+ char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
+} refdef_t;
+
+
+typedef enum {
+ STEREO_CENTER,
+ STEREO_LEFT,
+ STEREO_RIGHT
+} stereoFrame_t;
+
+
+/*
+** glconfig_t
+**
+** Contains variables specific to the OpenGL configuration
+** being run right now. These are constant once the OpenGL
+** subsystem is initialized.
+*/
+typedef enum {
+ TC_NONE,
+ TC_S3TC
+} textureCompression_t;
+
+typedef enum {
+ GLDRV_ICD, // driver is integrated with window system
+ // WARNING: there are tests that check for
+ // > GLDRV_ICD for minidriverness, so this
+ // should always be the lowest value in this
+ // enum set
+ GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver
+ GLDRV_VOODOO // driver is a 3Dfx standalone driver
+} glDriverType_t;
+
+typedef enum {
+ GLHW_GENERIC, // where everthing works the way it should
+ GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is
+ // the hardware type then there can NOT exist a secondary
+ // display adapter
+ GLHW_RIVA128, // where you can't interpolate alpha
+ GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures
+ GLHW_PERMEDIA2 // where you don't have src*dst
+} glHardwareType_t;
+
+typedef struct {
+ char renderer_string[MAX_STRING_CHARS];
+ char vendor_string[MAX_STRING_CHARS];
+ char version_string[MAX_STRING_CHARS];
+ char extensions_string[BIG_INFO_STRING];
+
+ int maxTextureSize; // queried from GL
+ int maxActiveTextures; // multitexture ability
+
+ int colorBits, depthBits, stencilBits;
+
+ glDriverType_t driverType;
+ glHardwareType_t hardwareType;
+
+ qboolean deviceSupportsGamma;
+ textureCompression_t textureCompression;
+ qboolean textureEnvAddAvailable;
+
+ int vidWidth, vidHeight;
+ // aspect is the screen's physical width / height, which may be different
+ // than scrWidth / scrHeight if the pixels are non-square
+ // normal screens should be 4/3, but wide aspect monitors may be 16/9
+ float windowAspect;
+
+ int displayFrequency;
+
+ // synonymous with "does rendering consume the entire screen?", therefore
+ // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that
+ // used CDS.
+ qboolean isFullscreen;
+ qboolean stereoEnabled;
+ qboolean smpActive; // dual processor
+} glconfig_t;
+
+// FIXME: VM should be OS agnostic .. in theory
+
+/*
+#ifdef Q3_VM
+
+#define _3DFX_DRIVER_NAME "Voodoo"
+#define OPENGL_DRIVER_NAME "Default"
+
+#elif defined(_WIN32)
+*/
+
+#if defined(Q3_VM) || defined(_WIN32)
+
+#define _3DFX_DRIVER_NAME "3dfxvgl"
+#define OPENGL_DRIVER_NAME "opengl32"
+
+#else
+
+#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so"
+// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=524
+#define OPENGL_DRIVER_NAME "libGL.so.1"
+
+#endif // !defined _WIN32
+
+#endif // __TR_TYPES_H