From 76a5aa612381ba1ba7567ca408197c235f5869e5 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Wed, 3 Jan 2001 21:54:12 +0000 Subject: im making a right mess of this --- src/cgame/cg_consolecmds.c | 307 ----- src/cgame/cg_draw.c | 2355 ------------------------------------ src/cgame/cg_drawtools.c | 854 -------------- src/cgame/cg_ents.c | 1016 ---------------- src/cgame/cg_event.c | 1018 ---------------- src/cgame/cg_local.h | 1630 ------------------------- src/cgame/cg_main.c | 1132 ------------------ src/cgame/cg_marks.c | 298 ----- src/cgame/cg_mem.c | 62 - src/cgame/cg_players.c | 2092 -------------------------------- src/cgame/cg_playerstate.c | 502 -------- src/cgame/cg_predict.c | 615 ---------- src/cgame/cg_public.h | 225 ---- src/cgame/cg_scanner.c | 117 -- src/cgame/cg_servercmds.c | 1021 ---------------- src/cgame/cg_snapshot.c | 402 ------- src/cgame/cg_syscalls.asm | 99 -- src/cgame/cg_syscalls.c | 396 ------- src/cgame/cg_view.c | 976 --------------- src/cgame/cg_weapons.c | 1994 ------------------------------- src/cgame/tr_types.h | 224 ---- src/game/bg_lib.c | 1337 --------------------- src/game/bg_lib.h | 94 -- src/game/bg_local.h | 110 -- src/game/bg_misc.c | 1709 --------------------------- src/game/bg_pmove.c | 2818 -------------------------------------------- src/game/bg_public.h | 783 ------------ src/game/bg_slidemove.c | 327 ----- src/game/g_active.c | 1059 ----------------- src/game/g_buildable.c | 627 ---------- src/game/g_client.c | 1543 ------------------------ src/game/g_cmds.c | 2050 -------------------------------- src/game/g_combat.c | 1193 ------------------- src/game/g_local.h | 977 --------------- src/game/g_main.c | 1881 ----------------------------- src/game/g_mem.c | 64 - src/game/g_misc.c | 384 ------ src/game/g_missile.c | 519 -------- src/game/g_mover.c | 1490 ----------------------- src/game/g_public.h | 413 ------- src/game/g_session.c | 188 --- src/game/g_spawn.c | 635 ---------- src/game/g_svcmds.c | 488 -------- src/game/g_syscalls.asm | 217 ---- src/game/g_syscalls.c | 765 ------------ src/game/g_target.c | 472 -------- src/game/g_team.c | 1046 ---------------- src/game/g_trigger.c | 469 -------- src/game/g_utils.c | 718 ----------- src/game/g_weapon.c | 800 ------------- src/game/q_math.c | 1355 --------------------- src/game/q_shared.c | 1229 ------------------- src/game/q_shared.h | 1206 ------------------- src/game/surfaceflags.h | 81 -- src/ui/ui_local.h | 1111 ----------------- src/ui/ui_public.h | 168 --- 56 files changed, 47661 deletions(-) delete mode 100644 src/cgame/cg_consolecmds.c delete mode 100644 src/cgame/cg_draw.c delete mode 100644 src/cgame/cg_drawtools.c delete mode 100644 src/cgame/cg_ents.c delete mode 100644 src/cgame/cg_event.c delete mode 100644 src/cgame/cg_local.h delete mode 100644 src/cgame/cg_main.c delete mode 100644 src/cgame/cg_marks.c delete mode 100644 src/cgame/cg_mem.c delete mode 100644 src/cgame/cg_players.c delete mode 100644 src/cgame/cg_playerstate.c delete mode 100644 src/cgame/cg_predict.c delete mode 100644 src/cgame/cg_public.h delete mode 100644 src/cgame/cg_scanner.c delete mode 100644 src/cgame/cg_servercmds.c delete mode 100644 src/cgame/cg_snapshot.c delete mode 100644 src/cgame/cg_syscalls.asm delete mode 100644 src/cgame/cg_syscalls.c delete mode 100644 src/cgame/cg_view.c delete mode 100644 src/cgame/cg_weapons.c delete mode 100644 src/cgame/tr_types.h delete mode 100644 src/game/bg_lib.c delete mode 100644 src/game/bg_lib.h delete mode 100644 src/game/bg_local.h delete mode 100644 src/game/bg_misc.c delete mode 100644 src/game/bg_pmove.c delete mode 100644 src/game/bg_public.h delete mode 100644 src/game/bg_slidemove.c delete mode 100644 src/game/g_active.c delete mode 100644 src/game/g_buildable.c delete mode 100644 src/game/g_client.c delete mode 100644 src/game/g_cmds.c delete mode 100644 src/game/g_combat.c delete mode 100644 src/game/g_local.h delete mode 100644 src/game/g_main.c delete mode 100644 src/game/g_mem.c delete mode 100644 src/game/g_misc.c delete mode 100644 src/game/g_missile.c delete mode 100644 src/game/g_mover.c delete mode 100644 src/game/g_public.h delete mode 100644 src/game/g_session.c delete mode 100644 src/game/g_spawn.c delete mode 100644 src/game/g_svcmds.c delete mode 100644 src/game/g_syscalls.asm delete mode 100644 src/game/g_syscalls.c delete mode 100644 src/game/g_target.c delete mode 100644 src/game/g_team.c delete mode 100644 src/game/g_trigger.c delete mode 100644 src/game/g_utils.c delete mode 100644 src/game/g_weapon.c delete mode 100644 src/game/q_math.c delete mode 100644 src/game/q_shared.c delete mode 100644 src/game/q_shared.h delete mode 100644 src/game/surfaceflags.h delete mode 100644 src/ui/ui_local.h delete mode 100644 src/ui/ui_public.h diff --git a/src/cgame/cg_consolecmds.c b/src/cgame/cg_consolecmds.c deleted file mode 100644 index ef5a79ee..00000000 --- a/src/cgame/cg_consolecmds.c +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_consolecmds.c -- text commands typed in at the local console, or -// executed by a key binding - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - - - -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 ) { - 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; - } -} - -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 ); -} - -/* -================== -CG_StartOrbit_f -================== -*/ - -static void CG_StartOrbit_f( void ) { - 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"); - } -} - - -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 }, - { "startOrbit", CG_StartOrbit_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 ("class"); - trap_AddCommand ("build"); - trap_AddCommand ("buy"); - trap_AddCommand ("itemact"); - trap_AddCommand ("itemdeact"); - trap_AddCommand ("itemtoggle"); - trap_AddCommand ("destroy"); - trap_AddCommand ("torch"); - trap_AddCommand ("menu"); - trap_AddCommand ("defmenu"); - trap_AddCommand ("undefmenu"); - trap_AddCommand ("loaddefered"); // spelled wrong, but not changing for demo -} diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c deleted file mode 100644 index 7dad03c3..00000000 --- a/src/cgame/cg_draw.c +++ /dev/null @@ -1,2355 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_draw.c -- draw all of the graphical elements during -// active (after loading) gameplay - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - -int drawTeamOverlayModificationCount = -1; -int sortedTeamPlayers[TEAM_MAXOVERLAY]; -int numSortedTeamPlayers; - -char systemChat[256]; -char teamChat1[256]; -char teamChat2[256]; - -/* -============== -CG_DrawField - -Draws large numbers for status bar and powerups -============== -*/ -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--; - } -} - - -/* -================ -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 );; - - CG_Draw3DModel( x, y, w, h, - team == TEAM_HUMANS ? cgs.media.redFlagModel : cgs.media.blueFlagModel, - 0, origin, angles ); - } else if ( cg_drawIcons.integer ) { - gitem_t *item = BG_FindItemForPowerup( team == TEAM_HUMANS ? PW_REDFLAG : PW_BLUEFLAG ); - - CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon ); - } -} - -/* -================ -CG_DrawStatusBarHead - -================ -*/ -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 ); -} - -/* -================ -CG_DrawStatusBarFlag - -================ -*/ -static void CG_DrawStatusBarFlag( float x, int team ) { - CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse ); -} - - -/* -================ -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_HUMANS ) { - hcolor[0] = 1; - hcolor[1] = 0; - hcolor[2] = 0; - } else if ( team == TEAM_DROIDS ) { - 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_DrawLighting - -================ -*/ -static void CG_DrawLighting( void ) -{ - centity_t *cent; - byte lum; - static byte lastLum; - vec3_t point, direction; - - cent = &cg_entities[cg.snap->ps.clientNum]; - - VectorCopy( cent->lerpOrigin, point ); - //TA: when wall climbing the viewheight is not straight up - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( point, 32, cg.predictedPlayerState.grapplePoint, point ); - else - point[ 2 ] += 32; - - AngleVectors( cg.predictedPlayerState.viewangles, direction, NULL, NULL ); - - lum = CG_LightFromDirection( point, direction ); - //CG_Printf( "%d\n", lum ); - if( abs( lastLum - lum ) > 4 ) - lastLum = lum; - - if( BG_activated( UP_NVG, cg.snap->ps.stats ) ) - CG_DrawPic( 0, 0, 640, 480, cgs.media.humanNV ); - - switch( cg.snap->ps.stats[ STAT_PCLASS ] ) - { - case PCL_D_BASE: - case PCL_D_BUILDER: - if( lastLum < 10 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav80 ); - else if( lastLum >= 10 && lastLum < 16 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav75 ); - else if( lastLum >= 16 && lastLum < 22 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav70 ); - else if( lastLum >= 22 && lastLum < 28 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav65 ); - else if( lastLum >= 28 && lastLum < 34 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav60 ); - else if( lastLum >= 34 && lastLum < 40 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav55 ); - else if( lastLum >= 40 && lastLum < 46 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav50 ); - else if( lastLum >= 46 && lastLum < 53 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav45 ); - else if( lastLum >= 53 && lastLum < 61 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav40 ); - else if( lastLum >= 61 && lastLum < 70 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav35 ); - else if( lastLum >= 70 && lastLum < 80 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav30 ); - else if( lastLum >= 80 && lastLum < 100 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav25 ); - else if( lastLum >= 100 && lastLum < 130 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav20 ); - else if( lastLum >= 130 && lastLum < 180 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav15 ); - else if( lastLum >= 180 ) - CG_DrawPic( -4, -4, 648, 488, cgs.media.droidNav10 ); - break; - } - - //fade to black if stamina is low - if( ( cg.snap->ps.stats[ STAT_STAMINA ] < -800 ) && - ( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) - { - vec4_t black = { 0, 0, 0, 0 }; - black[ 3 ] = 1.0 - ( (float)( cg.snap->ps.stats[ STAT_STAMINA ] + 1000 ) / 200.0f ); - trap_R_SetColor( black ); - CG_DrawPic( 0, 0, 640, 480, cgs.media.whiteShader ); - trap_R_SetColor( NULL ); - } -} - -/* -================ -CG_DrawStatusBar - -================ -*/ -static void CG_DrawStatusBar( void ) { - int color; - centity_t *cent; - playerState_t *ps; - int value; - int ammo, clips, maxclips; - vec4_t hcolor; - vec3_t angles; - vec3_t origin; - byte lum; - static byte lastLum; - 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} }; - { 0.3f, 0.4f, 0.3f, 1.0f } , // normal - { 1.0f, 0.2f, 0.2f, 1.0f }, // low health - {0.2f, 0.3f, 0.2f, 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 ); - - //TA: stop drawing all these silly 3d models on the hud. Saves space and is more realistic. - - // 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_HUMANS); - else if (cg.predictedPlayerState.powerups[PW_BLUEFLAG]) - CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_DROIDS);*/ - - /*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 ); - }*/ - - // - // ammo - // - if ( cent->currentState.weapon ) { - //TA: must mask off clips and maxClips - if( !BG_infiniteAmmo( cent->currentState.weapon ) ) - BG_unpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips, &maxclips ); - else - ammo = -1; - - if ( ammo > -1 ) { - if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING - && cg.predictedPlayerState.weaponTime > 100 ) { - // draw as dark grey when reloading - color = 2; // dark grey - } else { - if ( ammo >= 0 ) { - color = 0; // green - } else { - color = 1; // red - } - } - trap_R_SetColor( colors[color] ); - - CG_DrawField( 85, 432, 3, ammo); - - if( maxclips ) - CG_DrawField( 20, 432, 1, clips ); - - 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 ); - } - }*/ - } - } - - // - // stamina - // - #define STAM_HEIGHT 20 - #define STAM_WIDTH 10 - #define STAM_X 5 - #define STAM_Y 435 - if( ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - int stamina = ps->stats[ STAT_STAMINA ]; - int height = (int)( (float)stamina / ( 1000 / STAM_HEIGHT ) ); - vec4_t bcolor = { 0.5, 0.5, 0.5, 0.5 }; - - trap_R_SetColor( bcolor ); // white - CG_DrawPic( STAM_X, STAM_Y, STAM_WIDTH, STAM_HEIGHT * 2, cgs.media.whiteShader ); - - if( stamina > 0 ) - { - trap_R_SetColor( colors[0] ); // green - CG_DrawPic( STAM_X, STAM_Y + ( STAM_HEIGHT - height ), - STAM_WIDTH, height, cgs.media.whiteShader ); - } - - if( stamina < 0 ) - { - trap_R_SetColor( colors[1] ); // red - CG_DrawPic( STAM_X, STAM_Y + STAM_HEIGHT , STAM_WIDTH, -height, cgs.media.whiteShader ); - } - } - - // - // health+armor - // - if( ps->stats[ STAT_PTEAM ] == PTE_DROIDS ) - { - vec4_t fcolor = { 1, 0, 0, 0.5 }; //red half alpha - vec4_t tcolor = { 0.3, 0.8, 1, 1 }; //cyan no alpha - - value = (int)( (float)( (float)ps->stats[STAT_HEALTH] / ps->stats[STAT_MAX_HEALTH] ) * 100 ); - - CG_DrawFadePic( 20, 0, 30, 440, fcolor, tcolor, value, cgs.media.droidHealth ); - - value = (int)( (float)( (float)ps->stats[STAT_ARMOR] / ps->stats[STAT_MAX_HEALTH] ) * 100 ); - - if( value > 0 ) - CG_DrawFadePic( 580, 0, 30, 440, fcolor, tcolor, value, cgs.media.droidHealth ); - } - else - { - value = ps->stats[STAT_HEALTH]; - if ( value > 100 ) { - trap_R_SetColor( colors[0] ); // 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 ( 300, 432, 3, value); - CG_ColorForHealth( hcolor ); - trap_R_SetColor( hcolor ); - - value = ps->stats[STAT_ARMOR]; - if (value > 0 ) - { - trap_R_SetColor( colors[0] ); - CG_DrawField (541, 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 ); - }*/ - } - } - -} - -/* -=========================================================================================== - - 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_HUMANS && - cg.snap->ps.persistant[PERS_TEAM] != TEAM_DROIDS ) { - 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_HUMANS ) { - hcolor[0] = 1; - hcolor[1] = 0; - hcolor[2] = 0; - hcolor[3] = 0.33f; - } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_DROIDS ) - hcolor[0] = 0; - hcolor[1] = 0; - hcolor[2] = 1; - 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)) { - gitem_t *item; - - item = BG_FindItemForPowerup( j ); - - 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; -} - - -/* -===================== -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_DrawPoints - -Draw the small two score display -================= -*/ -static float CG_DrawPoints( float y ) -{ - const char *s; - int points, totalpoints, buildpoints; - int team; - int x, w; - float y1; - qboolean spectator; - - y -= BIGCHAR_HEIGHT + 8; - - y1 = y; - - - x = 640; - points = cg.snap->ps.persistant[PERS_POINTS]; - totalpoints = cg.snap->ps.persistant[PERS_TOTALPOINTS]; - - team = cg.snap->ps.stats[ STAT_PTEAM ]; - - if( team == PTE_DROIDS ) - buildpoints = cgs.aBuildPoints; - else if( team == PTE_HUMANS ) - buildpoints = cgs.hBuildPoints; - - spectator = ( team == PTE_NONE ); - - if( !spectator ) - { - s = va( "%2i", points ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - - CG_DrawBigString( x + 2, y, s, 1.0F ); - - s = va( "%2i", totalpoints ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - - CG_DrawBigString( x + 2, y, s, 1.0F ); - - s = va( "%2i", buildpoints ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8; - x -= w; - - CG_DrawBigString( x + 2, y, s, 1.0F ); - } - - return y1 - 8; -} - - -/* -================= -CG_DrawScores - -Draw the small two score display -================= -*/ -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; - color[1] = 0; - color[2] = 1; - 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_DROIDS ) { - 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; - color[1] = 0; - color[2] = 0; - 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_HUMANS ) { - 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] ); - } - } - } - - - 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; - color[1] = 0; - color[2] = 0; - 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; - color[1] = 0; - color[2] = 1; - 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; -} - -/* -================ -CG_DrawPowerups -================ -*/ -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; -} - - -/* -===================== -CG_DrawLowerRight - -===================== -*/ -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_DrawPoints( y ); - y = CG_DrawPowerups( y ); -} - -/* -=================== -CG_DrawPickupItem -=================== -*/ -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; -} - -/* -===================== -CG_DrawLowerLeft - -===================== -*/ -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 ); -} - - - -//=========================================================================================== - -/* -================= -CG_DrawTeamInfo -================= -*/ -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_HUMANS ) { - hcolor[0] = 1; - hcolor[1] = 0; - hcolor[2] = 0; - hcolor[3] = 0.33f; - } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_DROIDS ) { - hcolor[0] = 0; - hcolor[1] = 0; - hcolor[2] = 1; - hcolor[3] = 0.33f; - } else { - hcolor[0] = 0; - hcolor[1] = 1; - hcolor[2] = 0; - 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.0; - hcolor[3] = 1.0; - - 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 ); - } - } -} - -/* -=================== -CG_DrawHoldableItem -=================== -*/ -static void CG_DrawHoldableItem( void ) { - int value; - - //TA: not using q3 holdable item code - /*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 ); - }*/ - -} - - -/* -=================== -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 ); - - 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; - - // 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 - return; - } - - // also add text in center of screen - s = "Connection Interrupted"; - 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 - // - x = 640 - 48; - y = 480 - 48; - - 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; - 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; - - 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; - - 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; - w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH; - CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f ); - - 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); - } - 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; - } - s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo ); - CG_DrawSmallString( 0, 58, s, 1.0F ); -} - -/* -================= -CG_DrawTeamVote -================= -*/ -static void CG_DrawTeamVote(void) { - char *s; - int sec, cs_offset; - - if ( cgs.clientinfo->team == TEAM_HUMANS ) - cs_offset = 0; - else if ( cgs.clientinfo->team == TEAM_DROIDS ) - 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() { - return CG_DrawOldScoreboard(); -} - -/* -================= -CG_DrawIntermission -================= -*/ -static void CG_DrawIntermission( void ) { - if ( cgs.gametype == GT_SINGLE_PLAYER ) { - CG_DrawCenterString(); - return; - } - - 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); -} - -/* -================= -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 ); - 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 ); - } - } 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"; - } else { - s = ""; - } - 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 ); - } - - 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; - } - - w = CG_DrawStrlen( s ); - CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite, - qfalse, qtrue, cw, (int)(cw * 1.5), 0 ); -} - -//================================================================================== - -/* -================= -CG_Draw2D -================= -*/ -static void CG_Draw2D( void ) { - - // 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.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 ) { - CG_DrawLighting(); - CG_DrawStatusBar(); - CG_DrawAmmoWarning(); - CG_DrawCrosshair(); - CG_DrawCrosshairNames(); - CG_DrawWeaponSelect(); - CG_DrawHoldableItem(); - CG_DrawReward(); - } - if ( cgs.gametype >= GT_TEAM ) { - CG_DrawTeamInfo(); - } - if( cg.snap->ps.weapon == WP_SCANNER ) - CG_Scanner(); - } - - CG_DrawVote(); - CG_DrawTeamVote(); - - CG_DrawLagometer(); - - CG_DrawUpperRight(); - - CG_DrawLowerRight(); - - CG_DrawLowerLeft(); - - 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() { - CG_DrawOldTourneyScoreboard(); -} - - -/* -===================== -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/src/cgame/cg_drawtools.c b/src/cgame/cg_drawtools.c deleted file mode 100644 index e968fd8d..00000000 --- a/src/cgame/cg_drawtools.c +++ /dev/null @@ -1,854 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 ); -} - - -/* -================ -CG_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_DrawFadePic - -Coordinates are 640*480 virtual values -================= -*/ -void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor, vec4_t tcolor, float amount, qhandle_t hShader ) -{ - vec4_t finalcolor; - float inverse; - - inverse = 100 - amount; - - CG_AdjustFrom640( &x, &y, &width, &height ); - - finalcolor[0] = ( ( inverse * fcolor[0] ) + ( amount * tcolor[0] ) ) / 100; - finalcolor[1] = ( ( inverse * fcolor[1] ) + ( amount * tcolor[1] ) ) / 100; - finalcolor[2] = ( ( inverse * fcolor[2] ) + ( amount * tcolor[2] ) ) / 100; - finalcolor[3] = ( ( inverse * fcolor[3] ) + ( amount * tcolor[3] ) ) / 100; - - trap_R_SetColor( finalcolor ); - trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader ); - trap_R_SetColor( NULL ); -} - - -/* -=============== -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_HUMANS: - return red; - case TEAM_DROIDS: - 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 ); -} - - - - -/* -================= -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; - char ch; - 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; - char ch; - 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 ); -} - diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c deleted file mode 100644 index fc0783f7..00000000 --- a/src/cgame/cg_ents.c +++ /dev/null @@ -1,1016 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_ents.c -- present snapshot entities, happens every single frame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 && cent->currentState.eType != ET_TORCH ) - { - 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 = ¢->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 = ¢->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 ); - } - - // the weapons have their origin where they attatch to player - // models, so we need to offset them or they will rotate - // eccentricly - wi = NULL; - 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; - } - - // add to refresh list - trap_R_AddRefEntityToScene(&ent); - - // 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_Buildable -================== -*/ -static void CG_Buildable( centity_t *cent ) { - refEntity_t ent; - refEntity_t ent2; - entityState_t *es; - gitem_t *item; - int msec; - float frac; - float scale; - - es = ¢->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 ]; - - memset (&ent, 0, sizeof(ent)); - - VectorCopy( es->angles, cent->lerpAngles ); - AnglesToAxis( cent->lerpAngles, ent.axis ); - - 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; - } - - - //TA: might be useful later: - // 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; - }*/ - - //turret barrel bit - if( cg_items[ es->modelindex ].models[ 1 ] != 0 ) - { - vec3_t turretOrigin; - - memset( &ent2, 0, sizeof( ent2 ) ); - - AnglesToAxis( es->angles2, ent2.axis ); - - ent2.hModel = cg_items[ es->modelindex ].models[ 1 ]; - - VectorCopy( cent->lerpOrigin, turretOrigin ); - turretOrigin[ 2 ] += 5; - - VectorCopy( turretOrigin, ent2.origin ); - VectorCopy( turretOrigin, ent2.oldorigin ); - - ent2.nonNormalizedAxes = qfalse; - - trap_R_AddRefEntityToScene( &ent2 ); - } - - // add to refresh list - trap_R_AddRefEntityToScene(&ent); -} - - -//============================================================================ - -/* -=============== -CG_Missile -=============== -*/ -static void CG_Missile( centity_t *cent ) { - refEntity_t ent; - entityState_t *s1; - const weaponInfo_t *weapon; - - s1 = ¢->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 ); - } - - // 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( ¢->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; - } - - if( cent->currentState.weapon == WP_FLAMER ) - { - ent.reType = RT_SPRITE; - ent.radius = ( ( cg.time - s1->pos.trTime ) * ( cg.time - s1->pos.trTime ) ) / 6000; - ent.rotation = 0; - ent.customShader = cgs.media.flameShader; - trap_R_AddRefEntityToScene( &ent ); - return; - } - - // 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; - } - - // spin as it moves - if ( s1->pos.trType != TR_STATIONARY ) { - RotateAroundDirection( ent.axis, cg.time / 4 ); - } else { - RotateAroundDirection( ent.axis, s1->time ); - } - - // add to refresh list, possibly with quad glow - CG_AddRefEntityWithPowerups( &ent, s1->powerups, 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 = ¢->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 = ¢->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 = ¢->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 = ¢->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_TorchLight -=============== -*/ -static void CG_TorchLight( centity_t *cent ) -{ - float r, g, b; - int i, j, k; - byte lum; - - r = ( (float)( cent->currentState.constantLight & 0xFF ) ) / 255.0; - g = ( (float)( ( cent->currentState.constantLight >> 8 ) & 0xFF ) ) / 255.0; - b = ( (float)( ( cent->currentState.constantLight >> 16 ) & 0xFF ) ) / 255.0; - i = ( cent->currentState.constantLight >> 24 ) & 0xFF; - - lum = CG_AmbientLight( cent->lerpOrigin ); - - if( lum > 32 ) - { - k = 1; - } - else if( lum <= 32 ) - { - k = 2; - r *= 1.0f - ( (float)lum / 64.0f ); - g *= 1.0f - ( (float)lum / 64.0f ); - b *= 1.0f - ( (float)lum / 64.0f ); - } - - for( j = 0; j <= k; j++ ) - trap_R_AddLightToScene(cent->lerpOrigin, i*2, r, g, b ); -} - -/* -========================= -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( ¢->currentState.pos, fromTime, oldOrigin ); - BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles ); - - BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin ); - BG_EvaluateTrajectory( ¢->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( ¢->currentState.pos, cg.snap->serverTime, current ); - BG_EvaluateTrajectory( ¢->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( ¢->currentState.apos, cg.snap->serverTime, current ); - BG_EvaluateTrajectory( ¢->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( ¢->currentState.pos, cg.time, cent->lerpOrigin ); - BG_EvaluateTrajectory( ¢->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_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_CORPSE: - CG_Corpse( cent ); - break; - case ET_PLAYER: - CG_Player( cent ); - break; - case ET_ITEM: - CG_Item( cent ); - break; - case ET_BUILDABLE: - CG_Buildable( cent ); - break; - case ET_CREEP: - CG_Creep( cent ); - break; - case ET_MISSILE: - CG_Missile( cent ); - break; - case ET_TORCH: - CG_TorchLight( 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; - } -} - -/* -=============== -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 ] ); - - //TA: "empty" item position arrays - cgIP.numDroidItems = 0; - cgIP.numHumanItems = 0; - cgIP.numDroidClients = 0; - cgIP.numHumanClients = 0; - - for ( num = 0 ; num < cg.snap->numEntities ; num++ ) - { - cent = &cg_entities[ cg.snap->entities[ num ].number ]; - - if( cent->currentState.eType == ET_BUILDABLE ) - { - //TA: add to list of item positions (for creep) - if( cent->currentState.modelindex2 == BIT_DROIDS ) - { - VectorCopy( cent->lerpOrigin, cgIP.droidItemPositions[ cgIP.numDroidItems ] ); - cgIP.droidItemTimes[ cgIP.numDroidItems ] = cent->miscTime; - cgIP.numDroidItems++; - } - else if( cent->currentState.modelindex2 == BIT_HUMANS ) - { - VectorCopy( cent->lerpOrigin, cgIP.humanItemPositions[ cgIP.numHumanItems ] ); - cgIP.numHumanItems++; - } - } - - if( cent->currentState.eType == ET_PLAYER ) - { - int team = cent->currentState.powerups & 0x00FF; - int class = ( cent->currentState.powerups & 0xFF00 ) >> 8; - - if( team == PTE_DROIDS ) - { - VectorCopy( cent->lerpOrigin, cgIP.droidClientPositions[ cgIP.numDroidClients ] ); - cgIP.droidClientClass = class; - cgIP.numDroidClients++; - } - else if( team == PTE_HUMANS ) - { - VectorCopy( cent->lerpOrigin, cgIP.humanClientPositions[ cgIP.numHumanClients ] ); - cgIP.humanClientClass = class; - cgIP.numHumanClients++; - } - } - } - - //Com_Printf( "%d %d\n", cgIP.numDroidClients, cgIP.numHumanClients ); - - // 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/src/cgame/cg_event.c b/src/cgame/cg_event.c deleted file mode 100644 index d1372885..00000000 --- a/src/cgame/cg_event.c +++ /dev/null @@ -1,1018 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_event.c -- handle entity events at snapshot or playerstate transitions - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - -// for the voice chats -#include "../ta_ui/menudef.h" - -//========================================================================== - -/* -=================== -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; - case MOD_HSPAWN: - message = "should have run further"; - break; - case MOD_ASPAWN: - message = "was melted by the acid blood"; - break; - default: - message = NULL; - break; - } - - if (attacker == target) { - gender = ci->gender; - switch (mod) { - 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_FLAMER_SPLASH: - if ( gender == GENDER_FEMALE ) - message = "toasted herself"; - else if ( gender == GENDER_NEUTER ) - message = "toasted itself"; - else - message = "toasted himself"; - break; - case MOD_BFG_SPLASH: - message = "should have used a smaller gun"; - break; - 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 ); - } - CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); - - // 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_CHAINGUN: - message = "was chaingunned 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_FLAMER: - message = "was toasted by"; - message2 = "'s flamer"; - break; - case MOD_FLAMER_SPLASH: - message = "was toasted by"; - message2 = "'s flamer"; - break; - case MOD_RAILGUN: - message = "was railed by"; - break; - case MOD_LIGHTNING: - message = "was electrocuted by"; - break; - case MOD_VENOM: - message = "was biten by"; - break; - case MOD_BFG: - case MOD_BFG_SPLASH: - message = "was blasted by"; - message2 = "'s BFG"; - break; - 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 = ¢->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; - } - -} - -/* -================ -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_Menu -============== -*/ -void CG_Menu( centity_t *cent, int eventParm ) -{ - switch( eventParm ) - { - case MN_TEAM: - trap_SendConsoleCommand( "menu teammenu\n" ); - break; - - case MN_DROID: - trap_SendConsoleCommand( "menu aclassmenu\n" ); - break; - - case MN_HUMAN: - trap_SendConsoleCommand( "menu hsitemmenu\n" ); - break; - - case MN_ABUILD: - trap_SendConsoleCommand( "menu abuildmenu\n" ); - break; - - case MN_HBUILD: - trap_SendConsoleCommand( "menu hbuildmenu\n" ); - break; - - default: - Com_Printf( "cgame: debug: no such menu no %d\n", eventParm ); - - } -} - -/* -============== -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; - int steptime; - - BG_unpackAttributes( NULL, NULL, &steptime, cg.predictedPlayerState.stats ); - - es = ¢->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_FOOTSTEP_SQUELCH: - DEBUGNAME("EV_FOOTSTEP_SQUELCH"); - if (cg_footsteps.integer) { - trap_S_StartSound (NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_FLESH ][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 < steptime) { - oldStep = cg.stepChange * (steptime - delta) / steptime; - } 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; - 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 { - 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; - - //TA: make droid items "grow" - case EV_ITEM_GROW: - DEBUGNAME("EV_ITEM_GROW"); - cent->miscTime = cg.time; // scale up from this - 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; - - // - // 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_ITEM_EXPLOSION: - DEBUGNAME("EV_ITEM_EXPLOSION"); - ByteToDir( es->eventParm, dir ); - CG_Explosion( 0, position, dir ); - 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 - if ( es->eventParm != 255 ) { - ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT ); - } - CG_RailTrail( ci, es->origin2, es->pos.trBase ); - 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_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"); - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); - CG_GibPlayer( cent->lerpOrigin ); - break; - - case EV_GIB_GENERIC: - DEBUGNAME("EV_GIB_GENERIC"); - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); - CG_GenericGib( 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; - - case EV_MENU: - DEBUGNAME("EV_MENU"); - CG_Menu( cent, es->eventParm ); - 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 - } - 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( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin ); - CG_SetEntitySoundPosition( cent ); - - CG_EntityEvent( cent, cent->lerpOrigin ); -} - diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h deleted file mode 100644 index bbf15533..00000000 --- a/src/cgame/cg_local.h +++ /dev/null @@ -1,1630 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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. - - -#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" -#define DEFAULT_TEAM_MODEL "sarge" -#define DEFAULT_TEAM_HEAD "sarge" - -#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; - - 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; - - //TA: value to store corpse number - int corpseNum; -} 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 -} 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 -} leFlag_t; - -typedef enum { - LEMT_NONE, - LEMT_BURN, - LEMT_BLOOD, - LEMT_GREENBLOOD, //TA: when droids are injured - LEMT_BANG //TA: human item explosions -} leMarkType_t; // fragment local entities can leave marks on walls - -typedef enum { - LEBS_NONE, - LEBS_BLOOD, - LEBS_BANG, //TA: human item explosions - 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 color; - - 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 - - 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; - -typedef struct upgradeInfo_s { - qboolean registered; - gitem_t *item; - - qhandle_t upgradeIcon; -} upgradeInfo_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]; - - // 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; - - // 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]; -#ifdef NEW_ANIMS - qhandle_t flagPoleModel; - qhandle_t flagFlapModel; - - qhandle_t redFlagFlapSkin; - qhandle_t blueFlagFlapSkin; - qhandle_t neutralFlagFlapSkin; - - qhandle_t redFlagBaseModel; - qhandle_t blueFlagBaseModel; - qhandle_t neutralFlagBaseModel; - - 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; - - //TA: extra stuff - qhandle_t explosionShader; - qhandle_t greenBloodTrailShader; - qhandle_t greenBloodMarkShader; - qhandle_t greenBloodExplosionShader; - qhandle_t explosionTrailShader; - - qhandle_t humanNV; - qhandle_t droidNav10; - qhandle_t droidNav15; - qhandle_t droidNav20; - qhandle_t droidNav25; - qhandle_t droidNav30; - qhandle_t droidNav35; - qhandle_t droidNav40; - qhandle_t droidNav45; - qhandle_t droidNav50; - qhandle_t droidNav55; - qhandle_t droidNav60; - qhandle_t droidNav65; - qhandle_t droidNav70; - qhandle_t droidNav75; - qhandle_t droidNav80; - qhandle_t droidHealth; - - qhandle_t flameShader; - qhandle_t flameExplShader; - qhandle_t creepShader; - - qhandle_t scannerShader; - qhandle_t scannerBlipShader; - qhandle_t scannerLineShader; - - - 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; - - // 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; - 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; - - 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; - - int hBuildPoints, aBuildPoints; - - // - // 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]; - //TA: corpse info - clientInfo_t corpseinfo[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]; - -//TA: weapon limit expanded: -//extern weaponInfo_t cg_weapons[MAX_WEAPONS]; -extern weaponInfo_t cg_weapons[32]; -//TA: upgrade infos: -extern upgradeInfo_t cg_upgrades[32]; - -extern itemInfo_t cg_items[MAX_ITEMS]; -extern markPoly_t cg_markPolys[MAX_MARK_POLYS]; - -//TA: -typedef struct -{ - vec3_t droidItemPositions[ MAX_ITEMS ]; - int droidItemTimes[ MAX_ITEMS ]; - int numDroidItems; - - vec3_t humanItemPositions[ MAX_ITEMS ]; - int numHumanItems; - - vec3_t droidClientPositions[ MAX_CLIENTS ]; - int droidClientClass; - int numDroidClients; - - vec3_t humanClientPositions[ MAX_CLIENTS ]; - int humanClientClass; - int numHumanClients; - -} cgItemPos_t; - -extern cgItemPos_t cgIP; - - -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_creepRes; -extern vmCvar_t cg_drawSurfNormal; - -// -// 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 ); -//TA: draw a pic weighted between two colors. <- hmm me is turning into a yank. -void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor, vec4_t tcolor, float amount, 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 -// -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_Corpse( centity_t *cent ); -void CG_ResetPlayerEntity( centity_t *cent ); -void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int team ); -void CG_NewClientInfo( int clientNum ); -void CG_PrecacheClientInfo( 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_Explosion( int clientNum, vec3_t origin, vec3_t dir ); -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 ); -void CG_DrawWeaponSelect( void ); - -void CG_OutOfAmmoChange( void ); // should this be in pmove? - - -// -// cg_creep.c -// -void CG_Creep( centity_t *cent ); - -// -// cg_scanner.c -// -void CG_Scanner( void ); - -// -// 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 ); -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 ); - -// -//cg_mem.c -// -void *CG_Alloc( int size ); - -//=============================================== - -// -// 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 ); - -// 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 ); - -// repatialize 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_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 ); - -//TA: um... -//typedef enum { -// SYSTEM_PRINT, -// CHAT_PRINT, -// TEAMCHAT_PRINT -//}; - - -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 ); - diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c deleted file mode 100644 index da803ac0..00000000 --- a/src/cgame/cg_main.c +++ /dev/null @@ -1,1132 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_main.c -- initialization and primary entry point for cgame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - -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: - 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]; - -//TA: weapons limit expanded: -//weaponInfo_t cg_weapons[MAX_WEAPONS]; -weaponInfo_t cg_weapons[32]; -upgradeInfo_t cg_upgrades[32]; - -itemInfo_t cg_items[MAX_ITEMS]; - -//TA: -cgItemPos_t cgIP; - - -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_creepRes; -vmCvar_t cg_drawSurfNormal; - - -typedef struct { - vmCvar_t *vmCvar; - char *cvarName; - char *defaultString; - int cvarFlags; -} cvarTable_t; - -cvarTable_t cvarTable[] = { - { &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_ARCHIVE }, - { &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", CVAR_CHEAT }, - { &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 }, - { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE }, - { &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 }, - { &cg_creepRes, "cg_creepRes", "16", CVAR_ARCHIVE }, - { &cg_drawSurfNormal, "cg_drawSurfNormal", "0", CVAR_CHEAT }, - - // 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 - { &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_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE}, - { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE}, - -// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE } -}; - -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 ; ivmCvar ); - } - - // 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 - - cgs.media.oneMinuteSound = trap_S_RegisterSound( "sound/feedback/1_minute.wav", qfalse ); - cgs.media.fiveMinuteSound = trap_S_RegisterSound( "sound/feedback/5_minute.wav", qfalse ); - cgs.media.suddenDeathSound = trap_S_RegisterSound( "sound/feedback/sudden_death.wav", qfalse ); - cgs.media.oneFragSound = trap_S_RegisterSound( "sound/feedback/1_frag.wav", qfalse ); - cgs.media.twoFragSound = trap_S_RegisterSound( "sound/feedback/2_frags.wav", qfalse ); - cgs.media.threeFragSound = trap_S_RegisterSound( "sound/feedback/3_frags.wav", qfalse ); - cgs.media.count3Sound = trap_S_RegisterSound( "sound/feedback/three.wav", qfalse ); - cgs.media.count2Sound = trap_S_RegisterSound( "sound/feedback/two.wav", qfalse ); - cgs.media.count1Sound = trap_S_RegisterSound( "sound/feedback/one.wav", qfalse ); - cgs.media.countFightSound = trap_S_RegisterSound( "sound/feedback/fight.wav", qfalse ); - cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qfalse ); - - if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) { - cgs.media.captureAwardSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qfalse ); - cgs.media.redLeadsSound = trap_S_RegisterSound( "sound/feedback/redleads.wav", qfalse ); - cgs.media.blueLeadsSound = trap_S_RegisterSound( "sound/feedback/blueleads.wav", qfalse ); - cgs.media.teamsTiedSound = trap_S_RegisterSound( "sound/feedback/teamstied.wav", qfalse ); - cgs.media.hitTeamSound = trap_S_RegisterSound( "sound/feedback/hit_teammate.wav", qfalse ); - - cgs.media.redScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_red_scores.wav", qfalse ); - cgs.media.blueScoredSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_scores.wav", qfalse ); - - cgs.media.captureYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_yourteam.wav", qfalse ); - cgs.media.captureOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagcapture_opponent.wav", qfalse ); - - cgs.media.returnYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_yourteam.wav", qfalse ); - cgs.media.returnOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qfalse ); - - cgs.media.takenYourTeamSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_yourteam.wav", qfalse ); - cgs.media.takenOpponentSound = trap_S_RegisterSound( "sound/teamplay/flagtaken_opponent.wav", qfalse ); - - if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) { - cgs.media.redFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_red_returned.wav", qfalse ); - cgs.media.blueFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/voc_blue_returned.wav", qfalse ); - cgs.media.enemyTookYourFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_flag.wav", qfalse ); - cgs.media.yourTeamTookEnemyFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_flag.wav", qfalse ); - } - - cgs.media.youHaveFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_you_flag.wav", qfalse ); - cgs.media.holyShitSound = trap_S_RegisterSound("sound/feedback/voc_holyshit.wav", qfalse); - cgs.media.neutralFlagReturnedSound = trap_S_RegisterSound( "sound/teamplay/flagreturn_opponent.wav", qfalse ); - cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qfalse ); - cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qfalse ); - } - - 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 ); - - 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 ); - - cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav", qfalse ); - cgs.media.excellentSound = trap_S_RegisterSound( "sound/feedback/excellent.wav", qfalse ); - cgs.media.deniedSound = trap_S_RegisterSound( "sound/feedback/denied.wav", qfalse ); - cgs.media.humiliationSound = trap_S_RegisterSound( "sound/feedback/humiliation.wav", qfalse ); - cgs.media.assistSound = trap_S_RegisterSound( "sound/feedback/assist.wav", qfalse ); - cgs.media.defendSound = trap_S_RegisterSound( "sound/feedback/defense.wav", qfalse ); - - cgs.media.takenLeadSound = trap_S_RegisterSound( "sound/feedback/takenlead.wav", qfalse); - cgs.media.tiedLeadSound = trap_S_RegisterSound( "sound/feedback/tiedlead.wav", qfalse); - cgs.media.lostLeadSound = trap_S_RegisterSound( "sound/feedback/lostlead.wav", qfalse); - - 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); - - 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); - 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); -} - - -//=================================================================================== - - -/* -================= -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" ); - 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" ); - - - //TA: extra stuff - cgs.media.explosionShader = trap_R_RegisterShader( "grenadeExplosion" ); - cgs.media.greenBloodTrailShader = trap_R_RegisterShader( "greenBloodTrail" ); - cgs.media.greenBloodExplosionShader = trap_R_RegisterShader( "greenBloodExplosion" ); - cgs.media.greenBloodMarkShader = trap_R_RegisterShader( "greenBloodMark" ); - cgs.media.explosionTrailShader = trap_R_RegisterShader( "explosionTrail" ); - - cgs.media.flameShader = trap_R_RegisterShader( "sprites/flameball" ); - cgs.media.creepShader = trap_R_RegisterShader( "creep" ); - - cgs.media.scannerBlipShader = trap_R_RegisterShader( "gfx/2d/droidhealth" ); - cgs.media.scannerLineShader = trap_R_RegisterShader( "gfx/2d/func/mult2" ); - cgs.media.scannerShader = trap_R_RegisterShader( "gfx/2d/scanner" ); - - 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" ); - - if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) { - 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" ); - } - - if ( cgs.gametype == GT_CTF || cg_buildScript.integer ) { - 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" ); - } - - 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" ); - } - - //TA: screenfades - cgs.media.humanNV = trap_R_RegisterShader( "humanNV" ); - cgs.media.droidNav10 = trap_R_RegisterShader( "droidNav10" ); - cgs.media.droidNav15 = trap_R_RegisterShader( "droidNav15" ); - cgs.media.droidNav20 = trap_R_RegisterShader( "droidNav20" ); - cgs.media.droidNav25 = trap_R_RegisterShader( "droidNav25" ); - cgs.media.droidNav30 = trap_R_RegisterShader( "droidNav30" ); - cgs.media.droidNav35 = trap_R_RegisterShader( "droidNav35" ); - cgs.media.droidNav40 = trap_R_RegisterShader( "droidNav40" ); - cgs.media.droidNav45 = trap_R_RegisterShader( "droidNav45" ); - cgs.media.droidNav50 = trap_R_RegisterShader( "droidNav50" ); - cgs.media.droidNav55 = trap_R_RegisterShader( "droidNav55" ); - cgs.media.droidNav60 = trap_R_RegisterShader( "droidNav60" ); - cgs.media.droidNav65 = trap_R_RegisterShader( "droidNav65" ); - cgs.media.droidNav70 = trap_R_RegisterShader( "droidNav70" ); - cgs.media.droidNav75 = trap_R_RegisterShader( "droidNav75" ); - cgs.media.droidNav80 = trap_R_RegisterShader( "droidNav80" ); - cgs.media.droidHealth = trap_R_RegisterShader( "gfx/2d/droidhealth.tga" ); - - 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"); - cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" ); - cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" ); - - 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 ) ); - memset( cg_upgrades, 0, sizeof( cg_upgrades ) ); - - // 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_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 ); -} - - -/* -================= -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_upgrades, 0, sizeof(cg_upgrades) ); - 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" ); - - //TA: dyn memory - CG_InitMemory( ); - - CG_RegisterCvars(); - - CG_InitConsoleCommands(); - - //cg.weaponSelect = WP_MACHINEGUN; - //TA: if it does weird things, this is why: - cg.weaponSelect = WP_NONE; - - 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 ); - - 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 - - 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( "" ); - - 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 - -*/ -void CG_EventHandling(int type) { -} - - - -void CG_KeyEvent(int key, qboolean down) { -} - -void CG_MouseEvent(int x, int y) { -} - diff --git a/src/cgame/cg_marks.c b/src/cgame/cg_marks.c deleted file mode 100644 index 00fc89c2..00000000 --- a/src/cgame/cg_marks.c +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_marks.c -- wall marks - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 ); - } -} - diff --git a/src/cgame/cg_mem.c b/src/cgame/cg_mem.c deleted file mode 100644 index 1b0b2093..00000000 --- a/src/cgame/cg_mem.c +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// -// g_mem.c -// -//TA: hack to provide dynanmic allocation clientside - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - - -#define POOLSIZE (256 * 1024) - -static char memoryPool[POOLSIZE]; -static int allocPoint; - -void *CG_Alloc( int size ) { - char *p; - - /*if ( g_debugAlloc.integer ) { - G_Printf( "CG_Alloc of %i bytes (%i left)\n", size, POOLSIZE - allocPoint - ( ( size + 31 ) & ~31 ) ); - }*/ - - if ( allocPoint + size > POOLSIZE ) { - CG_Error( "CG_Alloc: failed on allocation of %u bytes\n", size ); - return NULL; - } - - p = &memoryPool[allocPoint]; - - allocPoint += ( size + 31 ) & ~31; - - return p; -} - -void CG_InitMemory( void ) { - allocPoint = 0; -} - diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c deleted file mode 100644 index 2b1b42bf..00000000 --- a/src/cgame/cg_players.c +++ /dev/null @@ -1,2092 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_players.c -- handle the media and animation for player entities - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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; - - // 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; - } - - // 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 ) { -#ifdef NEW_ANIMS - 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; - } -#endif - 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 && ilegsSkin = trap_R_RegisterSkin( filename ); - if (!ci->legsSkin) { - Com_Printf( "Leg skin load failure: %s\n", filename ); - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName ); - ci->torsoSkin = trap_R_RegisterSkin( filename ); - if (!ci->torsoSkin) { - Com_Printf( "Torso skin load failure: %s\n", filename ); - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName ); - ci->headSkin = trap_R_RegisterSkin( filename ); - if (!ci->headSkin) { - Com_Printf( "Head skin load failure: %s\n", filename ); - } - - 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 ) { - char filename[MAX_QPATH]; - - // load cmodels before models so filecache works - - Com_sprintf( filename, sizeof( filename ), "models/players/%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_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName ); - 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, modelName, skinName ) ) { - Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName ); - return qfalse; - } - - // load the animations - Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); - if ( !CG_ParseAnimationFile( filename, ci ) ) { - Com_Printf( "Failed to load animation file %s\n", filename ); - return qfalse; - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/icon_%s.tga", modelName, skinName ); - ci->modelIcon = trap_R_RegisterShaderNoMip( filename ); - if ( !ci->modelIcon ) { - Com_Printf( "Failed to load icon file: %s\n", filename ); - 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; - const char *s; - int clientNum; - - if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName ) ) { - if ( cg_buildScript.integer ) { - CG_Error( "CG_RegisterClientModelname( %s, %s ) failed", ci->modelName, ci->skinName ); - } - - // fall back - if ( cgs.gametype >= GT_TEAM ) { - // keep skin name - if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, ci->skinName ) ) { - CG_Error( "DEFAULT_MODEL / skin (%s/%s) failed to register", - DEFAULT_MODEL, ci->skinName ); - } - } else { - if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default" ) ) { - CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL ); - } - } - } - - // sounds - dir = ci->modelName; - fallback = DEFAULT_MODEL; - - for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) { - s = cg_customSoundNames[i]; - if ( !s ) { - break; - } - 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 - if( clientNum <= MAX_CLIENTS ) - { - 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; - - memcpy( to->animations, from->animations, sizeof( to->animations ) ); - memcpy( to->sounds, from->sounds, sizeof( to->sounds ) ); -} - - -/* -====================== -CG_GetCorpseNum -====================== -*/ -static int CG_GetCorpseNum( clientInfo_t *ci ) { - int i; - clientInfo_t *match; - - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - match = &cgs.corpseinfo[ i ]; - if ( !match->infoValid ) { - continue; - } - if ( match->deferred ) { - continue; - } - if ( !Q_stricmp( ci->modelName, match->modelName ) - && !Q_stricmp( ci->skinName, match->skinName ) ) { - // this clientinfo is identical, so use it's handles - - return i; - } - } - - //something has gone badly wrong - return -1; -} - - -/* -====================== -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 ) ) { - // 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 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 ) { - continue; - } - if ( Q_stricmp( ci->skinName, match->skinName ) ) { - 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_PrecacheClientInfo -====================== -*/ -void CG_PrecacheClientInfo( int clientNum ) { - clientInfo_t *ci; - clientInfo_t newInfo; - const char *configstring; - const char *v; - char *slash; - - ci = &cgs.corpseinfo[ clientNum - MAX_CLIENTS ]; - - //CG_Printf( "%d %d\n", clientNum, (clientNum - MAX_CLIENTS ) ); - - configstring = CG_ConfigString( clientNum + CS_PLAYERS ); - if ( !configstring[0] ) { - 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.color ); - - // 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" ); - 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; - } - - //CG_Printf( "PCI: %s\n", v ); - - // head model - v = Info_ValueForKey( configstring, "hmodel" ); - 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; - } - - newInfo.deferred = qfalse; - newInfo.infoValid = qtrue; - CG_LoadClientInfo( &newInfo ); - *ci = newInfo; -} - - -/* -====================== -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.color ); - - // 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" ); - 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; - } - - //CG_Printf( "NCI: %s\n", v ); - - // head model - v = Info_ValueForKey( configstring, "hmodel" ); - 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 - //TA: we should only defer models when ABSOLUTELY TOTALLY necessary since models are precached - if ( forceDefer ) //|| ( cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) - { - // keep whatever they had if it won't violate team skins - if ( ci->infoValid && - ( cgs.gametype < GT_TEAM || !Q_stricmp( newInfo.skinName, ci->skinName ) ) ) - { - CG_CopyClientInfoModel( ci, &newInfo ); - newInfo.deferred = qtrue; - } - else - { - // use whatever is available - 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 | ANIM_WALLCLIMBING ); - - 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 | ANIM_WALLCLIMBING ) ) == LEGS_IDLE ) { - CG_RunLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale ); - } else { - CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale ); - } - - *legsOld = cent->pe.legs.oldFrame; - *legs = cent->pe.legs.frame; - *legsBackLerp = cent->pe.legs.backlerp; - - CG_RunLerpFrame( ci, ¢->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; - - 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 | ANIM_WALLCLIMBING ) ) != LEGS_IDLE - || ( cent->currentState.torsoAnim & ~(ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) != 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 { - //TA: did use angles2.. now uses time2.. looks a bit funny but time2 isn't used othwise - dir = cent->currentState.time2; - 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, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing ); - CG_SwingAngles( legsAngles[YAW], 40, 90, cg_swingSpeed.value, ¢->pe.legs.yawAngle, ¢->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, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching ); - torsoAngles[PITCH] = cent->pe.torso.pitchAngle; - - // --------- 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; - } - - // 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 | ANIM_WALLCLIMBING ); - 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; -} - -/* -=============== -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_PlayerPowerups -=============== -*/ -#ifdef NEW_ANIMS -static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) { -#else -static void CG_PlayerPowerups( centity_t *cent ) { -#endif - 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.2, 0.2, 1 ); - } - - // flight plays a looped sound - if ( powerups & ( 1 << PW_FLIGHT ) ) { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.flightSound ); - } - - // redflag - if ( powerups & ( 1 << PW_REDFLAG ) ) { - CG_TrailItem( cent, cgs.media.redFlagModel ); - trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1, 0.2, 0.2 ); - } - - // blueflag - if ( powerups & ( 1 << PW_BLUEFLAG ) ) { - CG_TrailItem( cent, cgs.media.blueFlagModel ); - trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2, 0.2, 1 ); - } - - // 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; - } - - 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 ) { - 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; - - // 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, int powerups, int team ) { - - /*if ( powerups & ( 1 << PW_INVIS ) ) { - ent->customShader = cgs.media.invisShader; - trap_R_AddRefEntityToScene( ent ); - } else {*/ - trap_R_AddRefEntityToScene( ent ); - - /*if ( powerups & ( 1 << PW_QUAD ) ) - { - if (team == TEAM_HUMANS) - ent->customShader = cgs.media.redQuadShader; - else - ent->customShader = cgs.media.quadShader; - trap_R_AddRefEntityToScene( ent ); - } - if ( powerups & ( 1 << PW_REGEN ) ) { - if ( ( ( cg.time / 100 ) % 10 ) == 1 ) { - ent->customShader = cgs.media.regenShader; - trap_R_AddRefEntityToScene( ent ); - } - } - if ( 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_LightFromDirection -================= -*/ -int CG_LightFromDirection( vec3_t point, vec3_t direction ) -{ - int i, j; - float incoming; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - vec3_t result; - - trap_R_LightForPoint( point, ambientLight, directedLight, lightDir ); - - incoming = DotProduct (direction, lightDir); - if ( incoming <= 0 ) { - result[0] = ambientLight[0]; - result[1] = ambientLight[1]; - result[2] = ambientLight[2]; - return (int)((float)( result[0] + result[1] + result[2] ) / 3.0f ); - } - - j = ( ambientLight[0] + incoming * directedLight[0] ); - if ( j > 255 ) { - j = 255; - } - result[0] = j; - - j = ( ambientLight[1] + incoming * directedLight[1] ); - if ( j > 255 ) { - j = 255; - } - result[1] = j; - - j = ( ambientLight[2] + incoming * directedLight[2] ); - if ( j > 255 ) { - j = 255; - } - result[2] = j; - - return (int)((float)( result[0] + result[1] + result[2] ) / 3.0f ); -} - - -/* -================= -CG_AmbientLight -================= -*/ -int CG_AmbientLight( vec3_t point ) -{ - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - vec3_t result; - - trap_R_LightForPoint( point, ambientLight, directedLight, lightDir ); - - result[0] = ambientLight[0]; - result[1] = ambientLight[1]; - result[2] = ambientLight[2]; - return (int)((float)( result[0] + result[1] + result[2] ) / 3.0f ); -} - - -/* -=============== -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; - - // 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 ); - -#ifndef NEW_ANIMS - // add powerups floating behind the player - //CG_PlayerPowerups( cent ); -#endif - - // add the talk baloon or disconnect icon - CG_PlayerSprites( cent ); - - // add the shadow - //TA: but only for humans - if( ( cent->currentState.powerups & 0xFF ) == PTE_HUMANS ) - 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 - - // - // 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 - - //TA: rotate the model so it sits on a wall - if( cent->currentState.legsAnim & ANIM_WALLCLIMBING && - !( cent->currentState.eFlags & EF_DEAD ) && - !( cg.intermissionStarted ) ) - { - vec3_t forward, surfNormal; - trace_t tr; - - VectorCopy( cent->currentState.angles2, surfNormal ); - - /*CG_Printf( "%d: ", cent->currentState.number ); - CG_Printf( "%f ", surfNormal[ 0 ] ); - CG_Printf( "%f ", surfNormal[ 1 ] ); - CG_Printf( "%f ", surfNormal[ 2 ] ); - CG_Printf( "\n" );*/ - - AngleVectors( cent->lerpAngles, forward, NULL, NULL ); - VectorCopy( surfNormal, legs.axis[2] ); - ProjectPointOnPlane( legs.axis[0], forward, legs.axis[2] ); - if( !VectorNormalize( legs.axis[0] ) ) - { - AngleVectors( cent->lerpAngles, NULL, NULL, forward ); - ProjectPointOnPlane( legs.axis[0], forward, legs.axis[2] ); - VectorNormalize( legs.axis[0] ); - } - CrossProduct( legs.axis[0], legs.axis[2], legs.axis[1] ); - legs.axis[1][0] = -legs.axis[1][0]; - legs.axis[1][1] = -legs.axis[1][1]; - legs.axis[1][2] = -legs.axis[1][2]; - - VectorCopy( legs.origin, legs.lightingOrigin ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - } - - - //CG_AddRefEntityWithPowerups( &legs, cent->currentState.powerups, ci->team ); - trap_R_AddRefEntityToScene( &legs ); - - // 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.powerups, ci->team ); - trap_R_AddRefEntityToScene( &torso ); - - // - // 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.powerups, ci->team ); - trap_R_AddRefEntityToScene( &head ); - - // - // add the gun / barrel / flash - // - CG_AddPlayerWeapon( &torso, NULL, cent ); -} - -/* -=============== -CG_Corpse -=============== -*/ -void CG_Corpse( centity_t *cent ) -{ - clientInfo_t *ci; - refEntity_t legs; - refEntity_t torso; - refEntity_t head; - int clientNum; - int renderfx; - qboolean shadow; - float shadowPlane; - - //if this is the first time the function has been run set cent->corpseNum - if( cent->corpseNum < 1 ) - { - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - cent->corpseNum = CG_GetCorpseNum( ci ) + 1; - if ( cent->corpseNum < 1 || cent->corpseNum >= MAX_CLIENTS + 1 ) - { - CG_Error( "Bad corpseNum on corpse entity: %d", cent->corpseNum ); - } - } - - ci = &cgs.corpseinfo[ cent->corpseNum - 1 ]; - - // it is possible to see corpses from disconnected players that may - // not have valid clientinfo - if ( !ci->infoValid ) { - 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 ); - - //set the correct frame (should always be dead) - if ( cg_noPlayerAnims.integer ) - legs.oldframe = legs.frame = torso.oldframe = torso.frame = 0; - else - { - CG_RunLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, 1 ); - legs.oldframe = cent->pe.legs.oldFrame; - legs.frame = cent->pe.legs.frame; - legs.backlerp = cent->pe.legs.backlerp; - - CG_RunLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, 1 ); - torso.oldframe = cent->pe.torso.oldFrame; - torso.frame = cent->pe.torso.frame; - torso.backlerp = cent->pe.torso.backlerp; - } - - - // add the shadow - shadow = CG_PlayerShadow( cent, &shadowPlane ); - - // get the player model information - renderfx = 0; - if ( cg_shadows.integer == 3 && shadow ) { - renderfx |= RF_SHADOW_PLANE; - } - renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all - - // - // 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.powerups, ci->team ); - trap_R_AddRefEntityToScene( &legs ); - - // 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.powerups, ci->team ); - trap_R_AddRefEntityToScene( &torso ); - - // - // 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.powerups, ci->team ); - trap_R_AddRefEntityToScene( &head ); -} - - -//===================================================================== - -/* -=============== -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 ], ¢->pe.legs, cent->currentState.legsAnim ); - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim ); - - BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin ); - BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles ); - - VectorCopy( cent->lerpOrigin, cent->rawOrigin ); - VectorCopy( cent->lerpAngles, cent->rawAngles ); - - memset( ¢->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( ¢->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/src/cgame/cg_playerstate.c b/src/cgame/cg_playerstate.c deleted file mode 100644 index 3477f108..00000000 --- a/src/cgame/cg_playerstate.c +++ /dev/null @@ -1,502 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// 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 - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 ammo, clips, maxclips; - - // see about how many seconds of ammo we have remaining - total = 0; - for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) { - if ( !BG_gotWeapon( i, cg.snap->ps.stats ) ) { - continue; - } - - BG_unpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips, &maxclips ); - - switch ( i ) { - case WP_ROCKET_LAUNCHER: - case WP_GRENADE_LAUNCHER: - case WP_RAILGUN: - case WP_SHOTGUN: - total += ammo * 1000; - break; - default: - if( clips ) - total += 5000; - total += ammo * 200; - break; - } - if ( total >= 5000 || BG_infiniteAmmo( i ) ) { - 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;*/ - trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND ); - } 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]) { - sfx = cgs.media.impressiveSound; - 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]) { - sfx = cgs.media.excellentSound; - 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]) { - sfx = cgs.media.humiliationSound; - 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/src/cgame/cg_predict.c b/src/cgame/cg_predict.c deleted file mode 100644 index 0b9505ba..00000000 --- a/src/cgame/cg_predict.c +++ /dev/null @@ -1,615 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// 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 - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 = ¢->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 = ¢->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( ¢->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 = ¢->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; - int ammo, clips, maxclips; - - BG_unpackAmmoArray( item->giTag, cg.predictedPlayerState.ammo, cg.predictedPlayerState.powerups, &ammo, &clips, &maxclips ); - - if ( !cg_predictItems.integer ) { - return; - } - if ( !BG_PlayerTouchesItem( &cg.predictedPlayerState, ¢->currentState, cg.time ) ) { - return; - } - - // never pick an item up twice in a prediction - if ( cent->miscTime == cg.time ) { - return; - } - - if ( !BG_CanItemBeGrabbed( cgs.gametype, ¢->currentState, &cg.predictedPlayerState ) ) { - return; // can't hold it - } - - item = &bg_itemlist[ cent->currentState.modelindex ]; - - // 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 ) { - BG_packWeapon( item->giTag, cg.predictedPlayerState.stats ); - if ( ammo == 0 && clips == 0 ) { - BG_packAmmoArray( item->giTag, cg.predictedPlayerState.ammo, cg.predictedPlayerState.powerups, 1, 0, 0 ); - } - } -} - - -/* -========================= -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 = ¢->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/src/cgame/cg_public.h b/src/cgame/cg_public.h deleted file mode 100644 index 6da3b293..00000000 --- a/src/cgame/cg_public.h +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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_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/src/cgame/cg_scanner.c b/src/cgame/cg_scanner.c deleted file mode 100644 index 336b9864..00000000 --- a/src/cgame/cg_scanner.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - -void CG_Scanner( ) -{ - int i; - vec3_t origin; - vec3_t relOrigin; - vec3_t drawOrigin; - vec3_t up = { 0, 0, 1 }; - vec4_t hIabove = { 0, 1, 0, 1 }; - vec4_t hIbelow = { 0, 0.5, 0, 1 }; - vec4_t aIabove = { 1, 0, 0, 1 }; - vec4_t aIbelow = { 0.5, 0, 0, 1 }; - - VectorCopy( cg.refdef.vieworg, origin ); - - for( i = 0; i < cgIP.numHumanItems; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( cgIP.humanItemPositions[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < 1000 && ( relOrigin[ 2 ] < 0 ) ) - { - RotatePointAroundVector( drawOrigin, up, relOrigin, -cg.refdefViewAngles[ 1 ]-90 ); - drawOrigin[ 0 ] /= ( 1000 / 180 ); - drawOrigin[ 1 ] /= ( 1000 / 40 ); - drawOrigin[ 2 ] /= ( 1000 / 180 ); - - trap_R_SetColor( hIbelow ); - CG_DrawPic( 319 - drawOrigin[ 0 ], 360 + drawOrigin[ 1 ], 2, -drawOrigin[ 2 ], cgs.media.scannerLineShader ); - CG_DrawPic( 312 - drawOrigin[ 0 ], 356 + drawOrigin[ 1 ] - drawOrigin[ 2 ], 16, 8, cgs.media.scannerBlipShader ); - trap_R_SetColor( NULL ); - } - } - - for( i = 0; i < cgIP.numDroidItems; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( cgIP.droidItemPositions[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < 1000 && ( relOrigin[ 2 ] < 0 ) ) - { - RotatePointAroundVector( drawOrigin, up, relOrigin, -cg.refdefViewAngles[ 1 ]-90 ); - drawOrigin[ 0 ] /= ( 1000 / 180 ); - drawOrigin[ 1 ] /= ( 1000 / 40 ); - drawOrigin[ 2 ] /= ( 1000 / 180 ); - - trap_R_SetColor( aIbelow ); - CG_DrawPic( 319 - drawOrigin[ 0 ], 360 + drawOrigin[ 1 ], 2, -drawOrigin[ 2 ], cgs.media.scannerLineShader ); - CG_DrawPic( 312 - drawOrigin[ 0 ], 356 + drawOrigin[ 1 ] - drawOrigin[ 2 ], 16, 8, cgs.media.scannerBlipShader ); - trap_R_SetColor( NULL ); - } - } - - CG_DrawPic( 140, 320, 360, 80, cgs.media.scannerShader ); - - for( i = 0; i < cgIP.numHumanItems; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( cgIP.humanItemPositions[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < 1000 && ( relOrigin[ 2 ] > 0 ) ) - { - RotatePointAroundVector( drawOrigin, up, relOrigin, -cg.refdefViewAngles[ 1 ]-90 ); - drawOrigin[ 0 ] /= ( 1000 / 180 ); - drawOrigin[ 1 ] /= ( 1000 / 40 ); - drawOrigin[ 2 ] /= ( 1000 / 180 ); - - trap_R_SetColor( hIabove ); - CG_DrawPic( 319 - drawOrigin[ 0 ], 360 + drawOrigin[ 1 ], 2, -drawOrigin[ 2 ], cgs.media.scannerLineShader ); - CG_DrawPic( 312 - drawOrigin[ 0 ], 356 + drawOrigin[ 1 ] - drawOrigin[ 2 ], 16, 8, cgs.media.scannerBlipShader ); - trap_R_SetColor( NULL ); - } - } - for( i = 0; i < cgIP.numDroidItems; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( cgIP.droidItemPositions[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < 1000 && ( relOrigin[ 2 ] > 0 ) ) - { - RotatePointAroundVector( drawOrigin, up, relOrigin, -cg.refdefViewAngles[ 1 ]-90 ); - drawOrigin[ 0 ] /= ( 1000 / 180 ); - drawOrigin[ 1 ] /= ( 1000 / 40 ); - drawOrigin[ 2 ] /= ( 1000 / 180 ); - - trap_R_SetColor( aIabove ); - CG_DrawPic( 319 - drawOrigin[ 0 ], 360 + drawOrigin[ 1 ], 2, -drawOrigin[ 2 ], cgs.media.scannerLineShader ); - CG_DrawPic( 312 - drawOrigin[ 0 ], 356 + drawOrigin[ 1 ] - drawOrigin[ 2 ], 16, 8, cgs.media.scannerBlipShader ); - trap_R_SetColor( NULL ); - } - } -} diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c deleted file mode 100644 index 31264077..00000000 --- a/src/cgame/cg_servercmds.c +++ /dev/null @@ -1,1021 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// 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 - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - -#include "../ta_ui/menudef.h" - -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 }*/ - { NULL, 0 } -}; - -static const int numValidOrders = sizeof(validOrders) / sizeof(orderTask_t); - -/* -================= -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; - } - -} - -/* -================= -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 ) { - 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.aBuildPoints = atoi( CG_ConfigString( CS_ABPOINTS ) ); - cgs.hBuildPoints = atoi( CG_ConfigString( CS_HBPOINTS ) ); - - 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'; - } - 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_ABPOINTS ) { - cgs.aBuildPoints = atoi( str ); - } else if ( num == CS_HBPOINTS ) { - cgs.hBuildPoints = 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 ) ); - } 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 ) ); - } 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'; - } - } - 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(); - - // 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 ); - } -} - -#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; - - 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; - voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].numSounds] = - trap_S_RegisterSound( token , compress ); - 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); - 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[128], *headModelName; - - if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { - clientNum = 0; - } - ci = &cgs.clientinfo[ clientNum ]; - - headModelName = ci->headModelName; - if (headModelName[0] == '*') - 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 .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]; -int voiceChatBufferIn, voiceChatBufferOut; -int voiceChatTime; - -/* -================= -CG_PlayVoiceChat -================= -*/ -void CG_PlayVoiceChat( bufferedVoiceChat_t *vchat ) { - // 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->voiceOnly && !cg_noVoiceText.integer) { - CG_AddToTeamChat( vchat->message ); - CG_Printf( "%s\n", vchat->message ); - } - voiceChatBuffer[voiceChatBufferOut].snd = 0; -} - -/* -===================== -CG_PlayBufferedVoieChats -===================== -*/ -void CG_PlayBufferedVoiceChats( void ) { - if ( voiceChatTime < cg.time ) { - if (voiceChatBufferOut != voiceChatBufferIn && voiceChatBuffer[voiceChatBufferOut].snd) { - // - CG_PlayVoiceChat(&voiceChatBuffer[voiceChatBufferOut]); - // - voiceChatBufferOut = (voiceChatBufferOut + 1) % MAX_VOICECHATBUFFER; - voiceChatTime = cg.time + 1000; - } - } -} - -/* -===================== -CG_AddBufferedVoiceChat -===================== -*/ -void CG_AddBufferedVoiceChat( bufferedVoiceChat_t *vchat ) { - // if we are going into the intermission, don't start any voices - if ( cg.intermissionStarted ) { - return; - } - - memcpy(&voiceChatBuffer[voiceChatBufferIn], vchat, sizeof(bufferedVoiceChat_t)); - voiceChatBufferIn = (voiceChatBufferIn + 1) % MAX_VOICECHATBUFFER; - if (voiceChatBufferIn == voiceChatBufferOut) { - CG_PlayVoiceChat( &voiceChatBuffer[voiceChatBufferOut] ); - voiceChatBufferOut++; - } -} - -/* -================= -CG_VoiceChatLocal -================= -*/ -void CG_VoiceChatLocal( int mode, qboolean voiceOnly, int clientNum, int color, const char *cmd ) { - 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); - } - } -} - -/* -================= -CG_VoiceChat -================= -*/ -void CG_VoiceChat( int mode ) { - 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 ); -} - -/* -================= -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) ); - 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/src/cgame/cg_snapshot.c b/src/cgame/cg_snapshot.c deleted file mode 100644 index be64bc89..00000000 --- a/src/cgame/cg_snapshot.c +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_snapshot.c -- things that happen on snapshot transition, -// not necessarily every single rendered frame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "cg_local.h" - - - -/* -================== -CG_ResetEntity -================== -*/ -static void CG_ResetEntity( centity_t *cent ) { - // if an event is set, assume it is new enough to use - // if the event had timed out, it would have been cleared - 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(¢->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 ); - } - - 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(¢->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/src/cgame/cg_syscalls.asm b/src/cgame/cg_syscalls.asm deleted file mode 100644 index 3298ef73..00000000 --- a/src/cgame/cg_syscalls.asm +++ /dev/null @@ -1,99 +0,0 @@ -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 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/src/cgame/cg_syscalls.c b/src/cgame/cg_syscalls.c deleted file mode 100644 index 3e2e05fa..00000000 --- a/src/cgame/cg_syscalls.c +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_syscalls.c -- this file is only included when building a dll -// cg_syscalls.asm is included instead when building a qvm - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 ); -} - -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 ); -} - -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_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 ); -} - -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 ); -} - -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_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); -} - diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c deleted file mode 100644 index e4550a71..00000000 --- a/src/cgame/cg_view.c +++ /dev/null @@ -1,976 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_view.c -- setup all the parameters (position, angle, etc) -// for a 3D rendering - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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 " or "testgun ". - -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; - - //TA: when wall climbing the viewheight is not straight up - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, cg.predictedPlayerState.grapplePoint, cg.refdef.vieworg ); - else - 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 ); - - //TA: when wall climbing the viewheight is not straight up - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( view, 8, cg.predictedPlayerState.grapplePoint, view ); - else - 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; - int steptime; - - BG_unpackAttributes( NULL, NULL, &steptime, cg.predictedPlayerState.stats ); - - // smooth out stair climbing - timeDelta = cg.time - cg.stepTime; - if ( timeDelta < steptime ) { - cg.refdef.vieworg[2] -= cg.stepChange - * (steptime - timeDelta) / steptime; - } -} - -/* -=============== -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; - int bob2; - - 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 - //TA: bob amount is class dependant - BG_unpackAttributes( NULL, &bob2, NULL, cg.predictedPlayerState.stats ); - if( bob2 != 0 ) - { - // make sure the bob is visible even at low speeds - speed = cg.xyspeed > 200 ? cg.xyspeed : 200; - - delta = cg.bobfracsin * ( bob2 / 1000.0 ) * speed; - if (cg.predictedPlayerState.pm_flags & PMF_DUCKED) - delta *= 3; // crouching - angles[PITCH] += delta; - delta = cg.bobfracsin * ( bob2 / 1000.0 ) * speed; - if (cg.predictedPlayerState.pm_flags & PMF_DUCKED) - delta *= 3; // crouching accentuates roll - if (cg.bobcycle & 1) - delta = -delta; - angles[ROLL] += delta; - } - - //TA: this *feels* more realisitic for humans - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - angles[PITCH] += cg.bobfracsin * bob2 * 0.5; - - //TA: heavy breathing effects - if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ) - { - float deltaBreath = (float)( - cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ? - -cg.predictedPlayerState.stats[ STAT_STAMINA ] : - cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0; - float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath; - - deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5; - - angles[ PITCH ] -= deltaAngle; - } - } - -//=================================== - - // add view height - //TA: when wall climbing the viewheight is not straight up - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( origin, cg.predictedPlayerState.viewheight, cg.predictedPlayerState.grapplePoint, origin ); - else - 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; - } - - //TA: likewise for bob - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( origin, bob, cg.predictedPlayerState.grapplePoint, origin ); - else - 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; - int attribFov; - int a; - float b; - - BG_unpackAttributes( &attribFov, NULL, NULL, cg.predictedPlayerState.stats ); - - if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { - // if in intermission, use a fixed value - fov_x = 90; - } - else - { - //TA: don't lock the fov globally - we need to be able to change it - fov_x = attribFov; - - 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 > attribFov ) - zoomFov = attribFov; - - //TA: only do all the zoom stuff if the client CAN zoom - if( cg.predictedPlayerState.stats[ STAT_ABILITIES ] & SCA_CANZOOM ) - { - 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; - } - - // 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_DrawSurfNormal - -Draws a vector against -the surface player is looking at -=============== -*/ -static void CG_DrawSurfNormal( void ) -{ - trace_t tr; - vec3_t end, temp; - vec3_t up = { 0, 5, 0 }; - polyVert_t normal[4]; - - VectorMA( cg.refdef.vieworg, 8192, cg.refdef.viewaxis[ 0 ], end ); - - CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, end, cg.predictedPlayerState.clientNum, MASK_SOLID ); - //CG_Printf( "%f %f %f\n", tr.plane.normal[ 0 ], tr.plane.normal[ 1 ], tr.plane.normal[ 2 ] ); - - VectorCopy( tr.endpos, normal[0].xyz ); - normal[0].st[0] = 0; - normal[0].st[1] = 0; - normal[0].modulate[0] = 255; - normal[0].modulate[1] = 255; - normal[0].modulate[2] = 255; - normal[0].modulate[3] = 255; - - VectorAdd( up, tr.endpos, temp ); - VectorCopy( temp, normal[1].xyz); - normal[1].st[0] = 0; - normal[1].st[1] = 1; - normal[1].modulate[0] = 255; - normal[1].modulate[1] = 255; - normal[1].modulate[2] = 255; - normal[1].modulate[3] = 255; - - VectorMA( tr.endpos, 64, tr.plane.normal, temp ); - VectorAdd( temp, up, temp ); - VectorCopy( temp, normal[2].xyz ); - normal[2].st[0] = 1; - normal[2].st[1] = 1; - normal[2].modulate[0] = 255; - normal[2].modulate[1] = 255; - normal[2].modulate[2] = 255; - normal[2].modulate[3] = 255; - - VectorMA( tr.endpos, 64, tr.plane.normal, temp ); - VectorCopy( temp, normal[3].xyz ); - normal[3].st[0] = 1; - normal[3].st[1] = 0; - normal[3].modulate[0] = 255; - normal[3].modulate[1] = 255; - normal[3].modulate[2] = 255; - normal[3].modulate[3] = 255; - - trap_R_AddPolyToScene( cgs.media.whiteShader, 4, normal ); -} - - -/* -=============== -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; - - // 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; - } - - //draw the surface normal looking at - if( cg_drawSurfNormal.integer ) - CG_DrawSurfNormal( ); - - // 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_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/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c deleted file mode 100644 index a5535586..00000000 --- a/src/cgame/cg_weapons.c +++ /dev/null @@ -1,1994 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_weapons.c -- events and effects dealing with weapons - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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; - } -} - - -/* -========================== -CG_RailTrail -========================== -*/ -void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end ) { - localEntity_t *le; - refEntity_t *re; - - // - // rings - // - 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_RINGS; - re->customShader = cgs.media.railRingsShader; - - VectorCopy( start, re->origin ); - VectorCopy( end, re->oldorigin ); - - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - - le->color[0] = ci->color[0] * 0.75; - le->color[1] = ci->color[1] * 0.75; - le->color[2] = ci->color[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); - - // - // core - // - 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 ); - - // nudge down a bit so it isn't exactly in center - re->origin[2] -= 8; - re->oldorigin[2] -= 8; - - le->color[0] = ci->color[0] * 0.75; - le->color[1] = ci->color[1] * 0.75; - le->color[2] = ci->color[2] * 0.75; - le->color[3] = 1.0f; - - AxisClear( re->axis ); -} - -/* -========================== -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; - - 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; - } - -} - -/* -========================== -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_RegisterUpgrade - -The server says this item is used on this level -================= -*/ -void CG_RegisterUpgrade( int upgradeNum ) { - upgradeInfo_t *upgradeInfo; - gitem_t *item; - char path[MAX_QPATH]; - int i; - - upgradeInfo = &cg_upgrades[ upgradeNum ]; - - if ( upgradeNum == 0 ) { - return; - } - - if ( upgradeInfo->registered ) { - return; - } - - memset( upgradeInfo, 0, sizeof( *upgradeInfo ) ); - upgradeInfo->registered = qtrue; - - for ( item = bg_itemlist + 1 ; item->classname ; item++ ) { - if ( item->giType == IT_UPGRADE && item->giTag == upgradeNum ) { - upgradeInfo->item = item; - break; - } - } - if ( !item->classname ) { - CG_Error( "Couldn't find upgrade %i", upgradeNum ); - } - CG_RegisterItemVisuals( item - bg_itemlist ); - - upgradeInfo->upgradeIcon = trap_R_RegisterShader( item->icon ); -} - -/* -================= -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( "lightningBolt"); - 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; - - 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_CHAINGUN: - 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; - - 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; - - case WP_FLAMER: - weaponInfo->missileSound = trap_S_RegisterSound( "sound/weapons/plasma/lasfly.wav", qfalse ); - MAKERGB( weaponInfo->flashDlightColor, 0.25, 0.1, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/plasma/rg_hum.wav", qfalse ); - cgs.media.flameExplShader = trap_R_RegisterShader( "rocketExplosion" ); - break; - - case WP_PLASMAGUN: - 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" ); - 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; - - case WP_VENOM: - MAKERGB( weaponInfo->flashDlightColor, 0, 0, 0 ); - weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav", qfalse ); - break; - - case WP_ABUILD: - case WP_HBUILD: - case WP_SCANNER: - //nowt - 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; - int i; - - itemInfo = &cg_items[ itemNum ]; - if ( itemInfo->registered ) { - return; - } - - item = &bg_itemlist[ itemNum ]; - - memset( itemInfo, 0, sizeof( &itemInfo ) ); - itemInfo->registered = qtrue; - - itemInfo->icon = trap_R_RegisterShader( item->icon ); - - if ( item->giType == IT_WEAPON ) { - CG_RegisterWeapon( item->giTag ); - } - - for( i = 0; i < 4; i++ ) - { - if( item->world_model[ i ] ) - itemInfo->models[i] = trap_R_RegisterModel( item->world_model[i] ); - } - -} - - -/* -======================================================================================== - -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_ATTACK].firstFrame; - } - - return 0; -} - - -/* -============== -CG_CalculateWeaponPosition -============== -*/ -static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) { - float scale; - int delta; - float fracsin; - int bob; - - 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 - //TA: bob amount is class dependant - BG_unpackAttributes( NULL, &bob, NULL, cg.predictedPlayerState.stats ); - if( bob != 0 ) - { - 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 - if( !( cg.predictedPlayerState.stats[ STAT_ABILITIES ] & SCA_NOWEAPONDRIFT ) ) - { - 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; - } - - //TA: huh? why drop the weapon when stair climbing... just as well this isn't actually used :) -#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 ) ); - - // 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); - } - - 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 ) { - refEntity_t gun; - refEntity_t barrel; - refEntity_t flash; - vec3_t angles; - weapon_t weaponNum; - weaponInfo_t *weapon; - centity_t *nonPredictedCent; - - 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->color[0]; - flash.shaderRGBA[1] = 255 * ci->color[1]; - flash.shaderRGBA[2] = 255 * ci->color[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 ); - - // make a dlight for the flash - 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 - 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 ) { - //TA: the client side variable isn't used ( shouldn't iD have done this anyway? ) - if( cg.refdef.fov_y > 90 ) - fovOffset = -0.2 * ( cg.refdef.fov_y - 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 ); -} - -/* -============================================================================== - -WEAPON SELECTION - -============================================================================== -*/ - -/* -=================== -CG_DrawWeaponSelect - -=================== -*/ -void CG_DrawWeaponSelect( void ) { - int i; - //int count; - int x, y, w; - char *name; - float *color; - int ammo, clips, maxclips; - - // 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 - count = 0; - for ( i = WP_GAUNTLET; i < WP_NUM_WEAPONS; i++ ) { - if ( BG_gotWeapon( i, cg.snap->ps.stats ) ) { - count++; - } - }*/ - - //x = 320 - count * 20; - //y = 380; - - x = 10; - y = 10; - - for ( i = WP_GAUNTLET; i < WP_NUM_WEAPONS; i++ ) { - if( !BG_gotWeapon( i, cg.snap->ps.stats ) ) - continue; - - CG_RegisterWeapon( i ); - - // draw weapon icon - CG_DrawPic( x, y, 16, 16, cg_weapons[i].weaponIcon ); - - // draw selection marker - if ( i == cg.weaponSelect ) { - CG_DrawPic( x-2, y-2, 20, 20, cgs.media.selectShader ); - } - - BG_unpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips, &maxclips ); - - // no ammo cross on top - if ( !ammo && !clips && !BG_infiniteAmmo( i ) ) { - CG_DrawPic( x, y, 16, 16, cgs.media.noammoShader ); - } - - y += 20; - } - - for ( i = UP_TORCH; i < UP_NUM_UPGRADES; i++ ) { - if( !BG_gotItem( i, cg.snap->ps.stats ) ) - continue; - - CG_RegisterUpgrade( i ); - - // draw weapon icon - CG_DrawPic( x, y, 16, 16, cg_upgrades[i].upgradeIcon ); - - // draw selection marker - if ( i == ( cg.weaponSelect - 32 ) ) { - CG_DrawPic( x-2, y-2, 20, 20, cgs.media.selectShader ); - } - - y += 20; - } - - // draw the selected name - if( cg.weaponSelect <= 32 ) - { - 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); - } - } - } - else if( cg.weaponSelect > 32 ) - { - if ( cg_upgrades[ cg.weaponSelect - 32 ].item ) { - name = cg_upgrades[ cg.weaponSelect - 32 ].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 ) -{ - int ammo, clips, maxclips; - - BG_unpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips, &maxclips ); - - if ( !ammo && !clips && !BG_infiniteAmmo( i ) ) { - return qfalse; - } - if ( !BG_gotWeapon( i, cg.snap->ps.stats ) ) { - return qfalse; - } - - return qtrue; -} - - -/* -=============== -CG_ItemSelectable -=============== -*/ -static qboolean CG_ItemSelectable( int i ) -{ - if( !BG_gotItem( i, cg.snap->ps.stats ) ) { - 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 < 64 ; i++ ) { - cg.weaponSelect++; - if ( cg.weaponSelect == 64 ) { - cg.weaponSelect = 0; - } - /*if ( cg.weaponSelect == WP_GAUNTLET ) { - continue; // never cycle to gauntlet - }*/ - - if( cg.weaponSelect <= 32 ) - { - if ( CG_WeaponSelectable( cg.weaponSelect ) ) { - break; - } - } - else if( cg.weaponSelect > 32 ) - { - if ( CG_ItemSelectable( cg.weaponSelect - 32 ) ) { - break; - } - } - } - if ( i == 64 ) { - 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 < 64 ; i++ ) { - cg.weaponSelect--; - if ( cg.weaponSelect == -1 ) { - cg.weaponSelect = 63; - } - /*if ( cg.weaponSelect == WP_GAUNTLET ) { - continue; // never cycle to gauntlet - }*/ - if( cg.weaponSelect <= 32 ) - { - if ( CG_WeaponSelectable( cg.weaponSelect ) ) { - break; - } - } - else if( cg.weaponSelect > 32 ) - { - if ( CG_ItemSelectable( cg.weaponSelect - 32 ) ) { - break; - } - } - } - if ( i == 64 ) { - 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 > 31 ) { - return; - } - - cg.weaponSelectTime = cg.time; - - if ( !BG_gotWeapon( num, cg.snap->ps.stats ) ) { - 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; - - //TA: mwhaha, must manually change weapons - /*cg.weaponSelectTime = cg.time; - - for ( i = 31 ; 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 = ¢->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; - - 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: - 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; - 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; - 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_FLAMER: - mod = cgs.media.dishFlashModel; - shader = cgs.media.flameExplShader; - sfx = cgs.media.sfx_lghit2; - mark = cgs.media.burnMarkShader; - radius = 48; - isSprite = qtrue; - 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; - case WP_MACHINEGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - mark = cgs.media.bulletMarkShader; - case WP_CHAINGUN: - mod = cgs.media.bulletFlashModel; - shader = cgs.media.bulletExplosionShader; - 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; - } - - 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].color, 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].color; - 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: - 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 (FIXME: ranom seed isn't synce anymore) -================ -*/ -static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, 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 = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; - u = crandom() * 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->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/src/cgame/tr_types.h b/src/cgame/tr_types.h deleted file mode 100644 index c1cd2264..00000000 --- a/src/cgame/tr_types.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#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; - - -#if !defined _WIN32 - -#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so" -#define OPENGL_DRIVER_NAME "libGL.so" - -#else - -#define _3DFX_DRIVER_NAME "3dfxvgl" -#define OPENGL_DRIVER_NAME "opengl32" - -#endif // !defined _WIN32 - - -#endif // __TR_TYPES_H diff --git a/src/game/bg_lib.c b/src/game/bg_lib.c deleted file mode 100644 index e55b47bd..00000000 --- a/src/game/bg_lib.c +++ /dev/null @@ -1,1337 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_lib,c -- standard C library replacement routines used by code -// compiled for the virtual machine - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -#if 0 -static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* LIBC_SCCS and not lint */ - -//typedef int cmp_t(const void *, const void *); -static char* med3(char *, char *, char *, cmp_t *); -static void swapfunc(char *, char *, int, int); - -#ifndef min -#define min(a, b) (a) < (b) ? a : b -#endif - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; - -static void -swapfunc(a, b, n, swaptype) - char *a, *b; - int n, swaptype; -{ - if(swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} - -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -static char * -med3(a, b, c, cmp) - char *a, *b, *c; - cmp_t *cmp; -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); -} - -void -qsort(a, n, es, cmp) - void *a; - size_t n, es; - cmp_t *cmp; -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - swap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* qsort(pn - r, r / es, es, cmp);*/ -} - -//================================================================================== - - -// this file is excluded from release builds because of intrinsics - -size_t strlen( const char *string ) { - const char *s; - - s = string; - while ( *s ) { - s++; - } - return s - string; -} - - -char *strcat( char *strDestination, const char *strSource ) { - char *s; - - s = strDestination; - while ( *s ) { - s++; - } - while ( *strSource ) { - *s++ = *strSource++; - } - *s = 0; - return strDestination; -} - -char *strcpy( char *strDestination, const char *strSource ) { - char *s; - - s = strDestination; - while ( *strSource ) { - *s++ = *strSource++; - } - *s = 0; - return strDestination; -} - - -int strcmp( const char *string1, const char *string2 ) { - while ( *string1 == *string2 && *string1 && *string2 ) { - string1++; - string2++; - } - return *string1 - *string2; -} - - -char *strchr( const char *string, int c ) { - while ( *string ) { - if ( *string == c ) { - return ( char * )string; - } - string++; - } - return (char *)0; -} - -char *strstr( const char *string, const char *strCharSet ) { - while ( *string ) { - int i; - - for ( i = 0 ; strCharSet[i] ; i++ ) { - if ( string[i] != strCharSet[i] ) { - break; - } - } - if ( !strCharSet[i] ) { - return (char *)string; - } - string++; - } - return (char *)0; -} - -#if !defined ( _MSC_VER ) && !defined ( __linux__ ) - -int tolower( int c ) { - if ( c >= 'A' && c <= 'Z' ) { - c += 'a' - 'A'; - } - return c; -} - - -int toupper( int c ) { - if ( c >= 'a' && c <= 'z' ) { - c += 'A' - 'a'; - } - return c; -} - -#endif -//#ifndef _MSC_VER - -void *memmove( void *dest, const void *src, size_t count ) { - int i; - - if ( dest > src ) { - for ( i = count-1 ; i >= 0 ; i-- ) { - ((char *)dest)[i] = ((char *)src)[i]; - } - } else { - for ( i = 0 ; i < count ; i++ ) { - ((char *)dest)[i] = ((char *)src)[i]; - } - } - return dest; -} - - -#if 0 - -double floor( double x ) { - return (int)(x + 0x40000000) - 0x40000000; -} - -void *memset( void *dest, int c, size_t count ) { - while ( count-- ) { - ((char *)dest)[count] = c; - } - return dest; -} - -void *memcpy( void *dest, const void *src, size_t count ) { - while ( count-- ) { - ((char *)dest)[count] = ((char *)src)[count]; - } - return dest; -} - -char *strncpy( char *strDest, const char *strSource, size_t count ) { - char *s; - - s = strDest; - while ( *strSource && count ) { - *s++ = *strSource++; - count--; - } - while ( count-- ) { - *s++ = 0; - } - return strDest; -} - -double sqrt( double x ) { - float y; - float delta; - float maxError; - - if ( x <= 0 ) { - return 0; - } - - // initial guess - y = x / 2; - - // refine - maxError = x * 0.001; - - do { - delta = ( y * y ) - x; - y -= delta / ( 2 * y ); - } while ( delta > maxError || delta < -maxError ); - - return y; -} - - -float sintable[1024] = { -0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738, -0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008, -0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274, -0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535, -0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790, -0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035, -0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269, -0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490, -0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697, -0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888, -0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061, -0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213, -0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343, -0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450, -0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532, -0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586, -0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610, -0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604, -0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565, -0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492, -0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382, -0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234, -0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046, -0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816, -0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543, -0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225, -0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859, -0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445, -0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980, -0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463, -0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892, -0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266, -0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582, -0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838, -0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034, -0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168, -0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237, -0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241, -0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177, -0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043, -0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839, -0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563, -0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212, -0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786, -0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283, -0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701, -0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039, -0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294, -0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466, -0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553, -0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554, -0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466, -0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290, -0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022, -0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661, -0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207, -0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657, -0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011, -0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266, -0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422, -0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476, -0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429, -0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278, -0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021, -0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659, -0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188, -0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609, -0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920, -0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119, -0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206, -0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179, -0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036, -0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778, -0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402, -0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907, -0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293, -0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558, -0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701, -0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721, -0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616, -0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387, -0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032, -0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549, -0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939, -0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199, -0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330, -0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329, -0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197, -0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932, -0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534, -0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001, -0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332, -0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528, -0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587, -0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508, -0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291, -0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935, -0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440, -0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803, -0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026, -0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107, -0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046, -0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842, -0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494, -0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002, -0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366, -0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584, -0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657, -0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584, -0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365, -0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999, -0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485, -0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824, -0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014, -0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057, -0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950, -0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695, -0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291, -0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737, -0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033, -0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180, -0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176, -0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023, -0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719, -0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265, -0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660, -0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905, -0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999 -}; - -double sin( double x ) { - int index; - int quad; - - index = 1024 * x / (M_PI * 0.5); - quad = ( index >> 10 ) & 3; - index &= 1023; - switch ( quad ) { - case 0: - return sintable[index]; - case 1: - return sintable[1023-index]; - case 2: - return -sintable[index]; - case 3: - return -sintable[1023-index]; - } - return 0; -} - - -double cos( double x ) { - int index; - int quad; - - index = 1024 * x / (M_PI * 0.5); - quad = ( index >> 10 ) & 3; - index &= 1023; - switch ( quad ) { - case 3: - return sintable[index]; - case 0: - return sintable[1023-index]; - case 1: - return -sintable[index]; - case 2: - return -sintable[1023-index]; - } - return 0; -} - - -/* -void create_acostable( void ) { - int i; - FILE *fp; - float a; - - fp = fopen("c:\\acostable.txt", "w"); - fprintf(fp, "float acostable[] = {"); - for (i = 0; i < 1024; i++) { - if (!(i & 7)) - fprintf(fp, "\n"); - a = acos( (float) -1 + i / 512 ); - fprintf(fp, "%1.8f,", a); - } - fprintf(fp, "\n}\n"); - fclose(fp); -} -*/ - - -float acostable[] = { -3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422, -2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629, -2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962, -2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724, -2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926, -2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688, -2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735, -2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133, -2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440, -2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769, -2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409, -2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238, -2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096, -2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722, -2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034, -2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622, -2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379, -2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237, -2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964, -2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010, -2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388, -2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580, -2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460, -2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238, -2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408, -2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709, -2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092, -2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692, -2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805, -2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865, -2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435, -2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185, -2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884, -2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387, -2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628, -2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610, -2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399, -2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119, -1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942, -1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088, -1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818, -1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433, -1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266, -1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683, -1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076, -1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866, -1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495, -1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429, -1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151, -1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164, -1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985, -1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148, -1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198, -1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692, -1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199, -1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297, -1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571, -1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615, -1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028, -1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416, -1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388, -1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556, -1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536, -1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945, -1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403, -1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526, -1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933, -1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240, -1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060, -1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004, -1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677, -1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682, -1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612, -1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056, -1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594, -1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795, -1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222, -1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422, -1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932, -1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273, -1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951, -1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456, -1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257, -1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803, -1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519, -1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806, -1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037, -1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553, -1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663, -1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638, -1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709, -1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061, -1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831, -1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098, -1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882, -1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136, -1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735, -1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471, -1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039, -0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030, -0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912, -0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017, -0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524, -0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430, -0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531, -0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385, -0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277, -0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172, -0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655, -0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865, -0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402, -0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217, -0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469, -0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332, -0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753, -0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106, -0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735, -0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288, -0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758, -0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028, -0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573, -0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652, -0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513, -0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209, -0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574, -0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250, -0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575, -0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018, -}; - -double acos( double x ) { - int index; - - if (x < -1) - x = -1; - if (x > 1) - x = 1; - index = (float) (1.0 + x) * 511.9; - return acostable[index]; -} - - -double atan2( double y, double x ) { - float base; - float temp; - float dir; - float test; - int i; - - if ( x < 0 ) { - if ( y >= 0 ) { - // quad 1 - base = M_PI / 2; - temp = x; - x = y; - y = -temp; - } else { - // quad 2 - base = M_PI; - x = -x; - y = -y; - } - } else { - if ( y < 0 ) { - // quad 3 - base = 3 * M_PI / 2; - temp = x; - x = -y; - y = temp; - } - } - - if ( y > x ) { - base += M_PI/2; - temp = x; - x = y; - y = temp; - dir = -1; - } else { - dir = 1; - } - - // calcualte angle in octant 0 - if ( x == 0 ) { - return base; - } - y /= x; - - for ( i = 0 ; i < 512 ; i++ ) { - test = sintable[i] / sintable[1023-i]; - if ( test > y ) { - break; - } - } - - return base + dir * i * ( M_PI/2048); -} - - -#endif - -double tan( double x ) { - return sin(x) / cos(x); -} - - -static int randSeed = 0; - -void srand( unsigned seed ) { - randSeed = seed; -} - -int rand( void ) { - randSeed = (69069 * randSeed + 1); - return randSeed & 0x7fff; -} - -double atof( const char *string ) { - float sign; - float value; - int c; - - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - c = string[0]; - if ( c != '.' ) { - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - } else { - string++; - } - - // check for decimal point - if ( c == '.' ) { - double fraction; - - fraction = 0.1; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value += c * fraction; - fraction *= 0.1; - } while ( 1 ); - - } - - // not handling 10e10 notation... - - return value * sign; -} - -double _atof( const char **stringPtr ) { - const char *string; - float sign; - float value; - int c; - - string = *stringPtr; - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - *stringPtr = string; - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - if ( string[0] != '.' ) { - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - } - - // check for decimal point - if ( c == '.' ) { - double fraction; - - fraction = 0.1; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value += c * fraction; - fraction *= 0.1; - } while ( 1 ); - - } - - // not handling 10e10 notation... - *stringPtr = string; - - return value * sign; -} - - -#if !defined( _MSC_VER ) && !defined( __linux__ ) - -int atoi( const char *string ) { - int sign; - int value; - int c; - - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - - // not handling 10e10 notation... - - return value * sign; -} - - -int _atoi( const char **stringPtr ) { - int sign; - int value; - int c; - const char *string; - - string = *stringPtr; - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - - // not handling 10e10 notation... - - *stringPtr = string; - - return value * sign; -} - -int abs( int n ) { - return n < 0 ? -n : n; -} - -double fabs( double x ) { - return x < 0 ? -x : x; -} - - - -//========================================================= - - -#define ALT 0x00000001 /* alternate form */ -#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ -#define LADJUST 0x00000004 /* left adjustment */ -#define LONGDBL 0x00000008 /* long double */ -#define LONGINT 0x00000010 /* long integer */ -#define QUADINT 0x00000020 /* quad integer */ -#define SHORTINT 0x00000040 /* short integer */ -#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define FPT 0x00000100 /* floating point number */ - -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -void AddInt( char **buf_p, int val, int width, int flags ) { - char text[32]; - int digits; - int signedVal; - char *buf; - - digits = 0; - signedVal = val; - if ( val < 0 ) { - val = -val; - } - do { - text[digits++] = '0' + val % 10; - val /= 10; - } while ( val ); - - if ( signedVal < 0 ) { - text[digits++] = '-'; - } - - buf = *buf_p; - - if( !( flags & LADJUST ) ) { - while ( digits < width ) { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - width--; - } - } - - while ( digits-- ) { - *buf++ = text[digits]; - width--; - } - - if( flags & LADJUST ) { - while ( width-- ) { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - } - } - - *buf_p = buf; -} - -void AddFloat( char **buf_p, float fval, int width, int prec ) { - char text[32]; - int digits; - float signedVal; - char *buf; - int val; - - // get the sign - signedVal = fval; - if ( fval < 0 ) { - fval = -fval; - } - - // write the float number - digits = 0; - val = (int)fval; - do { - text[digits++] = '0' + val % 10; - val /= 10; - } while ( val ); - - if ( signedVal < 0 ) { - text[digits++] = '-'; - } - - buf = *buf_p; - - while ( digits < width ) { - *buf++ = ' '; - width--; - } - - while ( digits-- ) { - *buf++ = text[digits]; - } - - *buf_p = buf; - - if (prec < 0) - prec = 6; - // write the fraction - digits = 0; - while (digits < prec) { - fval -= (int) fval; - fval *= 10.0; - val = (int) fval; - text[digits++] = '0' + val % 10; - } - - if (digits > 0) { - buf = *buf_p; - *buf++ = '.'; - for (prec = 0; prec < digits; prec++) { - *buf++ = text[prec]; - } - *buf_p = buf; - } -} - - -void AddString( char **buf_p, char *string, int width, int prec ) { - int size; - char *buf; - - buf = *buf_p; - - if ( string == NULL ) { - string = "(null)"; - prec = -1; - } - - if ( prec >= 0 ) { - for( size = 0; size < prec; size++ ) { - if( string[size] == '\0' ) { - break; - } - } - } - else { - size = strlen( string ); - } - - width -= size; - - while( size-- ) { - *buf++ = *string++; - } - - while( width-- > 0 ) { - *buf++ = ' '; - } - - *buf_p = buf; -} - -/* -vsprintf - -I'm not going to support a bunch of the more arcane stuff in here -just to keep it simpler. For example, the '*' and '$' are not -currently supported. I've tried to make it so that it will just -parse and ignore formats we don't support. -*/ -int vsprintf( char *buffer, const char *fmt, va_list argptr ) { - int *arg; - char *buf_p; - char ch; - int flags; - int width; - int prec; - int n; - char sign; - - buf_p = buffer; - arg = (int *)argptr; - - while( qtrue ) { - // run through the format string until we hit a '%' or '\0' - for ( ch = *fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++ ) { - *buf_p++ = ch; - } - if ( ch == '\0' ) { - goto done; - } - - // skip over the '%' - fmt++; - - // reset formatting state - flags = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: - ch = *fmt++; -reswitch: - switch( ch ) { - case '-': - flags |= LADJUST; - goto rflag; - case '.': - n = 0; - while( is_digit( ( ch = *fmt++ ) ) ) { - n = 10 * n + ( ch - '0' ); - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - flags |= ZEROPAD; - goto rflag; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - n = 0; - do { - n = 10 * n + ( ch - '0' ); - ch = *fmt++; - } while( is_digit( ch ) ); - width = n; - goto reswitch; - case 'c': - *buf_p++ = (char)*arg; - arg++; - break; - case 'd': - case 'i': - AddInt( &buf_p, *arg, width, flags ); - arg++; - break; - case 'f': - AddFloat( &buf_p, *(double *)arg, width, prec ); -#ifdef __LCC__ - arg += 1; // everything is 32 bit in my compiler -#else - arg += 2; -#endif - break; - case 's': - AddString( &buf_p, (char *)*arg, width, prec ); - arg++; - break; - case '%': - *buf_p++ = ch; - break; - default: - *buf_p++ = (char)*arg; - arg++; - break; - } - } - -done: - *buf_p = 0; - return buf_p - buffer; -} - - -/* this is really crappy */ -int sscanf( const char *buffer, const char *fmt, ... ) { - int cmd; - int **arg; - int count; - - arg = (int **)&fmt + 1; - count = 0; - - while ( *fmt ) { - if ( fmt[0] != '%' ) { - fmt++; - continue; - } - - cmd = fmt[1]; - fmt += 2; - - switch ( cmd ) { - case 'i': - case 'd': - case 'u': - **arg = _atoi( &buffer ); - break; - case 'f': - *(float *)*arg = _atof( &buffer ); - break; - } - arg++; - } - - return count; -} - -#endif diff --git a/src/game/bg_lib.h b/src/game/bg_lib.h deleted file mode 100644 index 306684b0..00000000 --- a/src/game/bg_lib.h +++ /dev/null @@ -1,94 +0,0 @@ -// bg_lib.h -- standard C library replacement routines used by code -// compiled for the virtual machine - -// This file is NOT included on native builds - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -typedef int size_t; - -typedef char * va_list; -#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) -#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) -#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) -#define va_end(ap) ( ap = (va_list)0 ) - -#define CHAR_BIT 8 /* number of bits in a char */ -#define SCHAR_MIN (-128) /* minimum signed char value */ -#define SCHAR_MAX 127 /* maximum signed char value */ -#define UCHAR_MAX 0xff /* maximum unsigned char value */ - -#define SHRT_MIN (-32768) /* minimum (signed) short value */ -#define SHRT_MAX 32767 /* maximum (signed) short value */ -#define USHRT_MAX 0xffff /* maximum unsigned short value */ -#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ -#define INT_MAX 2147483647 /* maximum (signed) int value */ -#define UINT_MAX 0xffffffff /* maximum unsigned int value */ -#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */ -#define LONG_MAX 2147483647L /* maximum (signed) long value */ -#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */ - -// Misc functions -typedef int cmp_t(const void *, const void *); -void qsort(void *a, size_t n, size_t es, cmp_t *cmp); -void srand( unsigned seed ); -int rand( void ); - -// String functions -size_t strlen( const char *string ); -char *strcat( char *strDestination, const char *strSource ); -char *strcpy( char *strDestination, const char *strSource ); -int strcmp( const char *string1, const char *string2 ); -char *strchr( const char *string, int c ); -char *strstr( const char *string, const char *strCharSet ); -char *strncpy( char *strDest, const char *strSource, size_t count ); -int tolower( int c ); -int toupper( int c ); - -double atof( const char *string ); -double _atof( const char **stringPtr ); -int atoi( const char *string ); -int _atoi( const char **stringPtr ); - -int vsprintf( char *buffer, const char *fmt, va_list argptr ); -int sscanf( const char *buffer, const char *fmt, ... ); - -// Memory functions -void *memmove( void *dest, const void *src, size_t count ); -void *memset( void *dest, int c, size_t count ); -void *memcpy( void *dest, const void *src, size_t count ); - -// Math functions -double ceil( double x ); -double floor( double x ); -double sqrt( double x ); -double sin( double x ); -double cos( double x ); -double atan2( double y, double x ); -double tan( double x ); -int abs( int n ); -double fabs( double x ); -double acos( double x ); - diff --git a/src/game/bg_local.h b/src/game/bg_local.h deleted file mode 100644 index de2803ec..00000000 --- a/src/game/bg_local.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_local.h -- local definitions for the bg (both games) files - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes - -#define STEPSIZE 18 - -#define JUMP_VELOCITY 270 - -#define TIMER_LAND 130 -#define TIMER_GESTURE (34*66+50) - -#define OVERCLIP 1.001f - -// all of the locals will be zeroed before each -// pmove, just to make damn sure we don't have -// any differences when running on client or server -typedef struct { - vec3_t forward, right, up; - float frametime; - - int msec; - - qboolean walking; - qboolean groundPlane; - trace_t groundTrace; - - float impactSpeed; - - vec3_t previous_origin; - vec3_t previous_velocity; - int previous_waterlevel; -} pml_t; - -//TA: struct that stores smooth ops -// there is an array of these in bg_pmove.c -typedef struct -{ - float time; - - vec3_t rotAxis; - float rotAngle; -} smooth_t; - -//TA: make this into a cvar later.... -#define SMOOTHTIME 300 -#define MAXSMOOTHS 10 - -//TA: wall climbing local -typedef struct -{ - smooth_t sList[ MAXSMOOTHS ]; - - qboolean justFallen; - vec3_t lastNormal; - vec3_t nonSvangles; -} wcl_t; - -extern pmove_t *pm; -extern pml_t pml; - -// movement parameters -extern float pm_stopspeed; -extern float pm_duckScale; -extern float pm_swimScale; -extern float pm_wadeScale; - -extern float pm_accelerate; -extern float pm_airaccelerate; -extern float pm_wateraccelerate; -extern float pm_flyaccelerate; - -extern float pm_friction; -extern float pm_waterfriction; -extern float pm_flightfriction; - -extern int c_pmove; - -void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ); -void PM_AddTouchEnt( int entityNum ); -void PM_AddEvent( int newEvent ); - -qboolean PM_SlideMove( qboolean gravity ); -void PM_StepSlideMove( qboolean gravity ); - diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c deleted file mode 100644 index 130ff0d8..00000000 --- a/src/game/bg_misc.c +++ /dev/null @@ -1,1709 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_misc.c -- both games misc functions, all completely stateless - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" -#include "bg_public.h" - -/*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended -DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION. -The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface. - -If an item is the target of another entity, it will not spawn in until fired. - -An item fires all of its targets when it is picked up. If the toucher can't carry it, the targets won't be fired. - -"notfree" if set to 1, don't spawn in free for all games -"notteam" if set to 1, don't spawn in team games -"notsingle" if set to 1, don't spawn in single player games -"wait" override the default wait before respawning. -1 = never respawn automatically, which can be used with targeted spawning. -"random" random number of plus or minus seconds varied from the respawn time -"count" override quantity or duration on most items. -*/ - -gitem_t bg_itemlist[] = -{ - { - NULL, - NULL, - { NULL, - NULL, - 0, 0} , -/* icon */ NULL, -/* pickup */ NULL, - 0, - 0, - 0, -/* precache */ "", -/* sounds */ "" - }, // leave index 0 alone - - // - // ARMOR - // - -/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_armor_shard", - "sound/misc/ar1_pkup.wav", - { "models/powerups/armor/shard.md3", - "models/powerups/armor/shard_sphere.md3", - 0, 0} , - "icons/iconr_shard", - "Armor Shard", - 5, - IT_ARMOR, - 0, - "", - "" - },*/ - -/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_armor_combat", - "sound/misc/ar2_pkup.wav", - { "models/powerups/armor/armor_yel.md3", - 0, 0, 0}, - "icons/iconr_yellow", - "Armor", - 50, - IT_ARMOR, - 0, - "", - "" - },*/ - -/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_armor_body", - "sound/misc/ar3_pkup.wav", - { "models/powerups/armor/armor_red.md3", - 0, 0, 0}, - "icons/iconr_red", - "Heavy Armor", - 100, - IT_ARMOR, - 0, - "", - "" - },*/ - - // - // health - // -/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health_small", - "sound/items/s_health.wav", - { "models/powerups/health/small_cross.md3", - "models/powerups/health/small_sphere.md3", - 0, 0 }, - "icons/iconh_green", - "5 Health", - 5, - IT_HEALTH, - 0, - "", - "" - },*/ - -/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health", - "sound/items/n_health.wav", - { "models/powerups/health/medium_cross.md3", - "models/powerups/health/medium_sphere.md3", - 0, 0 }, - "icons/iconh_yellow", - "25 Health", - 25, - IT_HEALTH, - 0, - "", - "" - },*/ - -/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health_large", - "sound/items/l_health.wav", - { "models/powerups/health/large_cross.md3", - "models/powerups/health/large_sphere.md3", - 0, 0 }, - "icons/iconh_red", - "50 Health", - 50, - IT_HEALTH, - 0, - "", - "" - },*/ - -/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health_mega", - "sound/items/m_health.wav", - { "models/powerups/health/mega_cross.md3", - "models/powerups/health/mega_sphere.md3", - 0, 0 }, - "icons/iconh_mega", - "Mega Health", - 100, - IT_HEALTH, - 0, - "", - "" - },*/ - - - // - // WEAPONS - // - -/*QUAKED weapon_gauntlet (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - -//TA:FIXME: must keep gauntlet and machinegun for now or bots have a fit and prevent game working - - { - "weapon_gauntlet", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "Gauntlet", - 0, - IT_WEAPON, - WP_GAUNTLET, - "", - "" - }, - -/*QUAKED weapon_venom (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_venom", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "Venom", - 0, - IT_WEAPON, - WP_VENOM, - "", - "" - }, - -/*QUAKED weapon_abuild (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_abuild", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "ABuild", - 0, - IT_WEAPON, - WP_ABUILD, - "", - "" - }, - -/*QUAKED weapon_hbuild (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_hbuild", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "HBuild", - 0, - IT_WEAPON, - WP_HBUILD, - "", - "" - }, - -/*QUAKED weapon_scanner (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_scanner", - "sound/misc/w_pkup.wav", - { "models/weapons2/shotgun/shotgun.md3", - 0, 0, 0}, - "icons/iconw_shotgun", - "Scanner", - 0, - IT_WEAPON, - WP_SCANNER, - "", - "" - }, - -/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_shotgun", - "sound/misc/w_pkup.wav", - { "models/weapons2/shotgun/shotgun.md3", - 0, 0, 0}, - "icons/iconw_shotgun", - "Shotgun", - 10, - IT_WEAPON, - WP_SHOTGUN, - "", - "" - },*/ - -/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_machinegun", - "sound/misc/w_pkup.wav", - { "models/weapons2/machinegun/machinegun.md3", - 0, 0, 0}, - "icons/iconw_machinegun", - "Machinegun", - 40, - IT_WEAPON, - WP_MACHINEGUN, - "", - "" - }, - -/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_chaingun", - "sound/misc/w_pkup.wav", - { "models/weapons2/machinegun/machinegun.md3", - 0, 0, 0}, - "icons/iconw_machinegun", - "Chaingun", - 40, - IT_WEAPON, - WP_CHAINGUN, - "", - "" - }, - -/*QUAKED weapon_ggrenade (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_ggrenade", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "Gas Grenade", - 0, - IT_WEAPON, - WP_GGRENADE, - "", - "" - }, - -/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_grenadelauncher", - "sound/misc/w_pkup.wav", - { "models/weapons2/grenadel/grenadel.md3", - 0, 0, 0}, - "icons/iconw_grenade", - "Grenade Launcher", - 10, - IT_WEAPON, - WP_GRENADE_LAUNCHER, - "", - "sound/weapons/grenade/hgrenb1a.wav sound/weapons/grenade/hgrenb2a.wav" - },*/ - -/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_rocketlauncher", - "sound/misc/w_pkup.wav", - { "models/weapons2/rocketl/rocketl.md3", - 0, 0, 0}, - "icons/iconw_rocket", - "Rocket Launcher", - 10, - IT_WEAPON, - WP_ROCKET_LAUNCHER, - "", - "" - },*/ - -/*QUAKED weapon_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_lightning", - "sound/misc/w_pkup.wav", - { "models/weapons2/lightning/lightning.md3", - 0, 0, 0}, - "icons/iconw_lightning", - "Lightning Gun", - 100, - IT_WEAPON, - WP_LIGHTNING, - "", - "" - },*/ - -/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_railgun", - "sound/misc/w_pkup.wav", - { "models/weapons2/railgun/railgun.md3", - 0, 0, 0}, - "icons/iconw_railgun", - "Railgun", - 10, - IT_WEAPON, - WP_RAILGUN, - "", - "" - },*/ - -/*QUAKED weapon_plasmagun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_plasmagun", - "sound/misc/w_pkup.wav", - { "models/weapons2/plasma/plasma.md3", - 0, 0, 0}, - "icons/iconw_plasma", - "Plasma Gun", - 50, - IT_WEAPON, - WP_PLASMAGUN, - "", - "" - }, - -/*QUAKED weapon_flamer (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_flamer", - "sound/misc/w_pkup.wav", - { "models/weapons2/plasma/plasma.md3", - 0, 0, 0}, - "icons/iconw_plasma", - "Flame Thrower", - 50, - IT_WEAPON, - WP_FLAMER, - "", - "" - }, - -/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_bfg", - "sound/misc/w_pkup.wav", - { "models/weapons2/bfg/bfg.md3", - 0, 0, 0}, - "icons/iconw_bfg", - "Dual BFG", - 0, - IT_WEAPON, - WP_BFG, - "", - "" - }, - -/*QUAKED weapon_grapplinghook (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_grapplinghook", - "sound/misc/w_pkup.wav", - { "models/weapons2/grapple/grapple.md3", - 0, 0, 0}, - "icons/iconw_grapple", - "Grappling Hook", - 0, - IT_WEAPON, - WP_GRAPPLING_HOOK, - "", - "" - },*/ - - // - // AMMO ITEMS - // - -/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_shells", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/shotgunam.md3", - 0, 0, 0}, - "icons/icona_shotgun", - "Shells", - 10, - IT_AMMO, - WP_SHOTGUN, - "", - "" - },*/ - -/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_bullets", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/machinegunam.md3", - 0, 0, 0}, - "icons/icona_machinegun", - "Bullets", - 50, - IT_AMMO, - WP_MACHINEGUN, - "", - "" - },*/ - -/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_grenades", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/grenadeam.md3", - 0, 0, 0}, - "icons/icona_grenade", - "Grenades", - 5, - IT_AMMO, - WP_GRENADE_LAUNCHER, - "", - "" - },*/ - -/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_cells", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/plasmaam.md3", - 0, 0, 0}, - "icons/icona_plasma", - "Cells", - 30, - IT_AMMO, - WP_PLASMAGUN, - "", - "" - },*/ - -/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_lightning", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/lightningam.md3", - 0, 0, 0}, - "icons/icona_lightning", - "Lightning", - 60, - IT_AMMO, - WP_LIGHTNING, - "", - "" - },*/ - -/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_rockets", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/rocketam.md3", - 0, 0, 0}, - "icons/icona_rocket", - "Rockets", - 5, - IT_AMMO, - WP_ROCKET_LAUNCHER, - "", - "" - },*/ - -/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_slugs", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/railgunam.md3", - 0, 0, 0}, - "icons/icona_railgun", - "Slugs", - 10, - IT_AMMO, - WP_RAILGUN, - "", - "" - },*/ - -/*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_bfg", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/bfgam.md3", - 0, 0, 0}, - "icons/icona_bfg", - "Bfg Ammo", - 15, - IT_AMMO, - WP_BFG, - "", - "" - },*/ - - // - // HOLDABLE ITEMS - // -/*QUAKED holdable_teleporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "holdable_teleporter", - "sound/items/holdable.wav", - { "models/powerups/holdable/teleporter.md3", - 0, 0, 0}, - "icons/teleporter", - "Personal Teleporter", - 60, - IT_HOLDABLE, - HI_TELEPORTER, - "", - "" - },*/ - -/*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "holdable_medkit", - "sound/items/holdable.wav", - { "models/powerups/holdable/medkit.md3", - "models/powerups/holdable/medkit_sphere.md3", - 0, 0}, - "icons/medkit", - "Medkit", - 60, - IT_HOLDABLE, - HI_MEDKIT, - "", - "sound/items/use_medkit.wav" - },*/ - - // - // POWERUP ITEMS - // -/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_quad", - "sound/items/quaddamage.wav", - { "models/powerups/instant/quad.md3", - "models/powerups/instant/quad_ring.md3", - 0, 0 }, - "icons/quad", - "Quad Damage", - 30, - IT_POWERUP, - PW_QUAD, - "", - "sound/items/damage2.wav sound/items/damage3.wav" - },*/ - -/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_enviro", - "sound/items/protect.wav", - { "models/powerups/instant/enviro.md3", - "models/powerups/instant/enviro_ring.md3", - 0, 0 }, - "icons/envirosuit", - "Battle Suit", - 30, - IT_POWERUP, - PW_BATTLESUIT, - "", - "sound/items/airout.wav sound/items/protect3.wav" - },*/ - -/*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_haste", - "sound/items/haste.wav", - { "models/powerups/instant/haste.md3", - "models/powerups/instant/haste_ring.md3", - 0, 0 }, - "icons/haste", - "Speed", - 30, - IT_POWERUP, - PW_HASTE, - "", - "" - },*/ - -/*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_invis", - "sound/items/invisibility.wav", - { "models/powerups/instant/invis.md3", - "models/powerups/instant/invis_ring.md3", - 0, 0 }, - "icons/invis", - "Invisibility", - 30, - IT_POWERUP, - PW_INVIS, - "", - "" - },*/ - -/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_regen", - "sound/items/regeneration.wav", - { "models/powerups/instant/regen.md3", - "models/powerups/instant/regen_ring.md3", - 0, 0 }, - "icons/regen", - "Regeneration", - 30, - IT_POWERUP, - PW_REGEN, - "", - "sound/items/regen.wav" - },*/ - -/*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_flight", - "sound/items/flight.wav", - { "models/powerups/instant/flight.md3", - "models/powerups/instant/flight_ring.md3", - 0, 0 }, - "icons/flight", - "Flight", - 60, - IT_POWERUP, - PW_FLIGHT, - "", - "sound/items/flight.wav" - },*/ - -/*QUAKED team_droid_spawn (0 0 1) (-16 -16 -16) (16 16 16) -TA: droid spawn item -*/ - { - "team_droid_spawn", - "sound/items/holdable.wav", - { "models/bitems/aspawn.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Droid Spawn", //pickup - 0, - IT_BUILDABLE, - BA_A_SPAWN, - "", //precache - "" //sounds - }, - -/*QUAKED team_droid_def1 (0 0 1) (-16 -16 -16) (16 16 16) -TA: droid defense item -*/ - { - "team_droid_def1", - "sound/items/holdable.wav", - { "models/bitems/adef1.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Droid Defense", //pickup - 0, - IT_BUILDABLE, - BA_A_DEF1, - "", //precache - "" //sounds - }, - -/*QUAKED team_human_spawn (0 0 1) (-16 -16 -16) (16 16 16) -TA: human spawn item -*/ - { - "team_human_spawn", - "sound/items/holdable.wav", - { "models/bitems/hspawn.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Human Spawn", //pickup - 0, - IT_BUILDABLE, - BA_H_SPAWN, - "", //precache - "" //sounds - }, - -/*QUAKED team_human_def1 (0 0 1) (-16 -16 -16) (16 16 16) -TA: human defense item -*/ - { - "team_human_def1", - "sound/items/holdable.wav", - { "models/bitems/turret-base.md3", "models/bitems/turret-top.md3", 0, 0 }, - "icons/teleporter", //icon - "Human Defense", //pickup - 0, - IT_BUILDABLE, - BA_H_DEF1, - "", //precache - "" //sounds - }, - -/*QUAKED team_human_mcu (0 0 1) (-16 -16 -16) (16 16 16) -TA: human defense item -*/ - { - "team_human_mcu", - "sound/items/holdable.wav", - { "models/bitems/adef1.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Human MCU", //pickup - 0, - IT_BUILDABLE, - BA_H_MCU, - "", //precache - "" //sounds - }, - -/*QUAKED upgrade_torch (0 0 1) (-16 -16 -16) (16 16 16) -*/ - { - "upgrade_torch", - "sound/items/holdable.wav", - { 0, 0, 0, 0 }, - "icons/teleporter", //icon - "Torch", //pickup - 0, - IT_UPGRADE, - UP_TORCH, - "", //precache - "" //sounds - }, - -/*QUAKED upgrade_nvg (0 0 1) (-16 -16 -16) (16 16 16) -*/ - { - "upgrade_nvg", - "sound/items/holdable.wav", - { 0, 0, 0, 0 }, - "icons/teleporter", //icon - "NVG", //pickup - 0, - IT_UPGRADE, - UP_NVG, - "", //precache - "" //sounds - }, - -/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16) -Only in CTF games -*/ - /*{ - "team_CTF_redflag", - "sound/teamplay/flagtk_red.wav", - { "models/flags/r_flag.md3", - 0, 0, 0 }, - "icons/iconf_red1", - "Red Flag", - 0, - IT_TEAM, - PW_REDFLAG, - "", - "sound/teamplay/flagcap_red.wav sound/teamplay/flagtk_red.wav sound/teamplay/flagret_red.wav" - },*/ - -/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16) -Only in CTF games -*/ - /*{ - "team_CTF_blueflag", - "sound/teamplay/flagtk_blu.wav", - { "models/flags/b_flag.md3", - 0, 0, 0 }, - "icons/iconf_blu1", - "Blue Flag", - 0, - IT_TEAM, - PW_BLUEFLAG, - "", - "sound/teamplay/flagcap_blu.wav sound/teamplay/flagtk_blu.wav sound/teamplay/flagret_blu.wav" - },*/ - - // end of list marker - {NULL} -}; - -int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1; - - -/* -============== -BG_FindItemForPowerup -============== -*/ -gitem_t *BG_FindItemForPowerup( powerup_t pw ) { - int i; - - for ( i = 0 ; i < bg_numItems ; i++ ) { - if ( (bg_itemlist[i].giType == IT_POWERUP /*|| - bg_itemlist[i].giType == IT_TEAM || - bg_itemlist[i].giType == IT_PERSISTANT_POWERUP*/) && - bg_itemlist[i].giTag == pw ) { - return &bg_itemlist[i]; - } - } - - return NULL; -} - - -/* -============== -BG_FindItemForHoldable -============== -*/ -gitem_t *BG_FindItemForHoldable( holdable_t pw ) { - int i; - - for ( i = 0 ; i < bg_numItems ; i++ ) { - if ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) { - return &bg_itemlist[i]; - } - } - - Com_Error( ERR_DROP, "HoldableItem not found" ); - - return NULL; -} - - -/* -=============== -BG_FindItemForWeapon - -=============== -*/ -gitem_t *BG_FindItemForWeapon( weapon_t weapon ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_WEAPON && it->giTag == weapon ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for weapon %i", weapon); - return NULL; -} - - -/* -=============== -BG_FindItemForBuildable - -TA: new function for finding buildable items -=============== -*/ -gitem_t *BG_FindItemForBuildable( buildable_t buildable ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_BUILDABLE && it->giTag == buildable ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for buildable %i", buildable); - return NULL; -} - - -/* -=============== -BG_FindItemForUpgrade - -TA: new function for finding upgrade items -=============== -*/ -gitem_t *BG_FindItemForUpgrade( upgrade_t upgrade ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_UPGRADE && it->giTag == upgrade ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for upgrade %i", upgrade); - return NULL; -} - - -/* -=============== -BG_FindItem - -=============== -*/ -gitem_t *BG_FindItem( const char *pickupName ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++ ) { - if ( !Q_stricmp( it->pickup_name, pickupName ) ) - return it; - } - - return NULL; -} - -/* -============ -BG_PlayerTouchesItem - -Items can be picked up without actually touching their physical bounds to make -grabbing them easier -============ -*/ -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) { - vec3_t origin; - - BG_EvaluateTrajectory( &item->pos, atTime, origin ); - - // we are ignoring ducked differences here - if ( ps->origin[0] - origin[0] > 44 - || ps->origin[0] - origin[0] < -50 - || ps->origin[1] - origin[1] > 36 - || ps->origin[1] - origin[1] < -36 - || ps->origin[2] - origin[2] > 36 - || ps->origin[2] - origin[2] < -36 ) { - return qfalse; - } - - return qtrue; -} - -/* -================ -BG_CanItemBeGrabbed - -Returns false if the item should not be picked up. -This needs to be the same for client side prediction and server use. -================ -*/ -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) { - gitem_t *item; - - if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) { - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" ); - } - - item = &bg_itemlist[ent->modelindex]; - - switch( item->giType ) { - case IT_WEAPON: - return qtrue; // weapons are always picked up - - case IT_AMMO: - if ( ps->ammo[ item->giTag ] >= 200 ) { - return qfalse; // can't hold any more - } - return qtrue; - - case IT_ARMOR: - if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } - return qtrue; - - case IT_HEALTH: - // small and mega healths will go over the max, otherwise - // don't pick up if already at max - if ( item->quantity == 5 || item->quantity == 100 ) { - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } - return qtrue; - } - - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) { - return qfalse; - } - return qtrue; - - case IT_POWERUP: - return qtrue; // powerups are always picked up - - case IT_TEAM: // team items, such as flags - // ent->modelindex2 is non-zero on items if they are dropped - // we need to know this because we can pick up our dropped flag (and return it) - // but we can't pick up our flag at base - if (ps->persistant[PERS_TEAM] == TEAM_HUMANS) { - //TA: remove powerups - /*if (item->giTag == PW_BLUEFLAG || - (item->giTag == PW_REDFLAG && ent->modelindex2) || - (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG])) - return qtrue;*/ - } else if (ps->persistant[PERS_TEAM] == TEAM_DROIDS) { - /*if (item->giTag == PW_REDFLAG || - (item->giTag == PW_BLUEFLAG && ent->modelindex2) || - (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG])) - return qtrue;*/ - } - return qfalse; - - //TA: not using the q3 holdable items code - /*case IT_HOLDABLE: - // can only hold one item at a time - if ( ps->stats[STAT_HOLDABLE_ITEM] ) { - return qfalse; - } - return qtrue;*/ - - case IT_BAD: - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" ); - } - - return qfalse; -} - -//====================================================================== - -/* -================ -BG_EvaluateTrajectory - -================ -*/ -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) { - float deltaTime; - float phase; - - switch( tr->trType ) { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorCopy( tr->trBase, result ); - break; - case TR_LINEAR: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = sin( deltaTime * M_PI * 2 ); - VectorMA( tr->trBase, phase, tr->trDelta, result ); - break; - case TR_LINEAR_STOP: - if ( atTime > tr->trTime + tr->trDuration ) { - atTime = tr->trTime + tr->trDuration; - } - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - if ( deltaTime < 0 ) { - deltaTime = 0; - } - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... - break; - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime ); - break; - } -} - -/* -================ -BG_EvaluateTrajectoryDelta - -For determining velocity at a given time -================ -*/ -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) { - float deltaTime; - float phase; - - switch( tr->trType ) { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorClear( result ); - break; - case TR_LINEAR: - VectorCopy( tr->trDelta, result ); - break; - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos - phase *= 0.5; - VectorScale( tr->trDelta, phase, result ); - break; - case TR_LINEAR_STOP: - if ( atTime > tr->trTime + tr->trDuration ) { - VectorClear( result ); - return; - } - VectorCopy( tr->trDelta, result ); - break; - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorCopy( tr->trDelta, result ); - result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... - break; - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime ); - break; - } -} - -char *eventnames[] = { - "EV_NONE", - - "EV_FOOTSTEP", - "EV_FOOTSTEP_METAL", - "EV_FOOTSPLASH", - "EV_FOOTWADE", - "EV_SWIM", - - "EV_STEP_4", - "EV_STEP_8", - "EV_STEP_12", - "EV_STEP_16", - - "EV_FALL_SHORT", - "EV_FALL_MEDIUM", - "EV_FALL_FAR", - - "EV_JUMP_PAD", // boing sound at origin", jump sound on player - - "EV_JUMP", - "EV_WATER_TOUCH", // foot touches - "EV_WATER_LEAVE", // foot leaves - "EV_WATER_UNDER", // head touches - "EV_WATER_CLEAR", // head leaves - - "EV_ITEM_PICKUP", // normal item pickups are predictable - "EV_GLOBAL_ITEM_PICKUP", // powerup / team sounds are broadcast to everyone - - "EV_NOAMMO", - "EV_CHANGE_WEAPON", - "EV_FIRE_WEAPON", - - "EV_USE_ITEM0", - "EV_USE_ITEM1", - "EV_USE_ITEM2", - "EV_USE_ITEM3", - "EV_USE_ITEM4", - "EV_USE_ITEM5", - "EV_USE_ITEM6", - "EV_USE_ITEM7", - "EV_USE_ITEM8", - "EV_USE_ITEM9", - "EV_USE_ITEM10", - "EV_USE_ITEM11", - "EV_USE_ITEM12", - "EV_USE_ITEM13", - "EV_USE_ITEM14", - "EV_USE_ITEM15", - - "EV_ITEM_RESPAWN", - "EV_ITEM_POP", - "EV_PLAYER_TELEPORT_IN", - "EV_PLAYER_TELEPORT_OUT", - - "EV_GRENADE_BOUNCE", // eventParm will be the soundindex - - "EV_GENERAL_SOUND", - "EV_GLOBAL_SOUND", // no attenuation - "EV_GLOBAL_TEAM_SOUND", - - "EV_BULLET_HIT_FLESH", - "EV_BULLET_HIT_WALL", - - "EV_MISSILE_HIT", - "EV_MISSILE_MISS", - "EV_MISSILE_MISS_METAL", - "EV_RAILTRAIL", - "EV_SHOTGUN", - "EV_BULLET", // otherEntity is the shooter - - "EV_PAIN", - "EV_DEATH1", - "EV_DEATH2", - "EV_DEATH3", - "EV_OBITUARY", - - "EV_POWERUP_QUAD", - "EV_POWERUP_BATTLESUIT", - "EV_POWERUP_REGEN", - - "EV_GIB_PLAYER", // gib a previously living player - "EV_SCOREPLUM", // score plum - -//#ifdef MISSIONPACK - "EV_PROXIMITY_MINE_STICK", - "EV_PROXIMITY_MINE_TRIGGER", - "EV_KAMIKAZE", // kamikaze explodes - "EV_OBELISKEXPLODE", // obelisk explodes - "EV_INVUL_IMPACT", // invulnerability sphere impact - "EV_JUICED", // invulnerability juiced effect - "EV_LIGHTNINGBOLT", // lightning bolt bounced of invulnerability sphere -//#endif - - "EV_DEBUG_LINE", - "EV_STOPLOOPINGSOUND", - "EV_TAUNT" - -}; - -/* -=============== -BG_AddPredictableEventToPlayerstate - -Handles the sequence numbers -=============== -*/ - -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) { -#ifdef _DEBUG - { - char buf[256]; - trap_Cvar_VariableStringBuffer("showevents", buf, sizeof(buf)); - if ( atof(buf) != 0 ) { -#ifdef QAGAME - Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#else - Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#endif - } - } -#endif - ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent; - ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm; - ps->eventSequence++; -} - - -/* -======================== -BG_TouchJumpPad -======================== -*/ -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) { - vec3_t angles; - float p; - int effectNum; - - // spectators don't use jump pads - if ( ps->pm_type != PM_NORMAL ) { - return; - } - - // flying characters don't hit bounce pads - if ( ps->powerups[PW_FLIGHT] ) { - return; - } - - // if we didn't hit this same jumppad the previous frame - // then don't play the event sound again if we are in a fat trigger - if ( ps->jumppad_ent != jumppad->number ) { - - vectoangles( jumppad->origin2, angles); - p = fabs( AngleNormalize180( angles[PITCH] ) ); - if( p < 45 ) { - effectNum = 0; - } else { - effectNum = 1; - } - BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps ); - } - // remember hitting this jumppad this frame - ps->jumppad_ent = jumppad->number; - ps->jumppad_frame = ps->pmove_framecount; - // give the player the velocity from the jumppad - VectorCopy( jumppad->origin2, ps->velocity ); -} - - -/* -======================== -BG_PlayerStateToEntityState - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) { - int i; - vec3_t ceilingNormal = { 0, 0, -1 }; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; - } - - s->number = ps->clientNum; - - s->pos.trType = TR_INTERPOLATE; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - //set the trDelta for flag direction - VectorCopy( ps->velocity, s->pos.trDelta ); - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - //TA: i need for other things :) - //s->angles2[YAW] = ps->movementDir; - s->time2 = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - } - seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - if ( ps->entityEventSequence < ps->eventSequence ) { - ps->entityEventSequence++; - } - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - /*s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; - } - }*/ - - //TA: use powerups field to store team/class info: - s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 ); - - //TA: have to get the surfNormal thru somehow... - if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - VectorCopy( ceilingNormal, s->angles2 ); - } - else - { - VectorCopy( ps->grapplePoint, s->angles2 ); - } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; -} - - -/* -======================== -BG_PlayerStateToEntityStateExtraPolate - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) { - int i; - vec3_t ceilingNormal = { 0, 0, -1 }; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; - } - - s->number = ps->clientNum; - - s->pos.trType = TR_LINEAR_STOP; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - // set the trDelta for flag direction and linear prediction - VectorCopy( ps->velocity, s->pos.trDelta ); - // set the time for linear prediction - s->pos.trTime = time; - // set maximum extra polation time - s->pos.trDuration = 50; // 1000 / sv_fps (default = 20) - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - //TA: i need for other things :) - //s->angles2[YAW] = ps->movementDir; - s->time2 = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - } - seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - if ( ps->entityEventSequence < ps->eventSequence ) { - ps->entityEventSequence++; - } - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - /*s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; - } - }*/ - - //TA: use powerups field to store team/class info: - s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 ); - - //TA: have to get the surfNormal thru somehow... - if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - VectorCopy( ceilingNormal, s->angles2 ); - } - else - { - VectorCopy( ps->grapplePoint, s->angles2 ); - } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; -} - - -//TA: extract the ammo quantity from the array -void BG_unpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ) -{ - int ammoarray[32]; - int i; - - for( i = 0; i <= 15; i++ ) - ammoarray[ i ] = ammo[ i ]; - - for( i = 16; i <= 31; i++ ) - ammoarray[ i ] = ammo2[ i - 16 ]; - - if( quan != NULL ) - *quan = ammoarray[ weapon ] & 0x03FF; - - if( clips != NULL ) - *clips = ( ammoarray[ weapon ] >> 10 ) & 0x07; - - if( maxclips != NULL ) - *maxclips = ( ammoarray[ weapon ] >> 13 ) & 0x07; -} - -//TA: pack the ammo quantity into the array -void BG_packAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ) -{ - int weaponvalue; - - weaponvalue = quan | ( clips << 10 ) | ( maxclips << 13 ); - - if( weapon <= 15 ) - ammo[ weapon ] = weaponvalue; - else if( weapon >= 16 ) - ammo2[ weapon - 16 ] = weaponvalue; -} - -//TA: check whether infinite ammo -qboolean BG_infiniteAmmo( int weapon ) -{ - switch( weapon ) - { - case WP_VENOM: - case WP_ABUILD: - case WP_HBUILD: - case WP_SCANNER: - return qtrue; - break; - - //nothing else has infinite ammo - default: - return qfalse; - break; - } -} - -//TA: pack weapons into the array -void BG_packWeapon( int weapon, int stats[ ] ) -{ - int weaponList, i; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - weaponList |= ( 1 << weapon ); - - stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF; - stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16; - -} - -//TA: check whether array contains weapon -qboolean BG_gotWeapon( int weapon, int stats[ ] ) -{ - int weaponList, i; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - return( weaponList & ( 1 << weapon ) ); -} - -//TA: pack items into array -void BG_packItem( int item, int stats[ ] ) -{ - stats[ STAT_ITEMS ] |= ( 1 << item ); -} - -//TA: remove items from array -void BG_removeItem( int item, int stats[ ] ) -{ - stats[ STAT_ITEMS ] &= ~( 1 << item ); -} - -//TA: check if item is in array -qboolean BG_gotItem( int item, int stats[ ] ) -{ - return( stats[ STAT_ITEMS ] & ( 1 << item ) ); -} - -//TA: set item active in array -void BG_activateItem( int item, int stats[ ] ) -{ - stats[ STAT_ACTIVEITEMS ] |= ( 1 << item ); -} - -//TA: set item deactive in array -void BG_deactivateItem( int item, int stats[ ] ) -{ - stats[ STAT_ACTIVEITEMS ] &= ~( 1 << item ); -} - -//TA: check if item active in array -qboolean BG_activated( int item, int stats[ ] ) -{ - return( stats[ STAT_ACTIVEITEMS ] & ( 1 << item ) ); -} - -//TA: set attributes in array -void BG_packAttributes( int fov, int bob, int steptime, int stats[ ] ) -{ - stats[ STAT_ATTRIBS ] = ( ( (int)( (float)fov/10.0 ) & 0x1F ) << 10 ) | ( ( bob & 0x1F ) << 5 ) | ( (int)( (float)steptime/25.0 ) & 0x1F ); -} - -//TA: get attributes from array -void BG_unpackAttributes( int *fov, int *bob, int *steptime, int stats[ ] ) -{ - if( fov != NULL ) - *fov = ( ( stats[ STAT_ATTRIBS ] >> 10 ) & 0x1F ) * 10; - - if( bob != NULL ) - *bob = ( stats[ STAT_ATTRIBS ] >> 5 ) & 0x1F; - - if( steptime != NULL ) - *steptime = ( stats[ STAT_ATTRIBS ] & 0x1F ) * 25; -} diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c deleted file mode 100644 index e7be5798..00000000 --- a/src/game/bg_pmove.c +++ /dev/null @@ -1,2818 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_pmove.c -- both games player movement code -// takes a playerstate and a usercmd as input and returns a modifed playerstate - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" -#include "bg_public.h" -#include "bg_local.h" - -pmove_t *pm; -pml_t pml; - -//TA: wall climbing struct for EVERY client. Not c/s communicated so -// size isn't that important -wcl_t wcl[ MAX_CLIENTS ]; - -// movement parameters -float pm_stopspeed = 100.0f; -float pm_duckScale = 0.25f; -float pm_swimScale = 0.50f; -float pm_wadeScale = 0.70f; - -float pm_accelerate = 10.0f; -float pm_airaccelerate = 1.0f; -float pm_wateraccelerate = 4.0f; -float pm_flyaccelerate = 8.0f; - -float pm_friction = 6.0f; -float pm_waterfriction = 1.0f; -float pm_flightfriction = 3.0f; -float pm_spectatorfriction = 5.0f; - -int c_pmove = 0; - -/* -================ -PM_AddSmoothOp - -Add a smoothing operation to the smoothing queue -================ -*/ -static void PM_AddSmoothOp( vec3_t rotAxis, float rotAngle ) -{ - int i; - - //hack to prevent multiple identical rotations being added to the queue - //this happens often because groundtrace is called twice a frame - for( i = 0; i < MAXSMOOTHS; i++ ) - { - if( wcl[ pm->ps->clientNum ].sList[ i ].time >= pm->cmd.serverTime-100 ) - return; - - /*if( VectorCompare( sList[ i ].rotAxis, rotAxis ) ) - return;*/ - - } - - //iterate through smoothing array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //if a smooth has been performed it can be overwritten - if( wcl[ pm->ps->clientNum ].sList[ i ].time + SMOOTHTIME < pm->cmd.serverTime ) - { - //copy the new smooth into the array and stop - VectorCopy( rotAxis, wcl[ pm->ps->clientNum ].sList[ i ].rotAxis ); - wcl[ pm->ps->clientNum ].sList[ i ].rotAngle = rotAngle; - wcl[ pm->ps->clientNum ].sList[ i ].time = pm->cmd.serverTime; - return; - } - } - - //there are no free smooth slots -} - - -/* -================ -PM_PerformSmoothOps - -Perform all the smoothing operations in the smoothing queue -================ -*/ -static qboolean PM_PerformSmoothOps( vec3_t in[3], vec3_t out[3] ) -{ - int i; - float stLocal, sFraction; - vec3_t localIn[3], localOut[3]; - qboolean performed = qfalse; - - AxisCopy( in, localIn ); - - //iterate through smoothing array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //perform smooth - if( ( pm->cmd.serverTime < wcl[ pm->ps->clientNum ].sList[ i ].time + SMOOTHTIME ) && - ( VectorLength( wcl[ pm->ps->clientNum ].sList[ i ].rotAxis ) != 0 ) ) - { - //the rotAxis /should/ never be of zero length but q3 *will* crash if it is... - //better to be safe than sorry :) - - stLocal = 1.0 - ( ( ( wcl[ pm->ps->clientNum ].sList[ i ].time + SMOOTHTIME ) - pm->cmd.serverTime ) / SMOOTHTIME ); - - //some ppl might prefer this smoothing function: - //sFraction = -( 1.0 - sin( stLocal * M_PI / 2 ) ); - sFraction = -( cos( stLocal * M_PI ) + 1 ) / 2; - - RotatePointAroundVector( localOut[0], wcl[ pm->ps->clientNum ].sList[ i ].rotAxis, localIn[0], sFraction * wcl[ pm->ps->clientNum ].sList[ i ].rotAngle ); - RotatePointAroundVector( localOut[1], wcl[ pm->ps->clientNum ].sList[ i ].rotAxis, localIn[1], sFraction * wcl[ pm->ps->clientNum ].sList[ i ].rotAngle ); - RotatePointAroundVector( localOut[2], wcl[ pm->ps->clientNum ].sList[ i ].rotAxis, localIn[2], sFraction * wcl[ pm->ps->clientNum ].sList[ i ].rotAngle ); - - AxisCopy( localOut, localIn ); - performed = qtrue; - } - } - - AxisCopy( localOut, out ); - - return performed; -} - - -/* -=============== -PM_AddEvent - -=============== -*/ -void PM_AddEvent( int newEvent ) { - BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps ); -} - -/* -=============== -PM_AddTouchEnt -=============== -*/ -void PM_AddTouchEnt( int entityNum ) { - int i; - - if ( entityNum == ENTITYNUM_WORLD ) { - return; - } - if ( pm->numtouch == MAXTOUCH ) { - return; - } - - // see if it is already added - for ( i = 0 ; i < pm->numtouch ; i++ ) { - if ( pm->touchents[ i ] == entityNum ) { - return; - } - } - - // add it - pm->touchents[pm->numtouch] = entityNum; - pm->numtouch++; -} - -/* -=================== -PM_StartTorsoAnim -=================== -*/ -static void PM_StartTorsoAnim( int anim ) { - if ( pm->ps->pm_type >= PM_DEAD ) { - return; - } - pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) - | anim; -} -static void PM_StartLegsAnim( int anim ) { - if ( pm->ps->pm_type >= PM_DEAD ) { - return; - } - if ( pm->ps->legsTimer > 0 ) { - return; // a high priority animation is running - } - pm->ps->legsAnim = ( ( pm->ps->legsAnim & ( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) ^ ANIM_TOGGLEBIT ) - | anim; -} - -static void PM_ContinueLegsAnim( int anim ) { - if ( ( pm->ps->legsAnim & ~( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) == anim ) { - return; - } - if ( pm->ps->legsTimer > 0 ) { - return; // a high priority animation is running - } - PM_StartLegsAnim( anim ); -} - -static void PM_ContinueTorsoAnim( int anim ) { - if ( ( pm->ps->torsoAnim & ~( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) == anim ) { - return; - } - if ( pm->ps->torsoTimer > 0 ) { - return; // a high priority animation is running - } - PM_StartTorsoAnim( anim ); -} - -static void PM_ForceLegsAnim( int anim ) { - pm->ps->legsTimer = 0; - PM_StartLegsAnim( anim ); -} - - -/* -================== -PM_ClipVelocity - -Slide off of the impacting surface -================== -*/ -void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) { - float backoff; - float change; - int i; - - backoff = DotProduct (in, normal); - - if ( backoff < 0 ) { - backoff *= overbounce; - } else { - backoff /= overbounce; - } - - for ( i=0 ; i<3 ; i++ ) { - change = normal[i]*backoff; - out[i] = in[i] - change; - } -} - - -/* -================== -PM_Friction - -Handles both ground friction and water friction -================== -*/ -static void PM_Friction( void ) { - vec3_t vec; - float *vel; - float speed, newspeed, control; - float drop; - - vel = pm->ps->velocity; - - //TA: make sure vertical velocity is NOT set to zero when wall climbing - VectorCopy( vel, vec ); - if ( pml.walking && - pm->ps->stats[ STAT_STATE ] & ~SS_WALLCLIMBING ) { - vec[2] = 0; // ignore slope movement - } - - speed = VectorLength(vec); - if (speed < 1) { - vel[0] = 0; - vel[1] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - return; - } - - drop = 0; - - // apply ground friction - if ( pm->waterlevel <= 1 ) { - if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) { - // if getting knocked back, no friction - if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) { - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control*pm_friction*pml.frametime; - } - } - } - - // apply water friction even if just wading - if ( pm->waterlevel ) { - drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; - } - - // apply flying friction - if ( pm->ps->pm_type == PM_SPECTATOR ) { - drop += speed*pm_spectatorfriction*pml.frametime; - } - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) { - newspeed = 0; - } - newspeed /= speed; - - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; -} - - -/* -============== -PM_Accelerate - -Handles user intended acceleration -============== -*/ -static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { -#if 1 - // q2 style - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct (pm->ps->velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) { - return; - } - accelspeed = accel*pml.frametime*wishspeed; - if (accelspeed > addspeed) { - accelspeed = addspeed; - } - - for (i=0 ; i<3 ; i++) { - pm->ps->velocity[i] += accelspeed*wishdir[i]; - } -#else - // proper way (avoids strafe jump maxspeed bug), but feels bad - vec3_t wishVelocity; - vec3_t pushDir; - float pushLen; - float canPush; - - VectorScale( wishdir, wishspeed, wishVelocity ); - VectorSubtract( wishVelocity, pm->ps->velocity, pushDir ); - pushLen = VectorNormalize( pushDir ); - - canPush = accel*pml.frametime*wishspeed; - if (canPush > pushLen) { - canPush = pushLen; - } - - VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity ); -#endif -} - - - -/* -============ -PM_CmdScale - -Returns the scale factor to apply to cmd movements -This allows the clients to use axial -127 to 127 values for all directions -without getting a sqrt(2) distortion in speed. -============ -*/ -static float PM_CmdScale( usercmd_t *cmd ) { - int max; - float total; - float scale; - float modifier = 1.0; - static int time; - int dTime; - int aForward, aRight; - - dTime = pm->cmd.serverTime - time; - time = pm->cmd.serverTime; - - if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( !( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST ) ) - { - //if not sprinting - modifier *= 0.8; - } - else - { - //subtract stamina - pm->ps->stats[ STAT_STAMINA ] -= (dTime/4); - } - - aForward = abs( cmd->forwardmove ); - aRight = abs( cmd->rightmove ); - - if( ( aForward <= 64 && aForward > 5 ) && ( aRight <= 64 && aRight > 5 ) ) - { - //restore stamina - pm->ps->stats[ STAT_STAMINA ] += (dTime/5); - } - else if( aForward <= 5 && aRight <= 5 ) - { - //restore stamina faster - pm->ps->stats[ STAT_STAMINA ] += (dTime/4); - } - - if( cmd->forwardmove < 0 ) - { - //can't run backwards - modifier *= 0.5; - } - else if( cmd->rightmove ) - { - //can't move that fast sideways - modifier *= 0.75; - } - - //cap stamina - if( pm->ps->stats[ STAT_STAMINA ] > 1000 ) - pm->ps->stats[ STAT_STAMINA ] = 1000; - if( pm->ps->stats[ STAT_STAMINA ] < -1000 ) - pm->ps->stats[ STAT_STAMINA ] = -1000; - - //if not trying to run then not trying to sprint - if( abs( cmd->forwardmove ) <= 64 ) - pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; - - //must have +ve stamina to jump - if( pm->ps->stats[ STAT_STAMINA ] < 0 ) - cmd->upmove = 0; - - //slow down once stamina depletes - if( pm->ps->stats[ STAT_STAMINA ] <= -500 ) - modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + 1000 ) / 500.0f; - } - - if( !( pm->ps->stats[ STAT_ABILITIES ] & SCA_CANJUMP ) ) - cmd->upmove = 0; - - max = abs( cmd->forwardmove ); - if ( abs( cmd->rightmove ) > max ) { - max = abs( cmd->rightmove ); - } - if ( abs( cmd->upmove ) > max ) { - max = abs( cmd->upmove ); - } - if ( !max ) { - return 0; - } - - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - { - total = sqrt( cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove ); - } - else - { - total = sqrt( cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove ); - } - scale = (float)pm->ps->speed * max / ( 127.0 * total ) * modifier; - - return scale; -} - - -/* -================ -PM_SetMovementDir - -Determine the rotation of the legs reletive -to the facing dir -================ -*/ -static void PM_SetMovementDir( void ) { - if ( pm->cmd.forwardmove || pm->cmd.rightmove ) { - if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 0; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 1; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) { - pm->ps->movementDir = 2; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 3; - } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 4; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 5; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) { - pm->ps->movementDir = 6; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 7; - } - } else { - // if they aren't actively going directly sideways, - // change the animation to the diagonal so they - // don't stop too crooked - if ( pm->ps->movementDir == 2 ) { - pm->ps->movementDir = 1; - } else if ( pm->ps->movementDir == 6 ) { - pm->ps->movementDir = 7; - } - } -} - - -/* -============= -PM_CheckJump -============= -*/ -static qboolean PM_CheckJump( void ) { - if( !( pm->ps->stats[ STAT_ABILITIES ] & SCA_CANJUMP ) ) return qfalse; - - if( ( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) && - ( pm->ps->stats[ STAT_STAMINA ] < 0 ) ) - return qfalse; - - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { - return qfalse; // don't allow jump until all buttons are up - } - - if ( pm->cmd.upmove < 10 ) { - // not holding jump - return qfalse; - } - - // must wait for jump to be released - if ( pm->ps->pm_flags & PMF_JUMP_HELD ) { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return qfalse; - } - - pml.groundPlane = qfalse; // jumping away - pml.walking = qfalse; - pm->ps->pm_flags |= PMF_JUMP_HELD; - - //TA: take some stamina off - if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) - pm->ps->stats[ STAT_STAMINA ] -= 500; - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps->velocity[2] = JUMP_VELOCITY; - PM_AddEvent( EV_JUMP ); - - if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - return qtrue; -} - -/* -============= -PM_CheckWaterJump -============= -*/ -static qboolean PM_CheckWaterJump( void ) { - vec3_t spot; - int cont; - vec3_t flatforward; - - if (pm->ps->pm_time) { - return qfalse; - } - - // check for water jump - if ( pm->waterlevel != 2 ) { - return qfalse; - } - - flatforward[0] = pml.forward[0]; - flatforward[1] = pml.forward[1]; - flatforward[2] = 0; - VectorNormalize (flatforward); - - VectorMA (pm->ps->origin, 30, flatforward, spot); - spot[2] += 4; - cont = pm->pointcontents (spot, pm->ps->clientNum ); - if ( !(cont & CONTENTS_SOLID) ) { - return qfalse; - } - - spot[2] += 16; - cont = pm->pointcontents (spot, pm->ps->clientNum ); - if ( cont ) { - return qfalse; - } - - // jump out of water - VectorScale (pml.forward, 200, pm->ps->velocity); - pm->ps->velocity[2] = 350; - - pm->ps->pm_flags |= PMF_TIME_WATERJUMP; - pm->ps->pm_time = 2000; - - return qtrue; -} - -//============================================================================ - - -/* -=================== -PM_WaterJumpMove - -Flying out of the water -=================== -*/ -static void PM_WaterJumpMove( void ) { - // waterjump has no control, but falls - - PM_StepSlideMove( qtrue ); - - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - if (pm->ps->velocity[2] < 0) { - // cancel as soon as we are falling down again - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } -} - -/* -=================== -PM_WaterMove - -=================== -*/ -static void PM_WaterMove( void ) { - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - float vel; - - if ( PM_CheckWaterJump() ) { - PM_WaterJumpMove(); - return; - } -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) { - wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom - } else { - for (i=0 ; i<3 ; i++) - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - - wishvel[2] += scale * pm->cmd.upmove; - } - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - if ( wishspeed > pm->ps->speed * pm_swimScale ) { - wishspeed = pm->ps->speed * pm_swimScale; - } - - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - - // make sure we can go up slopes easily under water - if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) { - vel = VectorLength(pm->ps->velocity); - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - } - - PM_SlideMove( qfalse ); -} - - - -/* -=================== -PM_FlyMove - -Only with the flight powerup -=================== -*/ -static void PM_FlyMove( void ) { - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - - // normal slowdown - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) { - wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = 0; - } else { - for (i=0 ; i<3 ; i++) { - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - } - - wishvel[2] += scale * pm->cmd.upmove; - } - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); - - PM_StepSlideMove( qfalse ); -} - - -/* -=================== -PM_AirMove - -=================== -*/ -static void PM_AirMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - - PM_Friction(); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir(); - - // project moves down to flat plane - pml.forward[2] = 0; - pml.right[2] = 0; - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - - for ( i = 0 ; i < 2 ; i++ ) { - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; - } - wishvel[2] = 0; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( pml.groundPlane ) { - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - } - -#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif - - PM_StepSlideMove ( qtrue ); -} - -/* -=================== -PM_GrappleMove - -=================== -*/ -static void PM_GrappleMove( void ) { - vec3_t vel, v; - float vlen; - - VectorScale(pml.forward, -16, v); - VectorAdd(pm->ps->grapplePoint, v, v); - VectorSubtract(v, pm->ps->origin, vel); - vlen = VectorLength(vel); - VectorNormalize( vel ); - - if (vlen <= 100) - VectorScale(vel, 10 * vlen, vel); - else - VectorScale(vel, 800, vel); - - VectorCopy(vel, pm->ps->velocity); - - pml.groundPlane = qfalse; -} - - -/* -=================== -PM_ClimbMove - -=================== -*/ -static void PM_ClimbMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - float accelerate; - float vel; - - if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) { - // begin swimming - PM_WaterMove(); - return; - } - - - if ( PM_CheckJump () ) { - // jumped away - if ( pm->waterlevel > 1 ) { - PM_WaterMove(); - } else { - PM_AirMove(); - } - return; - } - - PM_Friction (); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir(); - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); - // - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - - for ( i = 0 ; i < 3 ; i++ ) { - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; - } - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // clamp the speed lower if ducking - if ( pm->ps->pm_flags & PMF_DUCKED ) { - if ( wishspeed > pm->ps->speed * pm_duckScale ) { - wishspeed = pm->ps->speed * pm_duckScale; - } - } - - // clamp the speed lower if wading or walking on the bottom - if ( pm->waterlevel ) { - float waterScale; - - waterScale = pm->waterlevel / 3.0; - waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps->speed * waterScale ) { - wishspeed = pm->ps->speed * waterScale; - } - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - accelerate = pm_airaccelerate; - } else { - accelerate = pm_accelerate; - } - - PM_Accelerate (wishdir, wishspeed, accelerate); - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - } else { - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - } - - vel = VectorLength(pm->ps->velocity); - - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - - // don't do anything if standing still - if (!pm->ps->velocity[0] && !pm->ps->velocity[1] && !pm->ps->velocity[2]) { - return; - } - - PM_StepSlideMove( qfalse ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - -} - - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - float accelerate; - float vel; - - if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) { - // begin swimming - PM_WaterMove(); - return; - } - - - if ( PM_CheckJump () ) { - // jumped away - if ( pm->waterlevel > 1 ) { - PM_WaterMove(); - } else { - PM_AirMove(); - } - return; - } - - PM_Friction (); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir(); - - // project moves down to flat plane - pml.forward[2] = 0; - pml.right[2] = 0; - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); - // - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - - for ( i = 0 ; i < 3 ; i++ ) { - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; - } - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // clamp the speed lower if ducking - if ( pm->ps->pm_flags & PMF_DUCKED ) { - if ( wishspeed > pm->ps->speed * pm_duckScale ) { - wishspeed = pm->ps->speed * pm_duckScale; - } - } - - // clamp the speed lower if wading or walking on the bottom - if ( pm->waterlevel ) { - float waterScale; - - waterScale = pm->waterlevel / 3.0; - waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps->speed * waterScale ) { - wishspeed = pm->ps->speed * waterScale; - } - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - accelerate = pm_airaccelerate; - } else { - accelerate = pm_accelerate; - } - - PM_Accelerate (wishdir, wishspeed, accelerate); - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - } else { - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - } - - vel = VectorLength(pm->ps->velocity); - - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - - // don't do anything if standing still - if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) { - return; - } - - PM_StepSlideMove( qfalse ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - -} - - -/* -============== -PM_DeadMove -============== -*/ -static void PM_DeadMove( void ) { - float forward; - - if ( !pml.walking ) { - return; - } - - // extra friction - - forward = VectorLength (pm->ps->velocity); - forward -= 20; - if ( forward <= 0 ) { - VectorClear (pm->ps->velocity); - } else { - VectorNormalize (pm->ps->velocity); - VectorScale (pm->ps->velocity, forward, pm->ps->velocity); - } -} - - -/* -=============== -PM_NoclipMove -=============== -*/ -static void PM_NoclipMove( void ) { - float speed, drop, friction, control, newspeed; - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - - pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - speed = VectorLength (pm->ps->velocity); - if (speed < 1) - { - VectorCopy (vec3_origin, pm->ps->velocity); - } - else - { - drop = 0; - - friction = pm_friction*1.5; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control*friction*pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity); - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - for (i=0 ; i<3 ; i++) - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; - wishvel[2] += pm->cmd.upmove; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); -} - -//============================================================================ - -/* -================ -PM_FootstepForSurface - -Returns an event number apropriate for the groundsurface -================ -*/ -static int PM_FootstepForSurface( void ) -{ - //TA: - if ( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED ) - return EV_FOOTSTEP_SQUELCH; - - if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) - return 0; - - if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) - return EV_FOOTSTEP_METAL; - - return EV_FOOTSTEP; -} - - -/* -================= -PM_CrashLand - -Check for hard landings that generate sound events -================= -*/ -static void PM_CrashLand( void ) { - float delta; - float dist; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) { - PM_ForceLegsAnim( LEGS_LANDB ); - } else { - PM_ForceLegsAnim( LEGS_LAND ); - } - - pm->ps->legsTimer = TIMER_LAND; - - // calculate the exact velocity on landing - dist = pm->ps->origin[2] - pml.previous_origin[2]; - vel = pml.previous_velocity[2]; - acc = -pm->ps->gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if ( den < 0 ) { - return; - } - t = (-b - sqrt( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta*delta * 0.0001; - - // ducking while falling doubles damage - if ( pm->ps->pm_flags & PMF_DUCKED ) { - delta *= 2; - } - - // never take falling damage if completely underwater - if ( pm->waterlevel == 3 ) { - return; - } - - // reduce falling damage if there is standing water - if ( pm->waterlevel == 2 ) { - delta *= 0.25; - } - if ( pm->waterlevel == 1 ) { - delta *= 0.5; - } - - if ( delta < 1 ) { - return; - } - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) { - if ( delta > 60 ) { - PM_AddEvent( EV_FALL_FAR ); - } else if ( delta > 40 ) { - // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) { - PM_AddEvent( EV_FALL_MEDIUM ); - } - } else if ( delta > 7 ) { - PM_AddEvent( EV_FALL_SHORT ); - } else { - PM_AddEvent( PM_FootstepForSurface() ); - } - } - - // start footstep cycle over - pm->ps->bobCycle = 0; -} - - -/* -============= -PM_CorrectAllSolid -============= -*/ -static int PM_CorrectAllSolid( trace_t *trace ) { - int i, j, k; - vec3_t point; - - if ( pm->debugLevel ) { - Com_Printf("%i:allsolid\n", c_pmove); - } - - // jitter around - for (i = -1; i <= 1; i++) { - for (j = -1; j <= 1; j++) { - for (k = -1; k <= 1; k++) { - VectorCopy(pm->ps->origin, point); - point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k; - pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - if ( !trace->allsolid ) { - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25; - - pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - pml.groundTrace = *trace; - return qtrue; - } - } - } - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; - - return qfalse; -} - - -/* -============= -PM_GroundTraceMissed - -The ground trace didn't hit a surface, so we are in freefall -============= -*/ -static void PM_GroundTraceMissed( void ) { - trace_t trace; - vec3_t point; - - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) { - // we just transitioned into freefall - if ( pm->debugLevel ) { - Com_Printf("%i:lift\n", c_pmove); - } - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - VectorCopy( pm->ps->origin, point ); - point[2] -= 64; - - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - if ( trace.fraction == 1.0 ) { - if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - } - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; -} - - -/* -============= -PM_GroundClimbTrace -============= -*/ -static void PM_GroundClimbTrace( void ) -{ - vec3_t surfNormal, movedir, forward, right, point, srotAxis; - vec3_t refNormal = { 0, 0, 1 }; - vec3_t ceilingNormal = { 0, 0, -1 }; - float toAngles[3], surfAngles[3], srotAngle; - trace_t trace; - int i; - qboolean smoothed = qtrue; - - //TA: If we're on the ceiling then grapplePoint is a rotation normal.. otherwise its a surface normal. - // would have been nice if Carmack had left a few random variables in the ps struct for mod makers - if( pm->ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - VectorCopy( ceilingNormal, surfNormal ); - else - VectorCopy( pm->ps->grapplePoint, surfNormal ); - - //construct a vector which reflects the direction the player is looking wrt the surface normal - AngleVectors( wcl[ pm->ps->clientNum ].nonSvangles, forward, NULL, NULL ); - CrossProduct( forward, surfNormal, right ); - VectorNormalize( right ); - CrossProduct( surfNormal, right, movedir ); - VectorNormalize( movedir ); - - //rotate this direction vector based upon what direction the player is /trying/ to move to - /*if( pm->cmd.forwardmove || pm->cmd.rightmove ) - { - if( ( pm->cmd.rightmove < 0 ) && ( pm->cmd.forwardmove > 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 45 ); - else if( ( pm->cmd.rightmove < 0 ) && ( pm->cmd.forwardmove == 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 90 ); - else if( ( pm->cmd.rightmove < 0 ) && ( pm->cmd.forwardmove < 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 135 ); - else if( ( pm->cmd.rightmove == 0 ) && ( pm->cmd.forwardmove < 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 180 ); - else if( ( pm->cmd.rightmove > 0 ) && ( pm->cmd.forwardmove < 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, -135 ); - else if( ( pm->cmd.rightmove > 0 ) && ( pm->cmd.forwardmove == 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, -90 ); - else if( ( pm->cmd.rightmove > 0 ) && ( pm->cmd.forwardmove > 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, -45 ); - }*/ - - //TA: 3am, code make no sense, but code work... leave it be... - if( pm->cmd.forwardmove < 0 ) - VectorInverse( movedir ); - //RotatePointAroundVector( movedir, surfNormal, movedir, 180 ); - - for(i = 0; i <= 3; i++) - { - - switch ( i ) - { - case 0: - //trace into direction we are moving - VectorMA( pm->ps->origin, 0.25, movedir, point ); - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - break; - - case 1: - //trace straight down anto "ground" surface - VectorMA( pm->ps->origin, -0.25, surfNormal, point ); - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - break; - - case 2: - //trace "underneath" BBOX so we can traverse angles > 180deg - //TA: I can't believe this actually works :0 - its gotta be messing with something - // I would like a better way if one exists... - if( pml.groundPlane != qfalse ) - { - VectorMA( pm->ps->origin, -16, surfNormal, point ); - VectorMA( point, -16, movedir, point ); - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - } - break; - - case 3: - //fall back so we don't have to modify PM_GroundTrace too much - VectorCopy( pm->ps->origin, point ); - point[2] = pm->ps->origin[2] - 0.25; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - break; - } - - //experimental: slow down speed around transitions - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLTRANSIDING; - - //if we hit something - if( trace.fraction < 1.0 && !( trace.surfaceFlags & ( SURF_SKY | SURF_NOIMPACT ) ) && !( trace.entityNum != 1022 && i != 3 ) ) - { - if( i == 2 ) - VectorCopy( trace.endpos, pm->ps->origin ); - - //if the trace result and old surface normal are different then we must have transided to a new - //surface... do some stuff... - if( !VectorCompare( trace.plane.normal, surfNormal ) ) - { - //experimental: slow down speed around transitions - pm->ps->stats[ STAT_STATE ] |= SS_WALLTRANSIDING; - - //if the trace result or the old vector is not the floor or ceiling correct the YAW angle - if( !VectorCompare( trace.plane.normal, refNormal ) && !VectorCompare( surfNormal, refNormal ) && - !VectorCompare( trace.plane.normal, ceilingNormal ) && !VectorCompare( surfNormal, ceilingNormal ) ) - { - vectoangles( trace.plane.normal, toAngles ); - vectoangles( surfNormal, surfAngles ); - - pm->ps->delta_angles[1] -= ANGLE2SHORT( surfAngles[1] - toAngles[1] ); - } - - //transition from wall to ceiling - //normal for subsequent viewangle rotations - if( VectorCompare( trace.plane.normal, ceilingNormal ) ) - { - CrossProduct( surfNormal, trace.plane.normal, pm->ps->grapplePoint ); - VectorNormalize( pm->ps->grapplePoint ); - pm->ps->stats[ STAT_STATE ] |= SS_GPISROTVEC; - } - - //transition from ceiling to wall - //we need to do some different angle correction here cos GPISROTVEC - if( VectorCompare( surfNormal, ceilingNormal ) ) - { - vectoangles( trace.plane.normal, toAngles ); - vectoangles( pm->ps->grapplePoint, surfAngles ); - - pm->ps->delta_angles[1] -= ANGLE2SHORT( ( ( surfAngles[1] - toAngles[1] ) * 2 ) - 180 ); - } - - //TA: smooth transitions - CrossProduct( surfNormal, trace.plane.normal, srotAxis ); - VectorNormalize( srotAxis ); - srotAngle = abs( RAD2DEG( arccos( DotProduct( surfNormal, trace.plane.normal ) ) ) ); - - PM_AddSmoothOp( srotAxis, srotAngle ); - smoothed = qfalse; - } - - pml.groundTrace = trace; - - //so everything knows where we're wallclimbing - pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBING; - pm->ps->legsAnim |= ANIM_WALLCLIMBING; - - //if we're not stuck to the ceiling then set grapplePoint to be a surface normal - if( !VectorCompare( trace.plane.normal, ceilingNormal ) ) - { - //so we know what surface we're stuck to - VectorCopy( trace.plane.normal, pm->ps->grapplePoint ); - pm->ps->stats[ STAT_STATE ] &= ~SS_GPISROTVEC; - } - - //so that surf -> empty space is smoothed - wcl[ pm->ps->clientNum ].justFallen = qtrue; - VectorCopy( pm->ps->grapplePoint, wcl[ pm->ps->clientNum ].lastNormal ); - - //IMPORTANT: break out of the for loop if we've hit something - break; - } - else if ( trace.allsolid ) - { - // do something corrective if the trace starts in a solid... - //TA: fuck knows what this does with all my new stuff :( - if ( !PM_CorrectAllSolid(&trace) ) - return; - } - } - - if ( trace.fraction >= 1.0 ) - { - // if the trace didn't hit anything, we are in free fall - //Com_Printf("trace missed\n"); - PM_GroundTraceMissed(); - pml.groundPlane = qfalse; - pml.walking = qfalse; - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - pm->ps->legsAnim &= ~ANIM_WALLCLIMBING; - - if( wcl[ pm->ps->clientNum ].justFallen && !smoothed ) - { - if( pm->ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - //FIXME: need some delta-correction here - //pm->ps->delta_angles[1] -= ANGLE2SHORT( ( ( nonSvangles[1] - pm->ps->grapplePoint[1] ) * 2) ); - AngleVectors( pm->ps->viewangles, NULL, srotAxis, NULL ); - - srotAngle = 180; - } - else - { - CrossProduct( wcl[ pm->ps->clientNum ].lastNormal, refNormal, srotAxis ); - VectorNormalize( srotAxis ); - srotAngle = abs( RAD2DEG( arccos( DotProduct( refNormal, wcl[ pm->ps->clientNum ].lastNormal ) ) ) ); - } - - PM_AddSmoothOp( srotAxis, srotAngle ); - } - - pm->ps->stats[ STAT_STATE ] &= ~SS_GPISROTVEC; - - //we get very bizarre effects if we don't do this :0 - VectorCopy( refNormal, pm->ps->grapplePoint ); - wcl[ pm->ps->clientNum ].justFallen = qfalse; - return; - } - - pml.groundPlane = qtrue; - pml.walking = qtrue; - - // hitting solid ground will end a waterjump - if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - } - - pm->ps->groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - PM_AddTouchEnt( trace.entityNum ); -} - - -/* -============= -PM_GroundTrace -============= -*/ -static void PM_GroundTrace( void ) { - vec3_t point, forward, srotAxis; - vec3_t refNormal = { 0, 0, 1 }; - vec3_t ceilingNormal = { 0, 0, -1 }; - trace_t trace; - float srotAngle; - - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && ( pm->cmd.upmove < 0 ) ) - { - PM_GroundClimbTrace( ); - return; - } - - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - pm->ps->legsAnim &= ~ANIM_WALLCLIMBING; - - //make sure that the surfNormal is reset to the ground - VectorCopy( refNormal, pm->ps->grapplePoint ); - - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25; - - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if ( trace.allsolid ) { - if ( !PM_CorrectAllSolid(&trace) ) - return; - } - - if( wcl[ pm->ps->clientNum ].justFallen ) - { - if( pm->ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - //FIXME: need some delta-correction here - //pm->ps->delta_angles[1] -= ANGLE2SHORT( ( ( nonSvangles[1] - pm->ps->grapplePoint[1] ) * 2) ); - AngleVectors( wcl[ pm->ps->clientNum ].nonSvangles, NULL, srotAxis, NULL ); - - srotAngle = 180; - } - else - { - CrossProduct( wcl[ pm->ps->clientNum ].lastNormal, refNormal, srotAxis ); - VectorNormalize( srotAxis ); - - srotAngle = abs( RAD2DEG( arccos( DotProduct( refNormal, wcl[ pm->ps->clientNum ].lastNormal ) ) ) ); - } - - PM_AddSmoothOp( srotAxis, srotAngle ); - } - - //things have already been smoothed.. - wcl[ pm->ps->clientNum ].justFallen = qfalse; - - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0 ) { - PM_GroundTraceMissed(); - pml.groundPlane = qfalse; - pml.walking = qfalse; - - pm->ps->stats[ STAT_STATE ] &= ~SS_GPISROTVEC; - - //we get very bizarre effects if we don't do this :0 - VectorCopy( refNormal, pm->ps->grapplePoint ); - - return; - } - - // check if getting thrown off the ground - if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) { - if ( pm->debugLevel ) { - Com_Printf("%i:kickoff\n", c_pmove); - } - // go into jump animation - if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; - return; - } - - // slopes that are too steep will not be considered onground - if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) { - if ( pm->debugLevel ) { - Com_Printf("%i:steep\n", c_pmove); - } - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qtrue; - pml.walking = qfalse; - return; - } - - pml.groundPlane = qtrue; - pml.walking = qtrue; - - // hitting solid ground will end a waterjump - if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - } - - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { - // just hit the ground - if ( pm->debugLevel ) { - Com_Printf("%i:Land\n", c_pmove); - } - - if( pm->ps->stats[ STAT_ABILITIES ] & SCA_TAKESFALLDAMAGE ) - PM_CrashLand(); - - // don't do landing time if we were just going down a slope - if ( pml.previous_velocity[2] < -200 ) { - // don't allow another jump for a little while - pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps->pm_time = 250; - } - } - - pm->ps->groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - PM_AddTouchEnt( trace.entityNum ); -} - - -/* -============= -PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving -============= -*/ -static void PM_SetWaterLevel( void ) { - vec3_t point; - int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - pm->waterlevel = 0; - pm->watertype = 0; - - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; - cont = pm->pointcontents( point, pm->ps->clientNum ); - - if ( cont & MASK_WATER ) { - sample2 = pm->ps->viewheight - MINS_Z; - sample1 = sample2 / 2; - - pm->watertype = cont; - pm->waterlevel = 1; - point[2] = pm->ps->origin[2] + MINS_Z + sample1; - cont = pm->pointcontents (point, pm->ps->clientNum ); - if ( cont & MASK_WATER ) { - pm->waterlevel = 2; - point[2] = pm->ps->origin[2] + MINS_Z + sample2; - cont = pm->pointcontents (point, pm->ps->clientNum ); - if ( cont & MASK_WATER ){ - pm->waterlevel = 3; - } - } - } - -} - - - -/* -============== -PM_CheckDuck - -Sets mins, maxs, and pm->ps->viewheight -============== -*/ -static void PM_CheckDuck (void) -{ - trace_t trace; - vec3_t PCmins, PCmaxs, PCcmaxs; - int PCvh, PCcvh; - - switch( pm->ps->stats[ STAT_PCLASS ] ) - { - case PCL_D_BUILDER: - VectorSet( PCmins, -15, -15, -20 ); - VectorSet( PCmaxs, 15, 15, 20 ); - VectorSet( PCcmaxs, 15, 15, 20 ); - PCvh = 12; - PCcvh = 12; - break; - - case PCL_D_BASE: - VectorSet( PCmins, -15, -15, -15 ); - VectorSet( PCmaxs, 15, 15, 15 ); - VectorSet( PCcmaxs, 15, 15, 15 ); - PCvh = 4; - PCcvh = 4; - break; - - case PCL_H_BASE: - VectorSet( PCmins, -15, -15, -24 ); - VectorSet( PCmaxs, 15, 15, 32 ); - VectorSet( PCcmaxs, 15, 15, 16 ); - PCvh = 26; - PCcvh = 12; - break; - - default: - VectorSet( PCmins, -15, -15, MINS_Z ); - VectorSet( PCmaxs, 15, 15, 32 ); - VectorSet( PCcmaxs, 15, 15, 16 ); - PCvh = DEFAULT_VIEWHEIGHT; - PCcvh = CROUCH_VIEWHEIGHT; - } - - //TA: iD bug? you can still crouch when you're a spectator - if( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) - PCcvh = PCvh; - - pm->mins[0] = PCmins[0]; - pm->mins[1] = PCmins[1]; - - pm->maxs[0] = PCmaxs[0]; - pm->maxs[1] = PCmaxs[1]; - - pm->mins[2] = PCmins[2]; - - if (pm->ps->pm_type == PM_DEAD) - { - pm->maxs[2] = -8; - pm->ps->viewheight = DEAD_VIEWHEIGHT; - return; - } - - //TA: If the standing and crouching viewheights are the same the class can't crouch - if ( ( pm->cmd.upmove < 0 ) && ( PCvh != PCcvh ) ) - { // duck - pm->ps->pm_flags |= PMF_DUCKED; - } - else - { // stand up if possible - if (pm->ps->pm_flags & PMF_DUCKED) - { - // try to stand up - pm->maxs[2] = PCmaxs[2]; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask ); - if (!trace.allsolid) - pm->ps->pm_flags &= ~PMF_DUCKED; - } - } - - if (pm->ps->pm_flags & PMF_DUCKED) - { - pm->maxs[2] = PCcmaxs[2]; - pm->ps->viewheight = PCcvh; - } - else - { - pm->maxs[2] = PCmaxs[2]; - pm->ps->viewheight = PCvh; - } -} - - - -//=================================================================== - - -/* -=============== -PM_Footsteps -=============== -*/ -static void PM_Footsteps( void ) { - float bobmove; - int old; - qboolean footstep; - - // - // calculate speed and cycle to be used for - // all cyclic walking effects - // - if( ( pm->ps->stats[STAT_ABILITIES] & SCA_WALLCLIMBER ) && ( pml.groundPlane ) ) - { - pm->xyspeed = DotProduct(pm->ps->velocity, pml.groundTrace.plane.normal); - } - else - pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0] - + pm->ps->velocity[1] * pm->ps->velocity[1] ); - - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { - // airborne leaves position in cycle intact, but doesn't advance - if ( pm->waterlevel > 1 ) { - PM_ContinueLegsAnim( LEGS_SWIM ); - } - return; - } - - // if not trying to move - if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) { - if ( pm->xyspeed < 5 ) { - pm->ps->bobCycle = 0; // start at beginning of cycle again - if ( pm->ps->pm_flags & PMF_DUCKED ) { - PM_ContinueLegsAnim( LEGS_IDLECR ); - } else { - PM_ContinueLegsAnim( LEGS_IDLE ); - } - } - return; - } - - - footstep = qfalse; - - if ( pm->ps->pm_flags & PMF_DUCKED ) { - bobmove = 0.5; // ducked characters bob much faster - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACKCR ); - } - else { - PM_ContinueLegsAnim( LEGS_WALKCR ); - } - // ducked characters never play footsteps - /* - } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { - bobmove = 0.4; // faster speeds bob faster - footstep = qtrue; - } else { - bobmove = 0.3; - } - PM_ContinueLegsAnim( LEGS_BACK ); - */ - } else { - //TA: switch walking/running anims based on speed - //if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { - if ( pm->xyspeed > 160 ) { - bobmove = 0.4f; // faster speeds bob faster - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACK ); - } - else { - PM_ContinueLegsAnim( LEGS_RUN ); - } - footstep = qtrue; - } else { - bobmove = 0.3f; // walking bobs slow - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACKWALK ); - } - else { - PM_ContinueLegsAnim( LEGS_WALK ); - } - } - } - - // check for footstep / splash sounds - old = pm->ps->bobCycle; - pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255; - - // if we just crossed a cycle boundary, play an apropriate footstep event - if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) { - if ( pm->waterlevel == 0 ) { - // on ground will only play sounds if running - if ( footstep && !pm->noFootsteps ) { - PM_AddEvent( PM_FootstepForSurface() ); - } - } else if ( pm->waterlevel == 1 ) { - // splashing - PM_AddEvent( EV_FOOTSPLASH ); - } else if ( pm->waterlevel == 2 ) { - // wading / swimming at surface - PM_AddEvent( EV_SWIM ); - } else if ( pm->waterlevel == 3 ) { - // no sound when completely underwater - - } - } -} - -/* -============== -PM_WaterEvents - -Generate sound events for entering and leaving water -============== -*/ -static void PM_WaterEvents( void ) { // FIXME? - // - // if just entered a water volume, play a sound - // - if (!pml.previous_waterlevel && pm->waterlevel) { - PM_AddEvent( EV_WATER_TOUCH ); - } - - // - // if just completely exited a water volume, play a sound - // - if (pml.previous_waterlevel && !pm->waterlevel) { - PM_AddEvent( EV_WATER_LEAVE ); - } - - // - // check for head just going under water - // - if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) { - PM_AddEvent( EV_WATER_UNDER ); - } - - // - // check for head just coming out of water - // - if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) { - PM_AddEvent( EV_WATER_CLEAR ); - } -} - - -/* -=============== -PM_BeginWeaponChange -=============== -*/ -static void PM_BeginWeaponChange( int weapon ) { - if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) { - return; - } - - if ( !BG_gotWeapon( weapon, pm->ps->stats ) ) { - return; - } - - if ( pm->ps->weaponstate == WEAPON_DROPPING ) { - return; - } - - PM_AddEvent( EV_CHANGE_WEAPON ); - pm->ps->weaponstate = WEAPON_DROPPING; - pm->ps->weaponTime += 200; - PM_StartTorsoAnim( TORSO_DROP ); -} - - -/* -=============== -PM_FinishWeaponChange -=============== -*/ -static void PM_FinishWeaponChange( void ) { - int weapon; - - weapon = pm->cmd.weapon; - if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) { - weapon = WP_NONE; - } - - if ( !BG_gotWeapon( weapon, pm->ps->stats ) ) { - weapon = WP_NONE; - } - - pm->ps->weapon = weapon; - pm->ps->weaponstate = WEAPON_RAISING; - pm->ps->weaponTime += 250; - PM_StartTorsoAnim( TORSO_RAISE ); -} - - -/* -============== -PM_TorsoAnimation - -============== -*/ -static void PM_TorsoAnimation( void ) { - if ( pm->ps->weaponstate == WEAPON_READY ) { - if ( pm->ps->weapon == WP_GAUNTLET ) { - PM_ContinueTorsoAnim( TORSO_STAND2 ); - } else { - PM_ContinueTorsoAnim( TORSO_STAND ); - } - return; - } -} - - -/* -============== -PM_Weapon - -Generates weapon events and modifes the weapon counter -============== -*/ -static void PM_Weapon( void ) { - int addTime; - int ammo, clips, maxclips; - static int chainGunAddTime; - - // don't allow attack until all buttons are up - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { - return; - } - - // ignore if spectator - if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { - return; - } - - // check for dead player - if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { - pm->ps->weapon = WP_NONE; - return; - } - - // check for item using - //TA: not using q3 holdable item code - /*if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) - { - if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) - { - if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT - && pm->ps->stats[STAT_HEALTH] >= pm->ps->stats[STAT_MAX_HEALTH] ) - { - // don't use medkit if at max health - } - else - { - pm->ps->pm_flags |= PMF_USE_ITEM_HELD; - PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag ); - pm->ps->stats[STAT_HOLDABLE_ITEM] = 0; - } - return; - } - } - else - { - pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD; - }*/ - - - // make weapon function - if ( pm->ps->weaponTime > 0 ) { - pm->ps->weaponTime -= pml.msec; - } - - // check for weapon change - // can't change if weapon is firing, but can change - // again if lowering or raising - if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) { - //TA: must press use to switch weapons - if( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) - { - if( !( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) - { - if( pm->cmd.weapon <= 32 ) - { - //if trying to select a weapon, select it - if ( pm->ps->weapon != pm->cmd.weapon ) - PM_BeginWeaponChange( pm->cmd.weapon ); - } - else if( pm->cmd.weapon > 32 ) - { - //if trying to toggle an upgrade, toggle it - if( BG_gotItem( pm->cmd.weapon - 32, pm->ps->stats ) ) //sanity check - { - if( BG_activated( pm->cmd.weapon - 32, pm->ps->stats ) ) - { - BG_deactivateItem( pm->cmd.weapon - 32, pm->ps->stats ); - } - else - { - BG_activateItem( pm->cmd.weapon - 32, pm->ps->stats ); - } - } - } - pm->ps->pm_flags |= PMF_USE_ITEM_HELD; - } - } - else - pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD; - } - - if ( pm->ps->weaponTime > 0 ) { - return; - } - - // change weapon if time - if ( pm->ps->weaponstate == WEAPON_DROPPING ) { - PM_FinishWeaponChange(); - return; - } - - if ( pm->ps->weaponstate == WEAPON_RAISING ) { - pm->ps->weaponstate = WEAPON_READY; - if ( pm->ps->weapon == WP_GAUNTLET ) { - PM_StartTorsoAnim( TORSO_STAND2 ); - } else { - PM_StartTorsoAnim( TORSO_STAND ); - } - return; - } - - if( pm->ps->weapon == WP_SCANNER ) - return; //doesn't actually do anything - - // check for fire - if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - chainGunAddTime = 120; - return; - } - - // start the animation even if out of ammo - if ( pm->ps->weapon == WP_GAUNTLET ) { - // the guantlet only "fires" when it actually hits something - if ( !pm->gauntletHit ) { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - PM_StartTorsoAnim( TORSO_ATTACK2 ); - } else { - PM_StartTorsoAnim( TORSO_ATTACK ); - } - - BG_unpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips ); - - // check for out of ammo - if ( !ammo && !clips && !BG_infiniteAmmo( pm->ps->weapon ) ) { - PM_AddEvent( EV_NOAMMO ); - pm->ps->weaponTime += 200; - return; - } - - //done reloading so give em some ammo - if( pm->ps->weaponstate == WEAPON_RELOADING ) - { - - switch( pm->ps->weapon ) - { - default: - case WP_MACHINEGUN: - clips--; - ammo = CS_MG; - break; - - } - - BG_packAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); - } - - // check for end of clip - if ( !ammo && clips ) - { - pm->ps->weaponstate = WEAPON_RELOADING; - - switch( pm->ps->weapon ) - { - default: - case WP_MACHINEGUN: - addTime = 2000; - break; - - } - - pm->ps->weaponTime += addTime; - return; - } - - pm->ps->weaponstate = WEAPON_FIRING; - - // take an ammo away if not infinite - if( !BG_infiniteAmmo( pm->ps->weapon ) ) - { - ammo--; - BG_packAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); - } - - // fire weapon - PM_AddEvent( EV_FIRE_WEAPON ); - - switch( pm->ps->weapon ) { - default: - case WP_GAUNTLET: - addTime = 400; - break; - case WP_LIGHTNING: - addTime = 50; - break; - case WP_SHOTGUN: - addTime = 1000; - break; - case WP_MACHINEGUN: - addTime = 100; - break; - case WP_CHAINGUN: - if( chainGunAddTime > 30 ) chainGunAddTime -= 2; - addTime = chainGunAddTime; - break; - case WP_GRENADE_LAUNCHER: - addTime = 800; - break; - case WP_ROCKET_LAUNCHER: - addTime = 800; - break; - case WP_FLAMER: - addTime = 80; - break; - case WP_RAILGUN: - addTime = 1500; - break; - case WP_BFG: - addTime = 200; - break; - case WP_GRAPPLING_HOOK: - addTime = 400; - break; - case WP_VENOM: - addTime = 200; - break; - case WP_ABUILD: - addTime = 1000; - break; - case WP_HBUILD: - addTime = 1000; - break; - case WP_SCANNER: - addTime = 1000; //abritutary since scaner doesn't "fire" - break; - } - - /*if ( pm->ps->powerups[PW_HASTE] ) { - addTime /= 1.3; - }*/ - - if( pm->ps->weapon == WP_CHAINGUN ) - { - if( pm->ps->pm_flags & PMF_DUCKED ) - { - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.125 ) * ( 30 / (float)addTime ) ); - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.25 ) * ( 30.0 / (float)addTime ) ); - } - else - { - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 8 ) - 2 ) * ( 30.0 / (float)addTime ) ); - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 8 ) - 4 ) * ( 30.0 / (float)addTime ) ); - } - } - - pm->ps->weaponTime += addTime; -} - -/* -================ -PM_Animate -================ -*/ -static void PM_Animate( void ) { - if ( pm->cmd.buttons & BUTTON_GESTURE ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_GESTURE ); - pm->ps->torsoTimer = TIMER_GESTURE; - PM_AddEvent( EV_TAUNT ); - } - } -} - - -/* -================ -PM_DropTimers -================ -*/ -static void PM_DropTimers( void ) { - // drop misc timing counter - if ( pm->ps->pm_time ) { - if ( pml.msec >= pm->ps->pm_time ) { - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } else { - pm->ps->pm_time -= pml.msec; - } - } - - // drop animation counter - if ( pm->ps->legsTimer > 0 ) { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) { - pm->ps->legsTimer = 0; - } - } - - if ( pm->ps->torsoTimer > 0 ) { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) { - pm->ps->torsoTimer = 0; - } - } -} - - -/* -================ -PM_UpdateViewAngles - -This can be used as another entry point when only the viewangles -are being updated isntead of a full move -================ -*/ -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) { - short temp[3]; - int i; - vec3_t surfNormal, xNormal; - vec3_t axis[3], rotaxis[3], smoothaxis[3]; - vec3_t refNormal = { 0, 0, 1 }; - vec3_t ceilingNormal = { 0, 0, -1 }; - float rotAngle; - vec3_t tempang, tempang2; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION ) { - return; // no view changes at all - } - - if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) { - return; // no view changes at all - } - - // circularly clamp the angles with deltas - for (i=0 ; i<3 ; i++) { - temp[i] = cmd->angles[i] + ps->delta_angles[i]; - - if ( i == PITCH ) { - // don't let the player look up or down more than 90 degrees - if ( temp[i] > 16000 ) { - ps->delta_angles[i] = 16000 - cmd->angles[i]; - temp[i] = 16000; - } else if ( temp[i] < -16000 ) { - ps->delta_angles[i] = -16000 - cmd->angles[i]; - temp[i] = -16000; - } - } - tempang[i] = SHORT2ANGLE( temp[i] ); - } - - /*Com_Printf( "%1.2f ", ps->grapplePoint[ 0 ] ); - Com_Printf( "%1.2f ", ps->grapplePoint[ 1 ] ); - Com_Printf( "%1.2f ", ps->grapplePoint[ 2 ] ); - Com_Printf( "\n" );*/ - - //convert viewangles -> axis - AnglesToAxis( tempang, axis ); - - //the grapplePoint being a surfNormal rotation Normal hack... see above :) - if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - VectorCopy( ceilingNormal, surfNormal ); - VectorCopy( ps->grapplePoint, xNormal ); - } - else - { - //cross the reference normal and the surface normal to get the rotation axis - VectorCopy( ps->grapplePoint, surfNormal ); - if( surfNormal[2] <= 0 ) - { - CrossProduct( refNormal, surfNormal, xNormal ); - } - else - { - CrossProduct( surfNormal, refNormal, xNormal ); - } - - VectorNormalize( xNormal ); - } - - //if we're a wall climber.. and we're climbing rotate the axis - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) && - ( VectorLength( xNormal ) != 0 ) ) - { - //if the normal pointing straight down then the rotAngle will always be 180deg - if( surfNormal[2] == -1 ) - rotAngle = 180; - /*else if( abs( RAD2DEG( arccos( DotProduct( ps->grapplePoint, surfNormal ) ) ) ) <= 90 ) - { - //WEIRD-BUG_WORKAROUND: - //for some reason surface normals on curves in a specfic quadrant are inverted.. dunno why - VectorInverse( surfNormal ); - rotAngle = -RAD2DEG( arccos( DotProduct( surfNormal, refNormal ) ) ); - }*/ - else - rotAngle = -RAD2DEG( arccos( DotProduct( surfNormal, refNormal ) ) ); - - //hmmm could get away with only one rotation and some clever stuff later... but i'm lazy - RotatePointAroundVector( rotaxis[0], xNormal, axis[0], rotAngle ); - RotatePointAroundVector( rotaxis[1], xNormal, axis[1], rotAngle ); - RotatePointAroundVector( rotaxis[2], xNormal, axis[2], rotAngle ); - //MAJOR FIXME: try to reduce the number of vector rotations.. they kill the QVM - } - else - { - //we can't wall climb/aren't wall climbing - rotAngle = 0; - AxisCopy( axis, rotaxis ); - } - - AxisToAngles( rotaxis, wcl[ pm->ps->clientNum ].nonSvangles ); - - //force angles to -180 <= x <= 180 - for( i = 0; i < 3; i++ ) - { - while( wcl[ pm->ps->clientNum ].nonSvangles[ i ] > 180 ) - wcl[ pm->ps->clientNum ].nonSvangles[ i ] -= 360; - - while( wcl[ pm->ps->clientNum ].nonSvangles[ i ] < 180 ) - wcl[ pm->ps->clientNum ].nonSvangles[ i ] += 360; - } - //AnglesSubtract( wcl[ pm->ps->clientNum ].nonSvangles, 0, wcl[ pm->ps->clientNum ].nonSvangles ); - - //smooth transitions - if( !PM_PerformSmoothOps( rotaxis, smoothaxis ) ) - AxisCopy( rotaxis, smoothaxis ); - - //convert the new axis back to angles - AxisToAngles( smoothaxis, tempang2 ); - - //force angles to -180 <= x <= 180 - //AnglesSubtract( tempang2, 0, tempang2 ); - for( i = 0; i < 3; i++ ) - { - while( tempang2[ i ] > 180 ) - tempang2[ i ] -= 360; - - while( tempang2[ i ] < 180 ) - tempang2[ i ] += 360; - } - - //actually set the viewangles - for (i=0 ; i<3 ; i++) { - ps->viewangles[i] = tempang2[i]; - } -} - - -/* -================ -PmoveSingle - -================ -*/ -void trap_SnapVector( float *v ); - -void PmoveSingle (pmove_t *pmove) -{ - int ammo, clips, maxclips; - pm = pmove; - - BG_unpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips ); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - c_pmove++; - - // clear results - pm->numtouch = 0; - pm->watertype = 0; - pm->waterlevel = 0; - - if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { - pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - } - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) { - pm->cmd.buttons &= ~BUTTON_WALKING; - } - - // set the talk balloon flag - if ( pm->cmd.buttons & BUTTON_TALK ) { - pm->ps->eFlags |= EF_TALK; - } else { - pm->ps->eFlags &= ~EF_TALK; - } - - // set the firing flag for continuous beam weapons - if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & BUTTON_ATTACK ) && ( ammo > 0 || clips > 0 ) ) { - pm->ps->eFlags |= EF_FIRING; - } else { - pm->ps->eFlags &= ~EF_FIRING; - } - - // clear the respawned flag if attack and use are cleared - if ( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) { - pm->ps->pm_flags &= ~PMF_RESPAWNED; - } - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - if ( pmove->cmd.buttons & BUTTON_TALK ) { - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - } - - // clear all pmove local vars - memset (&pml, 0, sizeof(pml)); - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps->commandTime; - if ( pml.msec < 1 ) { - pml.msec = 1; - } else if ( pml.msec > 200 ) { - pml.msec = 200; - } - pm->ps->commandTime = pmove->cmd.serverTime; - - // save old org in case we get stuck - VectorCopy (pm->ps->origin, pml.previous_origin); - - // save old velocity for crashlanding - VectorCopy (pm->ps->velocity, pml.previous_velocity); - - pml.frametime = pml.msec * 0.001; - - AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up); - - if ( pm->cmd.upmove < 10 ) { - // not holding jump - pm->ps->pm_flags &= ~PMF_JUMP_HELD; - } - - // decide if backpedaling animations should be used - if ( pm->cmd.forwardmove < 0 ) { - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) { - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN; - } - - if ( pm->ps->pm_type >= PM_DEAD ) { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - } - - if ( pm->ps->pm_type == PM_SPECTATOR ) { - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - PM_CheckDuck (); - PM_FlyMove (); - PM_DropTimers (); - return; - } - - if ( pm->ps->pm_type == PM_NOCLIP ) { - PM_NoclipMove (); - PM_DropTimers (); - return; - } - - if (pm->ps->pm_type == PM_FREEZE) { - return; // no movement at all - } - - if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION ) { - return; // no movement at all - } - - // set watertype, and waterlevel - PM_SetWaterLevel(); - pml.previous_waterlevel = pmove->waterlevel; - - // set mins, maxs, and viewheight - PM_CheckDuck (); - - // set groundentity - PM_GroundTrace(); - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - - if ( pm->ps->pm_type == PM_DEAD ) { - PM_DeadMove (); - } - - PM_DropTimers(); - - /*if ( pm->ps->powerups[PW_FLIGHT] ) { - // flight powerup doesn't allow jump and has different friction - PM_FlyMove(); - } else*/ if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) { - PM_WaterJumpMove(); - } else if ( pm->waterlevel > 1 ) { - // swimming - PM_WaterMove(); - } else if ( pml.walking ) { - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - PM_ClimbMove(); //TA: walking on any surface - else - PM_WalkMove(); // walking on ground - } else { - // airborne - PM_AirMove(); - } - - PM_Animate(); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace(); - //TA: must update after every GroundTrace() - yet more clock cycles down the drain :( (14 vec rotations/frame) - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - - PM_SetWaterLevel(); - - // weapons - PM_Weapon(); - - // torso animation - PM_TorsoAnimation(); - - // footstep events / legs animations - PM_Footsteps(); - - // entering / leaving water splashes - PM_WaterEvents(); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity ); -} - - -/* -================ -Pmove - -Can be called by either the server or the client -================ -*/ -void Pmove (pmove_t *pmove) { - int finalTime; - - finalTime = pmove->cmd.serverTime; - - if ( finalTime < pmove->ps->commandTime ) { - return; // should not happen - } - - if ( finalTime > pmove->ps->commandTime + 1000 ) { - pmove->ps->commandTime = finalTime - 1000; - } - - pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<ps->commandTime != finalTime ) { - int msec; - - msec = finalTime - pmove->ps->commandTime; - - if ( pmove->pmove_fixed ) { - if ( msec > pmove->pmove_msec ) { - msec = pmove->pmove_msec; - } - } - else { - if ( msec > 66 ) { - msec = 66; - } - } - - - pmove->cmd.serverTime = pmove->ps->commandTime + msec; - PmoveSingle( pmove ); - - if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) { - pmove->cmd.upmove = 20; - } - } - -} diff --git a/src/game/bg_public.h b/src/game/bg_public.h deleted file mode 100644 index fb8ffc66..00000000 --- a/src/game/bg_public.h +++ /dev/null @@ -1,783 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_public.h -- definitions shared by both the server game and client game modules - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -// because games can change separately from the main system version, we need a -// second version that must match between game and cgame -#define GAME_VERSION "baseq3-1" - -#define DEFAULT_GRAVITY 800 -#define GIB_HEALTH -40 -#define ARMOR_PROTECTION 0.66 - -#define MAX_ITEMS 256 - -#define RANK_TIED_FLAG 0x4000 - -#define DEFAULT_SHOTGUN_SPREAD 700 -#define DEFAULT_SHOTGUN_COUNT 11 - -#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection - -#define LIGHTNING_RANGE 768 - -#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present - -#define VOTE_TIME 30000 // 30 seconds before vote times out - -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT -16 - -// -// config strings are a general means of communicating variable length strings -// from the server to all connected clients. -// - -// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h -#define CS_MUSIC 2 -#define CS_MESSAGE 3 // from the map worldspawn's message field -#define CS_MOTD 4 // g_motd string for server message of the day -#define CS_WARMUP 5 // server time when the match will be restarted -#define CS_SCORES1 6 -#define CS_SCORES2 7 -#define CS_VOTE_TIME 8 -#define CS_VOTE_STRING 9 -#define CS_VOTE_YES 10 -#define CS_VOTE_NO 11 - -#define CS_TEAMVOTE_TIME 12 -#define CS_TEAMVOTE_STRING 14 -#define CS_TEAMVOTE_YES 16 -#define CS_TEAMVOTE_NO 18 - -#define CS_GAME_VERSION 20 -#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level -#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two -#define CS_FLAGSTATUS 23 // string indicating flag status in CTF -#define CS_SHADERSTATE 24 -#define CS_BOTINFO 25 - -#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present - -//TA: extra stuff: -#define CS_ABPOINTS 28 -#define CS_HBPOINTS 29 - -#define CS_MODELS 32 -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) -#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS) -#define MAX_PRECACHES 32 -#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS+MAX_PRECACHES) - -#define CS_MAX (CS_LOCATIONS+MAX_LOCATIONS) - -#if (CS_MAX) > MAX_CONFIGSTRINGS -#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS -#endif - -typedef enum { - GT_FFA, // free for all - GT_TOURNAMENT, // one on one tournament - GT_SINGLE_PLAYER, // single player ffa - - //-- team games go after this -- - - GT_TEAM, // team deathmatch - GT_CTF, // capture the flag - GT_1FCTF, - GT_OBELISK, - GT_HARVESTER, - - GT_MAX_GAME_TYPE -} gametype_t; - -typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t; - -/* -=================================================================================== - -PMOVE MODULE - -The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t -and some other output data. Used for local prediction on the client game and true -movement on the server game. -=================================================================================== -*/ - -typedef enum { - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -} pmtype_t; - -typedef enum { - WEAPON_READY, - WEAPON_RAISING, - WEAPON_DROPPING, - WEAPON_FIRING, - WEAPON_RELOADING -} weaponstate_t; - -//TA: clip-size defines -#define CS_MG 30 //clip-size -#define CS_CG 500 -#define CS_BFG 100 -#define CS_FLAMER 400 - -//TA: bitmasks to get ammo, clips and maxclips out of ammo array -#define BM_AMMO 0x3F -#define BM_CLIPS 0xC0 - -//TA: bitmasks to get weapons out of weapons store -#define BM_SWB 0x0000FFFF -#define BM_SW2B 0xFFFF0000 - -//TA: buildable item type -#define BIT_DROIDS 1 -#define BIT_HUMANS 2 - - -// pmove->pm_flags -#define PMF_DUCKED 1 -#define PMF_JUMP_HELD 2 -#define PMF_BACKWARDS_JUMP 8 // go into backwards land -#define PMF_BACKWARDS_RUN 16 // coast down to backwards run -#define PMF_TIME_LAND 32 // pm_time is time before rejump -#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time -#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump -#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up -#define PMF_USE_ITEM_HELD 1024 -#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location -#define PMF_FOLLOW 4096 // spectate following another player -#define PMF_SCOREBOARD 8192 // spectate as a scoreboard -#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size - - -#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK) - -#define MAXTOUCH 32 -typedef struct { - // state (in / out) - playerState_t *ps; - - // command (in) - usercmd_t cmd; - int tracemask; // collide against these types of surfaces - int debugLevel; // if set, diagnostic output will be printed - qboolean noFootsteps; // if the game is setup for no footsteps by the server - qboolean gauntletHit; // true if a gauntlet attack would actually hit something - - int framecount; - - // results (out) - int numtouch; - int touchents[MAXTOUCH]; - - vec3_t mins, maxs; // bounding box size - - int watertype; - int waterlevel; - - float xyspeed; - - // for fixed msec Pmove - int pmove_fixed; - int pmove_msec; - - // callbacks to test the world - // these will be different functions during game and cgame - void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask ); - int (*pointcontents)( const vec3_t point, int passEntityNum ); -} pmove_t; - -// if a full pmove isn't done on the client, you can just update the angles -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ); -void Pmove (pmove_t *pmove); - -//=================================================================================== - - -// player_state->stats[] indexes -typedef enum { - STAT_HEALTH, - STAT_ITEMS, - STAT_ACTIVEITEMS, - STAT_WEAPONS, // 16 bit fields - STAT_WEAPONS2, //TA: another 16 bits to push the max weapon count up - STAT_ARMOR, - STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?) - STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?) - STAT_MAX_HEALTH, // health / armor limit, changable by handicap - STAT_PCLASS, //TA: player class (for droids AND humans) - STAT_PTEAM, //TA: player team - STAT_ABILITIES, //TA: client abilities (based on class) - STAT_ATTRIBS, - STAT_STAMINA, //TA: stamina (human only) - STAT_STATE //TA: client states e.g. wall climbing -} statIndex_t; - -#define SCA_WALLCLIMBER 1 -#define SCA_TAKESFALLDAMAGE 2 -#define SCA_CANZOOM 4 -#define SCA_CANJUMP 8 -#define SCA_NOWEAPONDRIFT 16 - -#define SS_WALLCLIMBING 1 -#define SS_GPISROTVEC 2 -#define SS_CREEPSLOWED 4 -#define SS_WALLTRANSIDING 8 -#define SS_SPEEDBOOST 16 - - -// player_state->persistant[] indexes -// these fields are the only part of player_state that isn't -// cleared on respawn -typedef enum { - PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!! - PERS_HITS, // total points damage inflicted so damage beeps can sound on change - PERS_RANK, - PERS_TEAM, - PERS_SPAWN_COUNT, // incremented every respawn - PERS_PLAYEREVENTS, // 16 bits that can be flipped for events - PERS_REWARD, // a reward_t - PERS_ATTACKER, // clientnum of last damage inflicter - PERS_KILLED, // count of the number of times you died - // these were added for single player awards tracking - PERS_IMPRESSIVE_COUNT, - PERS_EXCELLENT_COUNT, - PERS_GAUNTLET_FRAG_COUNT, - PERS_ACCURACY_SHOTS, - PERS_ACCURACY_HITS, - //TA: FIXME: /\ get rid of award counts to make some room - - //TA: extra gubbins - PERS_POINTS, - PERS_TOTALPOINTS -} persEnum_t; - - -// entityState_t->eFlags -#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD -#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes -#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite -#define EF_BOUNCE 0x00000010 // for missiles -#define EF_BOUNCE_HALF 0x00000020 // for missiles -#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite -#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items) -#define EF_FIRING 0x00000100 // for lightning gun -#define EF_MOVER_STOP 0x00000400 // will push otherwise -#define EF_TALK 0x00001000 // draw a talk balloon -#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite -#define EF_VOTED 0x00004000 // already cast a vote -#define EF_TEAMVOTED 0x00008000 // already cast a vote -#define EF_AWARD_IMPRESSIVE 0x00010000 // draw an impressive sprite - -typedef enum { - PW_NONE, - - PW_QUAD, - PW_BATTLESUIT, - PW_HASTE, - PW_INVIS, - PW_REGEN, - PW_FLIGHT, - - PW_REDFLAG, - PW_BLUEFLAG, - PW_BALL, - - PW_NUM_POWERUPS -} powerup_t; - -typedef enum { - HI_NONE, - - HI_TELEPORTER, - HI_MEDKIT, - - HI_NUM_HOLDABLE -} holdable_t; - -typedef enum { - WP_NONE, - - WP_GAUNTLET, - WP_MACHINEGUN, - WP_CHAINGUN, - WP_SHOTGUN, - WP_GRENADE_LAUNCHER, - WP_ROCKET_LAUNCHER, - WP_LIGHTNING, - WP_RAILGUN, - WP_FLAMER, - WP_PLASMAGUN, - WP_BFG, - WP_GRAPPLING_HOOK, - WP_VENOM, - WP_HBUILD, - WP_ABUILD, - WP_SCANNER, - WP_GGRENADE, - - WP_NUM_WEAPONS -} weapon_t; - -typedef enum { - UP_NONE, - - UP_TORCH, - UP_NVG, - UP_CHESTARMOUR, - UP_LIMBARMOUR, - UP_HELMET, - UP_ANTITOXIN, - UP_BATTPACK, - UP_JETPACK, - UP_THREATHELMET, - UP_BATTLESUIT, - UP_IMPANTKIT, - - UP_NUM_UPGRADES -} upgrade_t; - -typedef enum { - BA_NONE, - - BA_A_SPAWN, - BA_A_DEF1, - BA_H_SPAWN, - BA_H_DEF1, - BA_H_MCU, - - BA_NUM_BUILDABLES -} buildable_t; - -// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS]) -#define PLAYEREVENT_DENIEDREWARD 0x0001 -#define PLAYEREVENT_GAUNTLETREWARD 0x0002 -#define PLAYEREVENT_HOLYSHIT 0x0004 - -// entityState_t->event values -// entity events are for effects that take place reletive -// to an existing entities origin. Very network efficient. - -// two bits at the top of the entityState->event field -// will be incremented with each change in the event so -// that an identical event started twice in a row can -// be distinguished. And off the value with ~EV_EVENT_BITS -// to retrieve the actual event number -#define EV_EVENT_BIT1 0x00000100 -#define EV_EVENT_BIT2 0x00000200 -#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2) - -typedef enum { - EV_NONE, - - EV_FOOTSTEP, - EV_FOOTSTEP_METAL, - EV_FOOTSTEP_SQUELCH, - EV_FOOTSPLASH, - EV_FOOTWADE, - EV_SWIM, - - EV_STEP_4, - EV_STEP_8, - EV_STEP_12, - EV_STEP_16, - - EV_FALL_SHORT, - EV_FALL_MEDIUM, - EV_FALL_FAR, - - EV_JUMP_PAD, // boing sound at origin, jump sound on player - - EV_JUMP, - EV_WATER_TOUCH, // foot touches - EV_WATER_LEAVE, // foot leaves - EV_WATER_UNDER, // head touches - EV_WATER_CLEAR, // head leaves - - EV_ITEM_PICKUP, // normal item pickups are predictable - EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone - - EV_NOAMMO, - EV_CHANGE_WEAPON, - EV_FIRE_WEAPON, - - EV_USE_ITEM0, - EV_USE_ITEM1, - EV_USE_ITEM2, - EV_USE_ITEM3, - EV_USE_ITEM4, - EV_USE_ITEM5, - EV_USE_ITEM6, - EV_USE_ITEM7, - EV_USE_ITEM8, - EV_USE_ITEM9, - EV_USE_ITEM10, - EV_USE_ITEM11, - EV_USE_ITEM12, - EV_USE_ITEM13, - EV_USE_ITEM14, - EV_USE_ITEM15, - - EV_ITEM_RESPAWN, - EV_ITEM_GROW, //droid items that grow - EV_ITEM_POP, - EV_PLAYER_TELEPORT_IN, - EV_PLAYER_TELEPORT_OUT, - - EV_GRENADE_BOUNCE, // eventParm will be the soundindex - - EV_GENERAL_SOUND, - EV_GLOBAL_SOUND, // no attenuation - - EV_BULLET_HIT_FLESH, - EV_BULLET_HIT_WALL, - - EV_MISSILE_HIT, - EV_MISSILE_MISS, - EV_MISSILE_MISS_METAL, - EV_ITEM_EXPLOSION, //TA: human item explosions - EV_RAILTRAIL, - EV_SHOTGUN, - EV_BULLET, // otherEntity is the shooter - - EV_PAIN, - EV_DEATH1, - EV_DEATH2, - EV_DEATH3, - EV_OBITUARY, - - EV_POWERUP_QUAD, - EV_POWERUP_BATTLESUIT, - EV_POWERUP_REGEN, - - EV_GIB_PLAYER, // gib a previously living player - EV_GIB_GENERIC, //TA: generic green gib for droids - - EV_DEBUG_LINE, - EV_STOPLOOPINGSOUND, - EV_TAUNT, - EV_TAUNT_YES, - EV_TAUNT_NO, - EV_TAUNT_FOLLOWME, - EV_TAUNT_GETFLAG, - EV_TAUNT_GUARDBASE, - EV_TAUNT_PATROL, - - EV_MENU //TA: menu event - -} entity_event_t; - -typedef enum -{ - MN_TEAM, - MN_DROID, - MN_HUMAN, - MN_ABUILD, - MN_HBUILD -} dynMenu_t; - -// animations -typedef enum { - BOTH_DEATH1, - BOTH_DEAD1, - BOTH_DEATH2, - BOTH_DEAD2, - BOTH_DEATH3, - BOTH_DEAD3, - - TORSO_GESTURE, - - TORSO_ATTACK, - TORSO_ATTACK2, - - TORSO_DROP, - TORSO_RAISE, - - TORSO_STAND, - TORSO_STAND2, - - LEGS_WALKCR, - LEGS_WALK, - LEGS_RUN, - LEGS_BACK, - LEGS_SWIM, - - LEGS_JUMP, - LEGS_LAND, - - LEGS_JUMPB, - LEGS_LANDB, - - LEGS_IDLE, - LEGS_IDLECR, - - LEGS_TURN, - -#ifdef NEW_ANIMS - TORSO_GETFLAG, - TORSO_GUARDBASE, - TORSO_PATROL, - TORSO_FOLLOWME, - TORSO_AFFIRMATIVE, - TORSO_NEGATIVE, -#endif - - MAX_ANIMATIONS, - - LEGS_BACKCR, - LEGS_BACKWALK, - FLAG_RUN, - FLAG_STAND, - FLAG_STAND2RUN, - - MAX_TOTALANIMATIONS -} animNumber_t; - - -typedef struct animation_s { - int firstFrame; - int numFrames; - int loopFrames; // 0 to numFrames - int frameLerp; // msec between frames - int initialLerp; // msec to get to first frame - int reversed; // true if animation is reversed - int flipflop; // true if animation should flipflop back to base -} animation_t; - - -// flip the togglebit every time an animation -// changes so a restart of the same anim can be detected -#define ANIM_TOGGLEBIT 128 -#define ANIM_WALLCLIMBING 64 - - -typedef enum { - TEAM_FREE, - TEAM_HUMANS, - TEAM_DROIDS, - TEAM_SPECTATOR, - - TEAM_NUM_TEAMS -} team_t; - -// Time between location updates -#define TEAM_LOCATION_UPDATE_TIME 1000 - -// How many players on the overlay -#define TEAM_MAXOVERLAY 32 - -//FIXME: switch to enums at some point -//TA: player classes -#define PCL_D_BUILDER 1 -#define PCL_D_BASE 2 -#define PCL_D_OFF1 3 -#define PCL_D_OFF2 4 -#define PCL_D_OFF3 5 -#define PCL_D_OFF4 6 -#define PCL_D_OFF5 7 -#define PCL_D_OFF6 8 -#define PCL_D_OFF7 9 -#define PCL_D_OFF8 10 - -#define PCL_H_BASE 11 - -//TA: player teams -#define PTE_NONE 0 -#define PTE_DROIDS 1 -#define PTE_HUMANS 2 - - -// means of death -typedef enum { - MOD_UNKNOWN, - MOD_SHOTGUN, - MOD_GAUNTLET, - MOD_MACHINEGUN, - MOD_CHAINGUN, - MOD_GRENADE, - MOD_GRENADE_SPLASH, - MOD_ROCKET, - MOD_ROCKET_SPLASH, - MOD_FLAMER, - MOD_FLAMER_SPLASH, - MOD_RAILGUN, - MOD_LIGHTNING, - MOD_BFG, - MOD_BFG_SPLASH, - MOD_WATER, - MOD_SLIME, - MOD_LAVA, - MOD_CRUSH, - MOD_TELEFRAG, - MOD_FALLING, - MOD_SUICIDE, - MOD_TARGET_LASER, - MOD_TRIGGER_HURT, - MOD_GRAPPLE, - MOD_VENOM, - MOD_HSPAWN, - MOD_ASPAWN -} meansOfDeath_t; - - -//--------------------------------------------------------- - -// gitem_t->type -typedef enum { - IT_BAD, - IT_WEAPON, // EFX: rotate + upscale + minlight - IT_BUILDABLE, //TA: gitem_t->type for buildable items (spawns etc.) - IT_UPGRADE, //TA: gitem_t->type for human upgrades - IT_AMMO, // EFX: rotate - IT_ARMOR, // EFX: rotate + minlight - IT_HEALTH, // EFX: static external sphere + rotating internal - IT_POWERUP, // instant on, timer based - // EFX: rotate + external ring that rotates - IT_HOLDABLE, // single use, holdable item - // EFX: rotate + bob - IT_TEAM -} itemType_t; - -#define MAX_ITEM_MODELS 4 - -typedef struct gitem_s { - char *classname; // spawning name - char *pickup_sound; - char *world_model[MAX_ITEM_MODELS]; - - char *icon; - char *pickup_name; // for printing on pickup - - int quantity; // for ammo how much, or duration of powerup - itemType_t giType; // IT_* flags - - int giTag; - - char *precaches; // string of all models and images this item will use - char *sounds; // string of all sounds this item will use -} gitem_t; - -// included in both the game dll and the client -extern gitem_t bg_itemlist[]; -extern int bg_numItems; - -gitem_t *BG_FindItem( const char *pickupName ); -gitem_t *BG_FindItemForWeapon( weapon_t weapon ); -gitem_t *BG_FindItemForBuildable( buildable_t buildable ); -gitem_t *BG_FindItemForUpgrade( upgrade_t upgrade ); -gitem_t *BG_FindItemForPowerup( powerup_t pw ); -gitem_t *BG_FindItemForHoldable( holdable_t pw ); -#define ITEM_INDEX(x) ((x)-bg_itemlist) - -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ); - - -// g_dmflags->integer flags -#define DF_NO_FALLING 8 -#define DF_FIXED_FOV 16 -#define DF_NO_FOOTSTEPS 32 - -// content masks -#define MASK_ALL (-1) -#define MASK_SOLID (CONTENTS_SOLID) -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) -#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP) -#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME) -#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA) -#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE) - - -// -// entityState_t->eType -// -typedef enum { - ET_GENERAL, - ET_PLAYER, - ET_ITEM, - - ET_BUILDABLE, //TA: buildable type - ET_CREEP, //TA: creep type - - ET_MISSILE, - ET_MOVER, - ET_BEAM, - ET_PORTAL, - ET_SPEAKER, - ET_PUSH_TRIGGER, - ET_TELEPORT_TRIGGER, - ET_INVISIBLE, - ET_GRAPPLE, // grapple hooked on wall - - ET_TORCH, //TA: torch type - ET_CORPSE, - - ET_EVENTS // any of the EV_* events can be added freestanding - // by setting eType to ET_EVENTS + eventNum - // this avoids having to set eFlags and eventNum -} entityType_t; - -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ); -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ); - -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ); - -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ); -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ); - -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ); - -//TA: extra bits: (which I apparently dont need) -/*void BG_unpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ); -void BG_packAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ); -qboolean BG_infiniteAmmo( int weapon ); -void BG_packWeapon( int weapon, int stats[ ] ); -qboolean BG_gotWeapon( int weapon, int stats[ ] );*/ - -#define CREEP_BASESIZE 120 - -#define ARENAS_PER_TIER 4 -#define MAX_ARENAS 1024 -#define MAX_ARENAS_TEXT 8192 - -#define MAX_BOTS 1024 -#define MAX_BOTS_TEXT 8192 - -//TA: conceptually should live in q_shared.h -void AxisToAngles( vec3_t axis[3], vec3_t angles); -float arccos( float x ); - diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c deleted file mode 100644 index 00ca010a..00000000 --- a/src/game/bg_slidemove.c +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_slidemove.c -- part of bg_pmove functionality - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" -#include "bg_public.h" -#include "bg_local.h" - -/* - -input: origin, velocity, bounds, groundPlane, trace function - -output: origin, velocity, impacts, stairup boolean - -*/ - -/* -================== -PM_SlideMove - -Returns qtrue if the velocity was clipped in some way -================== -*/ -#define MAX_CLIP_PLANES 5 -qboolean PM_SlideMove( qboolean gravity ) { - int bumpcount, numbumps; - vec3_t dir; - float d; - int numplanes; - vec3_t planes[MAX_CLIP_PLANES]; - vec3_t primal_velocity; - vec3_t clipVelocity; - int i, j, k; - trace_t trace; - vec3_t end; - float time_left; - float into; - vec3_t endVelocity; - vec3_t endClipVelocity; - - numbumps = 4; - - VectorCopy (pm->ps->velocity, primal_velocity); - - if ( gravity ) { - VectorCopy( pm->ps->velocity, endVelocity ); - endVelocity[2] -= pm->ps->gravity * pml.frametime; - pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - primal_velocity[2] = endVelocity[2]; - if ( pml.groundPlane ) { - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - } - } - - time_left = pml.frametime; - - // never turn against the ground plane - if ( pml.groundPlane ) { - numplanes = 1; - VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - } else { - numplanes = 0; - } - - // never turn against original velocity - VectorNormalize2( pm->ps->velocity, planes[numplanes] ); - numplanes++; - - for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { - - // calculate position we are trying to move to - VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); - - // see if we can make it there - pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); - - if (trace.allsolid) { - // entity is completely trapped in another solid - pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - return qtrue; - } - - if (trace.fraction > 0) { - // actually covered some distance - VectorCopy (trace.endpos, pm->ps->origin); - } - - if (trace.fraction == 1) { - break; // moved the entire distance - } - - // save entity for contact - PM_AddTouchEnt( trace.entityNum ); - - time_left -= time_left * trace.fraction; - - if (numplanes >= MAX_CLIP_PLANES) { - // this shouldn't really happen - VectorClear( pm->ps->velocity ); - return qtrue; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0 ; i < numplanes ; i++ ) { - if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) { - VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - break; - } - } - if ( i < numplanes ) { - continue; - } - VectorCopy (trace.plane.normal, planes[numplanes]); - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0 ; i < numplanes ; i++ ) { - into = DotProduct( pm->ps->velocity, planes[i] ); - if ( into >= 0.1 ) { - continue; // move doesn't interact with the plane - } - - // see how hard we are hitting things - if ( -into > pml.impactSpeed ) { - pml.impactSpeed = -into; - } - - // slide along the plane - PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); - - // slide along the plane - PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0 ; j < numplanes ; j++ ) { - if ( j == i ) { - continue; - } - if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { - continue; // move doesn't interact with the plane - } - - // try clipping the move to the plane - PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); - PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); - - // see if it goes back into the first clip plane - if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { - continue; - } - - // slide the original velocity along the crease - CrossProduct (planes[i], planes[j], dir); - VectorNormalize( dir ); - d = DotProduct( dir, pm->ps->velocity ); - VectorScale( dir, d, clipVelocity ); - - CrossProduct (planes[i], planes[j], dir); - VectorNormalize( dir ); - d = DotProduct( dir, endVelocity ); - VectorScale( dir, d, endClipVelocity ); - - // see if there is a third plane the the new move enters - for ( k = 0 ; k < numplanes ; k++ ) { - if ( k == i || k == j ) { - continue; - } - if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { - continue; // move doesn't interact with the plane - } - - // stop dead at a tripple plane interaction - VectorClear( pm->ps->velocity ); - return qtrue; - } - } - - // if we have fixed all interactions, try another move - VectorCopy( clipVelocity, pm->ps->velocity ); - VectorCopy( endClipVelocity, endVelocity ); - break; - } - } - - if ( gravity ) { - VectorCopy( endVelocity, pm->ps->velocity ); - } - - // don't change velocity if in a timer (FIXME: is this correct?) - if ( pm->ps->pm_time ) { - VectorCopy( primal_velocity, pm->ps->velocity ); - } - - return ( bumpcount != 0 ); -} - -/* -================== -PM_StepSlideMove - -================== -*/ -void PM_StepSlideMove( qboolean gravity ) { - vec3_t start_o, start_v; - vec3_t down_o, down_v; - trace_t trace; -// float down_dist, up_dist; -// vec3_t delta, delta2; - vec3_t up, down; - - VectorCopy (pm->ps->origin, start_o); - VectorCopy (pm->ps->velocity, start_v); - - if ( PM_SlideMove( gravity ) == 0 ) { - return; // we got exactly where we wanted to go first try - } - - VectorCopy(start_o, down); - down[2] -= STEPSIZE; - pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - VectorSet(up, 0, 0, 1); - // never step up when you still have up velocity - if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || - DotProduct(trace.plane.normal, up) < 0.7)) { - return; - } - - VectorCopy (pm->ps->origin, down_o); - VectorCopy (pm->ps->velocity, down_v); - - VectorCopy (start_o, up); - up[2] += STEPSIZE; - - // test the player position if they were a stepheight higher - pm->trace (&trace, up, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); - if ( trace.allsolid ) { - if ( pm->debugLevel ) { - Com_Printf("%i:bend can't step\n", c_pmove); - } - return; // can't step up - } - - // try slidemove from this position - VectorCopy (up, pm->ps->origin); - VectorCopy (start_v, pm->ps->velocity); - - PM_SlideMove( gravity ); - - // push down the final amount - VectorCopy (pm->ps->origin, down); - down[2] -= STEPSIZE; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - if ( !trace.allsolid ) { - VectorCopy (trace.endpos, pm->ps->origin); - } - if ( trace.fraction < 1.0 ) { - PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); - } - -#if 0 - // if the down trace can trace back to the original position directly, don't step - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask); - if ( trace.fraction == 1.0 ) { - // use the original move - VectorCopy (down_o, pm->ps->origin); - VectorCopy (down_v, pm->ps->velocity); - if ( pm->debugLevel ) { - Com_Printf("%i:bend\n", c_pmove); - } - } else -#endif - { - // use the step move - float delta; - - delta = pm->ps->origin[2] - start_o[2]; - if ( delta > 2 ) { - if ( delta < 7 ) { - PM_AddEvent( EV_STEP_4 ); - } else if ( delta < 11 ) { - PM_AddEvent( EV_STEP_8 ); - } else if ( delta < 15 ) { - PM_AddEvent( EV_STEP_12 ); - } else { - PM_AddEvent( EV_STEP_16 ); - } - } - if ( pm->debugLevel ) { - Com_Printf("%i:stepped\n", c_pmove); - } - } -} - diff --git a/src/game/g_active.c b/src/game/g_active.c deleted file mode 100644 index d8519184..00000000 --- a/src/game/g_active.c +++ /dev/null @@ -1,1059 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - -/* -=============== -G_DamageFeedback - -Called just before a snapshot is sent to the given player. -Totals up all damage and generates both the player_state_t -damage values to that client for pain blends and kicks, and -global pain sound events for all clients. -=============== -*/ -void P_DamageFeedback( gentity_t *player ) { - gclient_t *client; - float count; - vec3_t angles; - - client = player->client; - if ( client->ps.pm_type == PM_DEAD ) { - return; - } - - // total points of damage shot at the player this frame - count = client->damage_blood + client->damage_armor; - if ( count == 0 ) { - return; // didn't take any damage - } - - if ( count > 255 ) { - count = 255; - } - - // send the information to the client - - // world damage (falling, slime, etc) uses a special code - // to make the blend blob centered instead of positional - if ( client->damage_fromWorld ) { - client->ps.damagePitch = 255; - client->ps.damageYaw = 255; - - client->damage_fromWorld = qfalse; - } else { - vectoangles( client->damage_from, angles ); - client->ps.damagePitch = angles[PITCH]/360.0 * 256; - client->ps.damageYaw = angles[YAW]/360.0 * 256; - } - - // play an apropriate pain sound - if ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) ) { - player->pain_debounce_time = level.time + 700; - G_AddEvent( player, EV_PAIN, player->health ); - client->ps.damageEvent++; - } - - - client->ps.damageCount = count; - - // - // clear totals - // - client->damage_blood = 0; - client->damage_armor = 0; - client->damage_knockback = 0; -} - - - -/* -============= -P_WorldEffects - -Check for lava / slime contents and drowning -============= -*/ -void P_WorldEffects( gentity_t *ent ) { - qboolean envirosuit; - int waterlevel; - - if ( ent->client->noclip ) { - ent->client->airOutTime = level.time + 12000; // don't need air - return; - } - - waterlevel = ent->waterlevel; - - envirosuit = /*ent->client->ps.powerups[PW_BATTLESUIT]*/ 0 > level.time; - - // - // check for drowning - // - if ( waterlevel == 3 ) { - // envirosuit give air - if ( envirosuit ) { - ent->client->airOutTime = level.time + 10000; - } - - // if out of air, start drowning - if ( ent->client->airOutTime < level.time) { - // drown! - ent->client->airOutTime += 1000; - if ( ent->health > 0 ) { - // take more damage the longer underwater - ent->damage += 2; - if (ent->damage > 15) - ent->damage = 15; - - // play a gurp sound instead of a normal pain sound - if (ent->health <= ent->damage) { - G_Sound(ent, CHAN_VOICE, G_SoundIndex("*drown.wav")); - } else if (rand()&1) { - G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav")); - } else { - G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav")); - } - - // don't play a normal pain sound - ent->pain_debounce_time = level.time + 200; - - G_Damage (ent, NULL, NULL, NULL, NULL, - ent->damage, DAMAGE_NO_ARMOR, MOD_WATER); - } - } - } else { - ent->client->airOutTime = level.time + 12000; - ent->damage = 2; - } - - // - // check for sizzle damage (move to pmove?) - // - if (waterlevel && - (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) { - if (ent->health > 0 - && ent->pain_debounce_time <= level.time ) { - - if ( envirosuit ) { - G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 ); - } else { - if (ent->watertype & CONTENTS_LAVA) { - G_Damage (ent, NULL, NULL, NULL, NULL, - 30*waterlevel, 0, MOD_LAVA); - } - - if (ent->watertype & CONTENTS_SLIME) { - G_Damage (ent, NULL, NULL, NULL, NULL, - 10*waterlevel, 0, MOD_SLIME); - } - } - } - } -} - - - -/* -=============== -G_SetClientSound -=============== -*/ -void G_SetClientSound( gentity_t *ent ) { - if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) { - ent->client->ps.loopSound = level.snd_fry; - } else { - ent->client->ps.loopSound = 0; - } -} - - - -//============================================================== - -/* -============== -ClientImpacts -============== -*/ -void ClientImpacts( gentity_t *ent, pmove_t *pm ) { - int i, j; - trace_t trace; - gentity_t *other; - - memset( &trace, 0, sizeof( trace ) ); - for (i=0 ; inumtouch ; i++) { - for (j=0 ; jtouchents[j] == pm->touchents[i] ) { - break; - } - } - if (j != i) { - continue; // duplicated - } - other = &g_entities[ pm->touchents[i] ]; - - if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) { - ent->touch( ent, other, &trace ); - } - - if ( !other->touch ) { - continue; - } - - other->touch( other, ent, &trace ); - } - -} - -/* -============ -G_TouchTriggers - -Find all trigger entities that ent's current position touches. -Spectators will only interact with teleporters. -============ -*/ -void G_TouchTriggers( gentity_t *ent ) { - int i, num; - int touch[MAX_GENTITIES]; - gentity_t *hit; - trace_t trace; - vec3_t mins, maxs; - static vec3_t range = { 40, 40, 52 }; - - if ( !ent->client ) { - return; - } - - // dead clients don't activate triggers! - if ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) { - return; - } - - VectorSubtract( ent->client->ps.origin, range, mins ); - VectorAdd( ent->client->ps.origin, range, maxs ); - - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - // can't use ent->absmin, because that has a one unit pad - VectorAdd( ent->client->ps.origin, ent->r.mins, mins ); - VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs ); - - for ( i=0 ; itouch && !ent->touch ) { - continue; - } - if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) { - continue; - } - - // ignore most entities if a spectator - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - if ( hit->s.eType != ET_TELEPORT_TRIGGER && - // this is ugly but adding a new ET_? type will - // most likely cause network incompatibilities - hit->touch != Touch_DoorTrigger) { - continue; - } - } - - // use seperate code for determining if an item is picked up - // so you don't have to actually contact its bounding box - if ( hit->s.eType == ET_ITEM || hit->s.eType == ET_BUILDABLE ) { - if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) { - continue; - } - } else { - if ( !trap_EntityContact( mins, maxs, hit ) ) { - continue; - } - } - - memset( &trace, 0, sizeof(trace) ); - - if ( hit->touch ) { - hit->touch (hit, ent, &trace); - } - - if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) { - ent->touch( ent, hit, &trace ); - } - } - - // if we didn't touch a jump pad this pmove frame - if ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) { - ent->client->ps.jumppad_frame = 0; - ent->client->ps.jumppad_ent = 0; - } -} - -/* -================= -SpectatorThink -================= -*/ -void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) { - pmove_t pm; - gclient_t *client; - - client = ent->client; - - if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) { - - if( client->sess.spectatorState == SPECTATOR_LOCKED ) - client->ps.pm_type = PM_FREEZE; - else - client->ps.pm_type = PM_SPECTATOR; - - client->ps.speed = 400; // faster than normal - - // set up for pmove - memset (&pm, 0, sizeof(pm)); - pm.ps = &client->ps; - pm.cmd = *ucmd; - pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies - pm.trace = trap_Trace; - pm.pointcontents = trap_PointContents; - - // perform a pmove - Pmove (&pm); - - // save results of pmove - VectorCopy( client->ps.origin, ent->s.origin ); - - G_TouchTriggers( ent ); - trap_UnlinkEntity( ent ); - } - - client->oldbuttons = client->buttons; - client->buttons = ucmd->buttons; - - if ( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) ) - { - if( client->pers.pteam == PTE_NONE ) - { - G_AddPredictableEvent( ent, EV_MENU, MN_TEAM ); - } - else if( client->pers.pteam == PTE_DROIDS ) - { - G_AddPredictableEvent( ent, EV_MENU, MN_DROID ); - } - else if( client->pers.pteam == PTE_HUMANS ) - { - G_AddPredictableEvent( ent, EV_MENU, MN_HUMAN ); - } - } - - // attack button cycles through spectators - //TA: messes with the menus - /*if ( ( client->buttons & BUTTON_ATTACK ) && - !( client->oldbuttons & BUTTON_ATTACK ) && - ( client->sess.spectatorState != SPECTATOR_LOCKED ) ) - Cmd_FollowCycle_f( ent, 1 );*/ -} - - - -/* -================= -ClientInactivityTimer - -Returns qfalse if the client is dropped -================= -*/ -qboolean ClientInactivityTimer( gclient_t *client ) { - if ( ! g_inactivity.integer ) { - // give everyone some time, so if the operator sets g_inactivity during - // gameplay, everyone isn't kicked - client->inactivityTime = level.time + 60 * 1000; - client->inactivityWarning = qfalse; - } else if ( client->pers.cmd.forwardmove || - client->pers.cmd.rightmove || - client->pers.cmd.upmove || - (client->pers.cmd.buttons & BUTTON_ATTACK) ) { - client->inactivityTime = level.time + g_inactivity.integer * 1000; - client->inactivityWarning = qfalse; - } else if ( !client->pers.localClient ) { - if ( level.time > client->inactivityTime ) { - trap_DropClient( client - level.clients, "Dropped due to inactivity" ); - return qfalse; - } - if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) { - client->inactivityWarning = qtrue; - trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" ); - } - } - return qtrue; -} - -/* -================== -ClientTimerActions - -Actions that happen once a second -================== -*/ -void ClientTimerActions( gentity_t *ent, int msec ) { - gclient_t *client; - - client = ent->client; - client->timeResidual += msec; - - while ( client->timeResidual >= 1000 ) { - client->timeResidual -= 1000; - - // regenerate - /*if ( client->ps.powerups[PW_REGEN] ) - { - if ( ent->health < client->ps.stats[STAT_MAX_HEALTH]) - { - ent->health += 15; - if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 1.1 ) - { - ent->health = client->ps.stats[STAT_MAX_HEALTH] * 1.1; - } - G_AddEvent( ent, EV_POWERUP_REGEN, 0 ); - } - else if ( ent->health < client->ps.stats[STAT_MAX_HEALTH] * 2) - { - ent->health += 5; - if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 2 ) - { - ent->health = client->ps.stats[STAT_MAX_HEALTH] * 2; - } - G_AddEvent( ent, EV_POWERUP_REGEN, 0 ); - } - } - else - { - // count down health when over max - if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) - { - //TA: dont count health and armo(u)r down - //ent->health--; - } - }*/ - - // count down armor when over max - if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) { - //client->ps.stats[STAT_ARMOR]--; - } - - } -} - -/* -==================== -ClientIntermissionThink -==================== -*/ -void ClientIntermissionThink( gclient_t *client ) { - client->ps.eFlags &= ~EF_TALK; - client->ps.eFlags &= ~EF_FIRING; - - // the level will exit when everyone wants to or after timeouts - - // swap and latch button actions - client->oldbuttons = client->buttons; - client->buttons = client->pers.cmd.buttons; - if ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) { - client->readyToExit = 1; - } -} - - -/* -================ -ClientEvents - -Events will be passed on to the clients for presentation, -but any server game effects are handled here -================ -*/ -void ClientEvents( gentity_t *ent, int oldEventSequence ) { - int i, j; - int event; - gclient_t *client; - int damage; - vec3_t dir; - vec3_t origin, angles; -// qboolean fired; - gitem_t *item; - gentity_t *drop; - - client = ent->client; - - if ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) { - oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS; - } - for ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) { - event = client->ps.events[ i & (MAX_PS_EVENTS-1) ]; - - switch ( event ) { - case EV_FALL_MEDIUM: - case EV_FALL_FAR: - if ( ent->s.eType != ET_PLAYER ) { - break; // not in the player model - } - if ( g_dmflags.integer & DF_NO_FALLING ) { - break; - } - if ( event == EV_FALL_FAR ) { - damage = 10; - } else { - damage = 5; - } - VectorSet (dir, 0, 0, 1); - ent->pain_debounce_time = level.time + 200; // no normal pain sound - G_Damage (ent, NULL, NULL, NULL, NULL, damage, 0, MOD_FALLING); - break; - - case EV_FIRE_WEAPON: - FireWeapon( ent ); - break; - - case EV_USE_ITEM1: // teleporter - // drop flags in CTF - item = NULL; - j = 0; - - /*if ( ent->client->ps.powerups[ PW_REDFLAG ] ) { - item = BG_FindItemForPowerup( PW_REDFLAG ); - i = PW_REDFLAG; - } else if ( ent->client->ps.powerups[ PW_BLUEFLAG ] ) { - item = BG_FindItemForPowerup( PW_BLUEFLAG ); - i = PW_BLUEFLAG; - }*/ - - if ( item ) { - drop = Drop_Item( ent, item, 0 ); - // decide how many seconds it has left - drop->count = ( ent->client->ps.powerups[ j ] - level.time ) / 1000; - if ( drop->count < 1 ) { - drop->count = 1; - } - - ent->client->ps.powerups[ j ] = 0; - } - - SelectSpawnPoint( ent->client->ps.origin, origin, angles ); - TeleportPlayer( ent, origin, angles ); - break; - - case EV_USE_ITEM2: // medkit - ent->health = ent->client->ps.stats[STAT_MAX_HEALTH]; - break; - - default: - break; - } - } - -} - -/* -============== -StuckInOtherClient -============== -*/ -static int StuckInOtherClient(gentity_t *ent) { - int i; - gentity_t *ent2; - - ent2 = &g_entities[0]; - for ( i = 0; i < MAX_CLIENTS; i++, ent2++ ) { - if ( ent2 == ent ) { - continue; - } - if ( !ent2->inuse ) { - continue; - } - if ( !ent2->client ) { - continue; - } - if ( ent2->health <= 0 ) { - continue; - } - // - if (ent2->r.absmin[0] > ent->r.absmax[0]) - continue; - if (ent2->r.absmin[1] > ent->r.absmax[1]) - continue; - if (ent2->r.absmin[2] > ent->r.absmax[2]) - continue; - if (ent2->r.absmax[0] < ent->r.absmin[0]) - continue; - if (ent2->r.absmax[1] < ent->r.absmin[1]) - continue; - if (ent2->r.absmax[2] < ent->r.absmin[2]) - continue; - return qtrue; - } - return qfalse; -} - -//TA: rip bots -//void BotTestSolid(vec3_t origin); - -/* -============== -ClientThink - -This will be called once for each client frame, which will -usually be a couple times for each server frame on fast clients. - -If "g_synchronousClients 1" is set, this will be called exactly -once for each server frame, which makes for smooth demo recording. -============== -*/ -void ClientThink_real( gentity_t *ent ) { - gclient_t *client; - pmove_t pm; - int oldEventSequence; - int msec; - usercmd_t *ucmd; - float speed; - - //TA: torch - gentity_t *light; - - //TA: creep variables - gentity_t *creepNode; - vec3_t temp_v; - int i; - qboolean cSlowed = qfalse; - - //Com_Printf( "%d\n", G_LuminanceAtPoint( ent->s.origin ) ); - - client = ent->client; - - // don't think if the client is not yet connected (and thus not yet spawned in) - if (client->pers.connected != CON_CONNECTED) { - return; - } - - // mark the time, so the connection sprite can be removed - ucmd = &ent->client->pers.cmd; - - // sanity check the command time to prevent speedup cheating - if ( ucmd->serverTime > level.time + 200 ) { - ucmd->serverTime = level.time + 200; -// G_Printf("serverTime <<<<<\n" ); - } - if ( ucmd->serverTime < level.time - 1000 ) { - ucmd->serverTime = level.time - 1000; -// G_Printf("serverTime >>>>>\n" ); - } - - msec = ucmd->serverTime - client->ps.commandTime; - // following others may result in bad times, but we still want - // to check for follow toggles - if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) { - return; - } - if ( msec > 200 ) { - msec = 200; - } - - if ( pmove_msec.integer < 8 ) { - trap_Cvar_Set("pmove_msec", "8"); - } - else if (pmove_msec.integer > 33) { - trap_Cvar_Set("pmove_msec", "33"); - } - - if ( pmove_fixed.integer || client->pers.pmoveFixed ) { - ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer; - //if (ucmd->serverTime - client->ps.commandTime <= 0) - // return; - } - - // - // check for exiting intermission - // - if ( level.intermissiontime ) { - ClientIntermissionThink( client ); - return; - } - - // spectators don't do much - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { - if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { - return; - } - SpectatorThink( ent, ucmd ); - return; - } - - // check for inactivity timer, but never drop the local client of a non-dedicated server - if ( !ClientInactivityTimer( client ) ) { - return; - } - - // clear the rewards if time - if ( level.time > client->rewardTime ) { - client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET ); - } - - if ( client->noclip ) { - client->ps.pm_type = PM_NOCLIP; - } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) { - client->ps.pm_type = PM_DEAD; - } else { - client->ps.pm_type = PM_NORMAL; - } - - client->ps.gravity = g_gravity.value; - - // set speed - client->ps.speed = g_speed.value * client->classSpeed; - - //TA: slow player if standing in creep - for ( i = 1, creepNode = g_entities + i; i < level.num_entities; i++, creepNode++ ) - { - if( !Q_stricmp( creepNode->classname, "team_droid_creep" ) ) - { - VectorSubtract( client->ps.origin, creepNode->s.origin, temp_v ); - - if( ( VectorLength( temp_v ) <= creepNode->s.frame ) && - ( temp_v[ 2 ] <= 21 ) && //assumes mins of player is (x, x, -24) - ( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) - { - client->ps.speed *= 0.5; - client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED; - cSlowed = qtrue; - break; - } - } - } - - if( !cSlowed ) - client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED; - - /*if ( client->ps.powerups[PW_HASTE] ) { - client->ps.speed *= 1.3; - }*/ - - // Let go of the hook if we aren't firing - if ( client->ps.weapon == WP_GRAPPLING_HOOK && - client->hook && !( ucmd->buttons & BUTTON_ATTACK ) ) { - Weapon_HookFree(client->hook); - } - - //TA: torch stuff - if( client->torch == NULL && BG_activated( UP_TORCH, client->ps.stats ) ) - { - light = G_Spawn( ); - light->s.eType = ET_TORCH; - light->r.ownerNum = ent->s.number; - light->parent = ent; - client->torch = light; - } - else if( client->torch != NULL && !BG_activated( UP_TORCH, client->ps.stats ) ) - { - G_FreeEntity( client->torch ); - trap_LinkEntity( client->torch ); - client->torch = NULL; - } - - - if( client->torch != NULL ) - ShineTorch( client->torch ); - - // set up for pmove - oldEventSequence = client->ps.eventSequence; - - memset (&pm, 0, sizeof(pm)); - - //TA: gauntlet is a NULL weapon to be given to builder classes - // check for the hit-scan gauntlet, don't let the action - // go through as an attack unless it actually hits something - /*if ( client->ps.weapon == WP_GAUNTLET && !( ucmd->buttons & BUTTON_TALK ) && - ( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) { - pm.gauntletHit = CheckGauntletAttack( ent ); - }*/ - pm.gauntletHit = qfalse; - - if ( ent->flags & FL_FORCE_GESTURE ) { - ent->flags &= ~FL_FORCE_GESTURE; - ent->client->pers.cmd.buttons |= BUTTON_GESTURE; - } - - pm.ps = &client->ps; - pm.cmd = *ucmd; - if ( pm.ps->pm_type == PM_DEAD ) { - pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; - } - else if ( ent->r.svFlags & SVF_BOT ) { - pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP; - } - else { - pm.tracemask = MASK_PLAYERSOLID; - } - pm.trace = trap_Trace; - pm.pointcontents = trap_PointContents; - pm.debugLevel = g_debugMove.integer; - pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0; - - pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed; - pm.pmove_msec = pmove_msec.integer; - - VectorCopy( client->ps.origin, client->oldOrigin ); - - Pmove (&pm); - - // save results of pmove - if ( ent->client->ps.eventSequence != oldEventSequence ) { - ent->eventTime = level.time; - } - if (g_smoothClients.integer) { - BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); - } - else { - BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); - } - if ( !( ent->client->ps.eFlags & EF_FIRING ) ) { - client->fireHeld = qfalse; // for grapple - } - - // use the snapped origin for linking so it matches client predicted versions - VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin ); - - VectorCopy (pm.mins, ent->r.mins); - VectorCopy (pm.maxs, ent->r.maxs); - - ent->waterlevel = pm.waterlevel; - ent->watertype = pm.watertype; - - // execute client events - ClientEvents( ent, oldEventSequence ); - - // link entity now, after any personal teleporters have been used - trap_LinkEntity (ent); - if ( !ent->client->noclip ) { - G_TouchTriggers( ent ); - } - - // NOTE: now copy the exact origin over otherwise clients can be snapped into solid - VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); - - //test for solid areas in the AAS file - //TA: rip bots - //BotTestSolid(ent->r.currentOrigin); - - // touch other objects - ClientImpacts( ent, &pm ); - - // save results of triggers and client events - if (ent->client->ps.eventSequence != oldEventSequence) { - ent->eventTime = level.time; - } - - // swap and latch button actions - client->oldbuttons = client->buttons; - client->buttons = ucmd->buttons; - client->latched_buttons |= client->buttons & ~client->oldbuttons; - - // check for respawning - if ( client->ps.stats[STAT_HEALTH] <= 0 ) { - // wait for the attack button to be pressed - if ( level.time > client->respawnTime ) { - // forcerespawn is to prevent users from waiting out powerups - if ( g_forcerespawn.integer > 0 && - ( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) { - respawn( ent ); - return; - } - - // pressing attack or use is the normal respawn method - if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) { - respawn( ent ); - } - } - return; - } - - // perform once-a-second actions - ClientTimerActions( ent, msec ); -} - -/* -================== -ClientThink - -A new command has arrived from the client -================== -*/ -void ClientThink( int clientNum ) { - gentity_t *ent; - - ent = g_entities + clientNum; - trap_GetUsercmd( clientNum, &ent->client->pers.cmd ); - - // mark the time we got info, so we can display the - // phone jack if they don't get any for a while - ent->client->lastCmdTime = level.time; - - if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) { - ClientThink_real( ent ); - } -} - - -void G_RunClient( gentity_t *ent ) { - if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) { - return; - } - ent->client->pers.cmd.serverTime = level.time; - ClientThink_real( ent ); -} - - -/* -================== -SpectatorClientEndFrame - -================== -*/ -void SpectatorClientEndFrame( gentity_t *ent ) { - gclient_t *cl; - - // if we are doing a chase cam or a remote view, grab the latest info - if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { - int clientNum, flags; - - clientNum = ent->client->sess.spectatorClient; - - // team follow1 and team follow2 go to whatever clients are playing - if ( clientNum == -1 ) { - clientNum = level.follow1; - } else if ( clientNum == -2 ) { - clientNum = level.follow2; - } - if ( clientNum >= 0 ) { - cl = &level.clients[ clientNum ]; - if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) { - flags = (cl->ps.eFlags & ~(EF_VOTED | EF_TEAMVOTED)) | (ent->client->ps.eFlags & (EF_VOTED | EF_TEAMVOTED)); - ent->client->ps = cl->ps; - ent->client->ps.pm_flags |= PMF_FOLLOW; - ent->client->ps.eFlags = flags; - return; - } else { - // drop them to free spectators unless they are dedicated camera followers - if ( ent->client->sess.spectatorClient >= 0 ) { - ent->client->sess.spectatorState = SPECTATOR_FREE; - ClientBegin( ent->client - level.clients ); - } - } - } - } - - if ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { - ent->client->ps.pm_flags |= PMF_SCOREBOARD; - } else { - ent->client->ps.pm_flags &= ~PMF_SCOREBOARD; - } -} - -/* -============== -ClientEndFrame - -Called at the end of each server frame for each connected client -A fast client will have multiple ClientThink for each ClientEdFrame, -while a slow client may have multiple ClientEndFrame between ClientThink. -============== -*/ -void ClientEndFrame( gentity_t *ent ) { - int i; - clientPersistant_t *pers; - - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - SpectatorClientEndFrame( ent ); - return; - } - - pers = &ent->client->pers; - - // turn off any expired powerups - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ent->client->ps.powerups[ i ] < level.time ) { - ent->client->ps.powerups[ i ] = 0; - } - } - - // save network bandwidth -#if 0 - if ( !g_synchronousClients->integer && ent->client->ps.pm_type == PM_NORMAL ) { - // FIXME: this must change eventually for non-sync demo recording - VectorClear( ent->client->ps.viewangles ); - } -#endif - - // - // If the end of unit layout is displayed, don't give - // the player any normal movement attributes - // - if ( level.intermissiontime ) { - return; - } - - // burn from lava, etc - P_WorldEffects (ent); - - // apply all the damage taken this frame - P_DamageFeedback (ent); - - // add the EF_CONNECTION flag if we haven't gotten commands recently - if ( level.time - ent->client->lastCmdTime > 1000 ) { - ent->s.eFlags |= EF_CONNECTION; - } else { - ent->s.eFlags &= ~EF_CONNECTION; - } - - ent->client->ps.stats[STAT_HEALTH] = ent->health; // FIXME: get rid of ent->health... - - G_SetClientSound (ent); - - // set the latest infor - if (g_smoothClients.integer) { - BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); - } - else { - BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); - } - - // set the bit for the reachability area the client is currently in - // i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin ); - // ent->client->areabits[i >> 3] |= 1 << (i & 7); -} - - diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c deleted file mode 100644 index c8b8ab55..00000000 --- a/src/game/g_buildable.c +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - - -/* -================ -nullDieFunction - -hack to prevent compilers complaining about function pointer -> NULL conversion -================ -*/ -void nullDieFunction( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ -} - - -/* -================ -DSpawn_Melt - -Called when an droid spawn dies -================ -*/ -void DSpawn_Melt( gentity_t *self ) -{ - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, 2, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - if( ( self->timestamp + 10000 ) > level.time ) - { - self->nextthink = level.time + 500; - trap_LinkEntity( self ); - } - else - G_FreeEntity( self ); - - //update spawn counts - CalculateRanks( ); -} - -/* -================ -DSpawn_Die - -Called when an droid spawn dies -================ -*/ -void DSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[0] = dir[1] = 0; - dir[2] = 1; - - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - self->s.modelindex = 0; //don't draw the model once its destroyed - G_AddEvent( self, EV_GIB_GENERIC, DirToByte( dir ) ); - self->r.contents = CONTENTS_TRIGGER; - self->timestamp = level.time; - self->die = nullDieFunction; - self->think = DSpawn_Melt; - self->nextthink = level.time + 500; //wait .5 seconds before damaging others - - trap_LinkEntity( self ); -} - - -/* -================ -DDef1_Die - -Called when an droid spawn dies -================ -*/ -void DDef1_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[0] = dir[1] = 0; - dir[2] = 1; - - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - self->s.modelindex = 0; //don't draw the model once its destroyed - G_AddEvent( self, EV_GIB_GENERIC, DirToByte( dir ) ); - self->r.contents = CONTENTS_TRIGGER; - self->timestamp = level.time; - self->freeAfterEvent = qtrue; - self->die = nullDieFunction; -} - - -/* -================ -DSpawn_Think - -think function for Droid Spawn -================ -*/ -void DSpawn_Think( gentity_t *self ) -{ - if( self->parentNode == NULL ) - self->parentNode = createCreepNode( self->s.origin ); - - self->nextthink = level.time + 100; -} - - -/* -================ -DDef1_Think - -think function for Droid Spawn -================ -*/ -void DDef1_Think( gentity_t *self ) -{ - int i; - gentity_t *ent; - gentity_t *closestSpawn; - int distance = 0; - int minDistance = 10000; - vec3_t temp_v; - vec3_t dir = { 0, 0, 1 }; //up - - if( ( self->parentNode == NULL ) || !self->parentNode->inuse ) - { - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( !Q_stricmp( ent->classname, "team_droid_spawn" ) ) - { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - if( distance < minDistance ) - { - closestSpawn = ent; - minDistance = distance; - } - } - } - - if( minDistance <= CREEP_BASESIZE ) - self->parentNode = closestSpawn; - else - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - } - - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - self->nextthink = level.time + 100; -} - -//TA: the following defense turret code was written by -// "fuzzysteve" (fuzzysteve@quakefiles.com) and -// Anthony "inolen" Pesch (www.inolen.com) -//with modifications by me of course :) -#define HDEF1_RANGE 500 -#define HDEF1_ANGULARSPEED 15 -#define HDEF1_FIRINGSPEED 200 -#define HDEF1_ACCURACYTOLERANCE 10 -#define HDEF1_VERTICALCAP 20 - -/* -================ -hdef1_trackenemy - -Used by HDef1_Think to track enemy location -================ -*/ -qboolean hdef1_trackenemy( gentity_t *self ) -{ - vec3_t dirToTarget, angleToTarget, angularDiff; - - VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); - VectorNormalize( dirToTarget ); - vectoangles( dirToTarget, angleToTarget ); - - angularDiff[ PITCH ] = AngleSubtract( self->turloc[ PITCH ], angleToTarget[ PITCH ] ); - angularDiff[ YAW ] = AngleSubtract( self->turloc[ YAW ], angleToTarget[ YAW ] ); - - if( angularDiff[ PITCH ] < -HDEF1_ACCURACYTOLERANCE ) - self->turloc[ PITCH ] += HDEF1_ANGULARSPEED; - else if( angularDiff[ PITCH ] > HDEF1_ACCURACYTOLERANCE ) - self->turloc[ PITCH ] -= HDEF1_ANGULARSPEED; - else - self->turloc[ PITCH ] = angleToTarget[ PITCH ]; - - if( self->turloc[ PITCH ] < -HDEF1_VERTICALCAP ) - self->turloc[ PITCH ] = -HDEF1_VERTICALCAP; - - if( self->turloc[ PITCH ] > HDEF1_VERTICALCAP ) - self->turloc[ PITCH ] = HDEF1_VERTICALCAP; - - if( angularDiff[ YAW ] < -HDEF1_ACCURACYTOLERANCE ) - self->turloc[ YAW ] += HDEF1_ANGULARSPEED; - else if( angularDiff[ YAW ] > HDEF1_ACCURACYTOLERANCE ) - self->turloc[ YAW ] -= HDEF1_ANGULARSPEED; - else - self->turloc[ YAW ] = angleToTarget[ YAW ]; - - VectorCopy( self->turloc, self->s.angles2 ); - - trap_LinkEntity( self ); - - if( abs( angleToTarget[ YAW ] - self->turloc[ YAW ] ) <= HDEF1_ACCURACYTOLERANCE && - abs( angleToTarget[ PITCH ] - self->turloc[ PITCH ] ) <= HDEF1_ACCURACYTOLERANCE ) - return qtrue; - - return qfalse; -} - -/* -================ -hdef1_fireonemeny - -Used by HDef1_Think to fire at enemy -================ -*/ -void hdef1_fireonenemy( gentity_t *self ) -{ - vec3_t aimVector; - - AngleVectors( self->turloc, aimVector, NULL, NULL ); - //fire_flamer( self, self->s.pos.trBase, aimVector ); - fire_plasma( self, self->s.pos.trBase, aimVector ); - G_AddEvent( self, EV_FIRE_WEAPON, 0 ); - self->count = level.time + HDEF1_FIRINGSPEED; -} - -/* -================ -hdef1_checktarget - -Used by HDef1_Think to check enemies for validity -================ -*/ -qboolean hdef1_checktarget(gentity_t *self, gentity_t *target) -{ - vec3_t distance; - trace_t trace; - - if( !target ) // Do we have a target? - return qfalse; - if( !target->inuse ) // Does the target still exist? - return qfalse; - if( target == self ) // is the target us? - return qfalse; - if( !target->client ) // is the target a bot or player? - return qfalse; - if( target->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) // is the target one of us? - return qfalse; - if( target->client->sess.sessionTeam == TEAM_SPECTATOR ) // is the target alive? - return qfalse; - if( target->health <= 0 ) // is the target still alive? - return qfalse; - - VectorSubtract( target->r.currentOrigin, self->r.currentOrigin, distance ); - if( VectorLength( distance ) > HDEF1_RANGE ) // is the target within range? - return qfalse; - - trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT ); - if ( trace.contents & CONTENTS_SOLID ) // can we see the target? - return qfalse; - - return qtrue; -} - - -/* -================ -hdef1_findenemy - -Used by HDef1_Think to locate enemy gentities -================ -*/ -void hdef1_findenemy( gentity_t *ent ) -{ - gentity_t *target; - - target = g_entities; - - for (; target < &g_entities[ level.num_entities ]; target++) - { - if( !hdef1_checktarget( ent, target ) ) - continue; - - ent->enemy = target; - return; - } - - ent->enemy = NULL; -} - - -/* -================ -HDef1_Think - -think function for Human Defense -================ -*/ -void HDef1_Think( gentity_t *self ) -{ - self->nextthink = level.time + 50; - - if( !hdef1_checktarget( self, self->enemy) ) - hdef1_findenemy( self ); - if( !self->enemy ) - return; - - if( hdef1_trackenemy( self ) && ( self->count < level.time ) ) - hdef1_fireonenemy( self ); -} - - -/* -================ -HSpawn_blast - -Called when a human spawn explodes -think function -================ -*/ -void HSpawn_Blast( gentity_t *self ) -{ - G_RadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath ); - - G_FreeEntity( self ); - trap_LinkEntity( self ); - - //update spawn counts - CalculateRanks( ); -} - - -/* -================ -HSpawn_die - -Called when a human spawn dies -================ -*/ -void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[0] = dir[1] = 0; - dir[2] = 1; - - self->s.modelindex = 0; //don't draw the model once its destroyed - G_AddEvent( self, EV_ITEM_EXPLOSION, DirToByte( dir ) ); - self->r.contents = CONTENTS_TRIGGER; - self->timestamp = level.time; - self->die = nullDieFunction; - self->think = HSpawn_Blast; - self->nextthink = level.time + 1000; //wait 1.5 seconds before damaging others - - trap_LinkEntity( self ); -} - - -/* -================ -itemFits - -Checks to see if an item fits in a specific area -================ -*/ -qboolean itemFits( gentity_t *ent, gitem_t *item, int distance ) -{ - vec3_t forward; - vec3_t angles; - vec3_t player_origin, entity_origin; - vec3_t mins, maxs; - vec3_t temp_v; - trace_t tr1, tr2; - int i; - gentity_t *creepent; - qboolean creeptest; - qboolean nearcreep = qfalse; - - VectorCopy( ent->s.apos.trBase, angles ); - angles[PITCH] = 0; // always forward - - AngleVectors( angles, forward, NULL, NULL ); - VectorCopy( ent->s.pos.trBase, player_origin ); - VectorMA( player_origin, distance, forward, entity_origin ); - - if( !Q_stricmp( item->classname, "team_droid_spawn" ) ) - { - creeptest = qfalse; - VectorSet( mins, -15, -15, -15 ); - VectorSet( maxs, 15, 15, 15 ); - } - else if( !Q_stricmp( item->classname, "team_droid_def1" ) ) - { - creeptest = qtrue; - VectorSet( mins, -15, -15, -15 ); - VectorSet( maxs, 15, 15, 15 ); - } - else if( !Q_stricmp( item->classname, "team_human_spawn" ) ) - { - creeptest = qfalse; - VectorSet( mins, -40, -40, -4 ); - VectorSet( maxs, 40, 40, 4 ); - } - else if( !Q_stricmp( item->classname, "team_human_def1" ) ) - { - creeptest = qfalse; - VectorSet( mins, -24, -24, -11 ); - VectorSet( maxs, 24, 24, 11 ); - } - else if( !Q_stricmp( item->classname, "team_human_mcu" ) ) - { - creeptest = qfalse; - VectorSet( mins, -15, -15, -15 ); - VectorSet( maxs, 15, 15, 15 ); - } - - trap_Trace( &tr1, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_PLAYERSOLID ); - trap_Trace( &tr2, player_origin, NULL, NULL, entity_origin, ent->s.number, MASK_PLAYERSOLID ); - - if( creeptest ) - { - for ( i = 1, creepent = g_entities + i; i < level.num_entities; i++, creepent++ ) - { - if( !Q_stricmp( creepent->classname, "team_droid_spawn" ) ) - { - VectorSubtract( entity_origin, creepent->s.origin, temp_v ); - if( VectorLength( temp_v ) <= CREEP_BASESIZE ) - { - nearcreep = qtrue; - break; - } - } - } - } - else - nearcreep = qtrue; - - if( tr1.fraction >= 1.0 && tr2.fraction >= 1.0 && nearcreep ) - return qtrue; - else - return qfalse; -} - - -/* -================ -Build_Item - -Spawns an item and tosses it forward -================ -*/ -gentity_t *Build_Item( gentity_t *ent, gitem_t *item, int distance ) { - vec3_t forward; - vec3_t angles; - vec3_t origin; - gentity_t *built; - - VectorCopy( ent->s.apos.trBase, angles ); - angles[PITCH] = 0; // always forward - - AngleVectors( angles, forward, NULL, NULL ); - VectorCopy( ent->s.pos.trBase, origin ); - VectorMA( origin, distance, forward, origin ); - - built = G_Spawn(); - - built->s.eType = ET_BUILDABLE; - built->s.modelindex = item - bg_itemlist; // store item number in modelindex - - built->classname = item->classname; - built->item = item; - - if( !Q_stricmp( item->classname, "team_droid_spawn" ) ) - { - VectorSet( built->r.mins, -15, -15, -15 ); - VectorSet( built->r.maxs, 15, 15, 15 ); - - built->biteam = BIT_DROIDS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 50; - built->splashRadius = 200; - built->splashMethodOfDeath = MOD_ASPAWN; - built->s.modelindex2 = BIT_DROIDS; - G_AddEvent( built, EV_ITEM_GROW, 0 ); - //built->touch = ASpawn_Touch; - built->die = DSpawn_Die; - //built->pain = ASpawn_Pain; - built->think = DSpawn_Think; - built->nextthink = level.time + 100; - } - else if( !Q_stricmp( item->classname, "team_droid_def1" ) ) - { - VectorSet( built->r.mins, -15, -15, -15 ); - VectorSet( built->r.maxs, 15, 15, 15 ); - - built->biteam = BIT_DROIDS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 20; - built->splashRadius = 50; - built->splashMethodOfDeath = MOD_ASPAWN; - built->s.modelindex2 = BIT_DROIDS; - G_AddEvent( built, EV_ITEM_GROW, 0 ); - //built->touch = ASpawn_Touch; - built->die = DDef1_Die; - //built->pain = ASpawn_Pain; - built->think = DDef1_Think; - built->nextthink = level.time + 100; - } - else if( !Q_stricmp( item->classname, "team_human_spawn" ) ) - { - VectorSet( built->r.mins, -40, -40, -4 ); - VectorSet( built->r.maxs, 40, 40, 4 ); - - built->biteam = BIT_HUMANS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 50; - built->splashRadius = 150; - built->splashMethodOfDeath = MOD_HSPAWN; - built->s.modelindex2 = BIT_HUMANS; - //built->touch = HSpawn_Touch; - //built->think = HSpawn_Think; - //built->nextthink = level.time + 1000; - built->die = HSpawn_Die; - //built->pain = HSpawn_Pain; - } - else if( !Q_stricmp( item->classname, "team_human_def1" ) ) - { - VectorSet( built->r.mins, -24, -24, -11 ); - VectorSet( built->r.maxs, 24, 24, 11 ); - - built->biteam = BIT_HUMANS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 20; - built->splashRadius = 50; - built->splashMethodOfDeath = MOD_HSPAWN; - built->s.modelindex2 = BIT_HUMANS; - //built->touch = ASpawn_Touch; - built->die = HSpawn_Die; - //built->pain = ASpawn_Pain; - built->think = HDef1_Think; - built->enemy = NULL; - built->nextthink = level.time + 50; - } - else if( !Q_stricmp( item->classname, "team_human_mcu" ) ) - { - VectorSet( built->r.mins, -15, -15, -15 ); - VectorSet( built->r.maxs, 15, 15, 15 ); - - built->biteam = BIT_HUMANS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 50; - built->splashRadius = 150; - built->splashMethodOfDeath = MOD_HSPAWN; - built->s.modelindex2 = BIT_HUMANS; - //built->touch = HSpawn_Touch; - //built->think = HSpawn_Think; - //built->nextthink = level.time + 1000; - built->die = HSpawn_Die; - //built->pain = HSpawn_Pain; - } - - built->s.number = built - g_entities; - built->r.contents = CONTENTS_BODY; - built->clipmask = MASK_PLAYERSOLID; - - G_SetOrigin( built, origin ); - VectorCopy( angles, built->s.angles ); - built->turloc[ YAW ] = built->s.angles2[ YAW ] = angles[ YAW ]; - VectorCopy( origin, built->s.origin ); - built->s.pos.trType = TR_GRAVITY; - built->s.pos.trTime = level.time; - - //update spawn counts - CalculateRanks( ); - - trap_LinkEntity (built); - - return built; -} - diff --git a/src/game/g_client.c b/src/game/g_client.c deleted file mode 100644 index af9fdee7..00000000 --- a/src/game/g_client.c +++ /dev/null @@ -1,1543 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - -// g_client.c -- client functions that don't happen every frame - -static vec3_t playerMins = {-15, -15, -24}; -static vec3_t playerMaxs = {15, 15, 32}; - -/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial -potential spawning position for deathmatch games. -The first time a player enters the game, they will be at an 'initial' spot. -Targets will be fired when someone spawns in on them. -"nobots" will prevent bots from using this spot. -"nohumans" will prevent non-bots from using this spot. -*/ -void SP_info_player_deathmatch( gentity_t *ent ) { - int i; - - G_SpawnInt( "nobots", "0", &i); - if ( i ) { - ent->flags |= FL_NO_BOTS; - } - G_SpawnInt( "nohumans", "0", &i ); - if ( i ) { - ent->flags |= FL_NO_HUMANS; - } -} - -/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32) -equivelant to info_player_deathmatch -*/ -void SP_info_player_start(gentity_t *ent) { - ent->classname = "info_player_deathmatch"; - SP_info_player_deathmatch( ent ); -} - -/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_player_intermission( gentity_t *ent ) { - -} - -/*QUAKED info_droid_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_droid_intermission( gentity_t *ent ) { - -} - -/*QUAKED info_human_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_human_intermission( gentity_t *ent ) { - -} - - - -/* -======================================================================= - - SelectSpawnPoint - -======================================================================= -*/ - -/* -================ -SpotWouldTelefrag - -================ -*/ -qboolean SpotWouldTelefrag( gentity_t *spot ) { - int i, num; - int touch[MAX_GENTITIES]; - gentity_t *hit; - vec3_t mins, maxs; - - VectorAdd( spot->s.origin, playerMins, mins ); - VectorAdd( spot->s.origin, playerMaxs, maxs ); - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - for (i=0 ; iclient && hit->client->ps.stats[STAT_HEALTH] > 0 ) { - if( hit->client ) { - return qtrue; - } - - } - - return qfalse; -} - -/* -================ -SelectNearestDeathmatchSpawnPoint - -Find the spot that we DON'T want to use -================ -*/ -#define MAX_SPAWN_POINTS 128 -gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) { - gentity_t *spot; - vec3_t delta; - float dist, nearestDist; - gentity_t *nearestSpot; - - nearestDist = 999999; - nearestSpot = NULL; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - - VectorSubtract( spot->s.origin, from, delta ); - dist = VectorLength( delta ); - if ( dist < nearestDist ) { - nearestDist = dist; - nearestSpot = spot; - } - } - - return nearestSpot; -} - - -/* -================ -SelectRandomDeathmatchSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -#define MAX_SPAWN_POINTS 128 -gentity_t *SelectRandomDeathmatchSpawnPoint( void ) { - gentity_t *spot; - int count; - int selection; - gentity_t *spots[MAX_SPAWN_POINTS]; - - count = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { - continue; - } - spots[ count ] = spot; - count++; - } - - if ( !count ) { // no spots that won't telefrag - return G_Find( NULL, FOFS(classname), "info_player_deathmatch"); - } - - selection = rand() % count; - return spots[ selection ]; -} - - -/* -=========== -SelectRandomFurthestSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { - gentity_t *spot; - vec3_t delta; - float dist; - float list_dist[64]; - gentity_t *list_spot[64]; - int numSpots, rnd, i, j; - - numSpots = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { - continue; - } - VectorSubtract( spot->s.origin, avoidPoint, delta ); - dist = VectorLength( delta ); - for (i = 0; i < numSpots; i++) { - if ( dist > list_dist[i] ) { - if ( numSpots >= 64 ) - numSpots = 64-1; - for (j = numSpots; j > i; j--) { - list_dist[j] = list_dist[j-1]; - list_spot[j] = list_spot[j-1]; - } - list_dist[i] = dist; - list_spot[i] = spot; - numSpots++; - if (numSpots > 64) - numSpots = 64; - break; - } - } - if (i >= numSpots && numSpots < 64) { - list_dist[numSpots] = dist; - list_spot[numSpots] = spot; - numSpots++; - } - } - if (!numSpots) { - spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch"); - if (!spot) - G_Error( "Couldn't find a spawn point" ); - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - return spot; - } - - // select a random spot from the spawn points furthest away - rnd = random() * (numSpots / 2); - - VectorCopy (list_spot[rnd]->s.origin, origin); - origin[2] += 9; - VectorCopy (list_spot[rnd]->s.angles, angles); - - return list_spot[rnd]; -} - - -/* -================ -SelectDroidSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -gentity_t *SelectDroidSpawnPoint( void ) { - gentity_t *spot; - int count; - int selection; - gentity_t *spots[MAX_SPAWN_POINTS]; - - count = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "team_droid_spawn")) != NULL) { - if ( SpotWouldTelefrag( spot ) || ( spot->health <= 0 ) ) { - continue; - } - spots[ count ] = spot; - count++; - } - - if ( !count ) { // no spots that won't telefrag - spot = G_Find( NULL, FOFS(classname), "team_droid_spawn"); - if( spot->health > 0 ) - return spot; - else - return NULL; - - } - - selection = rand() % count; - return spots[ selection ]; -} - - -/* -================ -SelectHumanSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -gentity_t *SelectHumanSpawnPoint( void ) { - gentity_t *spot; - int count; - int selection; - gentity_t *spots[MAX_SPAWN_POINTS]; - - count = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "team_human_spawn")) != NULL) { - if ( SpotWouldTelefrag( spot ) || ( spot->health <= 0 ) ) { - continue; - } - spots[ count ] = spot; - count++; - } - - if ( !count ) { // no spots that won't telefrag - spot = G_Find( NULL, FOFS(classname), "team_human_spawn"); - if( spot->health > 0 ) - return spot; - else - return NULL; - } - - selection = rand() % count; - return spots[ selection ]; -} - - -/* -=========== -SelectSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { - return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles ); - - /* - gentity_t *spot; - gentity_t *nearestSpot; - - nearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint ); - - spot = SelectRandomDeathmatchSpawnPoint ( ); - if ( spot == nearestSpot ) { - // roll again if it would be real close to point of death - spot = SelectRandomDeathmatchSpawnPoint ( ); - if ( spot == nearestSpot ) { - // last try - spot = SelectRandomDeathmatchSpawnPoint ( ); - } - } - - // find a single player start spot - if (!spot) { - G_Error( "Couldn't find a spawn point" ); - } - - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - - return spot; - */ -} - - -/* -=========== -SelectTremulousSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectTremulousSpawnPoint( int team, vec3_t origin, vec3_t angles ) -{ - gentity_t *spot; - - if( team == PTE_DROIDS ) - spot = SelectDroidSpawnPoint( ); - else if( team == PTE_HUMANS ) - spot = SelectHumanSpawnPoint( ); - - //no available spots - if( !spot ) - { - return NULL; - } - - // find a single player start spot - if (!spot) { - //G_Error( "Couldn't find a spawn point" ); - } - - //TA: why isn't spot->s.origin being set? - VectorCopy (spot->s.pos.trBase, origin); - VectorCopy (spot->s.angles, angles); - - if( team == PTE_DROIDS ) - origin[2] += 40; - else if( team == PTE_HUMANS ) - origin[2] += 29; - - return spot; - -} - - -/* -=========== -SelectInitialSpawnPoint - -Try to find a spawn point marked 'initial', otherwise -use normal spawn selection. -============ -*/ -gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) { - gentity_t *spot; - - spot = NULL; - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( spot->spawnflags & 1 ) { - break; - } - } - - if ( !spot || SpotWouldTelefrag( spot ) ) { - return SelectSpawnPoint( vec3_origin, origin, angles ); - } - - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - - return spot; -} - -/* -=========== -SelectSpectatorSpawnPoint - -============ -*/ -gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) { - FindIntermissionPoint(); - - VectorCopy( level.intermission_origin, origin ); - VectorCopy( level.intermission_angle, angles ); - - return NULL; -} - - -/* -=========== -SelectDroidLockSpawnPoint - -Try to find a spawn point for droid intermission otherwise -use normal intermission spawn. -============ -*/ -gentity_t *SelectDroidLockSpawnPoint( vec3_t origin, vec3_t angles ) { - gentity_t *spot; - - spot = NULL; - spot = G_Find (spot, FOFS(classname), "info_droid_intermission"); - - if ( !spot ) { - return SelectSpectatorSpawnPoint( origin, angles ); - } - - VectorCopy (spot->s.origin, origin); - VectorCopy (spot->s.angles, angles); - - return spot; -} - - -/* -=========== -SelectHumanLockSpawnPoint - -Try to find a spawn point for human intermission otherwise -use normal intermission spawn. -============ -*/ -gentity_t *SelectHumanLockSpawnPoint( vec3_t origin, vec3_t angles ) { - gentity_t *spot; - - spot = NULL; - spot = G_Find (spot, FOFS(classname), "info_human_intermission"); - - if ( !spot ) { - return SelectSpectatorSpawnPoint( origin, angles ); - } - - VectorCopy (spot->s.origin, origin); - VectorCopy (spot->s.angles, angles); - - return spot; -} - - -/* -======================================================================= - -BODYQUE - -======================================================================= -*/ - -#if BODY_QUEUE_SIZE -/* -=============== -InitBodyQue -=============== -*/ -void InitBodyQue (void) { - int i; - gentity_t *ent; - - level.bodyQueIndex = 0; - for (i=0; iclassname = "bodyque"; - ent->neverFree = qtrue; - level.bodyQue[i] = ent; - } -} -#endif - -/* -============= -BodySink - -After sitting around for five seconds, fall into the ground and dissapear -============= -*/ -void BodySink( gentity_t *ent ) { - if ( level.time - ent->timestamp > 6500 ) { - // the body ques are never actually freed, they are just unlinked - trap_UnlinkEntity( ent ); - ent->physicsObject = qfalse; - return; - } - ent->nextthink = level.time + 100; - ent->s.pos.trBase[2] -= 1; -} - -/* -============= -CopyToBodyQue - -A player is respawning, so make an entity that looks -just like the existing corpse to leave behind. -============= -*/ -void CopyToBodyQue( gentity_t *ent ) { - gentity_t *body; - int contents; - - //TA: not really the place for this.. but hey.. - if( ent->client->torch != NULL && BG_activated( UP_TORCH, ent->client->ps.stats ) ) - { - G_FreeEntity( ent->client->torch ); - trap_UnlinkEntity( ent->client->torch ); - ent->client->torch = NULL; - } - - trap_UnlinkEntity (ent); - - // if client is in a nodrop area, don't leave the body - contents = trap_PointContents( ent->s.origin, -1 ); - if ( contents & CONTENTS_NODROP ) { - return; - } - - body = G_Spawn( ); - body->classname = "corpse"; - body->s = ent->s; - body->r.s = body->s; - body->s.eFlags = EF_DEAD; - body->s.eType = ET_CORPSE; - body->s.number = body - g_entities; - body->timestamp = level.time; - body->physicsObject = qtrue; - body->s.event = 0; - body->r.contents = CONTENTS_BODY; - body->clipmask = MASK_PLAYERSOLID; - - switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) { - case BOTH_DEATH1: - case BOTH_DEAD1: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1; - break; - case BOTH_DEATH2: - case BOTH_DEAD2: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2; - break; - case BOTH_DEATH3: - case BOTH_DEAD3: - default: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3; - break; - } - - //body->die = body_die; - - // don't take more damage if already gibbed - if ( ent->health <= GIB_HEALTH ) { - body->takedamage = qfalse; - } else { - body->takedamage = qtrue; - } - - //make the make player entity disappear - ent->takedamage = qfalse; - ent->s.eType = ET_INVISIBLE; - ent->r.contents = 0; - ent->s.solid = 0; - ent->r.s.solid = 0; - body->health = ent->health = ent->client->ps.stats[STAT_HEALTH]; - ent->health = ent->client->ps.stats[STAT_HEALTH] = GIB_HEALTH - 1; - - //FIXME: change body dimensions - VectorSet( body->r.mins, -15, -15, -15 ); - VectorSet( body->r.maxs, 15, 15, 15 ); - VectorSet( body->r.absmin, -15, -15, -15 ); - VectorSet( body->r.absmax, 15, 15, 15 ); - - if ( body->s.groundEntityNum == ENTITYNUM_NONE ) - { - body->s.pos.trType = TR_GRAVITY; - body->s.pos.trTime = level.time; - VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta ); - } - else - { - body->s.pos.trType = TR_STATIONARY; - } - - body->s.pos.trTime = level.time; - - VectorCopy ( body->s.pos.trBase, body->r.currentOrigin ); - trap_LinkEntity( body ); - -} - -//====================================================================== - - -/* -================== -SetClientViewAngle - -================== -*/ -void SetClientViewAngle( gentity_t *ent, vec3_t angle ) { - int i; - - // set the delta angle - for (i=0 ; i<3 ; i++) { - int cmdAngle; - - cmdAngle = ANGLE2SHORT(angle[i]); - ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i]; - } - VectorCopy( angle, ent->s.angles ); - VectorCopy (ent->s.angles, ent->client->ps.viewangles); -} - -/* -================ -respawn -================ -*/ -void respawn( gentity_t *ent ) { - gentity_t *tent; - - CopyToBodyQue (ent); - - //TA: Clients can't respawn - they must go thru the class cmd - ClientSpawn(ent); - - //FIXME: need different spawn/respawn functions for different teams - - // add a teleportation effect - //tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN ); - //tent->s.clientNum = ent->s.clientNum; -} - -/* -================ -TeamCount - -Returns number of players on a team -================ -*/ -team_t TeamCount( int ignoreClientNum, int team ) { - int i; - int count = 0; - - for ( i = 0 ; i < level.maxclients ; i++ ) { - if ( i == ignoreClientNum ) { - continue; - } - if ( level.clients[i].pers.connected == CON_DISCONNECTED ) { - continue; - } - if ( level.clients[i].sess.sessionTeam == team ) { - count++; - } - } - - return count; -} - - -/* -================ -TeamLeader - -Returns the client number of the team leader -================ -*/ -int TeamLeader( int team ) { - int i; - - for ( i = 0 ; i < level.maxclients ; i++ ) { - if ( level.clients[i].pers.connected == CON_DISCONNECTED ) { - continue; - } - if ( level.clients[i].sess.sessionTeam == team ) { - if ( level.clients[i].sess.teamLeader ) - return i; - } - } - - return -1; -} - - -/* -================ -PickTeam - -================ -*/ -team_t PickTeam( int ignoreClientNum ) { - int counts[TEAM_NUM_TEAMS]; - - counts[TEAM_DROIDS] = TeamCount( ignoreClientNum, TEAM_DROIDS ); - counts[TEAM_HUMANS] = TeamCount( ignoreClientNum, TEAM_HUMANS ); - - if ( counts[TEAM_DROIDS] > counts[TEAM_HUMANS] ) { - return TEAM_HUMANS; - } - if ( counts[TEAM_HUMANS] > counts[TEAM_DROIDS] ) { - return TEAM_DROIDS; - } - // equal team count, so join the team with the lowest score - if ( level.teamScores[TEAM_DROIDS] > level.teamScores[TEAM_HUMANS] ) { - return TEAM_HUMANS; - } - return TEAM_DROIDS; -} - -/* -=========== -ForceClientSkin - -Forces a client's skin (for teamplay) -=========== -*/ -static void ForceClientSkin( gclient_t *client, char *model, const char *skin ) { - char *p; - - if ((p = Q_strrchr(model, '/')) != 0) { - *p = 0; - } - - Q_strcat(model, MAX_QPATH, "/"); - Q_strcat(model, MAX_QPATH, skin); -} - - -/* -=========== -ClientCheckName -============ -*/ -static void ClientCleanName( const char *in, char *out, int outSize ) { - int len, colorlessLen; - char ch; - char *p; - int spaces; - - //save room for trailing null byte - outSize--; - - len = 0; - colorlessLen = 0; - p = out; - *p = 0; - spaces = 0; - - while( 1 ) { - ch = *in++; - if( !ch ) { - break; - } - - // don't allow leading spaces - if( !*p && ch == ' ' ) { - continue; - } - - // check colors - if( ch == Q_COLOR_ESCAPE ) { - // solo trailing carat is not a color prefix - if( !*in ) { - break; - } - - // don't allow black in a name, period - if( ColorIndex(*in) == 0 ) { - in++; - continue; - } - - // make sure room in dest for both chars - if( len > outSize - 2 ) { - break; - } - - *out++ = ch; - *out++ = *in++; - len += 2; - continue; - } - - // don't allow too many consecutive spaces - if( ch == ' ' ) { - spaces++; - if( spaces > 3 ) { - continue; - } - } - else { - spaces = 0; - } - - if( len > outSize - 1 ) { - break; - } - - *out++ = ch; - colorlessLen++; - len++; - } - *out = 0; - - // don't allow empty names - if( *p == 0 || colorlessLen == 0 ) { - Q_strncpyz( p, "UnnamedPlayer", outSize ); - } -} - - -/* -=========== -ClientUserInfoChanged - -Called from ClientConnect when the player first connects and -directly by the server system when the player updates a userinfo variable. - -The game can override any of the settings and call trap_SetUserinfo -if desired. -============ -*/ -void ClientUserinfoChanged( int clientNum ) { - gentity_t *ent; - int teamTask, teamLeader, team, health; - char *s; - char model[MAX_QPATH]; - char oldname[MAX_STRING_CHARS]; - gclient_t *client; - char c1[MAX_INFO_STRING]; - char redTeam[MAX_INFO_STRING]; - char blueTeam[MAX_INFO_STRING]; - char userinfo[MAX_INFO_STRING]; - - ent = g_entities + clientNum; - client = ent->client; - - trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); - - // check for malformed or illegal info strings - if ( !Info_Validate(userinfo) ) { - strcpy (userinfo, "\\name\\badinfo"); - } - - // check for local client - s = Info_ValueForKey( userinfo, "ip" ); - if ( !strcmp( s, "localhost" ) ) { - client->pers.localClient = qtrue; - } - - // check the item prediction - s = Info_ValueForKey( userinfo, "cg_predictItems" ); - if ( !atoi( s ) ) { - client->pers.predictItemPickup = qfalse; - } else { - client->pers.predictItemPickup = qtrue; - } - - // set name - Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) ); - s = Info_ValueForKey (userinfo, "name"); - ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) ); - - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { - if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { - Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) ); - } - } - - if ( client->pers.connected == CON_CONNECTED ) { - if ( strcmp( oldname, client->pers.netname ) ) { - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, - client->pers.netname) ); - } - } - - // set max health - health = atoi( Info_ValueForKey( userinfo, "handicap" ) ); - client->pers.maxHealth = health; - if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { - client->pers.maxHealth = 100; - } - //client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; - - // set model - //Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); - switch( client->pers.pclass ) - { - case PCL_D_BASE: - Q_strncpyz( model, "klesk", sizeof( model ) ); - break; - case PCL_D_BUILDER: - Q_strncpyz( model, "lucy", sizeof( model ) ); - break; - case PCL_H_BASE: - Q_strncpyz( model, "sarge", sizeof( model ) ); - break; - default: - Q_strncpyz( model, "grunt", sizeof( model ) ); - } - - // team - switch( client->sess.sessionTeam ) { - case TEAM_HUMANS: - ForceClientSkin(client, model, "red"); - break; - case TEAM_DROIDS: - ForceClientSkin(client, model, "blue"); - break; - } - if ( g_gametype.integer >= GT_TEAM && client->sess.sessionTeam == TEAM_SPECTATOR ) { - // don't ever use a default skin in teamplay, it would just waste memory - ForceClientSkin(client, model, "red"); - } - - - - // teamInfo - s = Info_ValueForKey( userinfo, "teamoverlay" ); - if ( ! *s || atoi( s ) != 0 ) { - client->pers.teamInfo = qtrue; - } else { - client->pers.teamInfo = qfalse; - } - - // team task (0 = none, 1 = offence, 2 = defence) - teamTask = atoi(Info_ValueForKey(userinfo, "teamtask")); - // team Leader (1 = leader, 0 is normal player) - teamLeader = client->sess.teamLeader; - - // colors - strcpy(c1, Info_ValueForKey( userinfo, "color" )); - strcpy(redTeam, "humans"); - strcpy(blueTeam, "droids"); - - // send over a subset of the userinfo keys so other clients can - // print scoreboards, display models, and play custom sounds - if ( ent->r.svFlags & SVF_BOT ) { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", - client->pers.netname, client->sess.sessionTeam, model, model, c1, - client->pers.maxHealth, client->sess.wins, client->sess.losses, - Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader ); - } else { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", - client->pers.netname, client->sess.sessionTeam, model, model, redTeam, blueTeam, c1, - client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader); - } - - trap_SetConfigstring( CS_PLAYERS+clientNum, s ); - - G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); -} - - -/* -=========== -ClientConnect - -Called when a player begins connecting to the server. -Called again for every map change or tournement restart. - -The session information will be valid after exit. - -Return NULL if the client should be allowed, otherwise return -a string with the reason for denial. - -Otherwise, the client will be sent the current gamestate -and will eventually get to ClientBegin. - -firstTime will be qtrue the very first time a client connects -to the server machine, but qfalse on map changes and tournement -restarts. -============ -*/ -char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { - char *value; - gclient_t *client; - char userinfo[MAX_INFO_STRING]; - gentity_t *ent; - - ent = &g_entities[ clientNum ]; - - trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); - - // check to see if they are on the banned IP list - value = Info_ValueForKey (userinfo, "ip"); - if ( G_FilterPacket( value ) ) { - return "Banned."; - } - - // check for a password - value = Info_ValueForKey (userinfo, "password"); - if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) && - strcmp( g_password.string, value) != 0) { - return "Invalid password"; - } - - // they can connect - ent->client = level.clients + clientNum; - client = ent->client; - - memset( client, 0, sizeof(*client) ); - - client->pers.connected = CON_CONNECTING; - - // read or initialize the session data - if ( firstTime || level.newSession ) { - G_InitSessionData( client, userinfo ); - } - G_ReadSessionData( client ); - - //TA: rip bots - /*if( isBot ) { - ent->r.svFlags |= SVF_BOT; - ent->inuse = qtrue; - if( !G_BotConnect( clientNum, !firstTime ) ) { - return "BotConnectfailed"; - } - }*/ - - // get and distribute relevent paramters - G_LogPrintf( "ClientConnect: %i\n", clientNum ); - ClientUserinfoChanged( clientNum ); - - // don't do the "xxx connected" messages if they were caried over from previous level - if ( firstTime ) { - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname) ); - } - - if ( g_gametype.integer >= GT_TEAM && - client->sess.sessionTeam != TEAM_SPECTATOR ) { - BroadcastTeamChange( client, -1 ); - } - - // count current clients and rank for scoreboard - CalculateRanks(); - - return NULL; -} - -/* -=========== -ClientBegin - -called when a client has finished connecting, and is ready -to be placed into the level. This will happen every level load, -and on transition between teams, but doesn't happen on respawns -============ -*/ -void ClientBegin( int clientNum ) { - gentity_t *ent; - gclient_t *client; - gentity_t *tent; - int flags; - - ent = g_entities + clientNum; - - //TA: rip bots - /*if( ent->botDelayBegin ) { - G_QueueBotBegin( clientNum ); - ent->botDelayBegin = qfalse; - return; - }*/ - - client = level.clients + clientNum; - - if ( ent->r.linked ) { - trap_UnlinkEntity( ent ); - } - G_InitGentity( ent ); - ent->touch = 0; - ent->pain = 0; - ent->client = client; - - client->pers.connected = CON_CONNECTED; - client->pers.enterTime = level.time; - client->pers.teamState.state = TEAM_BEGIN; - - // save eflags around this, because changing teams will - // cause this to happen with a valid entity, and we - // want to make sure the teleport bit is set right - // so the viewpoint doesn't interpolate through the - // world to the new position - flags = client->ps.eFlags; - memset( &client->ps, 0, sizeof( client->ps ) ); - client->ps.eFlags = flags; - - // locate ent at a spawn point - - ClientSpawn( ent ); - - if ( client->sess.sessionTeam != TEAM_SPECTATOR ) { - // send event - tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN ); - tent->s.clientNum = ent->s.clientNum; - - if ( g_gametype.integer != GT_TOURNAMENT ) { - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname) ); - } - } - G_LogPrintf( "ClientBegin: %i\n", clientNum ); - - // count current clients and rank for scoreboard - CalculateRanks(); -} - -/* -=========== -ClientSpawn - -Called every time a client is placed fresh in the world: -after the first ClientBegin, and after each respawn -Initializes all non-persistant parts of playerState -============ -*/ -void ClientSpawn(gentity_t *ent) { - int index; - vec3_t spawn_origin, spawn_angles; - gclient_t *client; - int i; - clientPersistant_t saved; - clientSession_t savedSess; - int persistant[MAX_PERSISTANT]; - gentity_t *spawnPoint; - int flags; - int savedPing; - int ammoIndex, ammoSubIndex; - int teamLocal; - int accuracy_hits, accuracy_shots; - int savedEvents[MAX_PS_EVENTS]; - int eventSequence; - char userinfo[MAX_INFO_STRING]; - - index = ent - g_entities; - client = ent->client; - - teamLocal = client->pers.pteam; - - //TA: only start client if chosen a class and joined a team - if( client->pers.pclass == 0 && teamLocal == 0 ) - { - client->sess.sessionTeam = TEAM_SPECTATOR; - client->sess.spectatorState = SPECTATOR_FREE; - } - else if( client->pers.pclass == 0 ) - { - client->sess.sessionTeam = TEAM_SPECTATOR; - client->sess.spectatorState = SPECTATOR_LOCKED; - } - - // find a spawn point - // do it before setting health back up, so farthest - // ranging doesn't count this client - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( teamLocal == PTE_NONE ) - spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles); - else if( teamLocal == PTE_DROIDS ) - spawnPoint = SelectDroidLockSpawnPoint ( spawn_origin, spawn_angles); - else if( teamLocal == PTE_HUMANS ) - spawnPoint = SelectHumanLockSpawnPoint ( spawn_origin, spawn_angles); - } - else - { - // don't spawn near existing origin if possible - spawnPoint = SelectTremulousSpawnPoint( teamLocal, spawn_origin, spawn_angles ); - - if( spawnPoint == NULL ) - { - trap_SendServerCommand( ent-g_entities, va("print \"No suitable spawns available\n\"" ) ); - return; - } - } - client->pers.teamState.state = TEAM_ACTIVE; - - // toggle the teleport bit so the client knows to not lerp - flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ); - flags ^= EF_TELEPORT_BIT; - - // clear everything but the persistant data - - saved = client->pers; - savedSess = client->sess; - savedPing = client->ps.ping; - accuracy_hits = client->accuracy_hits; - accuracy_shots = client->accuracy_shots; - for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { - persistant[i] = client->ps.persistant[i]; - } - // also save the predictable events otherwise we might get double or dropped events - for (i = 0; i < MAX_PS_EVENTS; i++) { - savedEvents[i] = client->ps.events[i]; - } - eventSequence = client->ps.eventSequence; - memset (client, 0, sizeof(*client)); - - client->pers = saved; - client->sess = savedSess; - client->ps.ping = savedPing; - client->accuracy_hits = accuracy_hits; - client->accuracy_shots = accuracy_shots; - client->lastkilled_client = -1; - for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { - client->ps.persistant[i] = persistant[i]; - } - for (i = 0; i < MAX_PS_EVENTS; i++) { - client->ps.events[i] = savedEvents[i]; - } - client->ps.eventSequence = eventSequence; - - if( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( teamLocal == PTE_DROIDS ) - G_AddEvent( ent, EV_MENU, MN_DROID ); - else if( teamLocal == PTE_HUMANS ) - G_AddEvent( ent, EV_MENU, MN_HUMAN ); - } - - // increment the spawncount so the client will detect the respawn - client->ps.persistant[PERS_SPAWN_COUNT]++; - client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam; - - client->airOutTime = level.time + 12000; - - trap_GetUserinfo( index, userinfo, sizeof(userinfo) ); - client->ps.eFlags = flags; - - //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.pclass ); - - ent->s.groundEntityNum = ENTITYNUM_NONE; - ent->client = &level.clients[index]; - ent->takedamage = qtrue; - ent->inuse = qtrue; - ent->classname = "player"; - ent->r.contents = CONTENTS_BODY; - ent->clipmask = MASK_PLAYERSOLID; - ent->die = player_die; - ent->waterlevel = 0; - ent->watertype = 0; - ent->flags = 0; - - client->ps.stats[ STAT_WEAPONS ] = 0; - client->ps.stats[ STAT_WEAPONS2 ] = 0; - - // clear entity values - switch( ent->client->pers.pclass ) - { - case PCL_D_BUILDER: - client->pers.maxHealth = 50; - client->ps.stats[STAT_MAX_HEALTH] = 50; - client->ps.stats[STAT_ARMOR] = 50; - - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - BG_packWeapon( WP_ABUILD, client->ps.stats ); - BG_packAmmoArray( WP_ABUILD, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - client->ps.stats[ STAT_ABILITIES ] |= SCA_TAKESFALLDAMAGE; - BG_packAttributes( 80, 15, 350, client->ps.stats ); - client->classSpeed = 0.5; - break; - - case PCL_D_BASE: - client->pers.maxHealth = 25; - client->ps.stats[STAT_MAX_HEALTH] = 25; - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - BG_packWeapon( WP_VENOM, client->ps.stats ); - BG_packAmmoArray( WP_VENOM, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - client->ps.stats[ STAT_ABILITIES ] |= SCA_WALLCLIMBER; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANJUMP; - client->ps.stats[ STAT_ABILITIES ] |= SCA_NOWEAPONDRIFT; - BG_packAttributes( 140, 0, 25, client->ps.stats ); - client->classSpeed = 2.0; - break; - - case PCL_H_BASE: - client->pers.maxHealth = 100; - client->ps.stats[STAT_MAX_HEALTH] = 100; - client->ps.stats[STAT_ARMOR] = 50; - - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - /*BG_packWeapon( WP_MACHINEGUN, client->ps.stats ); - BG_packAmmoArray( WP_MACHINEGUN, client->ps.ammo, client->ps.powerups, CS_MG, 4, 4 );*/ - - client->ps.stats[ STAT_ABILITIES ] |= SCA_TAKESFALLDAMAGE; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANJUMP; - BG_packAttributes( 90, 2, 200, client->ps.stats ); - client->classSpeed = 1.0; - break; - - //eventually remove this case (or report an error) when all classes implemented - default: - client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - BG_packWeapon( WP_MACHINEGUN, client->ps.stats ); - BG_packAmmoArray( WP_MACHINEGUN, client->ps.ammo, client->ps.powerups, 100, 0, 0 ); - - BG_packWeapon( WP_GAUNTLET, client->ps.stats ); - BG_packAmmoArray( WP_GAUNTLET, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - BG_packAmmoArray( WP_GRAPPLING_HOOK, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - client->ps.stats[ STAT_ABILITIES ] |= SCA_TAKESFALLDAMAGE; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANZOOM; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANJUMP; - BG_packAttributes( 90, 2, 200, client->ps.stats ); - client->classSpeed = 1.0; - - } - - ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.pclass; - ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.pteam; - - - // health will count down towards max_health - ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH]; //* 1.25; - - G_SetOrigin( ent, spawn_origin ); - VectorCopy( spawn_origin, client->ps.origin ); - - // the respawned flag will be cleared after the attack and jump keys come up - client->ps.pm_flags |= PMF_RESPAWNED; - - trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); - SetClientViewAngle( ent, spawn_angles ); - - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { - - } else { - G_KillBox( ent ); - trap_LinkEntity (ent); - - // force the base weapon up - client->ps.weapon = WP_NONE; - client->ps.weaponstate = WEAPON_READY; - - } - - // don't allow full run speed for a bit - client->ps.pm_flags |= PMF_TIME_KNOCKBACK; - client->ps.pm_time = 100; - - client->respawnTime = level.time; - client->inactivityTime = level.time + g_inactivity.integer * 1000; - client->latched_buttons = 0; - - // set default animations - client->ps.torsoAnim = TORSO_STAND; - client->ps.legsAnim = LEGS_IDLE; - - if ( level.intermissiontime ) { - MoveClientToIntermission( ent ); - } else { - // fire the targets of the spawn point - G_UseTargets( spawnPoint, ent ); - - // select the highest weapon number available, after any - // spawn given items have fired - client->ps.weapon = 1; - for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) { - if ( BG_gotWeapon( i, client->ps.stats ) ) { - client->ps.weapon = i; - break; - } - } - } - - // run a client frame to drop exactly to the floor, - // initialize animations and other things - client->ps.commandTime = level.time - 100; - ent->client->pers.cmd.serverTime = level.time; - ClientThink( ent-g_entities ); - - // positively link the client, even if the command times are weird - if ( client->sess.sessionTeam != TEAM_SPECTATOR ) { - BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); - VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); - trap_LinkEntity( ent ); - } - - //TA: must do this here so the number of active clients is calculated - CalculateRanks(); - - // run the presend to set anything else - ClientEndFrame( ent ); - - // clear entity state values - BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); -} - - -/* -=========== -ClientDisconnect - -Called when a player drops from the server. -Will not be called between levels. - -This should NOT be called directly by any game logic, -call trap_DropClient(), which will call this and do -server system housekeeping. -============ -*/ -void ClientDisconnect( int clientNum ) { - gentity_t *ent; - gentity_t *tent; - int i; - - ent = g_entities + clientNum; - if ( !ent->client ) { - return; - } - - // stop any following clients - for ( i = 0 ; i < level.maxclients ; i++ ) { - if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR - && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW - && level.clients[i].sess.spectatorClient == clientNum ) { - StopFollowing( &g_entities[i] ); - } - } - - // send effect if they were completely connected - if ( ent->client->pers.connected == CON_CONNECTED - && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { - tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); - tent->s.clientNum = ent->s.clientNum; - - // They don't get to take powerups with them! - // Especially important for stuff like CTF flags - TossClientItems ( ent ); - } - - G_LogPrintf( "ClientDisconnect: %i\n", clientNum ); - - // if we are playing in tourney mode and losing, give a win to the other player - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && !level.intermissiontime - && !level.warmupTime && level.sortedClients[1] == clientNum ) { - level.clients[ level.sortedClients[0] ].sess.wins++; - ClientUserinfoChanged( level.sortedClients[0] ); - } - - trap_UnlinkEntity (ent); - ent->s.modelindex = 0; - ent->inuse = qfalse; - ent->classname = "disconnected"; - ent->client->pers.connected = CON_DISCONNECTED; - ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE; - ent->client->sess.sessionTeam = TEAM_FREE; - - trap_SetConfigstring( CS_PLAYERS + clientNum, ""); - - CalculateRanks(); - - //TA: rip bots - /*if ( ent->r.svFlags & SVF_BOT ) { - BotAIShutdownClient( clientNum ); - }*/ -} diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c deleted file mode 100644 index 3fcc088b..00000000 --- a/src/game/g_cmds.c +++ /dev/null @@ -1,2050 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - -#include "../ta_ui/menudef.h" // for the voice chats - -/* -================== -DeathmatchScoreboardMessage - -================== -*/ -void DeathmatchScoreboardMessage( gentity_t *ent ) { - char entry[1024]; - char string[1400]; - int stringlength; - int i, j; - gclient_t *cl; - int numSorted; - int scoreFlags; - - // send the latest information on all clients - string[0] = 0; - stringlength = 0; - scoreFlags = 0; - - numSorted = level.numConnectedClients; - - for (i=0 ; i < numSorted ; i++) { - int ping; - - cl = &level.clients[level.sortedClients[i]]; - - if ( cl->pers.connected == CON_CONNECTING ) { - ping = -1; - } else { - ping = cl->ps.ping < 999 ? cl->ps.ping : 999; - } - Com_sprintf (entry, sizeof(entry), - " %i %i %i %i %i %i", level.sortedClients[i], - cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000, - scoreFlags, g_entities[level.sortedClients[i]].s.powerups); - j = strlen(entry); - if (stringlength + j > 1024) - break; - strcpy (string + stringlength, entry); - stringlength += j; - } - - trap_SendServerCommand( ent-g_entities, va("scores %i %i %i%s", i, - level.teamScores[TEAM_HUMANS], level.teamScores[TEAM_DROIDS], - string ) ); -} - - -/* -================== -Cmd_Score_f - -Request current scoreboard information -================== -*/ -void Cmd_Score_f( gentity_t *ent ) { - DeathmatchScoreboardMessage( ent ); -} - - - -/* -================== -CheatsOk -================== -*/ -qboolean CheatsOk( gentity_t *ent ) { - if ( !g_cheats.integer ) { - trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\"")); - return qfalse; - } - if ( ent->health <= 0 ) { - trap_SendServerCommand( ent-g_entities, va("print \"You must be alive to use this command.\n\"")); - return qfalse; - } - return qtrue; -} - - -/* -================== -ConcatArgs -================== -*/ -char *ConcatArgs( int start ) { - int i, c, tlen; - static char line[MAX_STRING_CHARS]; - int len; - char arg[MAX_STRING_CHARS]; - - len = 0; - c = trap_Argc(); - for ( i = start ; i < c ; i++ ) { - trap_Argv( i, arg, sizeof( arg ) ); - tlen = strlen( arg ); - if ( len + tlen >= MAX_STRING_CHARS - 1 ) { - break; - } - memcpy( line + len, arg, tlen ); - len += tlen; - if ( i != c - 1 ) { - line[len] = ' '; - len++; - } - } - - line[len] = 0; - - return line; -} - -/* -================== -SanitizeString - -Remove case and control characters -================== -*/ -void SanitizeString( char *in, char *out ) { - while ( *in ) { - if ( *in == 27 ) { - in += 2; // skip color code - continue; - } - if ( *in < 32 ) { - in++; - continue; - } - *out++ = tolower( *in++ ); - } - - *out = 0; -} - -/* -================== -ClientNumberFromString - -Returns a player number for either a number or name string -Returns -1 if invalid -================== -*/ -int ClientNumberFromString( gentity_t *to, char *s ) { - gclient_t *cl; - int idnum; - char s2[MAX_STRING_CHARS]; - char n2[MAX_STRING_CHARS]; - - // numeric values are just slot numbers - if (s[0] >= '0' && s[0] <= '9') { - idnum = atoi( s ); - if ( idnum < 0 || idnum >= level.maxclients ) { - trap_SendServerCommand( to-g_entities, va("print \"Bad client slot: %i\n\"", idnum)); - return -1; - } - - cl = &level.clients[idnum]; - if ( cl->pers.connected != CON_CONNECTED ) { - trap_SendServerCommand( to-g_entities, va("print \"Client %i is not active\n\"", idnum)); - return -1; - } - return idnum; - } - - // check for a name match - SanitizeString( s, s2 ); - for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) { - if ( cl->pers.connected != CON_CONNECTED ) { - continue; - } - SanitizeString( cl->pers.netname, n2 ); - if ( !strcmp( n2, s2 ) ) { - return idnum; - } - } - - trap_SendServerCommand( to-g_entities, va("print \"User %s is not on the server\n\"", s)); - return -1; -} - -/* -================== -Cmd_Give_f - -Give items to a client -================== -*/ -void Cmd_Give_f (gentity_t *ent) -{ - char *name; - gitem_t *it; - int i; - qboolean give_all; - gentity_t *it_ent; - trace_t trace; - - if ( !CheatsOk( ent ) ) { - return; - } - - name = ConcatArgs( 1 ); - - if (Q_stricmp(name, "all") == 0) - give_all = qtrue; - else - give_all = qfalse; - - if (give_all || Q_stricmp( name, "health") == 0) - { - ent->health = ent->client->ps.stats[STAT_MAX_HEALTH]; - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "weapons") == 0) - { - BG_packWeapon( (1 << WP_NUM_WEAPONS) - 1 - ( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE ), ent->client->ps.stats ); - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "ammo") == 0) - { - for ( i = 0 ; i < MAX_WEAPONS ; i++ ) { - BG_packAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, 999, 0, 0 ); - } - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "armor") == 0) - { - ent->client->ps.stats[STAT_ARMOR] = 200; - - if (!give_all) - return; - } - - // spawn a specific item right on the player - if ( !give_all ) { - it = BG_FindItem (name); - if (!it) { - return; - } - - it_ent = G_Spawn(); - VectorCopy( ent->r.currentOrigin, it_ent->s.origin ); - it_ent->classname = it->classname; - G_SpawnItem (it_ent, it); - FinishSpawningItem(it_ent ); - memset( &trace, 0, sizeof( trace ) ); - Touch_Item (it_ent, ent, &trace); - if (it_ent->inuse) { - G_FreeEntity( it_ent ); - } - } -} - - -/* -================== -Cmd_God_f - -Sets client to godmode - -argv(0) god -================== -*/ -void Cmd_God_f (gentity_t *ent) -{ - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - ent->flags ^= FL_GODMODE; - if (!(ent->flags & FL_GODMODE) ) - msg = "godmode OFF\n"; - else - msg = "godmode ON\n"; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_Notarget_f - -Sets client to notarget - -argv(0) notarget -================== -*/ -void Cmd_Notarget_f( gentity_t *ent ) { - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - ent->flags ^= FL_NOTARGET; - if (!(ent->flags & FL_NOTARGET) ) - msg = "notarget OFF\n"; - else - msg = "notarget ON\n"; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_Noclip_f - -argv(0) noclip -================== -*/ -void Cmd_Noclip_f( gentity_t *ent ) { - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - if ( ent->client->noclip ) { - msg = "noclip OFF\n"; - } else { - msg = "noclip ON\n"; - } - ent->client->noclip = !ent->client->noclip; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_LevelShot_f - -This is just to help generate the level pictures -for the menus. It goes to the intermission immediately -and sends over a command to the client to resize the view, -hide the scoreboard, and take a special screenshot -================== -*/ -void Cmd_LevelShot_f( gentity_t *ent ) { - if ( !CheatsOk( ent ) ) { - return; - } - - // doesn't work in single player - if ( g_gametype.integer != 0 ) { - trap_SendServerCommand( ent-g_entities, - "print \"Must be in g_gametype 0 for levelshot\n\"" ); - return; - } - - BeginIntermission(); - trap_SendServerCommand( ent-g_entities, "clientLevelShot" ); -} - - -void Cmd_TeamTask_f( gentity_t *ent ) { - char userinfo[MAX_INFO_STRING]; - char arg[MAX_TOKEN_CHARS]; - int task; - int client = ent->client - level.clients; - - if ( trap_Argc() != 2 ) { - return; - } - trap_Argv( 1, arg, sizeof( arg ) ); - task = atoi( arg ); - - trap_GetUserinfo(client, userinfo, sizeof(userinfo)); - Info_SetValueForKey(userinfo, "teamtask", va("%d", task)); - trap_SetUserinfo(client, userinfo); - ClientUserinfoChanged(client); -} - - -/* -================= -Cmd_Kill_f -================= -*/ -void Cmd_Kill_f( gentity_t *ent ) { - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - return; - } - if (ent->health <= 0) { - return; - } - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); -} - -/* -================= -BroadCastTeamChange - -Let everyone know about a team change -================= -*/ -void BroadcastTeamChange( gclient_t *client, int oldTeam ) -{ - if ( client->sess.sessionTeam == TEAM_HUMANS ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the humans.\n\"", - client->pers.netname) ); - } else if ( client->sess.sessionTeam == TEAM_DROIDS ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the droids.\n\"", - client->pers.netname)); - } else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the spectators.\n\"", - client->pers.netname)); - } else if ( client->sess.sessionTeam == TEAM_FREE ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the battle.\n\"", - client->pers.netname)); - } -} - -/* -================= -SetTeam -================= -*/ -void SetTeam( gentity_t *ent, char *s ) { - int team, oldTeam; - gclient_t *client; - int clientNum; - spectatorState_t specState; - int specClient; - - // - // see what change is requested - // - client = ent->client; - - clientNum = client - level.clients; - specClient = 0; - - specState = SPECTATOR_NOT; - if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_SCOREBOARD; - } else if ( !Q_stricmp( s, "follow1" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FOLLOW; - specClient = -1; - } else if ( !Q_stricmp( s, "follow2" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FOLLOW; - specClient = -2; - } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FREE; - } else if ( g_gametype.integer >= GT_TEAM ) { - // if running a team game, assign player to one of the teams - specState = SPECTATOR_NOT; - if ( !Q_stricmp( s, "humans" ) || !Q_stricmp( s, "h" ) ) { - team = TEAM_HUMANS; - } else if ( !Q_stricmp( s, "droids" ) || !Q_stricmp( s, "d" ) ) { - team = TEAM_DROIDS; - } else { - // pick the team with the least number of players - team = PickTeam( clientNum ); - } - - if ( g_teamForceBalance.integer ) { - int counts[TEAM_NUM_TEAMS]; - - counts[TEAM_DROIDS] = TeamCount( ent->client->ps.clientNum, TEAM_DROIDS ); - counts[TEAM_HUMANS] = TeamCount( ent->client->ps.clientNum, TEAM_HUMANS ); - - // We allow a spread of two - if ( team == TEAM_HUMANS && counts[TEAM_HUMANS] - counts[TEAM_DROIDS] > 1 ) { - trap_SendServerCommand( ent->client->ps.clientNum, - "cp \"Humans team has too many players.\n\"" ); - return; // ignore the request - } - if ( team == TEAM_DROIDS && counts[TEAM_DROIDS] - counts[TEAM_HUMANS] > 1 ) { - trap_SendServerCommand( ent->client->ps.clientNum, - "cp \"Droids team has too many players.\n\"" ); - return; // ignore the request - } - - // It's ok, the team we are switching to has less or same number of players - } - - } else { - // force them to spectators if there aren't any spots free - team = TEAM_FREE; - } - - // override decision if limiting the players - if ( (g_gametype.integer == GT_TOURNAMENT) - && level.numNonSpectatorClients >= 2 ) { - team = TEAM_SPECTATOR; - } else if ( g_maxGameClients.integer > 0 && - level.numNonSpectatorClients >= g_maxGameClients.integer ) { - team = TEAM_SPECTATOR; - } - - // - // decide if we will allow the change - // - oldTeam = client->sess.sessionTeam; - if ( team == oldTeam && team != TEAM_SPECTATOR ) { - return; - } - - // - // execute the team change - // - - // he starts at 'base' - client->pers.teamState.state = TEAM_BEGIN; - if ( oldTeam != TEAM_SPECTATOR ) { - // Kill him (makes sure he loses flags, etc) - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); - - } - // they go to the end of the line for tournements - if ( team == TEAM_SPECTATOR ) { - client->sess.spectatorTime = level.time; - } - - client->sess.sessionTeam = team; - client->sess.spectatorState = specState; - client->sess.spectatorClient = specClient; - - BroadcastTeamChange( client, oldTeam ); - - // get and distribute relevent paramters - ClientUserinfoChanged( clientNum ); - - ClientBegin( clientNum ); -} - -/* -================= -StopFollowing - -If the client being followed leaves the game, or you just want to drop -to free floating spectator mode -================= -*/ -void StopFollowing( gentity_t *ent ) { - ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR; - ent->client->sess.sessionTeam = TEAM_SPECTATOR; - ent->client->sess.spectatorState = SPECTATOR_FREE; - ent->client->ps.pm_flags &= ~PMF_FOLLOW; - ent->r.svFlags &= ~SVF_BOT; - ent->client->ps.clientNum = ent - g_entities; -} - -/* -================= -Cmd_Team_f -================= -*/ -void Cmd_Team_f( gentity_t *ent ) { - int oldTeam; - char s[MAX_TOKEN_CHARS]; - - //TA: rip out the q3a team system :) - - oldTeam = ent->client->pers.pteam; - - trap_Argv( 1, s, sizeof( s ) ); - - if( !strlen( s ) ) - { - trap_SendServerCommand( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.pteam ) ); - return; - } - - if(!Q_stricmp(s, "0")) - ent->client->pers.pteam = PTE_NONE; - else if(!Q_stricmp(s, "1")) - ent->client->pers.pteam = PTE_DROIDS; - else if(!Q_stricmp(s, "2")) - ent->client->pers.pteam = PTE_HUMANS; - - if( oldTeam != ent->client->pers.pteam ) - { - ent->client->pers.pclass = 0; - ClientSpawn( ent ); - } - - //FIXME: put some team change broadcast code here. -} - - -/* -================= -Cmd_Follow_f -================= -*/ -void Cmd_Follow_f( gentity_t *ent ) { - int i; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc() != 2 ) { - if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { - StopFollowing( ent ); - } - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - i = ClientNumberFromString( ent, arg ); - if ( i == -1 ) { - return; - } - - // can't follow self - if ( &level.clients[ i ] == ent->client ) { - return; - } - - // can't follow another spectator - if ( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR ) { - return; - } - - // if they are playing a tournement game, count as a loss - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - - // first set them to spectator - if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { - SetTeam( ent, "spectator" ); - } - - ent->client->sess.spectatorState = SPECTATOR_FOLLOW; - ent->client->sess.spectatorClient = i; -} - -/* -================= -Cmd_FollowCycle_f -================= -*/ -void Cmd_FollowCycle_f( gentity_t *ent, int dir ) { - int clientnum; - int original; - - // if they are playing a tournement game, count as a loss - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - // first set them to spectator - if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) { - SetTeam( ent, "spectator" ); - } - - if ( dir != 1 && dir != -1 ) { - G_Error( "Cmd_FollowCycle_f: bad dir %i", dir ); - } - - clientnum = ent->client->sess.spectatorClient; - original = clientnum; - do { - clientnum += dir; - if ( clientnum >= level.maxclients ) { - clientnum = 0; - } - if ( clientnum < 0 ) { - clientnum = level.maxclients - 1; - } - - // can only follow connected clients - if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) { - continue; - } - - // can't follow another spectator - if ( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) { - continue; - } - - // this is good, we can use it - ent->client->sess.spectatorClient = clientnum; - ent->client->sess.spectatorState = SPECTATOR_FOLLOW; - return; - } while ( clientnum != original ); - - // leave it where it was -} - - -/* -================== -G_Say -================== -*/ -static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) { - if (!other) { - return; - } - if (!other->inuse) { - return; - } - if (!other->client) { - return; - } - if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) { - return; - } - // no chatting to players in tournements - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && other->client->sess.sessionTeam == TEAM_FREE - && ent->client->sess.sessionTeam != TEAM_FREE ) { - return; - } - - trap_SendServerCommand( other-g_entities, va("%s \"%s%c%c%s\"", - mode == SAY_TEAM ? "tchat" : "chat", - name, Q_COLOR_ESCAPE, color, message)); -} - -#define EC "\x19" - -void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) { - int j; - gentity_t *other; - int color; - char name[64]; - // don't let text be too long for malicious reasons - char text[MAX_SAY_TEXT]; - char location[64]; - - if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) { - mode = SAY_ALL; - } - - switch ( mode ) { - default: - case SAY_ALL: - G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText ); - Com_sprintf (name, sizeof(name), "%s%c%c"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_GREEN; - break; - case SAY_TEAM: - G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText ); - if (Team_GetLocationMsg(ent, location, sizeof(location))) - Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC") (%s)"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location); - else - Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC")"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_CYAN; - break; - case SAY_TELL: - if (target && g_gametype.integer >= GT_TEAM && - target->client->sess.sessionTeam == ent->client->sess.sessionTeam && - Team_GetLocationMsg(ent, location, sizeof(location))) - Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"] (%s)"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location ); - else - Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"]"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_MAGENTA; - break; - } - - Q_strncpyz( text, chatText, sizeof(text) ); - - if ( target ) { - G_SayTo( ent, target, mode, color, name, text ); - return; - } - - // echo the text to the console - if ( g_dedicated.integer ) { - G_Printf( "%s%s\n", name, text); - } - - // send it to all the apropriate clients - for (j = 0; j < level.maxclients; j++) { - other = &g_entities[j]; - G_SayTo( ent, other, mode, color, name, text ); - } -} - - -/* -================== -Cmd_Say_f -================== -*/ -static void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) { - char *p; - - if ( trap_Argc () < 2 && !arg0 ) { - return; - } - - if (arg0) - { - p = ConcatArgs( 0 ); - } - else - { - p = ConcatArgs( 1 ); - } - - G_Say( ent, NULL, mode, p ); -} - -/* -================== -Cmd_Tell_f -================== -*/ -static void Cmd_Tell_f( gentity_t *ent ) { - int targetNum; - gentity_t *target; - char *p; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc () < 2 ) { - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - if ( targetNum < 0 || targetNum >= level.maxclients ) { - return; - } - - target = &g_entities[targetNum]; - if ( !target || !target->inuse || !target->client ) { - return; - } - - p = ConcatArgs( 2 ); - - G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p ); - G_Say( ent, target, SAY_TELL, p ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if ( ent != target && !(ent->r.svFlags & SVF_BOT)) { - G_Say( ent, ent, SAY_TELL, p ); - } -} - - -static void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) { - int color; - char *cmd; - - if (!other) { - return; - } - if (!other->inuse) { - return; - } - if (!other->client) { - return; - } - if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) { - return; - } - // no chatting to players in tournements - if ( (g_gametype.integer == GT_TOURNAMENT )) { - return; - } - - if (mode == SAY_TEAM) { - color = COLOR_CYAN; - cmd = "vtchat"; - } - else if (mode == SAY_TELL) { - color = COLOR_MAGENTA; - cmd = "vtell"; - } - else { - color = COLOR_GREEN; - cmd = "vchat"; - } - - trap_SendServerCommand( other-g_entities, va("%s %d %d %d %s", cmd, voiceonly, ent->s.number, color, id)); -} - - -void G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) { - int j; - gentity_t *other; - - if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) { - mode = SAY_ALL; - } - - if ( target ) { - G_VoiceTo( ent, target, mode, id, voiceonly ); - return; - } - - // echo the text to the console - if ( g_dedicated.integer ) { - G_Printf( "voice: %s %s\n", ent->client->pers.netname, id); - } - - // send it to all the apropriate clients - for (j = 0; j < level.maxclients; j++) { - other = &g_entities[j]; - G_VoiceTo( ent, other, mode, id, voiceonly ); - } -} - - -/* -================== -Cmd_Voice_f -================== -*/ -static void Cmd_Voice_f( gentity_t *ent, int mode, qboolean arg0, qboolean voiceonly ) { - char *p; - - if ( trap_Argc () < 2 && !arg0 ) { - return; - } - - if (arg0) - { - p = ConcatArgs( 0 ); - } - else - { - p = ConcatArgs( 1 ); - } - - G_Voice( ent, NULL, mode, p, voiceonly ); -} - - -/* -================== -Cmd_VoiceTell_f -================== -*/ -static void Cmd_VoiceTell_f( gentity_t *ent, qboolean voiceonly ) { - int targetNum; - gentity_t *target; - char *id; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc () < 2 ) { - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - if ( targetNum < 0 || targetNum >= level.maxclients ) { - return; - } - - target = &g_entities[targetNum]; - if ( !target || !target->inuse || !target->client ) { - return; - } - - id = ConcatArgs( 2 ); - - G_LogPrintf( "vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id ); - G_Voice( ent, target, SAY_TELL, id, voiceonly ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if ( ent != target && !(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, id, voiceonly ); - } -} - - -/* -================== -Cmd_VoiceTaunt_f -================== -*/ -static void Cmd_VoiceTaunt_f( gentity_t *ent ) { - gentity_t *who; - int i; - - if (!ent->client) { - return; - } - - // insult someone who just killed you - if (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) { - // i am a dead corpse - if (!(ent->enemy->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse ); - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse ); - } - ent->enemy = NULL; - return; - } - // insult someone you just killed - if (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) { - who = g_entities + ent->client->lastkilled_client; - if (who->client) { - // who is the person I just killed - if (who->client->lasthurt_mod == MOD_GAUNTLET) { - if (!(who->r.svFlags & SVF_BOT)) { - //G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); // and I killed them with a gauntlet - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); - } - } else { - if (!(who->r.svFlags & SVF_BOT)) { - //G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); // and I killed them with something else - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); - } - } - ent->client->lastkilled_client = -1; - return; - } - } - - if (g_gametype.integer >= GT_TEAM) { - // praise a team mate who just got a reward - for(i = 0; i < MAX_CLIENTS; i++) { - who = g_entities + i; - if (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) { - if (who->client->rewardTime > level.time) { - if (!(who->r.svFlags & SVF_BOT)) { - //G_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse ); - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse ); - } - return; - } - } - } - } - - // just say something - //G_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse ); -} - - -static char *gc_orders[] = { - "hold your position", - "hold this position", - "come here", - "cover me", - "guard location", - "search and destroy", - "report" -}; - -void Cmd_GameCommand_f( gentity_t *ent ) { - int player; - int order; - char str[MAX_TOKEN_CHARS]; - - trap_Argv( 1, str, sizeof( str ) ); - player = atoi( str ); - trap_Argv( 2, str, sizeof( str ) ); - order = atoi( str ); - - if ( player < 0 || player >= MAX_CLIENTS ) { - return; - } - if ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) { - return; - } - G_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] ); - G_Say( ent, ent, SAY_TELL, gc_orders[order] ); -} - -/* -================== -Cmd_Where_f -================== -*/ -void Cmd_Where_f( gentity_t *ent ) { - trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); -} - -static const char *gameNames[] = { - "Free For All", - "Tournament", - "Single Player", - "Team Deathmatch", - "Capture the Flag", - "One Flag CTF", - "Overload", - "Harvester" -}; - -/* -================== -Cmd_CallVote_f -================== -*/ -void Cmd_CallVote_f( gentity_t *ent ) { - int i; - char arg1[MAX_STRING_TOKENS]; - char arg2[MAX_STRING_TOKENS]; - - if ( !g_allowVote.integer ) { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" ); - return; - } - - if ( level.voteTime ) { - trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress.\n\"" ); - return; - } - if ( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) { - trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes.\n\"" ); - return; - } - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" ); - return; - } - - // make sure it is a valid command to vote on - trap_Argv( 1, arg1, sizeof( arg1 ) ); - trap_Argv( 2, arg2, sizeof( arg2 ) ); - - if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - return; - } - - if ( !Q_stricmp( arg1, "map_restart" ) ) { - } else if ( !Q_stricmp( arg1, "nextmap" ) ) { - } else if ( !Q_stricmp( arg1, "map" ) ) { - } else if ( !Q_stricmp( arg1, "g_gametype" ) ) { - } else if ( !Q_stricmp( arg1, "kick" ) ) { - } else if ( !Q_stricmp( arg1, "clientkick" ) ) { - } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) { - } else if ( !Q_stricmp( arg1, "timelimit" ) ) { - } else if ( !Q_stricmp( arg1, "fraglimit" ) ) { - } else { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map , g_gametype , kick , clientkick , g_doWarmup, timelimit