diff options
author | Tim Angus <tim@ngus.net> | 2005-12-10 03:18:22 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2005-12-10 03:18:22 +0000 |
commit | ef5d1d446e3c078b81882c2eda6525aee7ccfa1e (patch) | |
tree | 16c1e9460317f2ca507f8e1888216816d05f251c /src/cgame/cg_players.c | |
parent | 3b447421efc76ba76fbdae62f893fc6916af5433 (diff) |
* Moved existing src directory out the way whilst I merge ioq3
Diffstat (limited to 'src/cgame/cg_players.c')
-rw-r--r-- | src/cgame/cg_players.c | 2575 |
1 files changed, 0 insertions, 2575 deletions
diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c deleted file mode 100644 index ac1ec181..00000000 --- a/src/cgame/cg_players.c +++ /dev/null @@ -1,2575 +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 OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#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 ); - trap_FS_FCloseFile( f ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - skip = 0; // quite the compiler warning - - ci->footsteps = FOOTSTEP_NORMAL; - VectorClear( ci->headOffset ); - ci->gender = GENDER_MALE; - ci->fixedlegs = qfalse; - ci->fixedtorso = qfalse; - ci->nonsegmented = qfalse; - - // read optional parameters - while( 1 ) - { - prev = text_p; // so we can unget - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "footsteps" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) - ci->footsteps = FOOTSTEP_NORMAL; - else if( !Q_stricmp( token, "boot" ) ) - ci->footsteps = FOOTSTEP_BOOT; - else if( !Q_stricmp( token, "flesh" ) ) - ci->footsteps = FOOTSTEP_FLESH; - else if( !Q_stricmp( token, "mech" ) ) - ci->footsteps = FOOTSTEP_MECH; - else if( !Q_stricmp( token, "energy" ) ) - ci->footsteps = FOOTSTEP_ENERGY; - else if( !Q_stricmp( token, "none" ) ) - ci->footsteps = FOOTSTEP_NONE; - else if( !Q_stricmp( token, "custom" ) ) - ci->footsteps = FOOTSTEP_CUSTOM; - else - CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token ); - - continue; - } - else if( !Q_stricmp( token, "headoffset" ) ) - { - for( i = 0 ; i < 3 ; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - ci->headOffset[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "sex" ) ) - { - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( token[ 0 ] == 'f' || token[ 0 ] == 'F' ) - ci->gender = GENDER_FEMALE; - else if( token[ 0 ] == 'n' || token[ 0 ] == 'N' ) - ci->gender = GENDER_NEUTER; - else - ci->gender = GENDER_MALE; - - continue; - } - else if( !Q_stricmp( token, "fixedlegs" ) ) - { - ci->fixedlegs = qtrue; - continue; - } - else if( !Q_stricmp( token, "fixedtorso" ) ) - { - ci->fixedtorso = qtrue; - continue; - } - else if( !Q_stricmp( token, "nonsegmented" ) ) - { - ci->nonsegmented = qtrue; - continue; - } - - // if it is a number, start parsing animations - if( token[ 0 ] >= '0' && token[ 0 ] <= '9' ) - { - text_p = prev; // unget the token - break; - } - - Com_Printf( "unknown token '%s' is %s\n", token, filename ); - } - - if( !ci->nonsegmented ) - { - // read information for each frame - for( i = 0; i < MAX_PLAYER_ANIMATIONS; i++ ) - { - token = COM_Parse( &text_p ); - - if( !*token ) - { - if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) - { - animations[ i ].firstFrame = animations[ TORSO_GESTURE ].firstFrame; - animations[ i ].frameLerp = animations[ TORSO_GESTURE ].frameLerp; - animations[ i ].initialLerp = animations[ TORSO_GESTURE ].initialLerp; - animations[ i ].loopFrames = animations[ TORSO_GESTURE ].loopFrames; - animations[ i ].numFrames = animations[ TORSO_GESTURE ].numFrames; - animations[ i ].reversed = qfalse; - animations[ i ].flipflop = qfalse; - continue; - } - - break; - } - - animations[ i ].firstFrame = atoi( token ); - - // leg only frames are adjusted to not count the upper body only frames - if( i == LEGS_WALKCR ) - skip = animations[ LEGS_WALKCR ].firstFrame - animations[ TORSO_GESTURE ].firstFrame; - - if( i >= LEGS_WALKCR && i<TORSO_GETFLAG ) - animations[ i ].firstFrame -= skip; - - token = COM_Parse( &text_p ); - if( !*token ) - break; - - animations[ i ].numFrames = atoi( token ); - animations[ i ].reversed = qfalse; - animations[ i ].flipflop = qfalse; - - // if numFrames is negative the animation is reversed - if( animations[ i ].numFrames < 0 ) - { - animations[ i ].numFrames = -animations[ i ].numFrames; - animations[ i ].reversed = qtrue; - } - - token = COM_Parse( &text_p ); - - if( !*token ) - break; - - animations[ i ].loopFrames = atoi( token ); - - token = COM_Parse( &text_p ); - - if( !*token ) - break; - - fps = atof( token ); - if( fps == 0 ) - fps = 1; - - animations[ i ].frameLerp = 1000 / fps; - animations[ i ].initialLerp = 1000 / fps; - } - - if( i != MAX_PLAYER_ANIMATIONS ) - { - CG_Printf( "Error parsing animation file: %s", filename ); - return qfalse; - } - // crouch backward animation - memcpy( &animations[ LEGS_BACKCR ], &animations[ LEGS_WALKCR ], sizeof( animation_t ) ); - animations[ LEGS_BACKCR ].reversed = qtrue; - // walk backward animation - memcpy( &animations[ LEGS_BACKWALK ], &animations[ LEGS_WALK ], sizeof( animation_t ) ); - animations[ LEGS_BACKWALK ].reversed = qtrue; - // flag moving fast - animations[ FLAG_RUN ].firstFrame = 0; - animations[ FLAG_RUN ].numFrames = 16; - animations[ FLAG_RUN ].loopFrames = 16; - animations[ FLAG_RUN ].frameLerp = 1000 / 15; - animations[ FLAG_RUN ].initialLerp = 1000 / 15; - animations[ FLAG_RUN ].reversed = qfalse; - // flag not moving or moving slowly - animations[ FLAG_STAND ].firstFrame = 16; - animations[ FLAG_STAND ].numFrames = 5; - animations[ FLAG_STAND ].loopFrames = 0; - animations[ FLAG_STAND ].frameLerp = 1000 / 20; - animations[ FLAG_STAND ].initialLerp = 1000 / 20; - animations[ FLAG_STAND ].reversed = qfalse; - // flag speeding up - animations[ FLAG_STAND2RUN ].firstFrame = 16; - animations[ FLAG_STAND2RUN ].numFrames = 5; - animations[ FLAG_STAND2RUN ].loopFrames = 1; - animations[ FLAG_STAND2RUN ].frameLerp = 1000 / 15; - animations[ FLAG_STAND2RUN ].initialLerp = 1000 / 15; - animations[ FLAG_STAND2RUN ].reversed = qtrue; - } - else - { - // read information for each frame - for( i = 0; i < MAX_NONSEG_PLAYER_ANIMATIONS; i++ ) - { - token = COM_Parse( &text_p ); - - if( !*token ) - break; - - animations[ i ].firstFrame = atoi( token ); - - token = COM_Parse( &text_p ); - if( !*token ) - break; - - animations[ i ].numFrames = atoi( token ); - animations[ i ].reversed = qfalse; - animations[ i ].flipflop = qfalse; - - // if numFrames is negative the animation is reversed - if( animations[ i ].numFrames < 0 ) - { - animations[ i ].numFrames = -animations[ i ].numFrames; - animations[ i ].reversed = qtrue; - } - - token = COM_Parse( &text_p ); - - if( !*token ) - break; - - animations[ i ].loopFrames = atoi( token ); - - token = COM_Parse( &text_p ); - - if( !*token ) - break; - - fps = atof( token ); - if( fps == 0 ) - fps = 1; - - animations[ i ].frameLerp = 1000 / fps; - animations[ i ].initialLerp = 1000 / fps; - } - - if( i != MAX_NONSEG_PLAYER_ANIMATIONS ) - { - CG_Printf( "Error parsing animation file: %s", filename ); - return qfalse; - } - - // walk backward animation - memcpy( &animations[ NSPA_WALKBACK ], &animations[ NSPA_WALK ], sizeof( animation_t ) ); - animations[ NSPA_WALKBACK ].reversed = qtrue; - } - - return qtrue; -} - -/* -========================== -CG_RegisterClientSkin -========================== -*/ -static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *modelName, const char *skinName ) -{ - char filename[ MAX_QPATH ]; - - if( !ci->nonsegmented ) - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName ); - ci->legsSkin = trap_R_RegisterSkin( filename ); - if( !ci->legsSkin ) - Com_Printf( "Leg skin load failure: %s\n", filename ); - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/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; - } - else - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/nonseg_%s.skin", modelName, skinName ); - ci->nonSegSkin = trap_R_RegisterSkin( filename ); - if( !ci->nonSegSkin ) - Com_Printf( "Non-segmented skin load failure: %s\n", filename ); - - if( !ci->nonSegSkin ) - return qfalse; - } - - return qtrue; -} - -/* -========================== -CG_RegisterClientModelname -========================== -*/ -static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName ) -{ - char filename[ MAX_QPATH * 2 ]; - - //TA: do this first so the nonsegmented property is set - // 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; - } - - // load cmodels before models so filecache works - - if( !ci->nonsegmented ) - { - 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; - } - } - else - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/nonseg.md3", modelName ); - ci->nonSegModel = trap_R_RegisterModel( filename ); - if( !ci->nonSegModel ) - { - 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; - } - - //FIXME: skins do not load without icon present. do we want icons anyway? -/* 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 -=================== -*/ -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( !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; - - // fanny about a bit with sounds that are missing - if( !CG_FileExists( va( "sound/player/%s/%s", dir, s + 1 ) ) ) - { - //file doesn't exist - - if( i == 11 || i == 8 ) //fall or falling - { - ci->sounds[ i ] = trap_S_RegisterSound( "sound/null.wav", qfalse ); - } - else - { - if( i == 9 ) //gasp - s = cg_customSoundNames[ 7 ]; //pain100_1 - else if( i == 10 ) //drown - s = cg_customSoundNames[ 0 ]; //death1 - - 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 ); - } - } - else - { - 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 ); - } - } - - if( ci->footsteps == FOOTSTEP_CUSTOM ) - { - for( i = 0; i < 4; i++ ) - { - ci->customFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/%s/step%d.wav", dir, i + 1 ), qfalse ); - if( !ci->customFootsteps[ i ] ) - ci->customFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/footsteps/step%d.wav", i + 1 ), qfalse ); - - ci->customMetalFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/%s/clank%d.wav", dir, i + 1 ), qfalse ); - if( !ci->customMetalFootsteps[ i ] ) - ci->customMetalFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/footsteps/clank%d.wav", i + 1 ), qfalse ); - } - } - - // reset any existing players and bodies, because they might be in bad - // frames for this new model - clientNum = ci - cgs.clientinfo; - for( i = 0; i < MAX_GENTITIES; i++ ) - { - if( cg_entities[ i ].currentState.clientNum == clientNum && - cg_entities[ i ].currentState.eType == ET_PLAYER ) - CG_ResetPlayerEntity( &cg_entities[ i ] ); - } -} - -/* -====================== -CG_CopyClientInfoModel -====================== -*/ -static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) -{ - VectorCopy( from->headOffset, to->headOffset ); - to->footsteps = from->footsteps; - to->gender = from->gender; - - to->legsModel = from->legsModel; - to->legsSkin = from->legsSkin; - to->torsoModel = from->torsoModel; - to->torsoSkin = from->torsoSkin; - to->headModel = from->headModel; - to->headSkin = from->headSkin; - to->nonSegModel = from->nonSegModel; - to->nonSegSkin = from->nonSegSkin; - to->nonsegmented = from->nonsegmented; - to->modelIcon = from->modelIcon; - - memcpy( to->animations, from->animations, sizeof( to->animations ) ); - memcpy( to->sounds, from->sounds, sizeof( to->sounds ) ); - memcpy( to->customFootsteps, from->customFootsteps, sizeof( to->customFootsteps ) ); - memcpy( to->customMetalFootsteps, from->customMetalFootsteps, sizeof( to->customMetalFootsteps ) ); -} - - -/* -====================== -CG_GetCorpseNum -====================== -*/ -static int CG_GetCorpseNum( pClass_t class ) -{ - int i; - clientInfo_t *match; - char *modelName; - char *skinName; - - modelName = BG_FindModelNameForClass( class ); - skinName = BG_FindSkinNameForClass( class ); - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - match = &cgs.corpseinfo[ i ]; - - if( !match->infoValid ) - continue; - - if( !Q_stricmp( modelName, match->modelName ) - && !Q_stricmp( skinName, match->skinName ) ) - { - // this clientinfo is identical, so use it's handles - return i; - } - } - - //something has gone horribly wrong - return -1; -} - - -/* -====================== -CG_ScanForExistingClientInfo -====================== -*/ -static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) -{ - int i; - clientInfo_t *match; - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - match = &cgs.corpseinfo[ i ]; - - if( !match->infoValid ) - continue; - - if( !Q_stricmp( ci->modelName, match->modelName ) && - !Q_stricmp( ci->skinName, match->skinName ) ) - { - // this clientinfo is identical, so use it's handles - CG_CopyClientInfoModel( match, ci ); - - return qtrue; - } - } - - //TA: shouldn't happen - return qfalse; -} - - -/* -====================== -CG_PrecacheClientInfo -====================== -*/ -void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin ) -{ - clientInfo_t *ci; - clientInfo_t newInfo; - - ci = &cgs.corpseinfo[ class ]; - - // the old value - memset( &newInfo, 0, sizeof( newInfo ) ); - - // model - Q_strncpyz( newInfo.modelName, model, sizeof( newInfo.modelName ) ); - Q_strncpyz( newInfo.headModelName, model, sizeof( newInfo.headModelName ) ); - - // modelName didn not include a skin name - if( !skin ) - { - Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); - Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) ); - } - else - { - Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) ); - Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) ); - } - - newInfo.infoValid = qtrue; - - //TA: actually register the models - *ci = newInfo; - CG_LoadClientInfo( ci ); -} - - -/* -====================== -CG_NewClientInfo -====================== -*/ -void CG_NewClientInfo( int clientNum ) -{ - clientInfo_t *ci; - clientInfo_t newInfo; - const char *configstring; - const char *v; - char *slash; - - ci = &cgs.clientinfo[ clientNum ]; - - configstring = CG_ConfigString( clientNum + CS_PLAYERS ); - if( !configstring[ 0 ] ) - { - memset( ci, 0, sizeof( *ci ) ); - return; // player just left - } - - // the old value - memset( &newInfo, 0, sizeof( newInfo ) ); - - // isolate the player's name - v = Info_ValueForKey( configstring, "n" ); - Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) ); - - // colors - v = Info_ValueForKey( configstring, "c1" ); - CG_ColorFromString( v, newInfo.color1 ); - - v = Info_ValueForKey( configstring, "c2" ); - CG_ColorFromString( v, newInfo.color2 ); - - // bot skill - v = Info_ValueForKey( configstring, "skill" ); - newInfo.botSkill = atoi( v ); - - // handicap - v = Info_ValueForKey( configstring, "hc" ); - newInfo.handicap = atoi( v ); - - // wins - v = Info_ValueForKey( configstring, "w" ); - newInfo.wins = atoi( v ); - - // losses - v = Info_ValueForKey( configstring, "l" ); - newInfo.losses = atoi( v ); - - // team - v = Info_ValueForKey( configstring, "t" ); - newInfo.team = atoi( v ); - - // team task - v = Info_ValueForKey( configstring, "tt" ); - newInfo.teamTask = atoi( v ); - - // team leader - v = Info_ValueForKey( configstring, "tl" ); - newInfo.teamLeader = atoi( v ); - - v = Info_ValueForKey( configstring, "g_redteam" ); - Q_strncpyz( newInfo.redTeam, v, MAX_TEAMNAME ); - - v = Info_ValueForKey( configstring, "g_blueteam" ); - Q_strncpyz( newInfo.blueTeam, v, MAX_TEAMNAME ); - - // model - v = Info_ValueForKey( configstring, "model" ); - 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; - } - - // replace whatever was there with the new one - newInfo.infoValid = qtrue; - *ci = newInfo; - - // scan for an existing clientinfo that matches this modelname - // so we can avoid loading checks if possible - if( !CG_ScanForExistingClientInfo( ci ) ) - CG_LoadClientInfo( ci ); -} - - - -/* -============================================================================= - -PLAYER ANIMATION - -============================================================================= -*/ - - -/* -=============== -CG_SetLerpFrameAnimation - -may include ANIM_TOGGLEBIT -=============== -*/ -static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) -{ - animation_t *anim; - - lf->animationNumber = newAnimation; - newAnimation &= ~ANIM_TOGGLEBIT; - - if( newAnimation < 0 || newAnimation >= MAX_PLAYER_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_RunPlayerLerpFrame - -Sets cg.snap, cg.oldFrame, and cg.backlerp -cg.time should be between oldFrameTime and frameTime after exit -=============== -*/ -static void CG_RunPlayerLerpFrame( 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 = 1.0f; - - clientNum = cent->currentState.clientNum; - - if( cg_noPlayerAnims.integer ) - { - *legsOld = *legs = *torsoOld = *torso = 0; - return; - } - - ci = &cgs.clientinfo[ clientNum ]; - - // do the shuffle turn frames locally - if( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) - CG_RunPlayerLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale ); - else - CG_RunPlayerLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale ); - - *legsOld = cent->pe.legs.oldFrame; - *legs = cent->pe.legs.frame; - *legsBackLerp = cent->pe.legs.backlerp; - - CG_RunPlayerLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale ); - - *torsoOld = cent->pe.torso.oldFrame; - *torso = cent->pe.torso.frame; - *torsoBackLerp = cent->pe.torso.backlerp; -} - - -/* -=============== -CG_PlayerNonSegAnimation -=============== -*/ -static void CG_PlayerNonSegAnimation( centity_t *cent, int *nonSegOld, - int *nonSeg, float *nonSegBackLerp ) -{ - clientInfo_t *ci; - int clientNum; - float speedScale = 1.0f; - - clientNum = cent->currentState.clientNum; - - if( cg_noPlayerAnims.integer ) - { - *nonSegOld = *nonSeg = 0; - return; - } - - ci = &cgs.clientinfo[ clientNum ]; - - // do the shuffle turn frames locally - if( cent->pe.nonseg.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == NSPA_STAND ) - CG_RunPlayerLerpFrame( ci, ¢->pe.nonseg, NSPA_TURN, speedScale ); - else - CG_RunPlayerLerpFrame( ci, ¢->pe.nonseg, cent->currentState.legsAnim, speedScale ); - - *nonSegOld = cent->pe.nonseg.oldFrame; - *nonSeg = cent->pe.nonseg.frame; - *nonSegBackLerp = cent->pe.nonseg.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 srcAngles, - vec3_t legs[ 3 ], vec3_t torso[ 3 ], vec3_t head[ 3 ] ) -{ - vec3_t legsAngles, torsoAngles, headAngles; - float dest; - static int movementOffsets[ 8 ] = { 0, 22, 45, -22, 0, 22, -45, -22 }; - vec3_t velocity; - float speed; - int dir, clientNum; - clientInfo_t *ci; - - VectorCopy( srcAngles, headAngles ); - headAngles[ YAW ] = AngleMod( headAngles[ YAW ] ); - VectorClear( legsAngles ); - VectorClear( torsoAngles ); - - // --------- yaw ------------- - - // allow yaw to drift a bit - if( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE || - ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) - { - // if not standing still, always point all in the same direction - cent->pe.torso.yawing = qtrue; // always center - cent->pe.torso.pitching = qtrue; // always center - cent->pe.legs.yawing = qtrue; // always center - } - - // adjust legs for movement dir - if( cent->currentState.eFlags & EF_DEAD ) - { - // don't let dead bodies twitch - dir = 0; - } - else - { - //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 - if( cent->currentState.eFlags & EF_DEAD ) - { - CG_SwingAngles( torsoAngles[ YAW ], 0, 0, cg_swingSpeed.value, - ¢->pe.torso.yawAngle, ¢->pe.torso.yawing ); - CG_SwingAngles( legsAngles[ YAW ], 0, 0, cg_swingSpeed.value, - ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); - } - else - { - 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; - - // - clientNum = cent->currentState.clientNum; - - if( clientNum >= 0 && clientNum < MAX_CLIENTS ) - { - ci = &cgs.clientinfo[ clientNum ]; - if( ci->fixedtorso ) - torsoAngles[ PITCH ] = 0.0f; - } - - // --------- roll ------------- - - - // lean towards the direction of travel - VectorCopy( cent->currentState.pos.trDelta, velocity ); - speed = VectorNormalize( velocity ); - - if( speed ) - { - vec3_t axis[ 3 ]; - float side; - - speed *= 0.05f; - - AnglesToAxis( legsAngles, axis ); - side = speed * DotProduct( velocity, axis[ 1 ] ); - legsAngles[ ROLL ] -= side; - - side = speed * DotProduct( velocity, axis[ 0 ] ); - legsAngles[ PITCH ] += side; - } - - // - clientNum = cent->currentState.clientNum; - - if( clientNum >= 0 && clientNum < MAX_CLIENTS ) - { - ci = &cgs.clientinfo[ clientNum ]; - - if( ci->fixedlegs ) - { - legsAngles[ YAW ] = torsoAngles[ YAW ]; - legsAngles[ PITCH ] = 0.0f; - legsAngles[ ROLL ] = 0.0f; - } - } - - // pain twitch - CG_AddPainTwitch( cent, torsoAngles ); - - // pull the angles back out of the hierarchial chain - AnglesSubtract( headAngles, torsoAngles, headAngles ); - AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); - AnglesToAxis( legsAngles, legs ); - AnglesToAxis( torsoAngles, torso ); - AnglesToAxis( headAngles, head ); -} - -#define MODEL_WWSMOOTHTIME 200 - -/* -=============== -CG_PlayerWWSmoothing - -Smooth the angles of transitioning wall walkers -=============== -*/ -static void CG_PlayerWWSmoothing( centity_t *cent, vec3_t in[ 3 ], vec3_t out[ 3 ] ) -{ - entityState_t *es = ¢->currentState; - int i; - vec3_t surfNormal, rotAxis, temp; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - float stLocal, sFraction, rotAngle; - vec3_t inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ]; - - //set surfNormal - if( !(es->eFlags & EF_WALLCLIMB ) ) - VectorCopy( refNormal, surfNormal ); - else if( !( es->eFlags & EF_WALLCLIMBCEILING ) ) - VectorCopy( es->angles2, surfNormal ); - else - VectorCopy( ceilingNormal, surfNormal ); - - AxisCopy( in, inAxis ); - - if( !VectorCompare( surfNormal, cent->pe.lastNormal ) ) - { - //if we moving from the ceiling to the floor special case - //( x product of colinear vectors is undefined) - if( VectorCompare( ceilingNormal, cent->pe.lastNormal ) && - VectorCompare( refNormal, surfNormal ) ) - { - VectorCopy( in[ 1 ], rotAxis ); - rotAngle = 180.0f; - } - else - { - AxisCopy( cent->pe.lastAxis, lastAxis ); - rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) + - DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) + - DotProduct( inAxis[ 2 ], lastAxis[ 2 ] ); - - rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) ); - - CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp ); - VectorCopy( temp, rotAxis ); - CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp ); - VectorAdd( rotAxis, temp, rotAxis ); - CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp ); - VectorAdd( rotAxis, temp, rotAxis ); - - VectorNormalize( rotAxis ); - } - - //iterate through smooth array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //found an unused index in the smooth array - if( cent->pe.sList[ i ].time + MODEL_WWSMOOTHTIME < cg.time ) - { - //copy to array and stop - VectorCopy( rotAxis, cent->pe.sList[ i ].rotAxis ); - cent->pe.sList[ i ].rotAngle = rotAngle; - cent->pe.sList[ i ].time = cg.time; - break; - } - } - } - - //iterate through ops - for( i = MAXSMOOTHS - 1; i >= 0; i-- ) - { - //if this op has time remaining, perform it - if( cg.time < cent->pe.sList[ i ].time + MODEL_WWSMOOTHTIME ) - { - stLocal = 1.0f - ( ( ( cent->pe.sList[ i ].time + MODEL_WWSMOOTHTIME ) - cg.time ) / MODEL_WWSMOOTHTIME ); - sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f; - - RotatePointAroundVector( outAxis[ 0 ], cent->pe.sList[ i ].rotAxis, - inAxis[ 0 ], sFraction * cent->pe.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 1 ], cent->pe.sList[ i ].rotAxis, - inAxis[ 1 ], sFraction * cent->pe.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 2 ], cent->pe.sList[ i ].rotAxis, - inAxis[ 2 ], sFraction * cent->pe.sList[ i ].rotAngle ); - - AxisCopy( outAxis, inAxis ); - } - } - - //outAxis has been copied to inAxis - AxisCopy( inAxis, out ); -} - -/* -=============== -CG_PlayerNonSegAngles - -Resolve angles for non-segmented models -=============== -*/ -static void CG_PlayerNonSegAngles( centity_t *cent, vec3_t srcAngles, vec3_t nonSegAxis[ 3 ] ) -{ - vec3_t localAngles; - vec3_t velocity; - float speed; - int dir; - entityState_t *es = ¢->currentState; - vec3_t surfNormal; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - - VectorCopy( srcAngles, localAngles ); - localAngles[ YAW ] = AngleMod( localAngles[ YAW ] ); - localAngles[ PITCH ] = 0.0f; - localAngles[ ROLL ] = 0.0f; - - //set surfNormal - if( !( es->eFlags & EF_WALLCLIMBCEILING ) ) - VectorCopy( es->angles2, surfNormal ); - else - VectorCopy( ceilingNormal, surfNormal ); - - //make sure that WW transitions don't cause the swing stuff to go nuts - if( !VectorCompare( surfNormal, cent->pe.lastNormal ) ) - { - //stop CG_SwingAngles having an eppy - cent->pe.nonseg.yawAngle = localAngles[ YAW ]; - cent->pe.nonseg.yawing = qfalse; - } - - // --------- yaw ------------- - - // allow yaw to drift a bit - if( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != NSPA_STAND ) - { - // if not standing still, always point all in the same direction - cent->pe.nonseg.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" ); - } - - // torso - if( cent->currentState.eFlags & EF_DEAD ) - { - CG_SwingAngles( localAngles[ YAW ], 0, 0, cg_swingSpeed.value, - ¢->pe.nonseg.yawAngle, ¢->pe.nonseg.yawing ); - } - else - { - CG_SwingAngles( localAngles[ YAW ], 40, 90, cg_swingSpeed.value, - ¢->pe.nonseg.yawAngle, ¢->pe.nonseg.yawing ); - } - - localAngles[ YAW ] = cent->pe.nonseg.yawAngle; - - // --------- pitch ------------- - - //NO PITCH! - - - // --------- roll ------------- - - - // lean towards the direction of travel - VectorCopy( cent->currentState.pos.trDelta, velocity ); - speed = VectorNormalize( velocity ); - - if( speed ) - { - vec3_t axis[ 3 ]; - float side; - - //much less than with the regular model system - speed *= 0.01f; - - AnglesToAxis( localAngles, axis ); - side = speed * DotProduct( velocity, axis[ 1 ] ); - localAngles[ ROLL ] -= side; - - side = speed * DotProduct( velocity, axis[ 0 ] ); - localAngles[ PITCH ] += side; - } - - //FIXME: PAIN[123] animations? - // pain twitch - //CG_AddPainTwitch( cent, torsoAngles ); - - AnglesToAxis( localAngles, nonSegAxis ); -} - - -//========================================================================== - -/* -=============== -CG_PlayerUpgrade -=============== -*/ -static void CG_PlayerUpgrades( centity_t *cent, refEntity_t *torso ) -{ - int held, active; - refEntity_t jetpack; - refEntity_t battpack; - refEntity_t flash; - entityState_t *es = ¢->currentState; - - held = es->modelindex; - active = es->modelindex2; - - if( held & ( 1 << UP_JETPACK ) ) - { - memset( &jetpack, 0, sizeof( jetpack ) ); - VectorCopy( torso->lightingOrigin, jetpack.lightingOrigin ); - jetpack.shadowPlane = torso->shadowPlane; - jetpack.renderfx = torso->renderfx; - - jetpack.hModel = cgs.media.jetpackModel; - - //identity matrix - AxisCopy( axisDefault, jetpack.axis ); - - //FIXME: change to tag_back when it exists - CG_PositionRotatedEntityOnTag( &jetpack, torso, torso->hModel, "tag_head" ); - - trap_R_AddRefEntityToScene( &jetpack ); - - if( active & ( 1 << UP_JETPACK ) ) - { - if( es->pos.trDelta[ 2 ] > 10.0f ) - { - if( cent->jetPackState != JPS_ASCENDING ) - { - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - - cent->jetPackPS = CG_SpawnNewParticleSystem( cgs.media.jetPackAscendPS ); - cent->jetPackState = JPS_ASCENDING; - } - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.jetpackAscendSound ); - } - else if( es->pos.trDelta[ 2 ] < -10.0f ) - { - if( cent->jetPackState != JPS_DESCENDING ) - { - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - - cent->jetPackPS = CG_SpawnNewParticleSystem( cgs.media.jetPackDescendPS ); - cent->jetPackState = JPS_DESCENDING; - } - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.jetpackDescendSound ); - } - else - { - if( cent->jetPackState != JPS_HOVERING ) - { - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - - cent->jetPackPS = CG_SpawnNewParticleSystem( cgs.media.jetPackHoverPS ); - cent->jetPackState = JPS_HOVERING; - } - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.jetpackIdleSound ); - } - - memset( &flash, 0, sizeof( flash ) ); - VectorCopy( torso->lightingOrigin, flash.lightingOrigin ); - flash.shadowPlane = torso->shadowPlane; - flash.renderfx = torso->renderfx; - - flash.hModel = cgs.media.jetpackFlashModel; - if( !flash.hModel ) - return; - - AxisCopy( axisDefault, flash.axis ); - - CG_PositionRotatedEntityOnTag( &flash, &jetpack, jetpack.hModel, "tag_flash" ); - trap_R_AddRefEntityToScene( &flash ); - - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - { - CG_SetAttachmentTag( ¢->jetPackPS->attachment, - jetpack, jetpack.hModel, "tag_flash" ); - CG_SetAttachmentCent( ¢->jetPackPS->attachment, cent ); - CG_AttachToTag( ¢->jetPackPS->attachment ); - } - } - else if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - { - CG_DestroyParticleSystem( ¢->jetPackPS ); - cent->jetPackState = JPS_OFF; - } - } - else if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - { - CG_DestroyParticleSystem( ¢->jetPackPS ); - cent->jetPackState = JPS_OFF; - } - - if( held & ( 1 << UP_BATTPACK ) ) - { - memset( &battpack, 0, sizeof( battpack ) ); - VectorCopy( torso->lightingOrigin, battpack.lightingOrigin ); - battpack.shadowPlane = torso->shadowPlane; - battpack.renderfx = torso->renderfx; - - battpack.hModel = cgs.media.battpackModel; - - //identity matrix - AxisCopy( axisDefault, battpack.axis ); - - //FIXME: change to tag_back when it exists - CG_PositionRotatedEntityOnTag( &battpack, torso, torso->hModel, "tag_head" ); - - trap_R_AddRefEntityToScene( &battpack ); - } - - if( es->eFlags & EF_BLOBLOCKED ) - { - vec3_t temp, origin, up = { 0.0f, 0.0f, 1.0f }; - trace_t tr; - float size; - - VectorCopy( es->pos.trBase, temp ); - temp[ 2 ] -= 4096.0f; - - CG_Trace( &tr, es->pos.trBase, NULL, NULL, temp, es->number, MASK_SOLID ); - VectorCopy( tr.endpos, origin ); - - size = 32.0f; - - if( size > 0.0f ) - CG_ImpactMark( cgs.media.creepShader, origin, up, - 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue ); - } -} - - -/* -=============== -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 ) -{ - if( cent->currentState.eFlags & EF_CONNECTION ) - { - CG_PlayerFloatSprite( cent, cgs.media.connectionShader ); - return; - } - - if( cent->currentState.eFlags & EF_TALK ) - { - //TA: the masses have decreed this to be wrong -/* CG_PlayerFloatSprite( cent, cgs.media.balloonShader ); - 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, pClass_t class ) -{ - vec3_t end, mins, maxs; - trace_t trace; - float alpha; - entityState_t *es = ¢->currentState; - vec3_t surfNormal = { 0.0f, 0.0f, 1.0f }; - - BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); - mins[ 2 ] = 0.0f; - maxs[ 2 ] = 2.0f; - - if( es->eFlags & EF_WALLCLIMB ) - { - if( es->eFlags & EF_WALLCLIMBCEILING ) - VectorSet( surfNormal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( es->angles2, surfNormal ); - } - - *shadowPlane = 0; - - if( cg_shadows.integer == 0 ) - return qfalse; - - // send a trace down from the player to the ground - VectorCopy( cent->lerpOrigin, end ); - VectorMA( cent->lerpOrigin, -SHADOW_DISTANCE, surfNormal, end ); - - trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID ); - - // no shadow if too high - if( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) - return qfalse; - - //TA: FIXME: stencil shadows will be broken for walls. - // Unfortunately there isn't much that can be - // done since Q3 references only the Z coord - // of the shadowPlane - if( surfNormal[ 2 ] < 0.0f ) - *shadowPlane = trace.endpos[ 2 ] - 1.0f; - else - *shadowPlane = trace.endpos[ 2 ] + 1.0f; - - 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.0f * BG_FindShadowScaleForClass( class ), 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_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 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 ); -} - -#define TRACE_DEPTH 32.0f - -/* -=============== -CG_Player -=============== -*/ -void CG_Player( centity_t *cent ) -{ - clientInfo_t *ci; - - //TA: NOTE: legs is used for nonsegmented models - // this helps reduce code to be changed - refEntity_t legs; - refEntity_t torso; - refEntity_t head; - int clientNum; - int renderfx; - qboolean shadow = qfalse; - float shadowPlane; - entityState_t *es = ¢->currentState; - pClass_t class = ( es->powerups >> 8 ) & 0xFF; - float scale; - vec3_t tempAxis[ 3 ], tempAxis2[ 3 ]; - vec3_t angles; - int held = es->modelindex; - vec3_t surfNormal = { 0.0f, 0.0f, 1.0f }; - - // 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 = es->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; - - //don't draw - if( es->eFlags & EF_NODRAW ) - return; - - // get the player model information - renderfx = 0; - if( es->number == cg.snap->ps.clientNum ) - { - if( !cg.renderingThirdPerson ) - renderfx = RF_THIRD_PERSON; // only draw in mirrors - else if( cg_cameraMode.integer ) - return; - } - - if( cg_drawBBOX.integer ) - { - vec3_t mins, maxs; - - BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); - CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs ); - } - - memset( &legs, 0, sizeof( legs ) ); - memset( &torso, 0, sizeof( torso ) ); - memset( &head, 0, sizeof( head ) ); - - VectorCopy( cent->lerpAngles, angles ); - AnglesToAxis( cent->lerpAngles, tempAxis ); - - //rotate lerpAngles to floor - if( es->eFlags & EF_WALLCLIMB && - BG_RotateAxis( es->angles2, tempAxis, tempAxis2, qtrue, es->eFlags & EF_WALLCLIMBCEILING ) ) - AxisToAngles( tempAxis2, angles ); - else - VectorCopy( cent->lerpAngles, angles ); - - //normalise the pitch - if( angles[ PITCH ] < -180.0f ) - angles[ PITCH ] += 360.0f; - - // get the rotation information - if( !ci->nonsegmented ) - CG_PlayerAngles( cent, angles, legs.axis, torso.axis, head.axis ); - else - CG_PlayerNonSegAngles( cent, angles, legs.axis ); - - AxisCopy( legs.axis, tempAxis ); - - //rotate the legs axis to back to the wall - if( es->eFlags & EF_WALLCLIMB && - BG_RotateAxis( es->angles2, legs.axis, tempAxis, qfalse, es->eFlags & EF_WALLCLIMBCEILING ) ) - AxisCopy( tempAxis, legs.axis ); - - //smooth out WW transitions so the model doesn't hop around - CG_PlayerWWSmoothing( cent, legs.axis, legs.axis ); - - AxisCopy( tempAxis, cent->pe.lastAxis ); - - // get the animation state (after rotation, to allow feet shuffle) - if( !ci->nonsegmented ) - CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, - &torso.oldframe, &torso.frame, &torso.backlerp ); - else - CG_PlayerNonSegAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp ); - - // add the talk baloon or disconnect icon - CG_PlayerSprites( cent ); - - // add the shadow - if( ( es->number == cg.snap->ps.clientNum && cg.renderingThirdPerson ) || - es->number != cg.snap->ps.clientNum ) - shadow = CG_PlayerShadow( cent, &shadowPlane, class ); - - // 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 - // - if( !ci->nonsegmented ) - { - legs.hModel = ci->legsModel; - - if( held & ( 1 << UP_LIGHTARMOUR ) ) - legs.customSkin = cgs.media.larmourLegsSkin; - else - legs.customSkin = ci->legsSkin; - } - else - { - legs.hModel = ci->nonSegModel; - legs.customSkin = ci->nonSegSkin; - } - - 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 - - //move the origin closer into the wall with a CapTrace - if( es->eFlags & EF_WALLCLIMB && !( es->eFlags & EF_DEAD ) && !( cg.intermissionStarted ) ) - { - vec3_t start, end, mins, maxs; - trace_t tr; - - if( es->eFlags & EF_WALLCLIMBCEILING ) - VectorSet( surfNormal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( es->angles2, surfNormal ); - - BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); - - VectorMA( legs.origin, -TRACE_DEPTH, surfNormal, end ); - VectorMA( legs.origin, 1.0f, surfNormal, start ); - CG_CapTrace( &tr, start, mins, maxs, end, es->number, MASK_PLAYERSOLID ); - - //if the trace misses completely then just use legs.origin - //apparently capsule traces are "smaller" than box traces - if( tr.fraction != 1.0f ) - VectorMA( legs.origin, tr.fraction * -TRACE_DEPTH, surfNormal, legs.origin ); - - VectorCopy( legs.origin, legs.lightingOrigin ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - } - - //rescale the model - scale = BG_FindModelScaleForClass( class ); - - if( scale != 1.0f ) - { - VectorScale( legs.axis[ 0 ], scale, legs.axis[ 0 ] ); - VectorScale( legs.axis[ 1 ], scale, legs.axis[ 1 ] ); - VectorScale( legs.axis[ 2 ], scale, legs.axis[ 2 ] ); - - legs.nonNormalizedAxes = qtrue; - } - - //offset on the Z axis if required - VectorMA( legs.origin, BG_FindZOffsetForClass( class ), surfNormal, legs.origin ); - VectorCopy( legs.origin, legs.lightingOrigin ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - - trap_R_AddRefEntityToScene( &legs ); - - // if the model failed, allow the default nullmodel to be displayed - if( !legs.hModel ) - return; - - if( !ci->nonsegmented ) - { - // - // add the torso - // - torso.hModel = ci->torsoModel; - - if( held & ( 1 << UP_LIGHTARMOUR ) ) - torso.customSkin = cgs.media.larmourTorsoSkin; - else - torso.customSkin = ci->torsoSkin; - - if( !torso.hModel ) - return; - - VectorCopy( cent->lerpOrigin, torso.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso" ); - - torso.shadowPlane = shadowPlane; - torso.renderfx = renderfx; - - trap_R_AddRefEntityToScene( &torso ); - - // - // add the head - // - head.hModel = ci->headModel; - - if( held & ( 1 << UP_HELMET ) ) - head.customSkin = cgs.media.larmourHeadSkin; - else - head.customSkin = ci->headSkin; - - if( !head.hModel ) - return; - - VectorCopy( cent->lerpOrigin, head.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head" ); - - head.shadowPlane = shadowPlane; - head.renderfx = renderfx; - - trap_R_AddRefEntityToScene( &head ); - } - - // - // add the gun / barrel / flash - // - if( es->weapon != WP_NONE ) - { - if( !ci->nonsegmented ) - CG_AddPlayerWeapon( &torso, NULL, cent ); - else - CG_AddPlayerWeapon( &legs, NULL, cent ); - } - - CG_PlayerUpgrades( cent, &torso ); - - //sanity check that particle systems are stopped when dead - if( es->eFlags & EF_DEAD ) - { - if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) - CG_DestroyParticleSystem( ¢->muzzlePS ); - - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - } - - VectorCopy( surfNormal, cent->pe.lastNormal ); -} - -/* -=============== -CG_Corpse -=============== -*/ -void CG_Corpse( centity_t *cent ) -{ - clientInfo_t *ci; - refEntity_t legs; - refEntity_t torso; - refEntity_t head; - entityState_t *es = ¢->currentState; - int corpseNum; - int renderfx; - qboolean shadow = qfalse; - float shadowPlane; - vec3_t origin, liveZ, deadZ; - float scale; - - corpseNum = CG_GetCorpseNum( es->clientNum ); - - if( corpseNum < 0 || corpseNum >= MAX_CLIENTS ) - CG_Error( "Bad corpseNum on corpse entity: %d", corpseNum ); - - ci = &cgs.corpseinfo[ corpseNum ]; - - // 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 ) ); - - VectorCopy( cent->lerpOrigin, origin ); - BG_FindBBoxForClass( es->clientNum, liveZ, NULL, NULL, deadZ, NULL ); - origin[ 2 ] -= ( liveZ[ 2 ] - deadZ[ 2 ] ); - - VectorCopy( es->angles, cent->lerpAngles ); - - // get the rotation information - if( !ci->nonsegmented ) - CG_PlayerAngles( cent, cent->lerpAngles, legs.axis, torso.axis, head.axis ); - else - CG_PlayerNonSegAngles( cent, cent->lerpAngles, legs.axis ); - - //set the correct frame (should always be dead) - if( cg_noPlayerAnims.integer ) - legs.oldframe = legs.frame = torso.oldframe = torso.frame = 0; - else if( !ci->nonsegmented ) - { - memset( ¢->pe.legs, 0, sizeof( lerpFrame_t ) ); - CG_RunPlayerLerpFrame( ci, ¢->pe.legs, es->legsAnim, 1 ); - legs.oldframe = cent->pe.legs.oldFrame; - legs.frame = cent->pe.legs.frame; - legs.backlerp = cent->pe.legs.backlerp; - - memset( ¢->pe.torso, 0, sizeof( lerpFrame_t ) ); - CG_RunPlayerLerpFrame( ci, ¢->pe.torso, es->torsoAnim, 1 ); - torso.oldframe = cent->pe.torso.oldFrame; - torso.frame = cent->pe.torso.frame; - torso.backlerp = cent->pe.torso.backlerp; - } - else - { - memset( ¢->pe.nonseg, 0, sizeof( lerpFrame_t ) ); - CG_RunPlayerLerpFrame( ci, ¢->pe.nonseg, es->legsAnim, 1 ); - legs.oldframe = cent->pe.nonseg.oldFrame; - legs.frame = cent->pe.nonseg.frame; - legs.backlerp = cent->pe.nonseg.backlerp; - } - - // add the shadow - shadow = CG_PlayerShadow( cent, &shadowPlane, es->clientNum ); - - // 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 - // - if( !ci->nonsegmented ) - { - legs.hModel = ci->legsModel; - legs.customSkin = ci->legsSkin; - } - else - { - legs.hModel = ci->nonSegModel; - legs.customSkin = ci->nonSegSkin; - } - - VectorCopy( origin, legs.origin ); - - VectorCopy( origin, legs.lightingOrigin ); - legs.shadowPlane = shadowPlane; - legs.renderfx = renderfx; - legs.origin[ 2 ] += BG_FindZOffsetForClass( es->clientNum ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - - //rescale the model - scale = BG_FindModelScaleForClass( es->clientNum ); - - if( scale != 1.0f ) - { - VectorScale( legs.axis[ 0 ], scale, legs.axis[ 0 ] ); - VectorScale( legs.axis[ 1 ], scale, legs.axis[ 1 ] ); - VectorScale( legs.axis[ 2 ], scale, legs.axis[ 2 ] ); - - legs.nonNormalizedAxes = qtrue; - } - - //CG_AddRefEntityWithPowerups( &legs, es->powerups, ci->team ); - trap_R_AddRefEntityToScene( &legs ); - - // if the model failed, allow the default nullmodel to be displayed - if( !legs.hModel ) - return; - - if( !ci->nonsegmented ) - { - // - // add the torso - // - torso.hModel = ci->torsoModel; - if( !torso.hModel ) - return; - - torso.customSkin = ci->torsoSkin; - - VectorCopy( origin, torso.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso" ); - - torso.shadowPlane = shadowPlane; - torso.renderfx = renderfx; - - //CG_AddRefEntityWithPowerups( &torso, es->powerups, ci->team ); - trap_R_AddRefEntityToScene( &torso ); - - // - // add the head - // - head.hModel = ci->headModel; - if( !head.hModel ) - return; - - head.customSkin = ci->headSkin; - - VectorCopy( origin, head.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head"); - - head.shadowPlane = shadowPlane; - head.renderfx = renderfx; - - //CG_AddRefEntityWithPowerups( &head, es->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 ); - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], - ¢->pe.nonseg, cent->currentState.legsAnim ); - - 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; - - memset( ¢->pe.nonseg, 0, sizeof( cent->pe.nonseg ) ); - cent->pe.nonseg.yawAngle = cent->rawAngles[ YAW ]; - cent->pe.nonseg.yawing = qfalse; - cent->pe.nonseg.pitchAngle = cent->rawAngles[ PITCH ]; - cent->pe.nonseg.pitching = qfalse; - - if( cg_debugPosition.integer ) - CG_Printf( "%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle ); -} - -/* -================== -CG_PlayerDisconnect - -Player disconnecting -================== -*/ -void CG_PlayerDisconnect( vec3_t org ) -{ - particleSystem_t *ps; - - trap_S_StartSound( org, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.disconnectSound ); - - ps = CG_SpawnNewParticleSystem( cgs.media.disconnectPS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentPoint( &ps->attachment, org ); - CG_AttachToPoint( &ps->attachment ); - } -} - -/* -================= -CG_Bleed - -This is the spurt of blood when a character gets hit -================= -*/ -void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum ) -{ - pTeam_t team = cgs.clientinfo[ entityNum ].team; - qhandle_t bleedPS; - particleSystem_t *ps; - - if( !cg_blood.integer ) - return; - - if( team == PTE_ALIENS ) - bleedPS = cgs.media.alienBleedPS; - else if( team == PTE_HUMANS ) - bleedPS = cgs.media.humanBleedPS; - else - return; - - ps = CG_SpawnNewParticleSystem( bleedPS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentPoint( &ps->attachment, origin ); - CG_SetAttachmentCent( &ps->attachment, &cg_entities[ entityNum ] ); - CG_AttachToPoint( &ps->attachment ); - - CG_SetParticleSystemNormal( ps, normal ); - } -} |