2013-04-19 02:52:48 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
// cg_players.c -- handle the media and animation for player entities
# include "cg_local.h"
2013-04-19 03:47:29 +00:00
# include "../ghoul2/g2.h"
2013-04-19 02:52:48 +00:00
# include "bg_saga.h"
extern vmCvar_t cg_thirdPersonAlpha ;
extern int cgSiegeTeam1PlShader ;
extern int cgSiegeTeam2PlShader ;
extern void CG_AddRadarEnt ( centity_t * cent ) ; //cg_ents.c
extern void CG_AddBracketedEnt ( centity_t * cent ) ; //cg_ents.c
extern qboolean CG_InFighter ( void ) ;
extern qboolean WP_SaberBladeUseSecondBladeStyle ( saberInfo_t * saber , int bladeNum ) ;
//for g2 surface routines
# define TURN_ON 0x00000000
# define TURN_OFF 0x00000100
extern stringID_table_t animTable [ MAX_ANIMATIONS + 1 ] ;
char * cg_customSoundNames [ MAX_CUSTOM_SOUNDS ] = {
" *death1 " ,
" *death2 " ,
" *death3 " ,
" *jump1 " ,
" *pain25 " ,
" *pain50 " ,
" *pain75 " ,
" *pain100 " ,
" *falling1 " ,
" *choke1 " ,
" *choke2 " ,
" *choke3 " ,
" *gasp " ,
" *land1 " ,
" *taunt " ,
NULL
} ;
//NPC sounds:
//Used as a supplement to the basic set for enemies and hazard team
// (keep numbers in ascending order in order for variant-capping to work)
const char * cg_customCombatSoundNames [ MAX_CUSTOM_COMBAT_SOUNDS ] =
{
" *anger1 " , //Say when acquire an enemy when didn't have one before
" *anger2 " ,
" *anger3 " ,
" *victory1 " , //Say when killed an enemy
" *victory2 " ,
" *victory3 " ,
" *confuse1 " , //Say when confused
" *confuse2 " ,
" *confuse3 " ,
" *pushed1 " , //Say when force-pushed
" *pushed2 " ,
" *pushed3 " ,
" *choke1 " ,
" *choke2 " ,
" *choke3 " ,
" *ffwarn " ,
" *ffturn " ,
NULL
} ;
//Used as a supplement to the basic set for stormtroopers
// (keep numbers in ascending order in order for variant-capping to work)
const char * cg_customExtraSoundNames [ MAX_CUSTOM_EXTRA_SOUNDS ] =
{
" *chase1 " ,
" *chase2 " ,
" *chase3 " ,
" *cover1 " ,
" *cover2 " ,
" *cover3 " ,
" *cover4 " ,
" *cover5 " ,
" *detected1 " ,
" *detected2 " ,
" *detected3 " ,
" *detected4 " ,
" *detected5 " ,
" *lost1 " ,
" *outflank1 " ,
" *outflank2 " ,
" *escaping1 " ,
" *escaping2 " ,
" *escaping3 " ,
" *giveup1 " ,
" *giveup2 " ,
" *giveup3 " ,
" *giveup4 " ,
" *look1 " ,
" *look2 " ,
" *sight1 " ,
" *sight2 " ,
" *sight3 " ,
" *sound1 " ,
" *sound2 " ,
" *sound3 " ,
" *suspicious1 " ,
" *suspicious2 " ,
" *suspicious3 " ,
" *suspicious4 " ,
" *suspicious5 " ,
NULL
} ;
//Used as a supplement to the basic set for jedi
// (keep numbers in ascending order in order for variant-capping to work)
const char * cg_customJediSoundNames [ MAX_CUSTOM_JEDI_SOUNDS ] =
{
" *combat1 " ,
" *combat2 " ,
" *combat3 " ,
" *jdetected1 " ,
" *jdetected2 " ,
" *jdetected3 " ,
" *taunt1 " ,
" *taunt2 " ,
" *taunt3 " ,
" *jchase1 " ,
" *jchase2 " ,
" *jchase3 " ,
" *jlost1 " ,
" *jlost2 " ,
" *jlost3 " ,
" *deflect1 " ,
" *deflect2 " ,
" *deflect3 " ,
" *gloat1 " ,
" *gloat2 " ,
" *gloat3 " ,
" *pushfail " ,
NULL
} ;
//Used for DUEL taunts
const char * cg_customDuelSoundNames [ MAX_CUSTOM_DUEL_SOUNDS ] =
{
" *anger1 " , //Say when acquire an enemy when didn't have one before
" *anger2 " ,
" *anger3 " ,
" *victory1 " , //Say when killed an enemy
" *victory2 " ,
" *victory3 " ,
" *taunt1 " ,
" *taunt2 " ,
" *taunt3 " ,
" *deflect1 " ,
" *deflect2 " ,
" *deflect3 " ,
" *gloat1 " ,
" *gloat2 " ,
" *gloat3 " ,
NULL
} ;
void CG_Disintegration ( centity_t * cent , refEntity_t * ent ) ;
/*
= = = = = = = = = = = = = = = =
CG_CustomSound
= = = = = = = = = = = = = = = =
*/
sfxHandle_t CG_CustomSound ( int clientNum , const char * soundName ) {
clientInfo_t * ci ;
int i ;
int numCSounds = 0 ;
int numCComSounds = 0 ;
int numCExSounds = 0 ;
int numCJediSounds = 0 ;
int numCSiegeSounds = 0 ;
int numCDuelSounds = 0 ;
char lSoundName [ MAX_QPATH ] ;
if ( soundName [ 0 ] ! = ' * ' ) {
return trap_S_RegisterSound ( soundName ) ;
}
COM_StripExtension ( soundName , lSoundName ) ;
if ( clientNum < 0 )
{
clientNum = 0 ;
}
if ( clientNum > = MAX_CLIENTS )
{
ci = cg_entities [ clientNum ] . npcClient ;
}
else
{
ci = & cgs . clientinfo [ clientNum ] ;
}
if ( ! ci )
{
return 0 ;
}
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( ! cg_customSoundNames [ i ] )
{
numCSounds = i ;
break ;
}
}
if ( clientNum > = MAX_CLIENTS )
{ //these are only for npc's
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( ! cg_customCombatSoundNames [ i ] )
{
numCComSounds = i ;
break ;
}
}
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( ! cg_customExtraSoundNames [ i ] )
{
numCExSounds = i ;
break ;
}
}
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( ! cg_customJediSoundNames [ i ] )
{
numCJediSounds = i ;
break ;
}
}
}
if ( cgs . gametype > = GT_TEAM | | cg_buildScript . integer )
{ //siege only
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( ! bg_customSiegeSoundNames [ i ] )
{
numCSiegeSounds = i ;
break ;
}
}
}
if ( cgs . gametype = = GT_DUEL
| | cgs . gametype = = GT_POWERDUEL
| | cg_buildScript . integer )
{ //Duel only
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( ! cg_customDuelSoundNames [ i ] )
{
numCDuelSounds = i ;
break ;
}
}
}
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
if ( i < numCSounds & & ! strcmp ( lSoundName , cg_customSoundNames [ i ] ) )
{
return ci - > sounds [ i ] ;
}
else if ( ( cgs . gametype > = GT_TEAM | | cg_buildScript . integer ) & & i < numCSiegeSounds & & ! strcmp ( lSoundName , bg_customSiegeSoundNames [ i ] ) )
{ //siege only
return ci - > siegeSounds [ i ] ;
}
else if ( ( cgs . gametype = = GT_DUEL | | cgs . gametype = = GT_POWERDUEL | | cg_buildScript . integer ) & & i < numCDuelSounds & & ! strcmp ( lSoundName , cg_customDuelSoundNames [ i ] ) )
{ //siege only
return ci - > duelSounds [ i ] ;
}
else if ( clientNum > = MAX_CLIENTS & & i < numCComSounds & & ! strcmp ( lSoundName , cg_customCombatSoundNames [ i ] ) )
{ //npc only
return ci - > combatSounds [ i ] ;
}
else if ( clientNum > = MAX_CLIENTS & & i < numCExSounds & & ! strcmp ( lSoundName , cg_customExtraSoundNames [ i ] ) )
{ //npc only
return ci - > extraSounds [ i ] ;
}
else if ( clientNum > = MAX_CLIENTS & & i < numCJediSounds & & ! strcmp ( lSoundName , cg_customJediSoundNames [ i ] ) )
{ //npc only
return ci - > jediSounds [ i ] ;
}
}
//CG_Error( "Unknown custom sound: %s", lSoundName );
# ifndef FINAL_BUILD
Com_Printf ( " Unknown custom sound: %s " , lSoundName ) ;
# endif
return 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CLIENT INFO
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define MAX_SURF_LIST_SIZE 1024
qboolean CG_ParseSurfsFile ( const char * modelName , const char * skinName , char * surfOff , char * surfOn )
{
const char * text_p ;
int len ;
const char * token ;
const char * value ;
char text [ 20000 ] ;
char sfilename [ MAX_QPATH ] ;
fileHandle_t f ;
int i = 0 ;
while ( skinName & & skinName [ i ] )
{
if ( skinName [ i ] = = ' | ' )
{ //this is a multi-part skin, said skins do not support .surf files
return qfalse ;
}
i + + ;
}
// Load and parse .surf file
Com_sprintf ( sfilename , sizeof ( sfilename ) , " models/players/%s/model_%s.surf " , modelName , skinName ) ;
// load the file
len = trap_FS_FOpenFile ( sfilename , & f , FS_READ ) ;
if ( len < = 0 )
{ //no file
return qfalse ;
}
if ( len > = sizeof ( text ) - 1 )
{
Com_Printf ( " File %s too long \n " , sfilename ) ;
return qfalse ;
}
trap_FS_Read ( text , len , f ) ;
text [ len ] = 0 ;
trap_FS_FCloseFile ( f ) ;
// parse the text
text_p = text ;
memset ( ( char * ) surfOff , 0 , sizeof ( surfOff ) ) ;
memset ( ( char * ) surfOn , 0 , sizeof ( surfOn ) ) ;
// read information for surfOff and surfOn
while ( 1 )
{
token = COM_ParseExt ( & text_p , qtrue ) ;
if ( ! token | | ! token [ 0 ] )
{
break ;
}
// surfOff
if ( ! Q_stricmp ( token , " surfOff " ) )
{
if ( COM_ParseString ( & text_p , & value ) )
{
continue ;
}
if ( surfOff & & surfOff [ 0 ] )
{
Q_strcat ( surfOff , MAX_SURF_LIST_SIZE , " , " ) ;
Q_strcat ( surfOff , MAX_SURF_LIST_SIZE , value ) ;
}
else
{
Q_strncpyz ( surfOff , value , MAX_SURF_LIST_SIZE ) ;
}
continue ;
}
// surfOn
if ( ! Q_stricmp ( token , " surfOn " ) )
{
if ( COM_ParseString ( & text_p , & value ) )
{
continue ;
}
if ( surfOn & & surfOn [ 0 ] )
{
Q_strcat ( surfOn , MAX_SURF_LIST_SIZE , " , " ) ;
Q_strcat ( surfOn , MAX_SURF_LIST_SIZE , value ) ;
}
else
{
Q_strncpyz ( surfOn , value , MAX_SURF_LIST_SIZE ) ;
}
continue ;
}
}
return qtrue ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
CG_RegisterClientModelname
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "../namespace_begin.h"
qboolean BG_IsValidCharacterModel ( const char * modelName , const char * skinName ) ;
qboolean BG_ValidateSkinForTeam ( const char * modelName , char * skinName , int team , float * colors ) ;
# include "../namespace_end.h"
static qboolean CG_RegisterClientModelname ( clientInfo_t * ci , const char * modelName , const char * skinName , const char * teamName , int clientNum ) {
int handle ;
char afilename [ MAX_QPATH ] ;
char /**GLAName,*/ * slash ;
char GLAName [ MAX_QPATH ] ;
vec3_t tempVec = { 0 , 0 , 0 } ;
qboolean badModel = qfalse ;
char surfOff [ MAX_SURF_LIST_SIZE ] ;
char surfOn [ MAX_SURF_LIST_SIZE ] ;
int checkSkin ;
char * useSkinName ;
retryModel :
if ( badModel )
{
if ( modelName & & modelName [ 0 ] )
{
Com_Printf ( " WARNING: Attempted to load an unsupported multiplayer model %s! (bad or missing bone, or missing animation sequence) \n " , modelName ) ;
}
modelName = " kyle " ;
skinName = " default " ;
badModel = qfalse ;
}
// First things first. If this is a ghoul2 model, then let's make sure we demolish this first.
if ( ci - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{
trap_G2API_CleanGhoul2Models ( & ( ci - > ghoul2Model ) ) ;
}
if ( ! BG_IsValidCharacterModel ( modelName , skinName ) )
{
modelName = " kyle " ;
skinName = " default " ;
}
if ( cgs . gametype > = GT_TEAM & & ! cgs . jediVmerc & & cgs . gametype ! = GT_SIEGE )
{ //We won't force colors for siege.
BG_ValidateSkinForTeam ( ci - > modelName , ci - > skinName , ci - > team , ci - > colorOverride ) ;
skinName = ci - > skinName ;
}
else
{
ci - > colorOverride [ 0 ] = ci - > colorOverride [ 1 ] = ci - > colorOverride [ 2 ] = 0.0f ;
}
if ( strchr ( skinName , ' | ' ) )
{ //three part skin
useSkinName = va ( " models/players/%s/|%s " , modelName , skinName ) ;
}
else
{
useSkinName = va ( " models/players/%s/model_%s.skin " , modelName , skinName ) ;
}
checkSkin = trap_R_RegisterSkin ( useSkinName ) ;
if ( checkSkin )
{
ci - > torsoSkin = checkSkin ;
}
else
{ //fallback to the default skin
ci - > torsoSkin = trap_R_RegisterSkin ( va ( " models/players/%s/model_default.skin " , modelName , skinName ) ) ;
}
Com_sprintf ( afilename , sizeof ( afilename ) , " models/players/%s/model.glm " , modelName ) ;
handle = trap_G2API_InitGhoul2Model ( & ci - > ghoul2Model , afilename , 0 , ci - > torsoSkin , 0 , 0 , 0 ) ;
if ( handle < 0 )
{
return qfalse ;
}
// The model is now loaded.
trap_G2API_SetSkin ( ci - > ghoul2Model , 0 , ci - > torsoSkin , ci - > torsoSkin ) ;
GLAName [ 0 ] = 0 ;
trap_G2API_GetGLAName ( ci - > ghoul2Model , 0 , GLAName ) ;
if ( GLAName [ 0 ] ! = 0 )
{
if ( ! strstr ( GLAName , " players/_humanoid/ " ) /*&&
( ! strstr ( GLAName , " players/rockettrooper/ " ) | | cgs . gametype ! = GT_SIEGE ) */ ) //only allow rockettrooper in siege
{ //Bad!
badModel = qtrue ;
goto retryModel ;
}
}
if ( ! BGPAFtextLoaded )
{
if ( GLAName [ 0 ] = = 0 /*GLAName == NULL*/ )
{
badModel = qtrue ;
goto retryModel ;
}
Q_strncpyz ( afilename , GLAName , sizeof ( afilename ) ) ;
slash = Q_strrchr ( afilename , ' / ' ) ;
if ( slash )
{
strcpy ( slash , " /animation.cfg " ) ;
} // Now afilename holds just the path to the animation.cfg
else
{ // Didn't find any slashes, this is a raw filename right in base (whish isn't a good thing)
return qfalse ;
}
//rww - All player models must use humanoid, no matter what.
if ( Q_stricmp ( afilename , " models/players/_humanoid/animation.cfg " ) /*&&
Q_stricmp ( afilename , " models/players/rockettrooper/animation.cfg " ) */ )
{
Com_Printf ( " Model does not use supported animation config. \n " ) ;
return qfalse ;
}
else if ( BG_ParseAnimationFile ( " models/players/_humanoid/animation.cfg " , bgHumanoidAnimations , qtrue ) = = - 1 )
{
Com_Printf ( " Failed to load animation file models/players/_humanoid/animation.cfg \n " ) ;
return qfalse ;
}
BG_ParseAnimationEvtFile ( " models/players/_humanoid/ " , 0 , - 1 ) ; //get the sounds for the humanoid anims
// if (cgs.gametype == GT_SIEGE)
// {
// BG_ParseAnimationEvtFile( "models/players/rockettrooper/", 1, 1 ); //parse rockettrooper too
// }
//For the time being, we're going to have all real players use the generic humanoid soundset and that's it.
//Only npc's will use model-specific soundsets.
// BG_ParseAnimationSndFile(va("models/players/%s/", modelName), 0, -1);
}
else if ( ! bgAllEvents [ 0 ] . eventsParsed )
{ //make sure the player anim sounds are loaded even if the anims already are
BG_ParseAnimationEvtFile ( " models/players/_humanoid/ " , 0 , - 1 ) ;
// if (cgs.gametype == GT_SIEGE)
// {
// BG_ParseAnimationEvtFile( "models/players/rockettrooper/", 1, 1 );
// }
}
if ( CG_ParseSurfsFile ( modelName , skinName , surfOff , surfOn ) )
{ //turn on/off any surfs
const char * token ;
const char * p ;
//Now turn on/off any surfaces
if ( surfOff & & surfOff [ 0 ] )
{
p = surfOff ;
while ( 1 )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( ! token [ 0 ] )
{ //reached end of list
break ;
}
//turn off this surf
trap_G2API_SetSurfaceOnOff ( ci - > ghoul2Model , token , 0x00000002 /*G2SURFACEFLAG_OFF*/ ) ;
}
}
if ( surfOn & & surfOn [ 0 ] )
{
p = surfOn ;
while ( 1 )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( ! token [ 0 ] )
{ //reached end of list
break ;
}
//turn on this surf
trap_G2API_SetSurfaceOnOff ( ci - > ghoul2Model , token , 0 ) ;
}
}
}
ci - > bolt_rhand = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *r_hand " ) ;
if ( ! trap_G2API_SetBoneAnim ( ci - > ghoul2Model , 0 , " model_root " , 0 , 12 , BONE_ANIM_OVERRIDE_LOOP , 1.0f , cg . time , - 1 , - 1 ) )
{
badModel = qtrue ;
}
if ( ! trap_G2API_SetBoneAngles ( ci - > ghoul2Model , 0 , " upper_lumbar " , tempVec , BONE_ANGLES_POSTMULT , POSITIVE_X , NEGATIVE_Y , NEGATIVE_Z , NULL , 0 , cg . time ) )
{
badModel = qtrue ;
}
if ( ! trap_G2API_SetBoneAngles ( ci - > ghoul2Model , 0 , " cranium " , tempVec , BONE_ANGLES_POSTMULT , POSITIVE_Z , NEGATIVE_Y , POSITIVE_X , NULL , 0 , cg . time ) )
{
badModel = qtrue ;
}
ci - > bolt_lhand = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *l_hand " ) ;
//rhand must always be first bolt. lhand always second. Whichever you want the
//jetpack bolted to must always be third.
trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *chestg " ) ;
//claw bolts
trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *r_hand_cap_r_arm " ) ;
trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *l_hand_cap_l_arm " ) ;
ci - > bolt_head = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *head_top " ) ;
if ( ci - > bolt_head = = - 1 )
{
ci - > bolt_head = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " ceyebrow " ) ;
}
ci - > bolt_motion = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " Motion " ) ;
//We need a lower lumbar bolt for footsteps
ci - > bolt_llumbar = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " lower_lumbar " ) ;
if ( ci - > bolt_rhand = = - 1 | | ci - > bolt_lhand = = - 1 | | ci - > bolt_head = = - 1 | | ci - > bolt_motion = = - 1 | | ci - > bolt_llumbar = = - 1 )
{
badModel = qtrue ;
}
if ( badModel )
{
goto retryModel ;
}
if ( ! Q_stricmp ( modelName , " boba_fett " ) )
{ //special case, turn off the jetpack surfs
trap_G2API_SetSurfaceOnOff ( ci - > ghoul2Model , " torso_rjet " , TURN_OFF ) ;
trap_G2API_SetSurfaceOnOff ( ci - > ghoul2Model , " torso_cjet " , TURN_OFF ) ;
trap_G2API_SetSurfaceOnOff ( ci - > ghoul2Model , " torso_ljet " , TURN_OFF ) ;
}
// ent->s.radius = 90;
if ( clientNum ! = - 1 )
{
/*
if ( cg_entities [ clientNum ] . ghoul2 & & trap_G2_HaveWeGhoul2Models ( cg_entities [ clientNum ] . ghoul2 ) )
{
trap_G2API_CleanGhoul2Models ( & ( cg_entities [ clientNum ] . ghoul2 ) ) ;
}
trap_G2API_DuplicateGhoul2Instance ( ci - > ghoul2Model , & cg_entities [ clientNum ] . ghoul2 ) ;
*/
cg_entities [ clientNum ] . ghoul2weapon = NULL ;
}
Q_strncpyz ( ci - > teamName , teamName , sizeof ( ci - > teamName ) ) ;
// Model icon for drawing the portrait on screen
ci - > modelIcon = trap_R_RegisterShaderNoMip ( va ( " models/players/%s/icon_%s " , modelName , skinName ) ) ;
if ( ! ci - > modelIcon )
{
int i = 0 ;
int j ;
char iconName [ 1024 ] ;
strcpy ( iconName , " icon_ " ) ;
j = strlen ( iconName ) ;
while ( skinName [ i ] & & skinName [ i ] ! = ' | ' & & j < 1024 )
{
iconName [ j ] = skinName [ i ] ;
j + + ;
i + + ;
}
iconName [ j ] = 0 ;
if ( skinName [ i ] = = ' | ' )
{ //looks like it actually may be a custom model skin, let's try getting the icon...
ci - > modelIcon = trap_R_RegisterShaderNoMip ( va ( " models/players/%s/%s " , modelName , iconName ) ) ;
}
}
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_ColorFromInt
= = = = = = = = = = = = = = = = = = = =
*/
static void CG_ColorFromInt ( int val , vec3_t color ) {
VectorClear ( color ) ;
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 ;
}
}
//load anim info
int CG_G2SkelForModel ( void * g2 )
{
int animIndex = - 1 ;
char GLAName [ MAX_QPATH ] ;
char * slash ;
GLAName [ 0 ] = 0 ;
trap_G2API_GetGLAName ( g2 , 0 , GLAName ) ;
slash = Q_strrchr ( GLAName , ' / ' ) ;
if ( slash )
{
strcpy ( slash , " /animation.cfg " ) ;
animIndex = BG_ParseAnimationFile ( GLAName , NULL , qfalse ) ;
}
return animIndex ;
}
//get the appropriate anim events file index
int CG_G2EvIndexForModel ( void * g2 , int animIndex )
{
int evtIndex = - 1 ;
char GLAName [ MAX_QPATH ] ;
char * slash ;
if ( animIndex = = - 1 )
{
assert ( ! " shouldn't happen, bad animIndex " ) ;
return - 1 ;
}
GLAName [ 0 ] = 0 ;
trap_G2API_GetGLAName ( g2 , 0 , GLAName ) ;
slash = Q_strrchr ( GLAName , ' / ' ) ;
if ( slash )
{
slash + + ;
* slash = 0 ;
evtIndex = BG_ParseAnimationEvtFile ( GLAName , animIndex , bgNumAnimEvents ) ;
}
return evtIndex ;
}
# define DEFAULT_FEMALE_SOUNDPATH "chars / mp_generic_female / misc" //"chars/tavion/misc"
# define DEFAULT_MALE_SOUNDPATH "chars / mp_generic_male / misc" //"chars/kyle/misc"
void CG_LoadCISounds ( clientInfo_t * ci , qboolean modelloaded )
{
fileHandle_t f ;
qboolean isFemale = qfalse ;
int i = 0 ;
int fLen = 0 ;
const char * dir ;
char soundpath [ MAX_QPATH ] ;
char soundName [ 1024 ] ;
const char * s ;
dir = ci - > modelName ;
if ( ! ci - > skinName | | ! Q_stricmp ( " default " , ci - > skinName ) )
{ //try default sounds.cfg first
fLen = trap_FS_FOpenFile ( va ( " models/players/%s/sounds.cfg " , dir ) , & f , FS_READ ) ;
if ( ! f )
{ //no? Look for _default sounds.cfg
fLen = trap_FS_FOpenFile ( va ( " models/players/%s/sounds_default.cfg " , dir ) , & f , FS_READ ) ;
}
}
else
{ //use the .skin associated with this skin
fLen = trap_FS_FOpenFile ( va ( " models/players/%s/sounds_%s.cfg " , dir , ci - > skinName ) , & f , FS_READ ) ;
if ( ! f )
{ //fall back to default sounds
fLen = trap_FS_FOpenFile ( va ( " models/players/%s/sounds.cfg " , dir ) , & f , FS_READ ) ;
}
}
soundpath [ 0 ] = 0 ;
if ( f )
{
trap_FS_Read ( soundpath , fLen , f ) ;
soundpath [ fLen ] = 0 ;
i = fLen ;
while ( i > = 0 & & soundpath [ i ] ! = ' \n ' )
{
if ( soundpath [ i ] = = ' f ' )
{
isFemale = qtrue ;
soundpath [ i ] = 0 ;
}
i - - ;
}
i = 0 ;
while ( soundpath [ i ] & & soundpath [ i ] ! = ' \r ' & & soundpath [ i ] ! = ' \n ' )
{
i + + ;
}
soundpath [ i ] = 0 ;
trap_FS_FCloseFile ( f ) ;
}
if ( isFemale )
{
ci - > gender = GENDER_FEMALE ;
}
else
{
ci - > gender = GENDER_MALE ;
}
trap_S_ShutUp ( qtrue ) ;
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i + + )
{
s = cg_customSoundNames [ i ] ;
if ( ! s ) {
break ;
}
Com_sprintf ( soundName , sizeof ( soundName ) , " %s " , s + 1 ) ;
COM_StripExtension ( soundName , soundName ) ;
//strip the extension because we might want .mp3's
ci - > sounds [ i ] = 0 ;
// if the model didn't load use the sounds of the default model
if ( soundpath [ 0 ] )
{
ci - > sounds [ i ] = trap_S_RegisterSound ( va ( " sound/chars/%s/misc/%s " , soundpath , soundName ) ) ;
}
else
{
if ( modelloaded )
{
ci - > sounds [ i ] = trap_S_RegisterSound ( va ( " sound/chars/%s/misc/%s " , dir , soundName ) ) ;
}
}
if ( ! ci - > sounds [ i ] )
{ //failed the load, try one out of the generic path
if ( isFemale )
{
ci - > sounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , DEFAULT_FEMALE_SOUNDPATH , soundName ) ) ;
}
else
{
ci - > sounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , DEFAULT_MALE_SOUNDPATH , soundName ) ) ;
}
}
}
if ( cgs . gametype > = GT_TEAM | | cg_buildScript . integer )
{ //load the siege sounds then
for ( i = 0 ; i < MAX_CUSTOM_SIEGE_SOUNDS ; i + + )
{
s = bg_customSiegeSoundNames [ i ] ;
if ( ! s )
{
break ;
}
Com_sprintf ( soundName , sizeof ( soundName ) , " %s " , s + 1 ) ;
COM_StripExtension ( soundName , soundName ) ;
//strip the extension because we might want .mp3's
ci - > siegeSounds [ i ] = 0 ;
// if the model didn't load use the sounds of the default model
if ( soundpath [ 0 ] )
{
ci - > siegeSounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , soundpath , soundName ) ) ;
}
else
{
if ( modelloaded )
{
ci - > siegeSounds [ i ] = trap_S_RegisterSound ( va ( " sound/chars/%s/misc/%s " , dir , soundName ) ) ;
}
}
if ( ! ci - > siegeSounds [ i ] )
{ //failed the load, try one out of the generic path
if ( isFemale )
{
ci - > siegeSounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , DEFAULT_FEMALE_SOUNDPATH , soundName ) ) ;
}
else
{
ci - > siegeSounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , DEFAULT_MALE_SOUNDPATH , soundName ) ) ;
}
}
}
}
if ( cgs . gametype = = GT_DUEL
| | cgs . gametype = = GT_POWERDUEL
| | cg_buildScript . integer )
{ //load the Duel sounds then
for ( i = 0 ; i < MAX_CUSTOM_DUEL_SOUNDS ; i + + )
{
s = cg_customDuelSoundNames [ i ] ;
if ( ! s )
{
break ;
}
Com_sprintf ( soundName , sizeof ( soundName ) , " %s " , s + 1 ) ;
COM_StripExtension ( soundName , soundName ) ;
//strip the extension because we might want .mp3's
ci - > duelSounds [ i ] = 0 ;
// if the model didn't load use the sounds of the default model
if ( soundpath [ 0 ] )
{
ci - > duelSounds [ i ] = trap_S_RegisterSound ( va ( " sound/chars/%s/misc/%s " , soundpath , soundName ) ) ;
}
else
{
if ( modelloaded )
{
ci - > duelSounds [ i ] = trap_S_RegisterSound ( va ( " sound/chars/%s/misc/%s " , dir , soundName ) ) ;
}
}
if ( ! ci - > duelSounds [ i ] )
{ //failed the load, try one out of the generic path
if ( isFemale )
{
ci - > duelSounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , DEFAULT_FEMALE_SOUNDPATH , soundName ) ) ;
}
else
{
ci - > duelSounds [ i ] = trap_S_RegisterSound ( va ( " sound/%s/%s " , DEFAULT_MALE_SOUNDPATH , soundName ) ) ;
}
}
}
}
trap_S_ShutUp ( qfalse ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
CG_LoadClientInfo
Load it now , taking the disk hits .
This will usually be deferred to a safe time
= = = = = = = = = = = = = = = = = = =
*/
void CG_LoadClientInfo ( clientInfo_t * ci ) {
qboolean modelloaded ;
int clientNum ;
int i ;
char teamname [ MAX_QPATH ] ;
clientNum = ci - cgs . clientinfo ;
if ( clientNum < 0 | | clientNum > = MAX_CLIENTS )
{
clientNum = - 1 ;
}
ci - > deferred = qfalse ;
/*
if ( ci - > team = = TEAM_SPECTATOR )
{
// 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 ] ) ;
}
}
if ( ci - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{
trap_G2API_CleanGhoul2Models ( & ci - > ghoul2Model ) ;
}
return ;
}
*/
teamname [ 0 ] = 0 ;
if ( cgs . gametype > = GT_TEAM ) {
if ( ci - > team = = TEAM_BLUE ) {
Q_strncpyz ( teamname , DEFAULT_BLUETEAM_NAME /*cg_blueTeamName.string*/ , sizeof ( teamname ) ) ;
} else {
Q_strncpyz ( teamname , DEFAULT_REDTEAM_NAME /*cg_redTeamName.string*/ , sizeof ( teamname ) ) ;
}
}
if ( teamname [ 0 ] ) {
strcat ( teamname , " / " ) ;
}
modelloaded = qtrue ;
if ( cgs . gametype = = GT_SIEGE & &
( ci - > team = = TEAM_SPECTATOR | | ci - > siegeIndex = = - 1 ) )
{ //yeah.. kind of a hack I guess. Don't care until they are actually ingame with a valid class.
if ( ! CG_RegisterClientModelname ( ci , DEFAULT_MODEL , " default " , teamname , - 1 ) )
{
CG_Error ( " DEFAULT_MODEL (%s) failed to register " , DEFAULT_MODEL ) ;
}
}
else
{
if ( ! CG_RegisterClientModelname ( ci , ci - > modelName , ci - > skinName , teamname , clientNum ) ) {
//CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
//rww - DO NOT error out here! Someone could just type in a nonsense model name and crash everyone's client.
//Give it a chance to load default model for this client instead.
// fall back to default team name
if ( cgs . gametype > = GT_TEAM ) {
// keep skin name
if ( ci - > team = = TEAM_BLUE ) {
Q_strncpyz ( teamname , DEFAULT_BLUETEAM_NAME , sizeof ( teamname ) ) ;
} else {
Q_strncpyz ( teamname , DEFAULT_REDTEAM_NAME , sizeof ( teamname ) ) ;
}
if ( ! CG_RegisterClientModelname ( ci , DEFAULT_MODEL , ci - > skinName , teamname , - 1 ) ) {
CG_Error ( " DEFAULT_MODEL / skin (%s/%s) failed to register " , DEFAULT_MODEL , ci - > skinName ) ;
}
} else {
if ( ! CG_RegisterClientModelname ( ci , DEFAULT_MODEL , " default " , teamname , - 1 ) ) {
CG_Error ( " DEFAULT_MODEL (%s) failed to register " , DEFAULT_MODEL ) ;
}
}
modelloaded = qfalse ;
}
}
if ( clientNum ! = - 1 )
{
trap_G2API_ClearAttachedInstance ( clientNum ) ;
}
if ( clientNum ! = - 1 & & ci - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{
if ( cg_entities [ clientNum ] . ghoul2 & & trap_G2_HaveWeGhoul2Models ( cg_entities [ clientNum ] . ghoul2 ) )
{
trap_G2API_CleanGhoul2Models ( & cg_entities [ clientNum ] . ghoul2 ) ;
}
trap_G2API_DuplicateGhoul2Instance ( ci - > ghoul2Model , & cg_entities [ clientNum ] . ghoul2 ) ;
//Attach the instance to this entity num so we can make use of client-server
//shared operations if possible.
trap_G2API_AttachInstanceToEntNum ( cg_entities [ clientNum ] . ghoul2 , clientNum , qfalse ) ;
if ( trap_G2API_AddBolt ( cg_entities [ clientNum ] . ghoul2 , 0 , " face " ) = = - 1 )
{ //check now to see if we have this bone for setting anims and such
cg_entities [ clientNum ] . noFace = qtrue ;
}
cg_entities [ clientNum ] . localAnimIndex = CG_G2SkelForModel ( cg_entities [ clientNum ] . ghoul2 ) ;
cg_entities [ clientNum ] . eventAnimIndex = CG_G2EvIndexForModel ( cg_entities [ clientNum ] . ghoul2 , cg_entities [ clientNum ] . localAnimIndex ) ;
}
ci - > newAnims = qfalse ;
if ( ci - > torsoModel ) {
orientation_t tag ;
// if the torso model has the "tag_flag"
if ( trap_R_LerpTag ( & tag , ci - > torsoModel , 0 , 0 , 1 , " tag_flag " ) ) {
ci - > newAnims = qtrue ;
}
}
// sounds
if ( cgs . gametype = = GT_SIEGE & &
( ci - > team = = TEAM_SPECTATOR | | ci - > siegeIndex = = - 1 ) )
{ //don't need to load sounds
}
else
{
CG_LoadCISounds ( ci , modelloaded ) ;
}
ci - > deferred = qfalse ;
// reset any existing players and bodies, because they might be in bad
// frames for this new model
clientNum = ci - cgs . clientinfo ;
for ( i = 0 ; i < MAX_GENTITIES ; i + + ) {
if ( cg_entities [ i ] . currentState . clientNum = = clientNum
& & cg_entities [ i ] . currentState . eType = = ET_PLAYER ) {
CG_ResetPlayerEntity ( & cg_entities [ i ] ) ;
}
}
}
//Take care of initializing all the ghoul2 saber stuff based on clientinfo data. -rww
static void CG_InitG2SaberData ( int saberNum , clientInfo_t * ci )
{
trap_G2API_InitGhoul2Model ( & ci - > ghoul2Weapons [ saberNum ] , ci - > saber [ saberNum ] . model , 0 , ci - > saber [ saberNum ] . skin , 0 , 0 , 0 ) ;
if ( ci - > ghoul2Weapons [ saberNum ] )
{
int k = 0 ;
int tagBolt ;
char * tagName ;
if ( ci - > saber [ saberNum ] . skin )
{
trap_G2API_SetSkin ( ci - > ghoul2Weapons [ saberNum ] , 0 , ci - > saber [ saberNum ] . skin , ci - > saber [ saberNum ] . skin ) ;
}
if ( ci - > saber [ saberNum ] . saberFlags & SFL_BOLT_TO_WRIST )
{
trap_G2API_SetBoltInfo ( ci - > ghoul2Weapons [ saberNum ] , 0 , 3 + saberNum ) ;
}
else
{
trap_G2API_SetBoltInfo ( ci - > ghoul2Weapons [ saberNum ] , 0 , saberNum ) ;
}
while ( k < ci - > saber [ saberNum ] . numBlades )
{
tagName = va ( " *blade%i " , k + 1 ) ;
tagBolt = trap_G2API_AddBolt ( ci - > ghoul2Weapons [ saberNum ] , 0 , tagName ) ;
if ( tagBolt = = - 1 )
{
if ( k = = 0 )
{ //guess this is an 0ldsk3wl saber
tagBolt = trap_G2API_AddBolt ( ci - > ghoul2Weapons [ saberNum ] , 0 , " *flash " ) ;
if ( tagBolt = = - 1 )
{
assert ( 0 ) ;
}
break ;
}
if ( tagBolt = = - 1 )
{
assert ( 0 ) ;
break ;
}
}
k + + ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = =
CG_CopyClientInfoModel
= = = = = = = = = = = = = = = = = = = = = =
*/
static void CG_CopyClientInfoModel ( clientInfo_t * from , clientInfo_t * to )
{
VectorCopy ( from - > headOffset , to - > headOffset ) ;
// to->footsteps = from->footsteps;
to - > gender = from - > gender ;
to - > legsModel = from - > legsModel ;
to - > legsSkin = from - > legsSkin ;
to - > torsoModel = from - > torsoModel ;
to - > torsoSkin = from - > torsoSkin ;
//to->headModel = from->headModel;
//to->headSkin = from->headSkin;
to - > modelIcon = from - > modelIcon ;
to - > newAnims = from - > newAnims ;
//to->ghoul2Model = from->ghoul2Model;
//rww - Trying to use the same ghoul2 pointer for two seperate clients == DISASTER
assert ( to - > ghoul2Model ! = from - > ghoul2Model ) ;
if ( to - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( to - > ghoul2Model ) )
{
trap_G2API_CleanGhoul2Models ( & to - > ghoul2Model ) ;
}
if ( from - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( from - > ghoul2Model ) )
{
trap_G2API_DuplicateGhoul2Instance ( from - > ghoul2Model , & to - > ghoul2Model ) ;
}
//Don't do this, I guess. Just leave the saber info in the original, so it will be
//properly initialized.
/*
strcpy ( to - > saberName , from - > saberName ) ;
strcpy ( to - > saber2Name , from - > saber2Name ) ;
while ( i < MAX_SABERS )
{
if ( to - > ghoul2Weapons [ i ] & & trap_G2_HaveWeGhoul2Models ( to - > ghoul2Weapons [ i ] ) )
{
trap_G2API_CleanGhoul2Models ( & to - > ghoul2Weapons [ i ] ) ;
}
WP_SetSaber ( to - > saber , 0 , to - > saberName ) ;
WP_SetSaber ( to - > saber , 1 , to - > saber2Name ) ;
j = 0 ;
while ( j < MAX_SABERS )
{
if ( to - > saber [ j ] . model [ 0 ] )
{
CG_InitG2SaberData ( j , to ) ;
}
j + + ;
}
i + + ;
}
*/
to - > bolt_head = from - > bolt_head ;
to - > bolt_lhand = from - > bolt_lhand ;
to - > bolt_rhand = from - > bolt_rhand ;
to - > bolt_motion = from - > bolt_motion ;
to - > bolt_llumbar = from - > bolt_llumbar ;
to - > siegeIndex = from - > siegeIndex ;
memcpy ( to - > sounds , from - > sounds , sizeof ( to - > sounds ) ) ;
memcpy ( to - > siegeSounds , from - > siegeSounds , sizeof ( to - > siegeSounds ) ) ;
memcpy ( to - > duelSounds , from - > duelSounds , sizeof ( to - > duelSounds ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
CG_ScanForExistingClientInfo
= = = = = = = = = = = = = = = = = = = = = =
*/
static qboolean CG_ScanForExistingClientInfo ( clientInfo_t * ci , int clientNum ) {
int i ;
clientInfo_t * match ;
for ( i = 0 ; i < cgs . maxclients ; i + + ) {
match = & cgs . clientinfo [ i ] ;
if ( ! match - > infoValid ) {
continue ;
}
if ( match - > deferred ) {
continue ;
}
if ( ! Q_stricmp ( ci - > modelName , match - > modelName )
& & ! Q_stricmp ( ci - > skinName , match - > skinName )
& & ! Q_stricmp ( ci - > saberName , match - > saberName )
& & ! Q_stricmp ( ci - > saber2Name , match - > saber2Name )
// && !Q_stricmp( ci->headModelName, match->headModelName )
// && !Q_stricmp( ci->headSkinName, match->headSkinName )
// && !Q_stricmp( ci->blueTeam, match->blueTeam )
// && !Q_stricmp( ci->redTeam, match->redTeam )
& & ( cgs . gametype < GT_TEAM | | ci - > team = = match - > team )
& & ci - > siegeIndex = = match - > siegeIndex
& & match - > ghoul2Model
& & match - > bolt_head ) //if the bolts haven't been initialized, this "match" is useless to us
{
// this clientinfo is identical, so use it's handles
ci - > deferred = qfalse ;
//rww - Filthy hack. If this is actually the info already belonging to us, just reassign the pointer.
//Switching instances when not necessary produces small animation glitches.
//Actually, before, were we even freeing the instance attached to the old clientinfo before copying
//this new clientinfo over it? Could be a nasty leak possibility. (though this should remedy it in theory)
if ( clientNum = = i )
{
if ( match - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( match - > ghoul2Model ) )
{ //The match has a valid instance (if it didn't, we'd probably already be fudged (^_^) at this state)
if ( ci - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{ //First kill the copy we have if we have one. (but it should be null)
trap_G2API_CleanGhoul2Models ( & ci - > ghoul2Model ) ;
}
VectorCopy ( match - > headOffset , ci - > headOffset ) ;
// ci->footsteps = match->footsteps;
ci - > gender = match - > gender ;
ci - > legsModel = match - > legsModel ;
ci - > legsSkin = match - > legsSkin ;
ci - > torsoModel = match - > torsoModel ;
ci - > torsoSkin = match - > torsoSkin ;
ci - > modelIcon = match - > modelIcon ;
ci - > newAnims = match - > newAnims ;
ci - > bolt_head = match - > bolt_head ;
ci - > bolt_lhand = match - > bolt_lhand ;
ci - > bolt_rhand = match - > bolt_rhand ;
ci - > bolt_motion = match - > bolt_motion ;
ci - > bolt_llumbar = match - > bolt_llumbar ;
ci - > siegeIndex = match - > siegeIndex ;
memcpy ( ci - > sounds , match - > sounds , sizeof ( ci - > sounds ) ) ;
memcpy ( ci - > siegeSounds , match - > siegeSounds , sizeof ( ci - > siegeSounds ) ) ;
memcpy ( ci - > duelSounds , match - > duelSounds , sizeof ( ci - > duelSounds ) ) ;
//We can share this pointer, because it already belongs to this client.
//The pointer itself and the ghoul2 instance is never actually changed, just passed between
//clientinfo structures.
ci - > ghoul2Model = match - > ghoul2Model ;
//Don't need to do this I guess, whenever this function is called the saber stuff should
//already be taken care of in the new info.
/*
while ( k < MAX_SABERS )
{
if ( match - > ghoul2Weapons [ k ] & & match - > ghoul2Weapons [ k ] ! = ci - > ghoul2Weapons [ k ] )
{
if ( ci - > ghoul2Weapons [ k ] )
{
trap_G2API_CleanGhoul2Models ( & ci - > ghoul2Weapons [ k ] ) ;
}
ci - > ghoul2Weapons [ k ] = match - > ghoul2Weapons [ k ] ;
}
k + + ;
}
*/
}
}
else
{
CG_CopyClientInfoModel ( match , ci ) ;
}
return qtrue ;
}
}
// nothing matches, so defer the load
return qfalse ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
CG_SetDeferredClientInfo
We aren ' t going to load it now , so grab some other
client ' s info to use until we have some spare time .
= = = = = = = = = = = = = = = = = = = = = =
*/
static void CG_SetDeferredClientInfo ( clientInfo_t * ci ) {
int i ;
clientInfo_t * match ;
// if someone else is already the same models and skins we
// can just load the client info
for ( i = 0 ; i < cgs . maxclients ; i + + ) {
match = & cgs . clientinfo [ i ] ;
if ( ! match - > infoValid | | match - > deferred ) {
continue ;
}
if ( Q_stricmp ( ci - > skinName , match - > skinName ) | |
Q_stricmp ( ci - > modelName , match - > modelName ) | |
// Q_stricmp( ci->headModelName, match->headModelName ) ||
// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
( cgs . gametype > = GT_TEAM & & ci - > team ! = match - > team & & ci - > team ! = TEAM_SPECTATOR ) ) {
continue ;
}
/*
if ( Q_stricmp ( ci - > saberName , match - > saberName ) | |
Q_stricmp ( ci - > saber2Name , match - > saber2Name ) )
{
continue ;
}
*/
// just load the real info cause it uses the same models and skins
CG_LoadClientInfo ( ci ) ;
return ;
}
// if we are in teamplay, only grab a model if the skin is correct
if ( cgs . gametype > = GT_TEAM ) {
for ( i = 0 ; i < cgs . maxclients ; i + + ) {
match = & cgs . clientinfo [ i ] ;
if ( ! match - > infoValid | | match - > deferred ) {
continue ;
}
if ( ci - > team ! = TEAM_SPECTATOR & &
( Q_stricmp ( ci - > skinName , match - > skinName ) | |
( cgs . gametype > = GT_TEAM & & ci - > team ! = match - > team ) ) ) {
continue ;
}
/*
if ( Q_stricmp ( ci - > saberName , match - > saberName ) | |
Q_stricmp ( ci - > saber2Name , match - > saber2Name ) )
{
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 ;
}
/*
if ( Q_stricmp ( ci - > saberName , match - > saberName ) | |
Q_stricmp ( ci - > saber2Name , match - > saber2Name ) )
{
continue ;
}
*/
if ( match - > deferred )
{ //no deferring off of deferred info. Because I said so.
continue ;
}
ci - > deferred = qtrue ;
CG_CopyClientInfoModel ( match , ci ) ;
return ;
}
// we should never get here...
//CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
//Actually it is possible now because of the unique sabers.
CG_LoadClientInfo ( ci ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
CG_NewClientInfo
= = = = = = = = = = = = = = = = = = = = = =
*/
# include "../namespace_begin.h"
void WP_SetSaber ( int entNum , saberInfo_t * sabers , int saberNum , const char * saberName ) ;
# include "../namespace_end.h"
void CG_NewClientInfo ( int clientNum , qboolean entitiesInitialized ) {
clientInfo_t * ci ;
clientInfo_t newInfo ;
const char * configstring ;
const char * v ;
char * slash ;
void * oldGhoul2 ;
void * oldG2Weapons [ MAX_SABERS ] ;
int i = 0 ;
int k = 0 ;
qboolean saberUpdate [ MAX_SABERS ] ;
ci = & cgs . clientinfo [ clientNum ] ;
oldGhoul2 = ci - > ghoul2Model ;
while ( k < MAX_SABERS )
{
oldG2Weapons [ k ] = ci - > ghoul2Weapons [ k ] ;
k + + ;
}
configstring = CG_ConfigString ( clientNum + CS_PLAYERS ) ;
if ( ! configstring [ 0 ] ) {
if ( ci - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{ //clean this stuff up first
trap_G2API_CleanGhoul2Models ( & ci - > ghoul2Model ) ;
}
k = 0 ;
while ( k < MAX_SABERS )
{
if ( ci - > ghoul2Weapons [ k ] & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Weapons [ k ] ) )
{
trap_G2API_CleanGhoul2Models ( & ci - > ghoul2Weapons [ k ] ) ;
}
k + + ;
}
memset ( ci , 0 , sizeof ( * ci ) ) ;
return ; // player just left
}
// build into a temp buffer so the defer checks can use
// the old value
memset ( & newInfo , 0 , sizeof ( newInfo ) ) ;
// isolate the player's name
v = Info_ValueForKey ( configstring , " n " ) ;
Q_strncpyz ( newInfo . name , v , sizeof ( newInfo . name ) ) ;
// colors
v = Info_ValueForKey ( configstring , " c1 " ) ;
CG_ColorFromString ( v , newInfo . color1 ) ;
newInfo . icolor1 = atoi ( v ) ;
v = Info_ValueForKey ( configstring , " c2 " ) ;
CG_ColorFromString ( v , newInfo . color2 ) ;
newInfo . icolor2 = atoi ( v ) ;
// 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 ) ;
//copy team info out to menu
if ( clientNum = = cg . clientNum ) //this is me
{
trap_Cvar_Set ( " ui_team " , v ) ;
}
// team task
v = Info_ValueForKey ( configstring , " tt " ) ;
newInfo . teamTask = atoi ( v ) ;
// team leader
v = Info_ValueForKey ( configstring , " tl " ) ;
newInfo . teamLeader = atoi ( v ) ;
// v = Info_ValueForKey( configstring, "g_redteam" );
// Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
// v = Info_ValueForKey( configstring, "g_blueteam" );
// Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
// model
v = Info_ValueForKey ( configstring , " model " ) ;
if ( cg_forceModel . integer ) {
// forcemodel makes everyone use a single model
// to prevent load hitches
char modelStr [ MAX_QPATH ] ;
char * skin ;
trap_Cvar_VariableStringBuffer ( " model " , modelStr , sizeof ( modelStr ) ) ;
if ( ( skin = strchr ( modelStr , ' / ' ) ) = = NULL ) {
skin = " default " ;
} else {
* skin + + = 0 ;
}
Q_strncpyz ( newInfo . skinName , skin , sizeof ( newInfo . skinName ) ) ;
Q_strncpyz ( newInfo . modelName , modelStr , sizeof ( newInfo . modelName ) ) ;
if ( cgs . gametype > = GT_TEAM ) {
// keep skin name
slash = strchr ( v , ' / ' ) ;
if ( slash ) {
Q_strncpyz ( newInfo . skinName , slash + 1 , sizeof ( newInfo . skinName ) ) ;
}
}
} else {
Q_strncpyz ( newInfo . modelName , v , sizeof ( newInfo . modelName ) ) ;
slash = strchr ( newInfo . modelName , ' / ' ) ;
if ( ! slash ) {
// modelName didn not include a skin name
Q_strncpyz ( newInfo . skinName , " default " , sizeof ( newInfo . skinName ) ) ;
} else {
Q_strncpyz ( newInfo . skinName , slash + 1 , sizeof ( newInfo . skinName ) ) ;
// truncate modelName
* slash = 0 ;
}
}
if ( cgs . gametype = = GT_SIEGE )
{ //entries only sent in siege mode
//siege desired team
v = Info_ValueForKey ( configstring , " sdt " ) ;
if ( v & & v [ 0 ] )
{
newInfo . siegeDesiredTeam = atoi ( v ) ;
}
else
{
newInfo . siegeDesiredTeam = 0 ;
}
//siege classname
v = Info_ValueForKey ( configstring , " siegeclass " ) ;
newInfo . siegeIndex = - 1 ;
if ( v )
{
siegeClass_t * siegeClass = BG_SiegeFindClassByName ( v ) ;
if ( siegeClass )
{ //See if this class forces a model, if so, then use it. Same for skin.
newInfo . siegeIndex = BG_SiegeFindClassIndexByName ( v ) ;
if ( siegeClass - > forcedModel [ 0 ] )
{
Q_strncpyz ( newInfo . modelName , siegeClass - > forcedModel , sizeof ( newInfo . modelName ) ) ;
}
if ( siegeClass - > forcedSkin [ 0 ] )
{
Q_strncpyz ( newInfo . skinName , siegeClass - > forcedSkin , sizeof ( newInfo . skinName ) ) ;
}
if ( siegeClass - > hasForcedSaberColor )
{
newInfo . icolor1 = siegeClass - > forcedSaberColor ;
CG_ColorFromInt ( newInfo . icolor1 , newInfo . color1 ) ;
}
if ( siegeClass - > hasForcedSaber2Color )
{
newInfo . icolor2 = siegeClass - > forcedSaber2Color ;
CG_ColorFromInt ( newInfo . icolor2 , newInfo . color2 ) ;
}
}
}
}
saberUpdate [ 0 ] = qfalse ;
saberUpdate [ 1 ] = qfalse ;
//saber being used
v = Info_ValueForKey ( configstring , " st " ) ;
if ( v & & Q_stricmp ( v , ci - > saberName ) )
{
Q_strncpyz ( newInfo . saberName , v , 64 ) ;
WP_SetSaber ( clientNum , newInfo . saber , 0 , newInfo . saberName ) ;
saberUpdate [ 0 ] = qtrue ;
}
else
{
Q_strncpyz ( newInfo . saberName , ci - > saberName , 64 ) ;
memcpy ( & newInfo . saber [ 0 ] , & ci - > saber [ 0 ] , sizeof ( newInfo . saber [ 0 ] ) ) ;
newInfo . ghoul2Weapons [ 0 ] = ci - > ghoul2Weapons [ 0 ] ;
}
v = Info_ValueForKey ( configstring , " st2 " ) ;
if ( v & & Q_stricmp ( v , ci - > saber2Name ) )
{
Q_strncpyz ( newInfo . saber2Name , v , 64 ) ;
WP_SetSaber ( clientNum , newInfo . saber , 1 , newInfo . saber2Name ) ;
saberUpdate [ 1 ] = qtrue ;
}
else
{
Q_strncpyz ( newInfo . saber2Name , ci - > saber2Name , 64 ) ;
memcpy ( & newInfo . saber [ 1 ] , & ci - > saber [ 1 ] , sizeof ( newInfo . saber [ 1 ] ) ) ;
newInfo . ghoul2Weapons [ 1 ] = ci - > ghoul2Weapons [ 1 ] ;
}
if ( saberUpdate [ 0 ] | | saberUpdate [ 1 ] )
{
int j = 0 ;
while ( j < MAX_SABERS )
{
if ( saberUpdate [ j ] )
{
if ( newInfo . saber [ j ] . model [ 0 ] )
{
if ( oldG2Weapons [ j ] )
{ //free the old instance(s)
trap_G2API_CleanGhoul2Models ( & oldG2Weapons [ j ] ) ;
oldG2Weapons [ j ] = 0 ;
}
CG_InitG2SaberData ( j , & newInfo ) ;
}
else
{
if ( oldG2Weapons [ j ] )
{ //free the old instance(s)
trap_G2API_CleanGhoul2Models ( & oldG2Weapons [ j ] ) ;
oldG2Weapons [ j ] = 0 ;
}
}
cg_entities [ clientNum ] . weapon = 0 ;
cg_entities [ clientNum ] . ghoul2weapon = NULL ; //force a refresh
}
j + + ;
}
}
//Check for any sabers that didn't get set again, if they didn't, then reassign the pointers for the new ci
k = 0 ;
while ( k < MAX_SABERS )
{
if ( oldG2Weapons [ k ] )
{
newInfo . ghoul2Weapons [ k ] = oldG2Weapons [ k ] ;
}
k + + ;
}
//duel team
v = Info_ValueForKey ( configstring , " dt " ) ;
if ( v )
{
newInfo . duelTeam = atoi ( v ) ;
}
else
{
newInfo . duelTeam = 0 ;
}
// force powers
v = Info_ValueForKey ( configstring , " forcepowers " ) ;
Q_strncpyz ( newInfo . forcePowers , v , sizeof ( newInfo . forcePowers ) ) ;
if ( cgs . gametype > = GT_TEAM & & ! cgs . jediVmerc & & cgs . gametype ! = GT_SIEGE )
{ //We won't force colors for siege.
BG_ValidateSkinForTeam ( newInfo . modelName , newInfo . skinName , newInfo . team , newInfo . colorOverride ) ;
}
else
{
newInfo . colorOverride [ 0 ] = newInfo . colorOverride [ 1 ] = newInfo . colorOverride [ 2 ] = 0.0f ;
}
// scan for an existing clientinfo that matches this modelname
// so we can avoid loading checks if possible
if ( ! CG_ScanForExistingClientInfo ( & newInfo , clientNum ) ) {
// if we are defering loads, just have it pick the first valid
if ( cg . snap & & cg . snap - > ps . clientNum = = clientNum )
{ //rww - don't defer your own client info ever
CG_LoadClientInfo ( & newInfo ) ;
}
else if ( cg_deferPlayers . integer & & cgs . gametype ! = GT_SIEGE & & ! cg_buildScript . integer & & ! cg . loading ) {
// keep whatever they had if it won't violate team skins
CG_SetDeferredClientInfo ( & newInfo ) ;
} else {
CG_LoadClientInfo ( & newInfo ) ;
}
}
// replace whatever was there with the new one
newInfo . infoValid = qtrue ;
if ( ci - > ghoul2Model & &
ci - > ghoul2Model ! = newInfo . ghoul2Model & &
trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{ //We must kill this instance before we remove our only pointer to it from the cgame.
//Otherwise we will end up with extra instances all over the place, I think.
trap_G2API_CleanGhoul2Models ( & ci - > ghoul2Model ) ;
}
* ci = newInfo ;
//force a weapon change anyway, for all clients being rendered to the current client
while ( i < MAX_CLIENTS )
{
cg_entities [ i ] . ghoul2weapon = NULL ;
i + + ;
}
if ( clientNum ! = - 1 )
{ //don't want it using an invalid pointer to share
trap_G2API_ClearAttachedInstance ( clientNum ) ;
}
// Check if the ghoul2 model changed in any way. This is safer than assuming we have a legal cent shile loading info.
if ( entitiesInitialized & & ci - > ghoul2Model & & ( oldGhoul2 ! = ci - > ghoul2Model ) )
{ // Copy the new ghoul2 model to the centity.
animation_t * anim ;
centity_t * cent = & cg_entities [ clientNum ] ;
anim = & bgHumanoidAnimations [ ( cg_entities [ clientNum ] . currentState . legsAnim ) ] ;
if ( anim )
{
int flags = BONE_ANIM_OVERRIDE_FREEZE ;
int firstFrame = anim - > firstFrame ;
int setFrame = - 1 ;
float animSpeed = 50.0f / anim - > frameLerp ;
if ( anim - > loopFrames ! = - 1 )
{
flags = BONE_ANIM_OVERRIDE_LOOP ;
}
if ( cent - > pe . legs . frame > = anim - > firstFrame & & cent - > pe . legs . frame < = ( anim - > firstFrame + anim - > numFrames ) )
{
setFrame = cent - > pe . legs . frame ;
}
//rww - Set the animation again because it just got reset due to the model change
trap_G2API_SetBoneAnim ( ci - > ghoul2Model , 0 , " model_root " , firstFrame , anim - > firstFrame + anim - > numFrames , flags , animSpeed , cg . time , setFrame , 150 ) ;
cg_entities [ clientNum ] . currentState . legsAnim = 0 ;
}
anim = & bgHumanoidAnimations [ ( cg_entities [ clientNum ] . currentState . torsoAnim ) ] ;
if ( anim )
{
int flags = BONE_ANIM_OVERRIDE_FREEZE ;
int firstFrame = anim - > firstFrame ;
int setFrame = - 1 ;
float animSpeed = 50.0f / anim - > frameLerp ;
if ( anim - > loopFrames ! = - 1 )
{
flags = BONE_ANIM_OVERRIDE_LOOP ;
}
if ( cent - > pe . torso . frame > = anim - > firstFrame & & cent - > pe . torso . frame < = ( anim - > firstFrame + anim - > numFrames ) )
{
setFrame = cent - > pe . torso . frame ;
}
//rww - Set the animation again because it just got reset due to the model change
trap_G2API_SetBoneAnim ( ci - > ghoul2Model , 0 , " lower_lumbar " , firstFrame , anim - > firstFrame + anim - > numFrames , flags , animSpeed , cg . time , setFrame , 150 ) ;
cg_entities [ clientNum ] . currentState . torsoAnim = 0 ;
}
if ( cg_entities [ clientNum ] . ghoul2 & & trap_G2_HaveWeGhoul2Models ( cg_entities [ clientNum ] . ghoul2 ) )
{
trap_G2API_CleanGhoul2Models ( & cg_entities [ clientNum ] . ghoul2 ) ;
}
trap_G2API_DuplicateGhoul2Instance ( ci - > ghoul2Model , & cg_entities [ clientNum ] . ghoul2 ) ;
if ( clientNum ! = - 1 )
{
//Attach the instance to this entity num so we can make use of client-server
//shared operations if possible.
trap_G2API_AttachInstanceToEntNum ( cg_entities [ clientNum ] . ghoul2 , clientNum , qfalse ) ;
}
if ( trap_G2API_AddBolt ( cg_entities [ clientNum ] . ghoul2 , 0 , " face " ) = = - 1 )
{ //check now to see if we have this bone for setting anims and such
cg_entities [ clientNum ] . noFace = qtrue ;
}
cg_entities [ clientNum ] . localAnimIndex = CG_G2SkelForModel ( cg_entities [ clientNum ] . ghoul2 ) ;
cg_entities [ clientNum ] . eventAnimIndex = CG_G2EvIndexForModel ( cg_entities [ clientNum ] . ghoul2 , cg_entities [ clientNum ] . localAnimIndex ) ;
if ( cg_entities [ clientNum ] . currentState . number ! = cg . predictedPlayerState . clientNum & &
cg_entities [ clientNum ] . currentState . weapon = = WP_SABER )
{
cg_entities [ clientNum ] . weapon = cg_entities [ clientNum ] . currentState . weapon ;
if ( cg_entities [ clientNum ] . ghoul2 & & ci - > ghoul2Model )
{
CG_CopyG2WeaponInstance ( & cg_entities [ clientNum ] , cg_entities [ clientNum ] . currentState . weapon , cg_entities [ clientNum ] . ghoul2 ) ;
cg_entities [ clientNum ] . ghoul2weapon = CG_G2WeaponInstance ( & cg_entities [ clientNum ] , cg_entities [ clientNum ] . currentState . weapon ) ;
}
if ( ! cg_entities [ clientNum ] . currentState . saberHolstered )
{ //if not holstered set length and desired length for both blades to full right now.
int j ;
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
i = 0 ;
while ( i < MAX_SABERS )
{
j = 0 ;
while ( j < ci - > saber [ i ] . numBlades )
{
ci - > saber [ i ] . blade [ j ] . length = ci - > saber [ i ] . blade [ j ] . lengthMax ;
j + + ;
}
i + + ;
}
}
}
}
}
qboolean cgQueueLoad = qfalse ;
/*
= = = = = = = = = = = = = = = = = = = = = =
CG_ActualLoadDeferredPlayers
Called at the beginning of CG_Player if cgQueueLoad is set .
= = = = = = = = = = = = = = = = = = = = = =
*/
void CG_ActualLoadDeferredPlayers ( 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 ) {
CG_LoadClientInfo ( ci ) ;
// break;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = =
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 ) {
cgQueueLoad = qtrue ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
PLAYER ANIMATION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define FOOTSTEP_DISTANCE 32
static void _PlayerFootStep ( const vec3_t origin ,
const float orientation ,
const float radius ,
centity_t * const cent , footstepType_t footStepType )
{
vec3_t end , mins = { - 7 , - 7 , 0 } , maxs = { 7 , 7 , 2 } ;
trace_t trace ;
footstep_t soundType = FOOTSTEP_TOTAL ;
qboolean bMark = qfalse ;
qhandle_t footMarkShader ;
int effectID = - 1 ;
//float alpha;
// send a trace down from the player to the ground
VectorCopy ( origin , end ) ;
end [ 2 ] - = FOOTSTEP_DISTANCE ;
trap_CM_BoxTrace ( & trace , origin , end , mins , maxs , 0 , MASK_PLAYERSOLID ) ;
// no shadow if too high
if ( trace . fraction > = 1.0f )
{
return ;
}
//check for foot-steppable surface flag
switch ( trace . surfaceFlags & MATERIAL_MASK )
{
case MATERIAL_MUD :
bMark = qtrue ;
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_MUDRUN ;
} else {
soundType = FOOTSTEP_MUDWALK ;
}
effectID = cgs . effects . footstepMud ;
break ;
case MATERIAL_DIRT :
bMark = qtrue ;
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_DIRTRUN ;
} else {
soundType = FOOTSTEP_DIRTWALK ;
}
effectID = cgs . effects . footstepSand ;
break ;
case MATERIAL_SAND :
bMark = qtrue ;
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_SANDRUN ;
} else {
soundType = FOOTSTEP_SANDWALK ;
}
effectID = cgs . effects . footstepSand ;
break ;
case MATERIAL_SNOW :
bMark = qtrue ;
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_SNOWRUN ;
} else {
soundType = FOOTSTEP_SNOWWALK ;
}
effectID = cgs . effects . footstepSnow ;
break ;
case MATERIAL_SHORTGRASS :
case MATERIAL_LONGGRASS :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_GRASSRUN ;
} else {
soundType = FOOTSTEP_GRASSWALK ;
}
break ;
case MATERIAL_SOLIDMETAL :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_METALRUN ;
} else {
soundType = FOOTSTEP_METALWALK ;
}
break ;
case MATERIAL_HOLLOWMETAL :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_PIPERUN ;
} else {
soundType = FOOTSTEP_PIPEWALK ;
}
break ;
case MATERIAL_GRAVEL :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_GRAVELRUN ;
} else {
soundType = FOOTSTEP_GRAVELWALK ;
}
effectID = cgs . effects . footstepGravel ;
break ;
case MATERIAL_CARPET :
case MATERIAL_FABRIC :
case MATERIAL_CANVAS :
case MATERIAL_RUBBER :
case MATERIAL_PLASTIC :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_RUGRUN ;
} else {
soundType = FOOTSTEP_RUGWALK ;
}
break ;
case MATERIAL_SOLIDWOOD :
case MATERIAL_HOLLOWWOOD :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_WOODRUN ;
} else {
soundType = FOOTSTEP_WOODWALK ;
}
break ;
default :
//fall through
case MATERIAL_GLASS :
case MATERIAL_WATER :
case MATERIAL_FLESH :
case MATERIAL_BPGLASS :
case MATERIAL_DRYLEAVES :
case MATERIAL_GREENLEAVES :
case MATERIAL_TILES :
case MATERIAL_PLASTER :
case MATERIAL_SHATTERGLASS :
case MATERIAL_ARMOR :
case MATERIAL_COMPUTER :
case MATERIAL_CONCRETE :
case MATERIAL_ROCK :
case MATERIAL_ICE :
case MATERIAL_MARBLE :
if ( footStepType = = FOOTSTEP_HEAVY_R | | footStepType = = FOOTSTEP_HEAVY_L ) {
soundType = FOOTSTEP_STONERUN ;
} else {
soundType = FOOTSTEP_STONEWALK ;
}
break ;
}
if ( soundType < FOOTSTEP_TOTAL )
{
trap_S_StartSound ( NULL , cent - > currentState . clientNum , CHAN_BODY , cgs . media . footsteps [ soundType ] [ rand ( ) & 3 ] ) ;
}
if ( cg_footsteps . integer < 4 )
{ //debugging - 4 always does footstep effect
if ( cg_footsteps . integer < 2 ) //1 for sounds, 2 for effects, 3 for marks
{
return ;
}
}
if ( effectID ! = - 1 )
{
trap_FX_PlayEffectID ( effectID , trace . endpos , trace . plane . normal , - 1 , - 1 ) ;
}
if ( cg_footsteps . integer < 4 )
{ //debugging - 4 always does footstep effect
if ( ! bMark | | cg_footsteps . integer < 3 ) //1 for sounds, 2 for effects, 3 for marks
{
return ;
}
}
switch ( footStepType )
{
case FOOTSTEP_HEAVY_R :
footMarkShader = cgs . media . fshrMarkShader ;
break ;
case FOOTSTEP_HEAVY_L :
footMarkShader = cgs . media . fshlMarkShader ;
break ;
case FOOTSTEP_R :
footMarkShader = cgs . media . fsrMarkShader ;
break ;
default :
case FOOTSTEP_L :
footMarkShader = cgs . media . fslMarkShader ;
break ;
}
// 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
if ( trace . plane . normal [ 0 ] | | trace . plane . normal [ 1 ] | | trace . plane . normal [ 2 ] )
{
CG_ImpactMark ( footMarkShader , trace . endpos , trace . plane . normal ,
orientation , 1 , 1 , 1 , 1.0f , qfalse , radius , qfalse ) ;
}
}
static void CG_PlayerFootsteps ( centity_t * cent , footstepType_t footStepType )
{
if ( ! cg_footsteps . integer )
{
return ;
}
//FIXME: make this a feature of NPCs in the NPCs.cfg? Specify a footstep shader, if any?
if ( cent - > currentState . NPC_class ! = CLASS_ATST
& & cent - > currentState . NPC_class ! = CLASS_CLAW
& & cent - > currentState . NPC_class ! = CLASS_FISH
& & cent - > currentState . NPC_class ! = CLASS_FLIER2
& & cent - > currentState . NPC_class ! = CLASS_GLIDER
& & cent - > currentState . NPC_class ! = CLASS_INTERROGATOR
& & cent - > currentState . NPC_class ! = CLASS_MURJJ
& & cent - > currentState . NPC_class ! = CLASS_PROBE
& & cent - > currentState . NPC_class ! = CLASS_R2D2
& & cent - > currentState . NPC_class ! = CLASS_R5D2
& & cent - > currentState . NPC_class ! = CLASS_REMOTE
& & cent - > currentState . NPC_class ! = CLASS_SEEKER
& & cent - > currentState . NPC_class ! = CLASS_SENTRY
& & cent - > currentState . NPC_class ! = CLASS_SWAMP )
{
mdxaBone_t boltMatrix ;
vec3_t tempAngles , sideOrigin ;
int footBolt = - 1 ;
tempAngles [ PITCH ] = 0 ;
tempAngles [ YAW ] = cent - > pe . legs . yawAngle ;
tempAngles [ ROLL ] = 0 ;
switch ( footStepType )
{
case FOOTSTEP_R :
case FOOTSTEP_HEAVY_R :
footBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_leg_foot " ) ; //cent->gent->footRBolt;
break ;
case FOOTSTEP_L :
case FOOTSTEP_HEAVY_L :
default :
footBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_leg_foot " ) ; //cent->gent->footLBolt;
break ;
}
//FIXME: get yaw orientation of the foot and use on decal
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , footBolt , & boltMatrix , tempAngles , cent - > lerpOrigin ,
cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , sideOrigin ) ;
sideOrigin [ 2 ] + = 15 ; //fudge up a bit for coplanar
_PlayerFootStep ( sideOrigin , cent - > pe . legs . yawAngle , 6 , cent , footStepType ) ;
}
}
void CG_PlayerAnimEventDo ( centity_t * cent , animevent_t * animEvent )
{
soundChannel_t channel = CHAN_AUTO ;
clientInfo_t * client = NULL ;
qhandle_t swingSound = 0 ;
qhandle_t spinSound = 0 ;
if ( ! cent | | ! animEvent )
{
return ;
}
switch ( animEvent - > eventType )
{
case AEV_SOUNDCHAN :
channel = ( soundChannel_t ) animEvent - > eventData [ AED_SOUNDCHANNEL ] ;
case AEV_SOUND :
{ // are there variations on the sound?
const int holdSnd = animEvent - > eventData [ AED_SOUNDINDEX_START + Q_irand ( 0 , animEvent - > eventData [ AED_SOUND_NUMRANDOMSNDS ] ) ] ;
if ( holdSnd > 0 )
{
trap_S_StartSound ( NULL , cent - > currentState . number , channel , holdSnd ) ;
}
}
break ;
case AEV_SABER_SWING :
if ( cent - > currentState . eType = = ET_NPC )
{
client = cent - > npcClient ;
assert ( client ) ;
}
else
{
client = & cgs . clientinfo [ cent - > currentState . clientNum ] ;
}
if ( client & & client - > infoValid & & client - > saber [ animEvent - > eventData [ AED_SABER_SWING_SABERNUM ] ] . swingSound [ 0 ] )
{ //custom swing sound
swingSound = client - > saber [ 0 ] . swingSound [ Q_irand ( 0 , 2 ) ] ;
}
else
{
int randomSwing = 1 ;
switch ( animEvent - > eventData [ AED_SABER_SWING_TYPE ] )
{
default :
case 0 : //SWING_FAST
randomSwing = Q_irand ( 1 , 3 ) ;
break ;
case 1 : //SWING_MEDIUM
randomSwing = Q_irand ( 4 , 6 ) ;
break ;
case 2 : //SWING_STRONG
randomSwing = Q_irand ( 7 , 9 ) ;
break ;
}
swingSound = trap_S_RegisterSound ( va ( " sound/weapons/saber/saberhup%i.wav " , randomSwing ) ) ;
}
trap_S_StartSound ( cent - > currentState . pos . trBase , cent - > currentState . number , CHAN_AUTO , swingSound ) ;
break ;
case AEV_SABER_SPIN :
if ( cent - > currentState . eType = = ET_NPC )
{
client = cent - > npcClient ;
assert ( client ) ;
}
else
{
client = & cgs . clientinfo [ cent - > currentState . clientNum ] ;
}
if ( client
& & client - > infoValid
& & client - > saber [ AED_SABER_SPIN_SABERNUM ] . spinSound )
{ //use override
spinSound = client - > saber [ AED_SABER_SPIN_SABERNUM ] . spinSound ;
}
else
{
switch ( animEvent - > eventData [ AED_SABER_SPIN_TYPE ] )
{
case 0 : //saberspinoff
spinSound = trap_S_RegisterSound ( " sound/weapons/saber/saberspinoff.wav " ) ;
break ;
case 1 : //saberspin
spinSound = trap_S_RegisterSound ( " sound/weapons/saber/saberspin.wav " ) ;
break ;
case 2 : //saberspin1
spinSound = trap_S_RegisterSound ( " sound/weapons/saber/saberspin1.wav " ) ;
break ;
case 3 : //saberspin2
spinSound = trap_S_RegisterSound ( " sound/weapons/saber/saberspin2.wav " ) ;
break ;
case 4 : //saberspin3
spinSound = trap_S_RegisterSound ( " sound/weapons/saber/saberspin3.wav " ) ;
break ;
default : //random saberspin1-3
spinSound = trap_S_RegisterSound ( va ( " sound/weapons/saber/saberspin%d.wav " , Q_irand ( 1 , 3 ) ) ) ;
break ;
}
}
if ( spinSound )
{
trap_S_StartSound ( NULL , cent - > currentState . clientNum , CHAN_AUTO , spinSound ) ;
}
break ;
case AEV_FOOTSTEP :
CG_PlayerFootsteps ( cent , ( footstepType_t ) animEvent - > eventData [ AED_FOOTSTEP_TYPE ] ) ;
break ;
case AEV_EFFECT :
#if 0 //SP method
//add bolt, play effect
if ( animEvent - > stringData ! = NULL & & cent & & cent - > gent & & cent - > gent - > ghoul2 . size ( ) )
{ //have a bolt name we want to use
animEvent - > eventData [ AED_BOLTINDEX ] = gi . G2API_AddBolt ( & cent - > gent - > ghoul2 [ cent - > gent - > playerModel ] , animEvent - > stringData ) ;
animEvent - > stringData = NULL ; //so we don't try to do this again
}
if ( animEvent - > eventData [ AED_BOLTINDEX ] ! = - 1 )
{ //have a bolt we want to play the effect on
G_PlayEffect ( animEvent - > eventData [ AED_EFFECTINDEX ] , cent - > gent - > playerModel , animEvent - > eventData [ AED_BOLTINDEX ] , cent - > currentState . clientNum ) ;
}
else
{ //play at origin? FIXME: maybe allow a fwd/rt/up offset?
theFxScheduler . PlayEffect ( animEvent - > eventData [ AED_EFFECTINDEX ] , cent - > lerpOrigin , qfalse ) ;
}
# else //my method
if ( animEvent - > stringData & & animEvent - > stringData [ 0 ] & & cent & & cent - > ghoul2 )
{
animEvent - > eventData [ AED_MODELINDEX ] = 0 ;
if ( ( Q_stricmpn ( " *blade " , animEvent - > stringData , 6 ) = = 0
| | Q_stricmp ( " *flash " , animEvent - > stringData ) = = 0 ) )
{ //must be a weapon, try weapon 0?
animEvent - > eventData [ AED_BOLTINDEX ] = trap_G2API_AddBolt ( cent - > ghoul2 , 1 , animEvent - > stringData ) ;
if ( animEvent - > eventData [ AED_BOLTINDEX ] ! = - 1 )
{ //found it!
animEvent - > eventData [ AED_MODELINDEX ] = 1 ;
}
else
{ //hmm, just try on the player model, then?
animEvent - > eventData [ AED_BOLTINDEX ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , animEvent - > stringData ) ;
}
}
else
{
animEvent - > eventData [ AED_BOLTINDEX ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , animEvent - > stringData ) ;
}
animEvent - > stringData [ 0 ] = 0 ;
}
if ( animEvent - > eventData [ AED_BOLTINDEX ] ! = - 1 )
{
vec3_t lAngles ;
vec3_t bPoint , bAngle ;
mdxaBone_t matrix ;
VectorSet ( lAngles , 0 , cent - > lerpAngles [ YAW ] , 0 ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , animEvent - > eventData [ AED_MODELINDEX ] , animEvent - > eventData [ AED_BOLTINDEX ] , & matrix , lAngles ,
cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & matrix , ORIGIN , bPoint ) ;
VectorSet ( bAngle , 0 , 1 , 0 ) ;
trap_FX_PlayEffectID ( animEvent - > eventData [ AED_EFFECTINDEX ] , bPoint , bAngle , - 1 , - 1 ) ;
}
else
{
vec3_t bAngle ;
VectorSet ( bAngle , 0 , 1 , 0 ) ;
trap_FX_PlayEffectID ( animEvent - > eventData [ AED_EFFECTINDEX ] , cent - > lerpOrigin , bAngle , - 1 , - 1 ) ;
}
# endif
break ;
//Would have to keep track of this on server to for these, it's not worth it.
case AEV_FIRE :
case AEV_MOVE :
break ;
/*
case AEV_FIRE :
//add fire event
if ( animEvent - > eventData [ AED_FIRE_ALT ] )
{
G_AddEvent ( cent - > gent , EV_ALT_FIRE , 0 ) ;
}
else
{
G_AddEvent ( cent - > gent , EV_FIRE_WEAPON , 0 ) ;
}
break ;
case AEV_MOVE :
//make him jump
if ( cent & & cent - > gent & & cent - > gent - > client )
{
if ( cent - > gent - > client - > ps . groundEntityNum ! = ENTITYNUM_NONE )
{ //on something
vec3_t fwd , rt , up , angles = { 0 , cent - > gent - > client - > ps . viewangles [ YAW ] , 0 } ;
AngleVectors ( angles , fwd , rt , up ) ;
//FIXME: set or add to velocity?
VectorScale ( fwd , animEvent - > eventData [ AED_MOVE_FWD ] , cent - > gent - > client - > ps . velocity ) ;
VectorMA ( cent - > gent - > client - > ps . velocity , animEvent - > eventData [ AED_MOVE_RT ] , rt , cent - > gent - > client - > ps . velocity ) ;
VectorMA ( cent - > gent - > client - > ps . velocity , animEvent - > eventData [ AED_MOVE_UP ] , up , cent - > gent - > client - > ps . velocity ) ;
if ( animEvent - > eventData [ AED_MOVE_UP ] > 0 )
{ //a jump
cent - > gent - > client - > ps . pm_flags | = PMF_JUMPING ;
G_AddEvent ( cent - > gent , EV_JUMP , 0 ) ;
//FIXME: if have force jump, do this? or specify sound in the event data?
//cent->gent->client->ps.forceJumpZStart = cent->gent->client->ps.origin[2];//so we don't take damage if we land at same height
//G_SoundOnEnt( cent->gent, CHAN_BODY, "sound/weapons/force/jump.wav" );
}
}
}
break ;
*/
default :
return ;
break ;
}
}
/*
void CG_PlayerAnimEvents ( int animFileIndex , int eventFileIndex , qboolean torso , int oldFrame , int frame , const vec3_t org , int entNum )
play any keyframed sounds - only when start a new frame
This func is called once for legs and once for torso
*/
void CG_PlayerAnimEvents ( int animFileIndex , int eventFileIndex , qboolean torso , int oldFrame , int frame , int entNum )
{
int i ;
int firstFrame = 0 , lastFrame = 0 ;
qboolean doEvent = qfalse , inSameAnim = qfalse , loopAnim = qfalse , match = qfalse , animBackward = qfalse ;
animevent_t * animEvents = NULL ;
if ( torso )
{
animEvents = bgAllEvents [ eventFileIndex ] . torsoAnimEvents ;
}
else
{
animEvents = bgAllEvents [ eventFileIndex ] . legsAnimEvents ;
}
if ( fabs ( ( float ) ( oldFrame - frame ) ) > 1 )
{ //given a range, see if keyFrame falls in that range
int oldAnim , anim ;
if ( torso )
{
/*
if ( cg_reliableAnimSounds . integer > 1 )
{ //more precise, slower
oldAnim = PM_TorsoAnimForFrame ( & g_entities [ entNum ] , oldFrame ) ;
anim = PM_TorsoAnimForFrame ( & g_entities [ entNum ] , frame ) ;
}
else
*/
{ //less precise, but faster
oldAnim = cg_entities [ entNum ] . currentState . torsoAnim ;
anim = cg_entities [ entNum ] . nextState . torsoAnim ;
}
}
else
{
/*
if ( cg_reliableAnimSounds . integer > 1 )
{ //more precise, slower
oldAnim = PM_LegsAnimForFrame ( & g_entities [ entNum ] , oldFrame ) ;
anim = PM_TorsoAnimForFrame ( & g_entities [ entNum ] , frame ) ;
}
else
*/
{ //less precise, but faster
oldAnim = cg_entities [ entNum ] . currentState . legsAnim ;
anim = cg_entities [ entNum ] . nextState . legsAnim ;
}
}
if ( anim ! = oldAnim )
{ //not in same anim
inSameAnim = qfalse ;
//FIXME: we *could* see if the oldFrame was *just about* to play the keyframed sound...
}
else
{ //still in same anim, check for looping anim
animation_t * animation ;
inSameAnim = qtrue ;
animation = & bgAllAnims [ animFileIndex ] . anims [ anim ] ;
animBackward = ( animation - > frameLerp < 0 ) ;
if ( animation - > loopFrames ! = - 1 )
{ //a looping anim!
loopAnim = qtrue ;
firstFrame = animation - > firstFrame ;
lastFrame = animation - > firstFrame + animation - > numFrames ;
}
}
}
// Check for anim sound
for ( i = 0 ; i < MAX_ANIM_EVENTS ; + + i )
{
if ( animEvents [ i ] . eventType = = AEV_NONE ) // No event, end of list
{
break ;
}
match = qfalse ;
if ( animEvents [ i ] . keyFrame = = frame )
{ //exact match
match = qtrue ;
}
else if ( fabs ( ( float ) ( oldFrame - frame ) ) > 1 /*&& cg_reliableAnimSounds.integer*/ )
{ //given a range, see if keyFrame falls in that range
if ( inSameAnim )
{ //if changed anims altogether, sorry, the sound is lost
if ( fabs ( ( float ) ( oldFrame - animEvents [ i ] . keyFrame ) ) < = 3
| | fabs ( ( float ) ( frame - animEvents [ i ] . keyFrame ) ) < = 3 )
{ //must be at least close to the keyframe
if ( animBackward )
{ //animation plays backwards
if ( oldFrame > animEvents [ i ] . keyFrame & & frame < animEvents [ i ] . keyFrame )
{ //old to new passed through keyframe
match = qtrue ;
}
else if ( loopAnim )
{ //hmm, didn't pass through it linearally, see if we looped
if ( animEvents [ i ] . keyFrame > = firstFrame & & animEvents [ i ] . keyFrame < lastFrame )
{ //keyframe is in this anim
if ( oldFrame > animEvents [ i ] . keyFrame
& & frame > oldFrame )
{ //old to new passed through keyframe
match = qtrue ;
}
}
}
}
else
{ //anim plays forwards
if ( oldFrame < animEvents [ i ] . keyFrame & & frame > animEvents [ i ] . keyFrame )
{ //old to new passed through keyframe
match = qtrue ;
}
else if ( loopAnim )
{ //hmm, didn't pass through it linearally, see if we looped
if ( animEvents [ i ] . keyFrame > = firstFrame & & animEvents [ i ] . keyFrame < lastFrame )
{ //keyframe is in this anim
if ( oldFrame < animEvents [ i ] . keyFrame
& & frame < oldFrame )
{ //old to new passed through keyframe
match = qtrue ;
}
}
}
}
}
}
}
if ( match )
{
switch ( animEvents [ i ] . eventType )
{
case AEV_SOUND :
case AEV_SOUNDCHAN :
// Determine probability of playing sound
if ( ! animEvents [ i ] . eventData [ AED_SOUND_PROBABILITY ] ) // 100%
{
doEvent = qtrue ;
}
else if ( animEvents [ i ] . eventData [ AED_SOUND_PROBABILITY ] > Q_irand ( 0 , 99 ) )
{
doEvent = qtrue ;
}
break ;
case AEV_SABER_SWING :
// Determine probability of playing sound
if ( ! animEvents [ i ] . eventData [ AED_SABER_SWING_PROBABILITY ] ) // 100%
{
doEvent = qtrue ;
}
else if ( animEvents [ i ] . eventData [ AED_SABER_SWING_PROBABILITY ] > Q_irand ( 0 , 99 ) )
{
doEvent = qtrue ;
}
break ;
case AEV_SABER_SPIN :
// Determine probability of playing sound
if ( ! animEvents [ i ] . eventData [ AED_SABER_SPIN_PROBABILITY ] ) // 100%
{
doEvent = qtrue ;
}
else if ( animEvents [ i ] . eventData [ AED_SABER_SPIN_PROBABILITY ] > Q_irand ( 0 , 99 ) )
{
doEvent = qtrue ;
}
break ;
case AEV_FOOTSTEP :
// Determine probability of playing sound
if ( ! animEvents [ i ] . eventData [ AED_FOOTSTEP_PROBABILITY ] ) // 100%
{
doEvent = qtrue ;
}
else if ( animEvents [ i ] . eventData [ AED_FOOTSTEP_PROBABILITY ] > Q_irand ( 0 , 99 ) )
{
doEvent = qtrue ;
}
break ;
case AEV_EFFECT :
// Determine probability of playing sound
if ( ! animEvents [ i ] . eventData [ AED_EFFECT_PROBABILITY ] ) // 100%
{
doEvent = qtrue ;
}
else if ( animEvents [ i ] . eventData [ AED_EFFECT_PROBABILITY ] > Q_irand ( 0 , 99 ) )
{
doEvent = qtrue ;
}
break ;
case AEV_FIRE :
// Determine probability of playing sound
if ( ! animEvents [ i ] . eventData [ AED_FIRE_PROBABILITY ] ) // 100%
{
doEvent = qtrue ;
}
else if ( animEvents [ i ] . eventData [ AED_FIRE_PROBABILITY ] > Q_irand ( 0 , 99 ) )
{
doEvent = qtrue ;
}
break ;
case AEV_MOVE :
doEvent = qtrue ;
break ;
default :
//doEvent = qfalse;//implicit
break ;
}
// do event
if ( doEvent )
{
CG_PlayerAnimEventDo ( & cg_entities [ entNum ] , & animEvents [ i ] ) ;
}
}
}
}
void CG_TriggerAnimSounds ( centity_t * cent )
{ //this also sets the lerp frames, so I suggest you keep calling it regardless of if you want anim sounds.
int curFrame = 0 ;
float currentFrame = 0 ;
int sFileIndex ;
assert ( cent - > localAnimIndex > = 0 ) ;
sFileIndex = cent - > eventAnimIndex ;
if ( trap_G2API_GetBoneFrame ( cent - > ghoul2 , " model_root " , cg . time , & currentFrame , cgs . gameModels , 0 ) )
{
// the above may have failed, not sure what to do about it, current frame will be zero in that case
curFrame = floor ( currentFrame ) ;
}
if ( curFrame ! = cent - > pe . legs . frame )
{
CG_PlayerAnimEvents ( cent - > localAnimIndex , sFileIndex , qfalse , cent - > pe . legs . frame , curFrame , cent - > currentState . number ) ;
}
cent - > pe . legs . oldFrame = cent - > pe . torso . frame ;
cent - > pe . legs . frame = curFrame ;
if ( cent - > noLumbar )
{ //probably a droid or something.
cent - > pe . torso . oldFrame = cent - > pe . legs . oldFrame ;
cent - > pe . torso . frame = cent - > pe . legs . frame ;
return ;
}
if ( trap_G2API_GetBoneFrame ( cent - > ghoul2 , " lower_lumbar " , cg . time , & currentFrame , cgs . gameModels , 0 ) )
{
curFrame = floor ( currentFrame ) ;
}
if ( curFrame ! = cent - > pe . torso . frame )
{
CG_PlayerAnimEvents ( cent - > localAnimIndex , sFileIndex , qtrue , cent - > pe . torso . frame , curFrame , cent - > currentState . number ) ;
}
cent - > pe . torso . oldFrame = cent - > pe . torso . frame ;
cent - > pe . torso . frame = curFrame ;
cent - > pe . torso . backlerp = 1.0f - ( currentFrame - ( float ) curFrame ) ;
}
static qboolean CG_FirstAnimFrame ( lerpFrame_t * lf , qboolean torsoOnly , float speedScale ) ;
qboolean CG_InRoll ( centity_t * cent )
{
switch ( ( cent - > currentState . legsAnim ) )
{
case BOTH_GETUP_BROLL_B :
case BOTH_GETUP_BROLL_F :
case BOTH_GETUP_BROLL_L :
case BOTH_GETUP_BROLL_R :
case BOTH_GETUP_FROLL_B :
case BOTH_GETUP_FROLL_F :
case BOTH_GETUP_FROLL_L :
case BOTH_GETUP_FROLL_R :
case BOTH_ROLL_F :
case BOTH_ROLL_B :
case BOTH_ROLL_R :
case BOTH_ROLL_L :
if ( cent - > pe . legs . animationTime > cg . time )
{
return qtrue ;
}
break ;
}
return qfalse ;
}
qboolean CG_InRollAnim ( centity_t * cent )
{
switch ( ( cent - > currentState . legsAnim ) )
{
case BOTH_ROLL_F :
case BOTH_ROLL_B :
case BOTH_ROLL_R :
case BOTH_ROLL_L :
return qtrue ;
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = =
CG_SetLerpFrameAnimation
= = = = = = = = = = = = = = =
*/
# include "../namespace_begin.h"
qboolean BG_SaberStanceAnim ( int anim ) ;
qboolean PM_RunningAnim ( int anim ) ;
# include "../namespace_end.h"
static void CG_SetLerpFrameAnimation ( centity_t * cent , clientInfo_t * ci , lerpFrame_t * lf , int newAnimation , float animSpeedMult , qboolean torsoOnly , qboolean flipState ) {
animation_t * anim ;
float animSpeed ;
int flags = BONE_ANIM_OVERRIDE_FREEZE ;
int oldAnim = - 1 ;
int blendTime = 100 ;
float oldSpeed = lf - > animationSpeed ;
if ( cent - > localAnimIndex > 0 )
{ //rockettroopers can't have broken arms, nor can anything else but humanoids
ci - > brokenLimbs = cent - > currentState . brokenLimbs ;
}
oldAnim = lf - > animationNumber ;
lf - > animationNumber = newAnimation ;
if ( newAnimation < 0 | | newAnimation > = MAX_TOTALANIMATIONS ) {
CG_Error ( " Bad animation number: %i " , newAnimation ) ;
}
anim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ newAnimation ] ;
lf - > animation = anim ;
lf - > animationTime = lf - > frameTime + abs ( anim - > frameLerp ) ;
if ( cent - > localAnimIndex > 1 & &
anim - > firstFrame = = 0 & &
anim - > numFrames = = 0 )
{ //We'll allow this for non-humanoids.
return ;
}
if ( cg_debugAnim . integer & & ( cg_debugAnim . integer < 0 | | cg_debugAnim . integer = = cent - > currentState . clientNum ) ) {
if ( lf = = & cent - > pe . legs )
{
CG_Printf ( " %d: %d TORSO Anim: %i, '%s' \n " , cg . time , cent - > currentState . clientNum , newAnimation , GetStringForID ( animTable , newAnimation ) ) ;
}
else
{
CG_Printf ( " %d: %d LEGS Anim: %i, '%s' \n " , cg . time , cent - > currentState . clientNum , newAnimation , GetStringForID ( animTable , newAnimation ) ) ;
}
}
if ( cent - > ghoul2 )
{
qboolean resumeFrame = qfalse ;
int beginFrame = - 1 ;
int firstFrame ;
int lastFrame ;
#if 0 //disabled for now
float unused ;
# endif
animSpeed = 50.0f / anim - > frameLerp ;
if ( lf - > animation - > loopFrames ! = - 1 )
{
flags = BONE_ANIM_OVERRIDE_LOOP ;
}
if ( animSpeed < 0 )
{
lastFrame = anim - > firstFrame ;
firstFrame = anim - > firstFrame + anim - > numFrames ;
}
else
{
firstFrame = anim - > firstFrame ;
lastFrame = anim - > firstFrame + anim - > numFrames ;
}
if ( cg_animBlend . integer )
{
flags | = BONE_ANIM_BLEND ;
}
if ( BG_InDeathAnim ( newAnimation ) )
{
flags & = ~ BONE_ANIM_BLEND ;
}
else if ( oldAnim ! = - 1 & &
BG_InDeathAnim ( oldAnim ) )
{
flags & = ~ BONE_ANIM_BLEND ;
}
if ( flags & BONE_ANIM_BLEND )
{
if ( BG_FlippingAnim ( newAnimation ) )
{
blendTime = 200 ;
}
else if ( oldAnim ! = - 1 & &
( BG_FlippingAnim ( oldAnim ) ) )
{
blendTime = 200 ;
}
}
animSpeed * = animSpeedMult ;
BG_SaberStartTransAnim ( cent - > currentState . number , cent - > currentState . fireflag , cent - > currentState . weapon , newAnimation , & animSpeed , cent - > currentState . brokenLimbs ) ;
if ( torsoOnly )
{
if ( lf - > animationTorsoSpeed ! = animSpeedMult & & newAnimation = = oldAnim & &
flipState = = lf - > lastFlip )
{ //same animation, but changing speed, so we will want to resume off the frame we're on.
resumeFrame = qtrue ;
}
lf - > animationTorsoSpeed = animSpeedMult ;
}
else
{
if ( lf - > animationSpeed ! = animSpeedMult & & newAnimation = = oldAnim & &
flipState = = lf - > lastFlip )
{ //same animation, but changing speed, so we will want to resume off the frame we're on.
resumeFrame = qtrue ;
}
lf - > animationSpeed = animSpeedMult ;
}
//vehicles may have torso etc but we only want to animate the root bone
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE )
{
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " model_root " , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
return ;
}
if ( torsoOnly & & ! cent - > noLumbar )
{ //rww - The guesswork based on the lerp frame figures is usually BS, so I've resorted to a call to get the frame of the bone directly.
float GBAcFrame = 0 ;
if ( resumeFrame )
{ //we already checked, and this is the same anim, same flip state, but different speed, so we want to resume with the new speed off of the same frame.
trap_G2API_GetBoneFrame ( cent - > ghoul2 , " lower_lumbar " , cg . time , & GBAcFrame , NULL , 0 ) ;
beginFrame = GBAcFrame ;
}
//even if resuming, also be sure to check if we are running the same frame on the legs. If so, we want to use their frame no matter what.
trap_G2API_GetBoneFrame ( cent - > ghoul2 , " model_root " , cg . time , & GBAcFrame , NULL , 0 ) ;
if ( ( cent - > currentState . torsoAnim ) = = ( cent - > currentState . legsAnim ) & & GBAcFrame > = anim - > firstFrame & & GBAcFrame < = ( anim - > firstFrame + anim - > numFrames ) )
{ //if the legs are already running this anim, pick up on the exact same frame to avoid the "wobbly spine" problem.
beginFrame = GBAcFrame ;
}
if ( firstFrame > lastFrame | | ci - > torsoAnim = = newAnimation )
{ //don't resume on backwards playing animations.. I guess.
beginFrame = - 1 ;
}
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " lower_lumbar " , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
// Update the torso frame with the new animation
cent - > pe . torso . frame = firstFrame ;
if ( ci )
{
ci - > torsoAnim = newAnimation ;
}
}
else
{
if ( resumeFrame )
{ //we already checked, and this is the same anim, same flip state, but different speed, so we want to resume with the new speed off of the same frame.
float GBAcFrame = 0 ;
trap_G2API_GetBoneFrame ( cent - > ghoul2 , " model_root " , cg . time , & GBAcFrame , NULL , 0 ) ;
beginFrame = GBAcFrame ;
}
if ( ( beginFrame < firstFrame ) | | ( beginFrame > lastFrame ) )
{ //out of range, don't use it then.
beginFrame = - 1 ;
}
if ( cent - > currentState . torsoAnim = = cent - > currentState . legsAnim & &
( ci - > legsAnim ! = newAnimation | | oldSpeed ! = animSpeed ) )
{ //alright, we are starting an anim on the legs, and that same anim is already playing on the toro, so pick up the frame.
float GBAcFrame = 0 ;
int oldBeginFrame = beginFrame ;
trap_G2API_GetBoneFrame ( cent - > ghoul2 , " lower_lumbar " , cg . time , & GBAcFrame , NULL , 0 ) ;
beginFrame = GBAcFrame ;
if ( ( beginFrame < firstFrame ) | | ( beginFrame > lastFrame ) )
{ //out of range, don't use it then.
beginFrame = oldBeginFrame ;
}
}
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " model_root " , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
if ( ci )
{
ci - > legsAnim = newAnimation ;
}
}
if ( cent - > localAnimIndex < = 1 & & ( cent - > currentState . torsoAnim ) = = newAnimation & & ! cent - > noLumbar )
{ //make sure we're humanoid before we access the motion bone
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " Motion " , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
}
#if 0 //disabled for now
if ( cent - > localAnimIndex < = 1 & & cent - > currentState . brokenLimbs & &
( cent - > currentState . brokenLimbs & ( 1 < < BROKENLIMB_LARM ) ) )
{ //broken left arm
char * brokenBone = " lhumerus " ;
animation_t * armAnim ;
int armFirstFrame ;
int armLastFrame ;
int armFlags = 0 ;
float armAnimSpeed ;
armAnim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ BOTH_DEAD21 ] ;
ci - > brokenLimbs = cent - > currentState . brokenLimbs ;
armFirstFrame = armAnim - > firstFrame ;
armLastFrame = armAnim - > firstFrame + armAnim - > numFrames ;
armAnimSpeed = 50.0f / armAnim - > frameLerp ;
armFlags = BONE_ANIM_OVERRIDE_LOOP ;
if ( cg_animBlend . integer )
{
armFlags | = BONE_ANIM_BLEND ;
}
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , brokenBone , armFirstFrame , armLastFrame , armFlags , armAnimSpeed , cg . time , - 1 , blendTime ) ;
}
else if ( cent - > localAnimIndex < = 1 & & cent - > currentState . brokenLimbs & &
( cent - > currentState . brokenLimbs & ( 1 < < BROKENLIMB_RARM ) ) )
{ //broken right arm
char * brokenBone = " rhumerus " ;
char * supportBone = " lhumerus " ;
ci - > brokenLimbs = cent - > currentState . brokenLimbs ;
//Only put the arm in a broken pose if the anim is such that we
//want to allow it.
if ( ( //cent->currentState.weapon == WP_MELEE ||
cent - > currentState . weapon ! = WP_SABER | |
BG_SaberStanceAnim ( newAnimation ) | |
PM_RunningAnim ( newAnimation ) ) & &
cent - > currentState . torsoAnim = = newAnimation & &
( ! ci - > saber [ 1 ] . model [ 0 ] | | cent - > currentState . weapon ! = WP_SABER ) )
{
int armFirstFrame ;
int armLastFrame ;
int armFlags = 0 ;
float armAnimSpeed ;
animation_t * armAnim ;
if ( cent - > currentState . weapon = = WP_MELEE | |
cent - > currentState . weapon = = WP_SABER | |
cent - > currentState . weapon = = WP_BRYAR_PISTOL )
{ //don't affect this arm if holding a gun, just make the other arm support it
armAnim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ BOTH_ATTACK2 ] ;
//armFirstFrame = armAnim->firstFrame;
armFirstFrame = armAnim - > firstFrame + armAnim - > numFrames ;
armLastFrame = armAnim - > firstFrame + armAnim - > numFrames ;
armAnimSpeed = 50.0f / armAnim - > frameLerp ;
armFlags = BONE_ANIM_OVERRIDE_LOOP ;
/*
if ( cg_animBlend . integer )
{
armFlags | = BONE_ANIM_BLEND ;
}
*/
//No blend on the broken arm
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , brokenBone , armFirstFrame , armLastFrame , armFlags , armAnimSpeed , cg . time , - 1 , 0 ) ;
}
else
{ //we want to keep the broken bone updated for some cases
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , brokenBone , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
}
if ( newAnimation ! = BOTH_MELEE1 & &
newAnimation ! = BOTH_MELEE2 & &
( newAnimation = = TORSO_WEAPONREADY2 | | newAnimation = = BOTH_ATTACK2 | | cent - > currentState . weapon < WP_BRYAR_PISTOL ) )
{
//Now set the left arm to "support" the right one
armAnim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ BOTH_STAND2 ] ;
armFirstFrame = armAnim - > firstFrame ;
armLastFrame = armAnim - > firstFrame + armAnim - > numFrames ;
armAnimSpeed = 50.0f / armAnim - > frameLerp ;
armFlags = BONE_ANIM_OVERRIDE_LOOP ;
if ( cg_animBlend . integer )
{
armFlags | = BONE_ANIM_BLEND ;
}
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , supportBone , armFirstFrame , armLastFrame , armFlags , armAnimSpeed , cg . time , - 1 , 150 ) ;
}
else
{ //we want to keep the support bone updated for some cases
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , supportBone , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
}
}
else if ( cent - > currentState . torsoAnim = = newAnimation )
{ //otherwise, keep it set to the same as the torso
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , brokenBone , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , supportBone , firstFrame , lastFrame , flags , animSpeed , cg . time , beginFrame , blendTime ) ;
}
}
else if ( ci & &
( ci - > brokenLimbs | |
trap_G2API_GetBoneFrame ( cent - > ghoul2 , " lhumerus " , cg . time , & unused , cgs . gameModels , 0 ) | |
trap_G2API_GetBoneFrame ( cent - > ghoul2 , " rhumerus " , cg . time , & unused , cgs . gameModels , 0 ) ) )
//rwwFIXMEFIXME: brokenLimbs gets stomped sometimes, but it shouldn't.
{ //remove the bone now so it can be set again
char * brokenBone = NULL ;
int broken = 0 ;
//Warning: Don't remove bones that you've added as bolts unless you want to invalidate your bolt index
//(well, in theory, I haven't actually run into the problem)
if ( ci - > brokenLimbs & ( 1 < < BROKENLIMB_LARM ) )
{
brokenBone = " lhumerus " ;
broken | = ( 1 < < BROKENLIMB_LARM ) ;
}
else if ( ci - > brokenLimbs & ( 1 < < BROKENLIMB_RARM ) )
{ //can only have one arm broken at once.
brokenBone = " rhumerus " ;
broken | = ( 1 < < BROKENLIMB_RARM ) ;
//want to remove the support bone too then
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " lhumerus " , 0 , 1 , 0 , 0 , cg . time , - 1 , 0 ) ;
if ( ! trap_G2API_RemoveBone ( cent - > ghoul2 , " lhumerus " , 0 ) )
{
assert ( 0 ) ;
Com_Printf ( " WARNING: Failed to remove lhumerus \n " ) ;
}
}
if ( ! brokenBone )
{
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " lhumerus " , 0 , 1 , 0 , 0 , cg . time , - 1 , 0 ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " rhumerus " , 0 , 1 , 0 , 0 , cg . time , - 1 , 0 ) ;
trap_G2API_RemoveBone ( cent - > ghoul2 , " lhumerus " , 0 ) ;
trap_G2API_RemoveBone ( cent - > ghoul2 , " rhumerus " , 0 ) ;
ci - > brokenLimbs = 0 ;
}
else
{
//Set the flags and stuff to 0, so that the remove will succeed
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , brokenBone , 0 , 1 , 0 , 0 , cg . time , - 1 , 0 ) ;
//Now remove it
if ( ! trap_G2API_RemoveBone ( cent - > ghoul2 , brokenBone , 0 ) )
{
assert ( 0 ) ;
Com_Printf ( " WARNING: Failed to remove %s \n " , brokenBone ) ;
}
ci - > brokenLimbs & = ~ broken ;
}
}
# endif
}
}
/*
= = = = = = = = = = = = = = =
CG_FirstAnimFrame
Returns true if the lerpframe is on its first frame of animation .
Otherwise false .
This is used to scale an animation into higher - speed without restarting
the animation before it completes at normal speed , in the case of a looping
animation ( such as the leg running anim ) .
= = = = = = = = = = = = = = =
*/
static qboolean CG_FirstAnimFrame ( lerpFrame_t * lf , qboolean torsoOnly , float speedScale )
{
if ( torsoOnly )
{
if ( lf - > animationTorsoSpeed = = speedScale )
{
return qfalse ;
}
}
else
{
if ( lf - > animationSpeed = = speedScale )
{
return qfalse ;
}
}
//I don't care where it is in the anim now, I am going to pick up from the same bone frame.
/*
if ( lf - > animation - > numFrames < 2 )
{
return qtrue ;
}
if ( lf - > animation - > firstFrame = = lf - > frame )
{
return qtrue ;
}
*/
return qtrue ;
}
/*
= = = = = = = = = = = = = = =
CG_RunLerpFrame
Sets cg . snap , cg . oldFrame , and cg . backlerp
cg . time should be between oldFrameTime and frameTime after exit
= = = = = = = = = = = = = = =
*/
static void CG_RunLerpFrame ( centity_t * cent , clientInfo_t * ci , lerpFrame_t * lf , qboolean flipState , int newAnimation , float speedScale , qboolean torsoOnly )
{
// 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 ( cent - > currentState . forceFrame )
{
if ( lf - > lastForcedFrame ! = cent - > currentState . forceFrame )
{
int flags = BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ;
float animSpeed = 1.0f ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " lower_lumbar " , cent - > currentState . forceFrame , cent - > currentState . forceFrame + 1 , flags , animSpeed , cg . time , - 1 , 150 ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " model_root " , cent - > currentState . forceFrame , cent - > currentState . forceFrame + 1 , flags , animSpeed , cg . time , - 1 , 150 ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " Motion " , cent - > currentState . forceFrame , cent - > currentState . forceFrame + 1 , flags , animSpeed , cg . time , - 1 , 150 ) ;
}
lf - > lastForcedFrame = cent - > currentState . forceFrame ;
lf - > animationNumber = 0 ;
}
else
{
lf - > lastForcedFrame = - 1 ;
if ( ( newAnimation ! = lf - > animationNumber | | cent - > currentState . brokenLimbs ! = ci - > brokenLimbs | | lf - > lastFlip ! = flipState | | ! lf - > animation ) | | ( CG_FirstAnimFrame ( lf , torsoOnly , speedScale ) ) )
{
CG_SetLerpFrameAnimation ( cent , ci , lf , newAnimation , speedScale , torsoOnly , flipState ) ;
}
}
lf - > lastFlip = flipState ;
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 ( centity_t * cent , clientInfo_t * ci , lerpFrame_t * lf , int animationNumber , qboolean torsoOnly ) {
lf - > frameTime = lf - > oldFrameTime = cg . time ;
CG_SetLerpFrameAnimation ( cent , ci , lf , animationNumber , 1 , torsoOnly , qfalse ) ;
if ( lf - > animation - > frameLerp < 0 )
{ //Plays backwards
lf - > oldFrame = lf - > frame = ( lf - > animation - > firstFrame + lf - > animation - > numFrames ) ;
}
else
{
lf - > oldFrame = lf - > frame = lf - > animation - > firstFrame ;
}
}
/*
= = = = = = = = = = = = = = =
CG_PlayerAnimation
= = = = = = = = = = = = = = =
*/
# include "../namespace_begin.h"
qboolean PM_WalkingAnim ( int anim ) ;
# include "../namespace_end.h"
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 ( ! PM_RunningAnim ( cent - > currentState . legsAnim ) & &
! PM_WalkingAnim ( cent - > currentState . legsAnim ) )
{ //if legs are not in a walking/running anim then just animate at standard speed
speedScale = 1.0f ;
}
else if ( cent - > currentState . forcePowersActive & ( 1 < < FP_RAGE ) )
{
speedScale = 1.3f ;
}
else if ( cent - > currentState . forcePowersActive & ( 1 < < FP_SPEED ) )
{
speedScale = 1.7f ;
}
else
{
speedScale = 1.0f ;
}
if ( cent - > currentState . eType = = ET_NPC )
{
ci = cent - > npcClient ;
assert ( ci ) ;
}
else
{
ci = & cgs . clientinfo [ clientNum ] ;
}
CG_RunLerpFrame ( cent , ci , & cent - > pe . legs , cent - > currentState . legsFlip , cent - > currentState . legsAnim , speedScale , qfalse ) ;
if ( ! ( cent - > currentState . forcePowersActive & ( 1 < < FP_RAGE ) ) )
{ //don't affect torso anim speed unless raged
speedScale = 1.0f ;
}
else
{
speedScale = 1.7f ;
}
* legsOld = cent - > pe . legs . oldFrame ;
* legs = cent - > pe . legs . frame ;
* legsBackLerp = cent - > pe . legs . backlerp ;
// If this is not a vehicle, you may lerm the frame (since vehicles never have a torso anim). -AReis
if ( cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{
CG_RunLerpFrame ( cent , ci , & cent - > pe . torso , cent - > currentState . torsoFlip , cent - > currentState . torsoAnim , speedScale , qtrue ) ;
* torsoOld = cent - > pe . torso . oldFrame ;
* torso = cent - > pe . torso . frame ;
* torsoBackLerp = cent - > pe . torso . backlerp ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
PLAYER ANGLES
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
#if 0
typedef struct boneAngleParms_s {
void * ghoul2 ;
int modelIndex ;
char * boneName ;
vec3_t angles ;
int flags ;
int up ;
int right ;
int forward ;
qhandle_t * modelList ;
int blendTime ;
int currentTime ;
qboolean refreshSet ;
} boneAngleParms_t ;
boneAngleParms_t cgBoneAnglePostSet ;
# endif
void CG_G2SetBoneAngles ( void * ghoul2 , int modelIndex , const char * boneName , const vec3_t angles , const int flags ,
const int up , const int right , const int forward , qhandle_t * modelList ,
int blendTime , int currentTime )
{ //we want to hold off on setting the bone angles until the end of the frame, because every time we set
//them the entire skeleton has to be reconstructed.
#if 0
//This function should ONLY be called from CG_Player() or a function that is called only within CG_Player().
//At the end of the frame we will check to use this information to call SetBoneAngles
memset ( & cgBoneAnglePostSet , 0 , sizeof ( cgBoneAnglePostSet ) ) ;
cgBoneAnglePostSet . ghoul2 = ghoul2 ;
cgBoneAnglePostSet . modelIndex = modelIndex ;
cgBoneAnglePostSet . boneName = ( char * ) boneName ;
cgBoneAnglePostSet . angles [ 0 ] = angles [ 0 ] ;
cgBoneAnglePostSet . angles [ 1 ] = angles [ 1 ] ;
cgBoneAnglePostSet . angles [ 2 ] = angles [ 2 ] ;
cgBoneAnglePostSet . flags = flags ;
cgBoneAnglePostSet . up = up ;
cgBoneAnglePostSet . right = right ;
cgBoneAnglePostSet . forward = forward ;
cgBoneAnglePostSet . modelList = modelList ;
cgBoneAnglePostSet . blendTime = blendTime ;
cgBoneAnglePostSet . currentTime = currentTime ;
cgBoneAnglePostSet . refreshSet = qtrue ;
# endif
//We don't want to go with the delayed approach, we want out bolt points and everything to be updated in realtime.
//We'll just take the reconstructs and live with them.
trap_G2API_SetBoneAngles ( ghoul2 , modelIndex , boneName , angles , flags , up , right , forward , modelList ,
blendTime , currentTime ) ;
}
/*
= = = = = = = = = = = = = = = =
CG_Rag_Trace
Variant on CG_Trace . Doesn ' t trace for ents because ragdoll engine trace code has no entity
trace access . Maybe correct this sometime , so bmodel col . at least works with ragdoll .
But I don ' t want to slow it down . .
= = = = = = = = = = = = = = = =
*/
void CG_Rag_Trace ( trace_t * result , const vec3_t start , const vec3_t mins , const vec3_t maxs , const vec3_t end ,
int skipNumber , int mask ) {
trap_CM_BoxTrace ( result , start , end , mins , maxs , 0 , mask ) ;
result - > entityNum = result - > fraction ! = 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE ;
}
//#define _RAG_BOLT_TESTING
# ifdef _RAG_BOLT_TESTING
void CG_TempTestFunction ( centity_t * cent , vec3_t forcedAngles )
{
mdxaBone_t boltMatrix ;
vec3_t tAngles ;
vec3_t bOrg ;
vec3_t bDir ;
vec3_t uOrg ;
VectorSet ( tAngles , 0 , cent - > lerpAngles [ YAW ] , 0 ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 1 , 0 , & boltMatrix , tAngles , cent - > lerpOrigin ,
cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , bOrg ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_Y , bDir ) ;
VectorMA ( bOrg , 40 , bDir , uOrg ) ;
CG_TestLine ( bOrg , uOrg , 50 , 0x0000ff , 1 ) ;
cent - > turAngles [ YAW ] = forcedAngles [ YAW ] ;
}
# endif
//list of valid ragdoll effectors
static const char * cg_effectorStringTable [ ] =
{ //commented out the ones I don't want dragging to affect
// "thoracic",
// "rhand",
" lhand " ,
" rtibia " ,
" ltibia " ,
" rtalus " ,
" ltalus " ,
// "rradiusX",
" lradiusX " ,
" rfemurX " ,
" lfemurX " ,
// "ceyebrow",
NULL //always terminate
} ;
//we want to see which way the pelvis is facing to get a relatively oriented base settling frame
//this is to avoid the arms stretching in opposite directions on the body trying to reach the base
//pose if the pelvis is flipped opposite of the base pose or something -rww
static int CG_RagAnimForPositioning ( centity_t * cent )
{
int bolt ;
vec3_t dir ;
mdxaBone_t matrix ;
assert ( cent - > ghoul2 ) ;
bolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " pelvis " ) ;
assert ( bolt > - 1 ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , bolt , & matrix , cent - > turAngles , cent - > lerpOrigin ,
cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & matrix , NEGATIVE_Z , dir ) ;
if ( dir [ 2 ] > 0.0f )
{ //facing up
return BOTH_DEADFLOP2 ;
}
else
{ //facing down
return BOTH_DEADFLOP1 ;
}
}
//rww - cgame interface for the ragdoll stuff.
//Returns qtrue if the entity is now in a ragdoll state, otherwise qfalse.
qboolean CG_RagDoll ( centity_t * cent , vec3_t forcedAngles )
{
vec3_t usedOrg ;
qboolean inSomething = qfalse ;
int ragAnim ; //BOTH_DEAD1; //BOTH_DEATH1;
if ( ! cg_ragDoll . integer )
{
return qfalse ;
}
if ( cent - > localAnimIndex )
{ //don't rag non-humanoids
return qfalse ;
}
VectorCopy ( cent - > lerpOrigin , usedOrg ) ;
if ( ! cent - > isRagging )
{ //If we're not in a ragdoll state, perform the checks.
if ( cent - > currentState . eFlags & EF_RAG )
{ //want to go into it no matter what then
inSomething = qtrue ;
}
else if ( cent - > currentState . groundEntityNum = = ENTITYNUM_NONE )
{
vec3_t cVel ;
VectorCopy ( cent - > currentState . pos . trDelta , cVel ) ;
if ( VectorNormalize ( cVel ) > 400 )
{ //if he's flying through the air at a good enough speed, switch into ragdoll
inSomething = qtrue ;
}
}
if ( cent - > currentState . eType = = ET_BODY )
{ //just rag bodies immediately if their own was ragging on respawn
if ( cent - > ownerRagging )
{
cent - > isRagging = qtrue ;
return qfalse ;
}
}
if ( cg_ragDoll . integer > 1 )
{
inSomething = qtrue ;
}
if ( ! inSomething )
{
int anim = ( cent - > currentState . legsAnim ) ;
int dur = ( bgAllAnims [ cent - > localAnimIndex ] . anims [ anim ] . numFrames - 1 ) * fabs ( ( float ) ( bgAllAnims [ cent - > localAnimIndex ] . anims [ anim ] . frameLerp ) ) ;
int i = 0 ;
int boltChecks [ 5 ] ;
vec3_t boltPoints [ 5 ] ;
vec3_t trStart , trEnd ;
vec3_t tAng ;
qboolean deathDone = qfalse ;
trace_t tr ;
mdxaBone_t boltMatrix ;
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
if ( cent - > pe . legs . animationTime > 50 & & ( cg . time - cent - > pe . legs . animationTime ) > dur )
{ //Looks like the death anim is done playing
deathDone = qtrue ;
}
if ( deathDone )
{ //only trace from the hands if the death anim is already done.
boltChecks [ 0 ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " rhand " ) ;
boltChecks [ 1 ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " lhand " ) ;
}
else
{ //otherwise start the trace loop at the cranium.
i = 2 ;
}
boltChecks [ 2 ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " cranium " ) ;
//boltChecks[3] = trap_G2API_AddBolt(cent->ghoul2, 0, "rtarsal");
//boltChecks[4] = trap_G2API_AddBolt(cent->ghoul2, 0, "ltarsal");
boltChecks [ 3 ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " rtalus " ) ;
boltChecks [ 4 ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " ltalus " ) ;
//This may seem bad, but since we have a bone cache now it should manage to not be too disgustingly slow.
//Do the head first, because the hands reference it anyway.
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , boltChecks [ 2 ] , & boltMatrix , tAng , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltPoints [ 2 ] ) ;
while ( i < 5 )
{
if ( i < 2 )
{ //when doing hands, trace to the head instead of origin
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , boltChecks [ i ] , & boltMatrix , tAng , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltPoints [ i ] ) ;
VectorCopy ( boltPoints [ i ] , trStart ) ;
VectorCopy ( boltPoints [ 2 ] , trEnd ) ;
}
else
{
if ( i > 2 )
{ //2 is the head, which already has the bolt point.
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , boltChecks [ i ] , & boltMatrix , tAng , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltPoints [ i ] ) ;
}
VectorCopy ( boltPoints [ i ] , trStart ) ;
VectorCopy ( cent - > lerpOrigin , trEnd ) ;
}
//Now that we have all that sorted out, trace between the two points we desire.
CG_Rag_Trace ( & tr , trStart , NULL , NULL , trEnd , cent - > currentState . number , MASK_SOLID ) ;
if ( tr . fraction ! = 1.0 | | tr . startsolid | | tr . allsolid )
{ //Hit something or start in solid, so flag it and break.
//This is a slight hack, but if we aren't done with the death anim, we don't really want to
//go into ragdoll unless our body has a relatively "flat" pitch.
#if 0
vec3_t vSub ;
//Check the pitch from the head to the right foot (should be reasonable)
VectorSubtract ( boltPoints [ 2 ] , boltPoints [ 3 ] , vSub ) ;
VectorNormalize ( vSub ) ;
vectoangles ( vSub , vSub ) ;
if ( deathDone | | ( vSub [ PITCH ] < 50 & & vSub [ PITCH ] > - 50 ) )
{
inSomething = qtrue ;
}
# else
inSomething = qtrue ;
# endif
break ;
}
i + + ;
}
}
if ( inSomething )
{
cent - > isRagging = qtrue ;
#if 0
VectorClear ( cent - > lerpOriginOffset ) ;
# endif
}
}
if ( cent - > isRagging )
{ //We're in a ragdoll state, so make the call to keep our positions updated and whatnot.
sharedRagDollParams_t tParms ;
sharedRagDollUpdateParams_t tuParms ;
ragAnim = CG_RagAnimForPositioning ( cent ) ;
if ( cent - > ikStatus )
{ //ik must be reset before ragdoll is started, or you'll get some interesting results.
trap_G2API_SetBoneIKState ( cent - > ghoul2 , cg . time , NULL , IKS_NONE , NULL ) ;
cent - > ikStatus = qfalse ;
}
//these will be used as "base" frames for the ragoll settling.
tParms . startFrame = bgAllAnims [ cent - > localAnimIndex ] . anims [ ragAnim ] . firstFrame ; // + bgAllAnims[cent->localAnimIndex].anims[ragAnim].numFrames;
tParms . endFrame = bgAllAnims [ cent - > localAnimIndex ] . anims [ ragAnim ] . firstFrame + bgAllAnims [ cent - > localAnimIndex ] . anims [ ragAnim ] . numFrames ;
#if 0
{
float animSpeed = 0 ;
int blendTime = 600 ;
int flags = 0 ; //BONE_ANIM_OVERRIDE_FREEZE;
if ( bgAllAnims [ cent - > localAnimIndex ] . anims [ ragAnim ] . loopFrames ! = - 1 )
{
flags = BONE_ANIM_OVERRIDE_LOOP ;
}
/*
if ( cg_animBlend . integer )
{
flags | = BONE_ANIM_BLEND ;
}
*/
animSpeed = 50.0f / bgAllAnims [ cent - > localAnimIndex ] . anims [ ragAnim ] . frameLerp ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " lower_lumbar " , tParms . startFrame , tParms . endFrame , flags , animSpeed , cg . time , - 1 , blendTime ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " Motion " , tParms . startFrame , tParms . endFrame , flags , animSpeed , cg . time , - 1 , blendTime ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " model_root " , tParms . startFrame , tParms . endFrame , flags , animSpeed , cg . time , - 1 , blendTime ) ;
}
# elif 1 //with my new method of doing things I want it to continue the anim
{
float currentFrame ;
int startFrame , endFrame ;
int flags ;
float animSpeed ;
if ( trap_G2API_GetBoneAnim ( cent - > ghoul2 , " model_root " , cg . time , & currentFrame , & startFrame , & endFrame , & flags , & animSpeed , cgs . gameModels , 0 ) )
{ //lock the anim on the current frame.
int blendTime = 500 ;
animation_t * curAnim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ cent - > currentState . legsAnim ] ;
if ( currentFrame > = ( curAnim - > firstFrame + curAnim - > numFrames - 1 ) )
{ //this is sort of silly but it works for now.
currentFrame = ( curAnim - > firstFrame + curAnim - > numFrames - 2 ) ;
}
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " lower_lumbar " , currentFrame , currentFrame + 1 , flags , animSpeed , cg . time , currentFrame , blendTime ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " model_root " , currentFrame , currentFrame + 1 , flags , animSpeed , cg . time , currentFrame , blendTime ) ;
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " Motion " , currentFrame , currentFrame + 1 , flags , animSpeed , cg . time , currentFrame , blendTime ) ;
}
}
# endif
CG_G2SetBoneAngles ( cent - > ghoul2 , 0 , " upper_lumbar " , vec3_origin , BONE_ANGLES_POSTMULT , POSITIVE_X , NEGATIVE_Y , NEGATIVE_Z , cgs . gameModels , 0 , cg . time ) ;
CG_G2SetBoneAngles ( cent - > ghoul2 , 0 , " lower_lumbar " , vec3_origin , BONE_ANGLES_POSTMULT , POSITIVE_X , NEGATIVE_Y , NEGATIVE_Z , cgs . gameModels , 0 , cg . time ) ;
CG_G2SetBoneAngles ( cent - > ghoul2 , 0 , " thoracic " , vec3_origin , BONE_ANGLES_POSTMULT , POSITIVE_X , NEGATIVE_Y , NEGATIVE_Z , cgs . gameModels , 0 , cg . time ) ;
CG_G2SetBoneAngles ( cent - > ghoul2 , 0 , " cervical " , vec3_origin , BONE_ANGLES_POSTMULT , POSITIVE_X , NEGATIVE_Y , NEGATIVE_Z , cgs . gameModels , 0 , cg . time ) ;
VectorCopy ( forcedAngles , tParms . angles ) ;
VectorCopy ( usedOrg , tParms . position ) ;
VectorCopy ( cent - > modelScale , tParms . scale ) ;
tParms . me = cent - > currentState . number ;
tParms . collisionType = 1 ;
tParms . RagPhase = RP_DEATH_COLLISION ;
tParms . fShotStrength = 4 ;
trap_G2API_SetRagDoll ( cent - > ghoul2 , & tParms ) ;
VectorCopy ( forcedAngles , tuParms . angles ) ;
VectorCopy ( usedOrg , tuParms . position ) ;
VectorCopy ( cent - > modelScale , tuParms . scale ) ;
tuParms . me = cent - > currentState . number ;
tuParms . settleFrame = tParms . endFrame - 1 ;
if ( cent - > currentState . groundEntityNum ! = ENTITYNUM_NONE )
{
VectorClear ( tuParms . velocity ) ;
}
else
{
VectorScale ( cent - > currentState . pos . trDelta , 2.0f , tuParms . velocity ) ;
}
trap_G2API_AnimateG2Models ( cent - > ghoul2 , cg . time , & tuParms ) ;
//So if we try to get a bolt point it's still correct
cent - > turAngles [ YAW ] =
cent - > lerpAngles [ YAW ] =
cent - > pe . torso . yawAngle =
cent - > pe . legs . yawAngle = forcedAngles [ YAW ] ;
if ( cent - > currentState . ragAttach & &
( cent - > currentState . eType ! = ET_NPC | | cent - > currentState . NPC_class ! = CLASS_VEHICLE ) )
{
centity_t * grabEnt ;
if ( cent - > currentState . ragAttach = = ENTITYNUM_NONE )
{ //switch cl 0 and entitynum_none, so we can operate on the "if non-0" concept
grabEnt = & cg_entities [ 0 ] ;
}
else
{
grabEnt = & cg_entities [ cent - > currentState . ragAttach ] ;
}
if ( grabEnt - > ghoul2 )
{
mdxaBone_t matrix ;
vec3_t bOrg ;
vec3_t thisHand ;
vec3_t hands ;
vec3_t pcjMin , pcjMax ;
vec3_t pDif ;
vec3_t thorPoint ;
float difLen ;
int thorBolt ;
//Get the person who is holding our hand's hand location
trap_G2API_GetBoltMatrix ( grabEnt - > ghoul2 , 0 , 0 , & matrix , grabEnt - > turAngles , grabEnt - > lerpOrigin ,
cg . time , cgs . gameModels , grabEnt - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & matrix , ORIGIN , bOrg ) ;
//Get our hand's location
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , 0 , & matrix , cent - > turAngles , cent - > lerpOrigin ,
cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & matrix , ORIGIN , thisHand ) ;
//Get the position of the thoracic bone for hinting its velocity later on
thorBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " thoracic " ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , thorBolt , & matrix , cent - > turAngles , cent - > lerpOrigin ,
cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & matrix , ORIGIN , thorPoint ) ;
VectorSubtract ( bOrg , thisHand , hands ) ;
if ( VectorLength ( hands ) < 3.0f )
{
trap_G2API_RagForceSolve ( cent - > ghoul2 , qfalse ) ;
}
else
{
trap_G2API_RagForceSolve ( cent - > ghoul2 , qtrue ) ;
}
//got the hand pos of him, now we want to make our hand go to it
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rhand " , bOrg ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rradius " , bOrg ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rradiusX " , bOrg ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rhumerusX " , bOrg ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rhumerus " , bOrg ) ;
//Make these two solve quickly so we can update decently
trap_G2API_RagPCJGradientSpeed ( cent - > ghoul2 , " rhumerus " , 1.5f ) ;
trap_G2API_RagPCJGradientSpeed ( cent - > ghoul2 , " rradius " , 1.5f ) ;
//Break the constraints on them I suppose
VectorSet ( pcjMin , - 999 , - 999 , - 999 ) ;
VectorSet ( pcjMax , 999 , 999 , 999 ) ;
trap_G2API_RagPCJConstraint ( cent - > ghoul2 , " rhumerus " , pcjMin , pcjMax ) ;
trap_G2API_RagPCJConstraint ( cent - > ghoul2 , " rradius " , pcjMin , pcjMax ) ;
cent - > overridingBones = cg . time + 2000 ;
//hit the thoracic velocity to the hand point
VectorSubtract ( bOrg , thorPoint , hands ) ;
VectorNormalize ( hands ) ;
VectorScale ( hands , 2048.0f , hands ) ;
trap_G2API_RagEffectorKick ( cent - > ghoul2 , " thoracic " , hands ) ;
trap_G2API_RagEffectorKick ( cent - > ghoul2 , " ceyebrow " , hands ) ;
VectorSubtract ( cent - > ragLastOrigin , cent - > lerpOrigin , pDif ) ;
VectorCopy ( cent - > lerpOrigin , cent - > ragLastOrigin ) ;
if ( cent - > ragLastOriginTime > = cg . time & & cent - > currentState . groundEntityNum ! = ENTITYNUM_NONE )
{ //make sure it's reasonably updated
difLen = VectorLength ( pDif ) ;
if ( difLen > 0.0f )
{ //if we're being dragged, then kick all the bones around a bit
vec3_t dVel ;
vec3_t rVel ;
int i = 0 ;
if ( difLen < 12.0f )
{
VectorScale ( pDif , 12.0f / difLen , pDif ) ;
difLen = 12.0f ;
}
while ( cg_effectorStringTable [ i ] )
{
VectorCopy ( pDif , dVel ) ;
dVel [ 2 ] = 0 ;
//Factor in a random velocity
VectorSet ( rVel , flrand ( - 0.1f , 0.1f ) , flrand ( - 0.1f , 0.1f ) , flrand ( 0.1f , 0.5 ) ) ;
VectorScale ( rVel , 8.0f , rVel ) ;
VectorAdd ( dVel , rVel , dVel ) ;
VectorScale ( dVel , 10.0f , dVel ) ;
trap_G2API_RagEffectorKick ( cent - > ghoul2 , cg_effectorStringTable [ i ] , dVel ) ;
#if 0
{
mdxaBone_t bm ;
vec3_t borg ;
vec3_t vorg ;
int b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , cg_effectorStringTable [ i ] ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , b , & bm , cent - > turAngles , cent - > lerpOrigin , cg . time ,
cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & bm , ORIGIN , borg ) ;
VectorMA ( borg , 1.0f , dVel , vorg ) ;
CG_TestLine ( borg , vorg , 50 , 0x0000ff , 1 ) ;
}
# endif
i + + ;
}
}
}
cent - > ragLastOriginTime = cg . time + 1000 ;
}
}
else if ( cent - > overridingBones )
{ //reset things to their normal rag state
vec3_t pcjMin , pcjMax ;
vec3_t dVel ;
//got the hand pos of him, now we want to make our hand go to it
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rhand " , NULL ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rradius " , NULL ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rradiusX " , NULL ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rhumerusX " , NULL ) ;
trap_G2API_RagEffectorGoal ( cent - > ghoul2 , " rhumerus " , NULL ) ;
VectorSet ( dVel , 0.0f , 0.0f , - 64.0f ) ;
trap_G2API_RagEffectorKick ( cent - > ghoul2 , " rhand " , dVel ) ;
trap_G2API_RagPCJGradientSpeed ( cent - > ghoul2 , " rhumerus " , 0.0f ) ;
trap_G2API_RagPCJGradientSpeed ( cent - > ghoul2 , " rradius " , 0.0f ) ;
VectorSet ( pcjMin , - 100.0f , - 40.0f , - 15.0f ) ;
VectorSet ( pcjMax , - 15.0f , 80.0f , 15.0f ) ;
trap_G2API_RagPCJConstraint ( cent - > ghoul2 , " rhumerus " , pcjMin , pcjMax ) ;
VectorSet ( pcjMin , - 25.0f , - 20.0f , - 20.0f ) ;
VectorSet ( pcjMax , 90.0f , 20.0f , - 20.0f ) ;
trap_G2API_RagPCJConstraint ( cent - > ghoul2 , " rradius " , pcjMin , pcjMax ) ;
if ( cent - > overridingBones < cg . time )
{
trap_G2API_RagForceSolve ( cent - > ghoul2 , qfalse ) ;
cent - > overridingBones = 0 ;
}
else
{
trap_G2API_RagForceSolve ( cent - > ghoul2 , qtrue ) ;
}
}
return qtrue ;
}
return qfalse ;
}
//set the bone angles of this client entity based on data from the server -rww
void CG_G2ServerBoneAngles ( centity_t * cent )
{
int i = 0 ;
int bone = cent - > currentState . boneIndex1 ;
int flags , up , right , forward ;
vec3_t boneAngles ;
VectorCopy ( cent - > currentState . boneAngles1 , boneAngles ) ;
while ( i < 4 )
{ //cycle through the 4 bone index values on the entstate
if ( bone )
{ //if it's non-0 then it could have something in it.
const char * boneName = CG_ConfigString ( CS_G2BONES + bone ) ;
if ( boneName & & boneName [ 0 ] )
{ //got the bone, now set the angles from the corresponding entitystate boneangles value.
flags = BONE_ANGLES_POSTMULT ;
//get the orientation out of our bit field
forward = ( cent - > currentState . boneOrient ) & 7 ; //3 bits from bit 0
right = ( cent - > currentState . boneOrient > > 3 ) & 7 ; //3 bits from bit 3
up = ( cent - > currentState . boneOrient > > 6 ) & 7 ; //3 bits from bit 6
trap_G2API_SetBoneAngles ( cent - > ghoul2 , 0 , boneName , boneAngles , flags , up , right , forward , cgs . gameModels , 100 , cg . time ) ;
}
}
switch ( i )
{
case 0 :
bone = cent - > currentState . boneIndex2 ;
VectorCopy ( cent - > currentState . boneAngles2 , boneAngles ) ;
break ;
case 1 :
bone = cent - > currentState . boneIndex3 ;
VectorCopy ( cent - > currentState . boneAngles3 , boneAngles ) ;
break ;
case 2 :
bone = cent - > currentState . boneIndex4 ;
VectorCopy ( cent - > currentState . boneAngles4 , boneAngles ) ;
break ;
default :
break ;
}
i + + ;
}
}
/*
- - - - - - - - - - - - - - - - - - - - - - - - -
CG_G2SetHeadBlink
- - - - - - - - - - - - - - - - - - - - - - - - -
*/
static void CG_G2SetHeadBlink ( centity_t * cent , qboolean bStart )
{
vec3_t desiredAngles ;
int blendTime = 80 ;
qboolean bWink = qfalse ;
const int hReye = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " reye " ) ;
const int hLeye = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " leye " ) ;
if ( hLeye = = - 1 )
{
return ;
}
VectorClear ( desiredAngles ) ;
if ( bStart )
{
desiredAngles [ YAW ] = - 50 ;
if ( random ( ) > 0.95f )
{
bWink = qtrue ;
blendTime / = 3 ;
}
}
trap_G2API_SetBoneAngles ( cent - > ghoul2 , 0 , " leye " , desiredAngles ,
BONE_ANGLES_POSTMULT , POSITIVE_Y , POSITIVE_Z , POSITIVE_X , NULL , blendTime , cg . time ) ;
if ( hReye = = - 1 )
{
return ;
}
if ( ! bWink )
{
trap_G2API_SetBoneAngles ( cent - > ghoul2 , 0 , " reye " , desiredAngles ,
BONE_ANGLES_POSTMULT , POSITIVE_Y , POSITIVE_Z , POSITIVE_X , NULL , blendTime , cg . time ) ;
}
}
/*
- - - - - - - - - - - - - - - - - - - - - - - - -
CG_G2SetHeadAnims
- - - - - - - - - - - - - - - - - - - - - - - - -
*/
static void CG_G2SetHeadAnim ( centity_t * cent , int anim )
{
const int blendTime = 50 ;
const animation_t * animations = bgAllAnims [ cent - > localAnimIndex ] . anims ;
int animFlags = BONE_ANIM_OVERRIDE ; //| BONE_ANIM_BLEND;
// animSpeed is 1.0 if the frameLerp (ms/frame) is 50 (20 fps).
// float timeScaleMod = (cg_timescale.value&&gent&&gent->s.clientNum==0&&!player_locked&&!MatrixMode&&gent->client->ps.forcePowersActive&(1<<FP_SPEED))?(1.0/cg_timescale.value):1.0;
const float timeScaleMod = ( cg_timescale . value ) ? ( 1.0 / cg_timescale . value ) : 1.0 ;
float animSpeed = 50.0f / animations [ anim ] . frameLerp * timeScaleMod ;
int firstFrame ;
int lastFrame ;
if ( animations [ anim ] . numFrames < = 0 )
{
return ;
}
if ( anim = = FACE_DEAD )
{
animFlags | = BONE_ANIM_OVERRIDE_FREEZE ;
}
// animSpeed is 1.0 if the frameLerp (ms/frame) is 50 (20 fps).
if ( animSpeed < 0 )
{ //play anim backwards
lastFrame = animations [ anim ] . firstFrame - 1 ;
firstFrame = ( animations [ anim ] . numFrames - 1 ) + animations [ anim ] . firstFrame ;
}
else
{
firstFrame = animations [ anim ] . firstFrame ;
lastFrame = ( animations [ anim ] . numFrames ) + animations [ anim ] . firstFrame ;
}
// first decide if we are doing an animation on the head already
// int startFrame, endFrame;
// const qboolean animatingHead = gi.G2API_GetAnimRangeIndex(&gent->ghoul2[gent->playerModel], cent->gent->faceBone, &startFrame, &endFrame);
// if (!animatingHead || ( animations[anim].firstFrame != startFrame ) )// only set the anim if we aren't going to do the same animation again
{
// gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], cent->gent->faceBone,
// firstFrame, lastFrame, animFlags, animSpeed, cg.time, -1, blendTime);
trap_G2API_SetBoneAnim ( cent - > ghoul2 , 0 , " face " , firstFrame , lastFrame , animFlags , animSpeed ,
cg . time , - 1 , blendTime ) ;
}
}
qboolean CG_G2PlayerHeadAnims ( centity_t * cent )
{
clientInfo_t * ci = NULL ;
int anim = - 1 ;
int voiceVolume = 0 ;
if ( cent - > localAnimIndex > 1 )
{ //only do this for humanoids
return qfalse ;
}
if ( cent - > noFace )
{ // i don't have a face
return qfalse ;
}
if ( cent - > currentState . number < MAX_CLIENTS )
{
ci = & cgs . clientinfo [ cent - > currentState . number ] ;
}
else
{
ci = cent - > npcClient ;
}
if ( ! ci )
{
return qfalse ;
}
if ( cent - > currentState . eFlags & EF_DEAD )
{ //Dead people close their eyes and don't make faces!
anim = FACE_DEAD ;
ci - > facial_blink = - 1 ;
}
else
{
if ( ! ci - > facial_blink )
{ // set the timers
ci - > facial_blink = cg . time + flrand ( 4000.0 , 8000.0 ) ;
ci - > facial_frown = cg . time + flrand ( 6000.0 , 10000.0 ) ;
ci - > facial_aux = cg . time + flrand ( 6000.0 , 10000.0 ) ;
}
//are we blinking?
if ( ci - > facial_blink < 0 )
{ // yes, check if we are we done blinking ?
if ( - ( ci - > facial_blink ) < cg . time )
{ // yes, so reset blink timer
ci - > facial_blink = cg . time + flrand ( 4000.0 , 8000.0 ) ;
CG_G2SetHeadBlink ( cent , qfalse ) ; //stop the blink
}
}
else // no we aren't blinking
{
if ( ci - > facial_blink < cg . time ) // but should we start ?
{
CG_G2SetHeadBlink ( cent , qtrue ) ;
if ( ci - > facial_blink = = 1 )
{ //requested to stay shut by SET_FACEEYESCLOSED
ci - > facial_blink = - ( cg . time + 99999999.0f ) ; // set blink timer
}
else
{
ci - > facial_blink = - ( cg . time + 300.0f ) ; // set blink timer
}
}
}
voiceVolume = trap_S_GetVoiceVolume ( cent - > currentState . number ) ;
if ( voiceVolume > 0 ) // if we aren't talking, then it will be 0, -1 for talking but paused
{
anim = FACE_TALK1 + voiceVolume - 1 ;
}
else if ( voiceVolume = = 0 ) //don't do aux if in a slient part of speech
{ //not talking
if ( ci - > facial_aux < 0 ) // are we auxing ?
{ //yes
if ( - ( ci - > facial_aux ) < cg . time ) // are we done auxing ?
{ // yes, reset aux timer
ci - > facial_aux = cg . time + flrand ( 7000.0 , 10000.0 ) ;
}
else
{ // not yet, so choose aux
anim = FACE_ALERT ;
}
}
else // no we aren't auxing
{ // but should we start ?
if ( ci - > facial_aux < cg . time )
{ //yes
anim = FACE_ALERT ;
// set aux timer
ci - > facial_aux = - ( cg . time + 2000.0 ) ;
}
}
if ( anim ! = - 1 ) //we we are auxing, see if we should override with a frown
{
if ( ci - > facial_frown < 0 ) // are we frowning ?
{ // yes,
if ( - ( ci - > facial_frown ) < cg . time ) //are we done frowning ?
{ // yes, reset frown timer
ci - > facial_frown = cg . time + flrand ( 7000.0 , 10000.0 ) ;
}
else
{ // not yet, so choose frown
anim = FACE_FROWN ;
}
}
else // no we aren't frowning
{ // but should we start ?
if ( ci - > facial_frown < cg . time )
{
anim = FACE_FROWN ;
// set frown timer
ci - > facial_frown = - ( cg . time + 2000.0 ) ;
}
}
}
} //talking
} //dead
if ( anim ! = - 1 )
{
CG_G2SetHeadAnim ( cent , anim ) ;
return qtrue ;
}
return qfalse ;
}
static void CG_G2PlayerAngles ( centity_t * cent , vec3_t legs [ 3 ] , vec3_t legsAngles )
{
clientInfo_t * ci ;
//rww - now do ragdoll stuff
if ( ( cent - > currentState . eFlags & EF_DEAD ) | | ( cent - > currentState . eFlags & EF_RAG ) )
{
vec3_t forcedAngles ;
VectorClear ( forcedAngles ) ;
forcedAngles [ YAW ] = cent - > lerpAngles [ YAW ] ;
if ( CG_RagDoll ( cent , forcedAngles ) )
{ //if we managed to go into the rag state, give our ent axis the forced angles and return.
AnglesToAxis ( forcedAngles , legs ) ;
VectorCopy ( forcedAngles , legsAngles ) ;
return ;
}
}
else if ( cent - > isRagging )
{
cent - > isRagging = qfalse ;
trap_G2API_SetRagDoll ( cent - > ghoul2 , NULL ) ; //calling with null parms resets to no ragdoll.
}
if ( cent - > currentState . eType = = ET_NPC )
{
ci = cent - > npcClient ;
assert ( ci ) ;
}
else
{
ci = & cgs . clientinfo [ cent - > currentState . number ] ;
}
//rww - Quite possibly the most arguments for a function ever.
if ( cent - > localAnimIndex < = 1 )
{ //don't do these things on non-humanoids
vec3_t lookAngles ;
entityState_t * emplaced = NULL ;
if ( cent - > currentState . hasLookTarget )
{
VectorSubtract ( cg_entities [ cent - > currentState . lookTarget ] . lerpOrigin , cent - > lerpOrigin , lookAngles ) ;
vectoangles ( lookAngles , lookAngles ) ;
ci - > lookTime = cg . time + 1000 ;
}
else
{
VectorCopy ( cent - > lerpAngles , lookAngles ) ;
}
lookAngles [ PITCH ] = 0 ;
if ( cent - > currentState . otherEntityNum2 )
{
emplaced = & cg_entities [ cent - > currentState . otherEntityNum2 ] . currentState ;
}
BG_G2PlayerAngles ( cent - > ghoul2 , ci - > bolt_motion , & cent - > currentState , cg . time ,
cent - > lerpOrigin , cent - > lerpAngles , legs , legsAngles , & cent - > pe . torso . yawing , & cent - > pe . torso . pitching ,
& cent - > pe . legs . yawing , & cent - > pe . torso . yawAngle , & cent - > pe . torso . pitchAngle , & cent - > pe . legs . yawAngle ,
cg . frametime , cent - > turAngles , cent - > modelScale , ci - > legsAnim , ci - > torsoAnim , & ci - > corrTime ,
lookAngles , ci - > lastHeadAngles , ci - > lookTime , emplaced , & ci - > superSmoothTime ) ;
if ( cent - > currentState . heldByClient & & cent - > currentState . heldByClient < = MAX_CLIENTS )
{ //then put our arm in this client's hand
//is index+1 because index 0 is valid.
int heldByIndex = cent - > currentState . heldByClient - 1 ;
centity_t * other = & cg_entities [ heldByIndex ] ;
if ( other & & other - > ghoul2 & & ci - > bolt_lhand )
{
mdxaBone_t boltMatrix ;
vec3_t boltOrg ;
trap_G2API_GetBoltMatrix ( other - > ghoul2 , 0 , ci - > bolt_lhand , & boltMatrix , other - > turAngles , other - > lerpOrigin , cg . time , cgs . gameModels , other - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltOrg ) ;
BG_IK_MoveArm ( cent - > ghoul2 , ci - > bolt_lhand , cg . time , & cent - > currentState ,
cent - > currentState . torsoAnim /*BOTH_DEAD1*/ , boltOrg , & cent - > ikStatus , cent - > lerpOrigin , cent - > lerpAngles , cent - > modelScale , 500 , qfalse ) ;
}
}
else if ( cent - > ikStatus )
{ //make sure we aren't IKing if we don't have anyone to hold onto us.
BG_IK_MoveArm ( cent - > ghoul2 , ci - > bolt_lhand , cg . time , & cent - > currentState ,
cent - > currentState . torsoAnim /*BOTH_DEAD1*/ , vec3_origin , & cent - > ikStatus , cent - > lerpOrigin , cent - > lerpAngles , cent - > modelScale , 500 , qtrue ) ;
}
}
else if ( cent - > m_pVehicle & & cent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_WALKER )
{
vec3_t lookAngles ;
VectorCopy ( cent - > lerpAngles , legsAngles ) ;
legsAngles [ PITCH ] = 0 ;
AnglesToAxis ( legsAngles , legs ) ;
VectorCopy ( cent - > lerpAngles , lookAngles ) ;
lookAngles [ YAW ] = lookAngles [ ROLL ] = 0 ;
BG_G2ATSTAngles ( cent - > ghoul2 , cg . time , lookAngles ) ;
}
else
{
if ( cent - > currentState . eType = = ET_NPC & &
cent - > currentState . NPC_class = = CLASS_VEHICLE & &
cent - > m_pVehicle & &
cent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //fighters actually want to take pitch and roll into account for the axial angles
VectorCopy ( cent - > lerpAngles , legsAngles ) ;
AnglesToAxis ( legsAngles , legs ) ;
}
else if ( cent - > currentState . eType = = ET_NPC & &
cent - > currentState . m_iVehicleNum & &
cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{ //an NPC bolted to a vehicle should use the full angles
VectorCopy ( cent - > lerpAngles , legsAngles ) ;
AnglesToAxis ( legsAngles , legs ) ;
}
else
{
vec3_t nhAngles ;
if ( cent - > currentState . eType = = ET_NPC & &
cent - > currentState . NPC_class = = CLASS_VEHICLE & &
cent - > m_pVehicle & &
cent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_SPEEDER )
{ //yeah, a hack, sorry.
VectorSet ( nhAngles , 0 , cent - > lerpAngles [ YAW ] , cent - > lerpAngles [ ROLL ] ) ;
}
else
{
VectorSet ( nhAngles , 0 , cent - > lerpAngles [ YAW ] , 0 ) ;
}
AnglesToAxis ( nhAngles , legs ) ;
}
}
//See if we have any bone angles sent from the server
CG_G2ServerBoneAngles ( cent ) ;
}
//==========================================================================
/*
= = = = = = = = = = = = = = =
CG_TrailItem
= = = = = = = = = = = = = = =
*/
#if 0
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 ) ;
}
# endif
/*
= = = = = = = = = = = = = = =
CG_PlayerFlag
= = = = = = = = = = = = = = =
*/
static void CG_PlayerFlag ( centity_t * cent , qhandle_t hModel ) {
refEntity_t ent ;
vec3_t angles ;
vec3_t axis [ 3 ] ;
vec3_t boltOrg , tAng , getAng , right ;
mdxaBone_t boltMatrix ;
clientInfo_t * ci ;
if ( cent - > currentState . number = = cg . snap - > ps . clientNum & &
! cg . renderingThirdPerson )
{
return ;
}
if ( ! cent - > ghoul2 )
{
return ;
}
if ( cent - > currentState . eType = = ET_NPC )
{
ci = cent - > npcClient ;
assert ( ci ) ;
}
else
{
ci = & cgs . clientinfo [ cent - > currentState . number ] ;
}
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_llumbar , & boltMatrix , tAng , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltOrg ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , POSITIVE_X , tAng ) ;
vectoangles ( tAng , tAng ) ;
VectorCopy ( cent - > lerpAngles , angles ) ;
boltOrg [ 2 ] - = 12 ;
VectorSet ( getAng , 0 , cent - > lerpAngles [ 1 ] , 0 ) ;
AngleVectors ( getAng , 0 , right , 0 ) ;
boltOrg [ 0 ] + = right [ 0 ] * 8 ;
boltOrg [ 1 ] + = right [ 1 ] * 8 ;
boltOrg [ 2 ] + = right [ 2 ] * 8 ;
angles [ PITCH ] = - cent - > lerpAngles [ PITCH ] / 2 - 30 ;
angles [ YAW ] = tAng [ YAW ] + 270 ;
AnglesToAxis ( angles , axis ) ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorMA ( boltOrg , 24 , axis [ 0 ] , ent . origin ) ;
angles [ ROLL ] + = 20 ;
AnglesToAxis ( angles , ent . axis ) ;
ent . hModel = hModel ;
ent . modelScale [ 0 ] = 0.5 ;
ent . modelScale [ 1 ] = 0.5 ;
ent . modelScale [ 2 ] = 0.5 ;
ScaleModelAxis ( & ent ) ;
/*
if ( cent - > currentState . number = = cg . snap - > ps . clientNum )
{ //If we're the current client (in third person), render the flag on our back transparently
ent . renderfx | = RF_FORCE_ENT_ALPHA ;
ent . shaderRGBA [ 3 ] = 100 ;
}
*/
//FIXME: Not doing this at the moment because sorting totally messes up
trap_R_AddRefEntityToScene ( & ent ) ;
}
/*
= = = = = = = = = = = = = = =
CG_PlayerPowerups
= = = = = = = = = = = = = = =
*/
static void CG_PlayerPowerups ( centity_t * cent , refEntity_t * torso ) {
int powerups ;
clientInfo_t * ci ;
powerups = cent - > currentState . powerups ;
if ( ! powerups ) {
return ;
}
// quad gives a dlight
if ( powerups & ( 1 < < PW_QUAD ) ) {
trap_R_AddLightToScene ( cent - > lerpOrigin , 200 + ( rand ( ) & 31 ) , 0.2f , 0.2f , 1 ) ;
}
if ( cent - > currentState . eType = = ET_NPC )
{
ci = cent - > npcClient ;
assert ( ci ) ;
}
else
{
ci = & cgs . clientinfo [ cent - > currentState . clientNum ] ;
}
// redflag
if ( powerups & ( 1 < < PW_REDFLAG ) ) {
CG_PlayerFlag ( cent , cgs . media . redFlagModel ) ;
trap_R_AddLightToScene ( cent - > lerpOrigin , 200 + ( rand ( ) & 31 ) , 1.0 , 0.2f , 0.2f ) ;
}
// blueflag
if ( powerups & ( 1 < < PW_BLUEFLAG ) ) {
CG_PlayerFlag ( cent , cgs . media . blueFlagModel ) ;
trap_R_AddLightToScene ( cent - > lerpOrigin , 200 + ( rand ( ) & 31 ) , 0.2f , 0.2f , 1.0 ) ;
}
// neutralflag
if ( powerups & ( 1 < < PW_NEUTRALFLAG ) ) {
trap_R_AddLightToScene ( cent - > lerpOrigin , 200 + ( rand ( ) & 31 ) , 1.0 , 1.0 , 1.0 ) ;
}
// haste leaves smoke trails
/*
if ( powerups & ( 1 < < PW_HASTE ) ) {
CG_HasteTrail ( cent ) ;
}
*/
}
/*
= = = = = = = = = = = = = = =
CG_PlayerFloatSprite
Float a sprite over the player ' s head
= = = = = = = = = = = = = = =
*/
static void CG_PlayerFloatSprite ( centity_t * cent , qhandle_t shader ) {
int rf ;
refEntity_t ent ;
if ( cent - > currentState . number = = cg . snap - > ps . clientNum & & ! cg . renderingThirdPerson ) {
rf = RF_THIRD_PERSON ; // only show in mirrors
} else {
rf = 0 ;
}
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( cent - > lerpOrigin , ent . origin ) ;
ent . origin [ 2 ] + = 48 ;
ent . reType = RT_SPRITE ;
ent . customShader = shader ;
ent . radius = 10 ;
ent . renderfx = rf ;
ent . shaderRGBA [ 0 ] = 255 ;
ent . shaderRGBA [ 1 ] = 255 ;
ent . shaderRGBA [ 2 ] = 255 ;
ent . shaderRGBA [ 3 ] = 255 ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
/*
= = = = = = = = = = = = = = =
CG_PlayerFloatSprite
Same as above but allows custom RGBA values
= = = = = = = = = = = = = = =
*/
#if 0
static void CG_PlayerFloatSpriteRGBA ( centity_t * cent , qhandle_t shader , vec4_t rgba ) {
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 ] = rgba [ 0 ] ;
ent . shaderRGBA [ 1 ] = rgba [ 1 ] ;
ent . shaderRGBA [ 2 ] = rgba [ 2 ] ;
ent . shaderRGBA [ 3 ] = rgba [ 3 ] ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
# endif
/*
= = = = = = = = = = = = = = =
CG_PlayerSprites
Float sprites over the player ' s head
= = = = = = = = = = = = = = =
*/
static void CG_PlayerSprites ( centity_t * cent ) {
// int team;
if ( cg . snap & &
CG_IsMindTricked ( cent - > currentState . trickedentindex ,
cent - > currentState . trickedentindex2 ,
cent - > currentState . trickedentindex3 ,
cent - > currentState . trickedentindex4 ,
cg . snap - > ps . clientNum ) )
{
return ; //this entity is mind-tricking the current client, so don't render it
}
if ( cent - > currentState . eFlags & EF_CONNECTION ) {
CG_PlayerFloatSprite ( cent , cgs . media . connectionShader ) ;
return ;
}
if ( cent - > vChatTime > cg . time )
{
CG_PlayerFloatSprite ( cent , cgs . media . vchatShader ) ;
}
else if ( cent - > currentState . eType ! = ET_NPC & & //don't draw talk balloons on NPCs
( cent - > currentState . eFlags & EF_TALK ) )
{
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 ) {
vec3_t end , mins = { - 15 , - 15 , 0 } , maxs = { 15 , 15 , 2 } ;
trace_t trace ;
float alpha ;
float radius = 24.0f ;
* shadowPlane = 0 ;
if ( cg_shadows . integer = = 0 ) {
return qfalse ;
}
// no shadows when cloaked
if ( cent - > currentState . powerups & ( 1 < < PW_CLOAKED ) )
{
return qfalse ;
}
if ( cent - > currentState . eFlags & EF_DEAD )
{
return qfalse ;
}
if ( CG_IsMindTricked ( cent - > currentState . trickedentindex ,
cent - > currentState . trickedentindex2 ,
cent - > currentState . trickedentindex3 ,
cent - > currentState . trickedentindex4 ,
cg . snap - > ps . clientNum ) )
{
return qfalse ; //this entity is mind-tricking the current client, so don't render it
}
if ( cg_shadows . integer = = 1 )
{ //dropshadow
if ( cent - > currentState . m_iVehicleNum & &
cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{ //riding a vehicle, no dropshadow
return qfalse ;
}
}
// send a trace down from the player to the ground
VectorCopy ( cent - > lerpOrigin , end ) ;
if ( cg_shadows . integer = = 2 )
{ //stencil
end [ 2 ] - = 4096.0f ;
trap_CM_BoxTrace ( & trace , cent - > lerpOrigin , end , mins , maxs , 0 , MASK_PLAYERSOLID ) ;
if ( trace . fraction = = 1.0 | | trace . startsolid | | trace . allsolid )
{
trace . endpos [ 2 ] = cent - > lerpOrigin [ 2 ] - 25.0f ;
}
}
else
{
end [ 2 ] - = SHADOW_DISTANCE ;
trap_CM_BoxTrace ( & trace , cent - > lerpOrigin , end , mins , maxs , 0 , MASK_PLAYERSOLID ) ;
// no shadow if too high
if ( trace . fraction = = 1.0 | | trace . startsolid | | trace . allsolid ) {
return qfalse ;
}
}
if ( cg_shadows . integer = = 2 )
{ //stencil shadows need plane to be on ground
* shadowPlane = trace . endpos [ 2 ] ;
}
else
{
* shadowPlane = trace . endpos [ 2 ] + 1 ;
}
if ( cg_shadows . integer ! = 1 ) { // no mark for stencil or projection shadows
return qtrue ;
}
// fade the shadow out with height
alpha = 1.0 - trace . fraction ;
// bk0101022 - hack / FPE - bogus planes?
//assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
// add the mark as a temporary, so it goes directly to the renderer
// without taking a spot in the cg_marks array
if ( cent - > currentState . NPC_class = = CLASS_REMOTE
| | cent - > currentState . NPC_class = = CLASS_SEEKER )
{
radius = 8.0f ;
}
CG_ImpactMark ( cgs . media . shadowMarkShader , trace . endpos , trace . plane . normal ,
cent - > pe . legs . yawAngle , alpha , alpha , alpha , 1 , qfalse , radius , 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 ) ;
}
# define REFRACT_EFFECT_DURATION 500
static void CG_ForcePushBlur ( vec3_t org , centity_t * cent )
{
if ( ! cent | | ! cg_renderToTextureFX . integer )
{
localEntity_t * ex ;
ex = CG_AllocLocalEntity ( ) ;
ex - > leType = LE_PUFF ;
ex - > refEntity . reType = RT_SPRITE ;
ex - > radius = 2.0f ;
ex - > startTime = cg . time ;
ex - > endTime = ex - > startTime + 120 ;
VectorCopy ( org , ex - > pos . trBase ) ;
ex - > pos . trTime = cg . time ;
ex - > pos . trType = TR_LINEAR ;
VectorScale ( cg . refdef . viewaxis [ 1 ] , 55 , ex - > pos . trDelta ) ;
ex - > color [ 0 ] = 24 ;
ex - > color [ 1 ] = 32 ;
ex - > color [ 2 ] = 40 ;
ex - > refEntity . customShader = trap_R_RegisterShader ( " gfx/effects/forcePush " ) ;
ex = CG_AllocLocalEntity ( ) ;
ex - > leType = LE_PUFF ;
ex - > refEntity . reType = RT_SPRITE ;
ex - > refEntity . rotation = 180.0f ;
ex - > radius = 2.0f ;
ex - > startTime = cg . time ;
ex - > endTime = ex - > startTime + 120 ;
VectorCopy ( org , ex - > pos . trBase ) ;
ex - > pos . trTime = cg . time ;
ex - > pos . trType = TR_LINEAR ;
VectorScale ( cg . refdef . viewaxis [ 1 ] , - 55 , ex - > pos . trDelta ) ;
ex - > color [ 0 ] = 24 ;
ex - > color [ 1 ] = 32 ;
ex - > color [ 2 ] = 40 ;
ex - > refEntity . customShader = trap_R_RegisterShader ( " gfx/effects/forcePush " ) ;
}
else
{ //superkewl "refraction" (well sort of) effect -rww
refEntity_t ent ;
vec3_t ang ;
float scale ;
float vLen ;
float alpha ;
int tDif ;
if ( ! cent - > bodyFadeTime )
{ //the duration for the expansion and fade
cent - > bodyFadeTime = cg . time + REFRACT_EFFECT_DURATION ;
}
//closer tDif is to 0, the closer we are to
//being "done"
tDif = ( cent - > bodyFadeTime - cg . time ) ;
if ( ( REFRACT_EFFECT_DURATION - tDif ) < 200 )
{ //stop following the hand after a little and stay in a fixed spot
//save the initial spot of the effect
VectorCopy ( org , cent - > pushEffectOrigin ) ;
}
//scale from 1.0f to 0.1f then hold at 0.1 for the rest of the duration
if ( cent - > currentState . powerups & ( 1 < < PW_PULL ) )
{
scale = ( float ) ( REFRACT_EFFECT_DURATION - tDif ) * 0.003f ;
}
else
{
scale = ( float ) ( tDif ) * 0.003f ;
}
if ( scale > 1.0f )
{
scale = 1.0f ;
}
else if ( scale < 0.2f )
{
scale = 0.2f ;
}
//start alpha at 244, fade to 10
alpha = ( float ) tDif * 0.488f ;
if ( alpha > 244.0f )
{
alpha = 244.0f ;
}
else if ( alpha < 10.0f )
{
alpha = 10.0f ;
}
memset ( & ent , 0 , sizeof ( ent ) ) ;
ent . shaderTime = ( cent - > bodyFadeTime - REFRACT_EFFECT_DURATION ) / 1000.0f ;
VectorCopy ( cent - > pushEffectOrigin , ent . origin ) ;
VectorSubtract ( ent . origin , cg . refdef . vieworg , ent . axis [ 0 ] ) ;
vLen = VectorLength ( ent . axis [ 0 ] ) ;
if ( vLen < = 0.1f )
{ // Entity is right on vieworg. quit.
return ;
}
vectoangles ( ent . axis [ 0 ] , ang ) ;
ang [ ROLL ] + = 180.0f ;
AnglesToAxis ( ang , ent . axis ) ;
//radius must be a power of 2, and is the actual captured texture size
if ( vLen < 128 )
{
ent . radius = 256 ;
}
else if ( vLen < 256 )
{
ent . radius = 128 ;
}
else if ( vLen < 512 )
{
ent . radius = 64 ;
}
else
{
ent . radius = 32 ;
}
VectorScale ( ent . axis [ 0 ] , scale , ent . axis [ 0 ] ) ;
VectorScale ( ent . axis [ 1 ] , scale , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 2 ] , scale , ent . axis [ 2 ] ) ;
ent . hModel = cgs . media . halfShieldModel ;
ent . customShader = cgs . media . refractionShader ; //cgs.media.cloakedShader;
ent . nonNormalizedAxes = qtrue ;
//make it partially transparent so it blends with the background
ent . renderfx = ( RF_DISTORTION | RF_FORCE_ENT_ALPHA ) ;
ent . shaderRGBA [ 0 ] = 255.0f ;
ent . shaderRGBA [ 1 ] = 255.0f ;
ent . shaderRGBA [ 2 ] = 255.0f ;
ent . shaderRGBA [ 3 ] = alpha ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
}
static const char * cg_pushBoneNames [ ] =
{
" cranium " ,
" lower_lumbar " ,
" rhand " ,
" lhand " ,
" ltibia " ,
" rtibia " ,
" lradius " ,
" rradius " ,
NULL
} ;
static void CG_ForcePushBodyBlur ( centity_t * cent )
{
vec3_t fxOrg ;
mdxaBone_t boltMatrix ;
int bolt ;
int i ;
if ( cent - > localAnimIndex > 1 )
{ //Sorry, the humanoid IS IN ANOTHER CASTLE.
return ;
}
if ( cg . snap & &
CG_IsMindTricked ( cent - > currentState . trickedentindex ,
cent - > currentState . trickedentindex2 ,
cent - > currentState . trickedentindex3 ,
cent - > currentState . trickedentindex4 ,
cg . snap - > ps . clientNum ) )
{
return ; //this entity is mind-tricking the current client, so don't render it
}
assert ( cent - > ghoul2 ) ;
for ( i = 0 ; cg_pushBoneNames [ i ] ; i + + )
{ //go through all the bones we want to put a blur effect on
bolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , cg_pushBoneNames [ i ] ) ;
if ( bolt = = - 1 )
{
assert ( ! " You've got an invalid bone/bolt name in cg_pushBoneNames " ) ;
continue ;
}
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , bolt , & boltMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , fxOrg ) ;
//standard effect, don't be refractive (for now)
CG_ForcePushBlur ( fxOrg , NULL ) ;
}
}
static void CG_ForceGripEffect ( vec3_t org )
{
localEntity_t * ex ;
float wv = sin ( cg . time * 0.004f ) * 0.08f + 0.1f ;
ex = CG_AllocLocalEntity ( ) ;
ex - > leType = LE_PUFF ;
ex - > refEntity . reType = RT_SPRITE ;
ex - > radius = 2.0f ;
ex - > startTime = cg . time ;
ex - > endTime = ex - > startTime + 120 ;
VectorCopy ( org , ex - > pos . trBase ) ;
ex - > pos . trTime = cg . time ;
ex - > pos . trType = TR_LINEAR ;
VectorScale ( cg . refdef . viewaxis [ 1 ] , 55 , ex - > pos . trDelta ) ;
ex - > color [ 0 ] = 200 + ( ( wv * 255 ) ) ;
if ( ex - > color [ 0 ] > 255 )
{
ex - > color [ 0 ] = 255 ;
}
ex - > color [ 1 ] = 0 ;
ex - > color [ 2 ] = 0 ;
ex - > refEntity . customShader = trap_R_RegisterShader ( " gfx/effects/forcePush " ) ;
ex = CG_AllocLocalEntity ( ) ;
ex - > leType = LE_PUFF ;
ex - > refEntity . reType = RT_SPRITE ;
ex - > refEntity . rotation = 180.0f ;
ex - > radius = 2.0f ;
ex - > startTime = cg . time ;
ex - > endTime = ex - > startTime + 120 ;
VectorCopy ( org , ex - > pos . trBase ) ;
ex - > pos . trTime = cg . time ;
ex - > pos . trType = TR_LINEAR ;
VectorScale ( cg . refdef . viewaxis [ 1 ] , - 55 , ex - > pos . trDelta ) ;
/*
ex - > color [ 0 ] = 200 + ( ( wv * 255 ) ) ;
if ( ex - > color [ 0 ] > 255 )
{
ex - > color [ 0 ] = 255 ;
}
*/
ex - > color [ 0 ] = 255 ;
ex - > color [ 1 ] = 255 ;
ex - > color [ 2 ] = 255 ;
ex - > refEntity . customShader = cgs . media . redSaberGlowShader ; //trap_R_RegisterShader( "gfx/effects/forcePush" );
}
/*
= = = = = = = = = = = = = = =
CG_AddRefEntityWithPowerups
Adds a piece with modifications or duplications for powerups
Also called by CG_Missile for quad rockets , but nobody can tell . . .
= = = = = = = = = = = = = = =
*/
void CG_AddRefEntityWithPowerups ( refEntity_t * ent , entityState_t * state , int team ) {
if ( CG_IsMindTricked ( state - > trickedentindex ,
state - > trickedentindex2 ,
state - > trickedentindex3 ,
state - > trickedentindex4 ,
cg . snap - > ps . clientNum ) )
{
return ; //this entity is mind-tricking the current client, so don't render it
}
trap_R_AddRefEntityToScene ( ent ) ;
}
# define MAX_SHIELD_TIME 2000.0
# define MIN_SHIELD_TIME 2000.0
void CG_PlayerShieldHit ( int entitynum , vec3_t dir , int amount )
{
centity_t * cent ;
int time ;
if ( entitynum < 0 | | entitynum > = MAX_ENTITIES )
{
return ;
}
cent = & cg_entities [ entitynum ] ;
if ( amount > 100 )
{
time = cg . time + MAX_SHIELD_TIME ; // 2 sec.
}
else
{
time = cg . time + 500 + amount * 15 ;
}
if ( time > cent - > damageTime )
{
cent - > damageTime = time ;
VectorScale ( dir , - 1 , dir ) ;
vectoangles ( dir , cent - > damageAngles ) ;
}
}
void CG_DrawPlayerShield ( centity_t * cent , vec3_t origin )
{
refEntity_t ent ;
int alpha ;
float scale ;
// Don't draw the shield when the player is dead.
if ( cent - > currentState . eFlags & EF_DEAD )
{
return ;
}
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( origin , ent . origin ) ;
ent . origin [ 2 ] + = 10.0 ;
AnglesToAxis ( cent - > damageAngles , ent . axis ) ;
alpha = 255.0 * ( ( cent - > damageTime - cg . time ) / MIN_SHIELD_TIME ) + random ( ) * 16 ;
if ( alpha > 255 )
alpha = 255 ;
// Make it bigger, but tighter if more solid
scale = 1.4 - ( ( float ) alpha * ( 0.4 / 255.0 ) ) ; // Range from 1.0 to 1.4
VectorScale ( ent . axis [ 0 ] , scale , ent . axis [ 0 ] ) ;
VectorScale ( ent . axis [ 1 ] , scale , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 2 ] , scale , ent . axis [ 2 ] ) ;
ent . hModel = cgs . media . halfShieldModel ;
ent . customShader = cgs . media . halfShieldShader ;
ent . shaderRGBA [ 0 ] = alpha ;
ent . shaderRGBA [ 1 ] = alpha ;
ent . shaderRGBA [ 2 ] = alpha ;
ent . shaderRGBA [ 3 ] = 255 ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
void CG_PlayerHitFX ( centity_t * cent )
{
// only do the below fx if the cent in question is...uh...me, and it's first person.
if ( cent - > currentState . clientNum ! = cg . predictedPlayerState . clientNum | | cg . renderingThirdPerson )
{
if ( cent - > damageTime > cg . time
& & cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{
CG_DrawPlayerShield ( cent , cent - > lerpOrigin ) ;
}
return ;
}
}
/*
= = = = = = = = = = = = = = = = =
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 ;
}
static void CG_RGBForSaberColor ( saber_colors_t color , vec3_t rgb )
{
switch ( color )
{
case SABER_RED :
VectorSet ( rgb , 1.0f , 0.2f , 0.2f ) ;
break ;
case SABER_ORANGE :
VectorSet ( rgb , 1.0f , 0.5f , 0.1f ) ;
break ;
case SABER_YELLOW :
VectorSet ( rgb , 1.0f , 1.0f , 0.2f ) ;
break ;
case SABER_GREEN :
VectorSet ( rgb , 0.2f , 1.0f , 0.2f ) ;
break ;
case SABER_BLUE :
VectorSet ( rgb , 0.2f , 0.4f , 1.0f ) ;
break ;
case SABER_PURPLE :
VectorSet ( rgb , 0.9f , 0.2f , 1.0f ) ;
break ;
}
}
static void CG_DoSaberLight ( saberInfo_t * saber )
{
vec3_t positions [ MAX_BLADES * 2 ] , mid = { 0 } , rgbs [ MAX_BLADES * 2 ] , rgb = { 0 } ;
float lengths [ MAX_BLADES * 2 ] = { 0 } , totallength = 0 , numpositions = 0 , dist , diameter = 0 ;
int i , j ;
//RGB combine all the colors of the sabers you're using into one averaged color!
if ( ! saber )
{
return ;
}
if ( ( saber - > saberFlags2 & SFL2_NO_DLIGHT ) )
{ //no dlight!
return ;
}
for ( i = 0 ; i < saber - > numBlades ; i + + )
{
if ( saber - > blade [ i ] . length > = 0.5f )
{
//FIXME: make RGB sabers
CG_RGBForSaberColor ( saber - > blade [ i ] . color , rgbs [ i ] ) ;
lengths [ i ] = saber - > blade [ i ] . length ;
if ( saber - > blade [ i ] . length * 2.0f > diameter )
{
diameter = saber - > blade [ i ] . length * 2.0f ;
}
totallength + = saber - > blade [ i ] . length ;
VectorMA ( saber - > blade [ i ] . muzzlePoint , saber - > blade [ i ] . length , saber - > blade [ i ] . muzzleDir , positions [ i ] ) ;
if ( ! numpositions )
{ //first blade, store middle of that as midpoint
VectorMA ( saber - > blade [ i ] . muzzlePoint , saber - > blade [ i ] . length * 0.5 , saber - > blade [ i ] . muzzleDir , mid ) ;
VectorCopy ( rgbs [ i ] , rgb ) ;
}
numpositions + + ;
}
}
if ( totallength )
{ //actually have something to do
if ( numpositions = = 1 )
{ //only 1 blade, midpoint is already set (halfway between the start and end of that blade), rgb is already set, so it diameter
}
else
{ //multiple blades, calc averages
VectorClear ( mid ) ;
VectorClear ( rgb ) ;
//now go through all the data and get the average RGB and middle position and the radius
for ( i = 0 ; i < MAX_BLADES * 2 ; i + + )
{
if ( lengths [ i ] )
{
VectorMA ( rgb , lengths [ i ] , rgbs [ i ] , rgb ) ;
VectorAdd ( mid , positions [ i ] , mid ) ;
}
}
//get middle rgb
VectorScale ( rgb , 1 / totallength , rgb ) ; //get the average, normalized RGB
//get mid position
VectorScale ( mid , 1 / numpositions , mid ) ;
//find the farthest distance between the blade tips, this will be our diameter
for ( i = 0 ; i < MAX_BLADES * 2 ; i + + )
{
if ( lengths [ i ] )
{
for ( j = 0 ; j < MAX_BLADES * 2 ; j + + )
{
if ( lengths [ j ] )
{
dist = Distance ( positions [ i ] , positions [ j ] ) ;
if ( dist > diameter )
{
diameter = dist ;
}
}
}
}
}
}
trap_R_AddLightToScene ( mid , diameter + ( random ( ) * 8.0f ) , rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] ) ;
}
}
void CG_DoSaber ( vec3_t origin , vec3_t dir , float length , float lengthMax , float radius , saber_colors_t color , int rfx , qboolean doLight )
{
vec3_t mid ;
qhandle_t blade = 0 , glow = 0 ;
refEntity_t saber ;
float radiusmult ;
float radiusRange ;
float radiusStart ;
if ( length < 0.5f )
{
// if the thing is so short, just forget even adding me.
return ;
}
// Find the midpoint of the saber for lighting purposes
VectorMA ( origin , length * 0.5f , dir , mid ) ;
switch ( color )
{
case SABER_RED :
glow = cgs . media . redSaberGlowShader ;
blade = cgs . media . redSaberCoreShader ;
break ;
case SABER_ORANGE :
glow = cgs . media . orangeSaberGlowShader ;
blade = cgs . media . orangeSaberCoreShader ;
break ;
case SABER_YELLOW :
glow = cgs . media . yellowSaberGlowShader ;
blade = cgs . media . yellowSaberCoreShader ;
break ;
case SABER_GREEN :
glow = cgs . media . greenSaberGlowShader ;
blade = cgs . media . greenSaberCoreShader ;
break ;
case SABER_BLUE :
glow = cgs . media . blueSaberGlowShader ;
blade = cgs . media . blueSaberCoreShader ;
break ;
case SABER_PURPLE :
glow = cgs . media . purpleSaberGlowShader ;
blade = cgs . media . purpleSaberCoreShader ;
break ;
default :
glow = cgs . media . blueSaberGlowShader ;
blade = cgs . media . blueSaberCoreShader ;
break ;
}
if ( doLight )
{ // always add a light because sabers cast a nice glow before they slice you in half!! or something...
vec3_t rgb = { 1 , 1 , 1 } ;
CG_RGBForSaberColor ( color , rgb ) ;
trap_R_AddLightToScene ( mid , ( length * 1.4f ) + ( random ( ) * 3.0f ) , rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] ) ;
}
memset ( & saber , 0 , sizeof ( refEntity_t ) ) ;
// Saber glow is it's own ref type because it uses a ton of sprites, otherwise it would eat up too many
// refEnts to do each glow blob individually
saber . saberLength = length ;
// Jeff, I did this because I foolishly wished to have a bright halo as the saber is unleashed.
// It's not quite what I'd hoped tho. If you have any ideas, go for it! --Pat
if ( length < lengthMax )
{
radiusmult = 1.0 + ( 2.0 / length ) ; // Note this creates a curve, and length cannot be < 0.5.
}
else
{
radiusmult = 1.0 ;
}
if ( cg_saberTrail . integer = = 2 & & cg_shadows . integer ! = 2 & & cgs . glconfig . stencilBits > = 4 )
{ //draw the blade as a post-render so it doesn't get in the cap...
rfx | = RF_FORCEPOST ;
}
radiusRange = radius * 0.075f ;
radiusStart = radius - radiusRange ;
saber . radius = ( radiusStart + crandom ( ) * radiusRange ) * radiusmult ;
//saber.radius = (2.8f + crandom() * 0.2f)*radiusmult;
VectorCopy ( origin , saber . origin ) ;
VectorCopy ( dir , saber . axis [ 0 ] ) ;
saber . reType = RT_SABER_GLOW ;
saber . customShader = glow ;
saber . shaderRGBA [ 0 ] = saber . shaderRGBA [ 1 ] = saber . shaderRGBA [ 2 ] = saber . shaderRGBA [ 3 ] = 0xff ;
saber . renderfx = rfx ;
trap_R_AddRefEntityToScene ( & saber ) ;
// Do the hot core
VectorMA ( origin , length , dir , saber . origin ) ;
VectorMA ( origin , - 1 , dir , saber . oldorigin ) ;
// CG_TestLine(saber.origin, saber.oldorigin, 50, 0x000000ff, 3);
saber . customShader = blade ;
saber . reType = RT_LINE ;
radiusStart = radius / 3.0f ;
saber . radius = ( radiusStart + crandom ( ) * radiusRange ) * radiusmult ;
// saber.radius = (1.0 + crandom() * 0.2f)*radiusmult;
saber . shaderTexCoord [ 0 ] = saber . shaderTexCoord [ 1 ] = 1.0f ;
saber . shaderRGBA [ 0 ] = saber . shaderRGBA [ 1 ] = saber . shaderRGBA [ 2 ] = saber . shaderRGBA [ 3 ] = 0xff ;
trap_R_AddRefEntityToScene ( & saber ) ;
}
//--------------------------------------------------------------
// CG_GetTagWorldPosition
//
// Can pass in NULL for the axis
//--------------------------------------------------------------
void CG_GetTagWorldPosition ( refEntity_t * model , char * tag , vec3_t pos , vec3_t axis [ 3 ] )
{
orientation_t orientation ;
int i = 0 ;
// Get the requested tag
trap_R_LerpTag ( & orientation , model - > hModel , model - > oldframe , model - > frame ,
1.0f - model - > backlerp , tag ) ;
VectorCopy ( model - > origin , pos ) ;
for ( i = 0 ; i < 3 ; i + + )
{
VectorMA ( pos , orientation . origin [ i ] , model - > axis [ i ] , pos ) ;
}
if ( axis )
{
MatrixMultiply ( orientation . axis , model - > axis , axis ) ;
}
}
# define MAX_MARK_FRAGMENTS 128
# define MAX_MARK_POINTS 384
extern markPoly_t * CG_AllocMark ( ) ;
void CG_CreateSaberMarks ( vec3_t start , vec3_t end , vec3_t normal )
{
// byte colors[4];
int i , j ;
int numFragments ;
vec3_t axis [ 3 ] , originalPoints [ 4 ] , mid ;
vec3_t markPoints [ MAX_MARK_POINTS ] , projection ;
polyVert_t * v , verts [ MAX_VERTS_ON_POLY ] ;
markPoly_t * mark ;
markFragment_t markFragments [ MAX_MARK_FRAGMENTS ] , * mf ;
float radius = 0.65f ;
if ( ! cg_addMarks . integer )
{
return ;
}
VectorSubtract ( end , start , axis [ 1 ] ) ;
VectorNormalize ( axis [ 1 ] ) ;
// create the texture axis
VectorCopy ( normal , axis [ 0 ] ) ;
CrossProduct ( axis [ 1 ] , axis [ 0 ] , axis [ 2 ] ) ;
// create the full polygon that we'll project
for ( i = 0 ; i < 3 ; i + + )
{ // stretch a bit more in the direction that we are traveling in... debateable as to whether this makes things better or worse
originalPoints [ 0 ] [ i ] = start [ i ] - radius * axis [ 1 ] [ i ] - radius * axis [ 2 ] [ i ] ;
originalPoints [ 1 ] [ i ] = end [ i ] + radius * axis [ 1 ] [ i ] - radius * axis [ 2 ] [ i ] ;
originalPoints [ 2 ] [ i ] = end [ i ] + radius * axis [ 1 ] [ i ] + radius * axis [ 2 ] [ i ] ;
originalPoints [ 3 ] [ i ] = start [ i ] - radius * axis [ 1 ] [ i ] + radius * axis [ 2 ] [ i ] ;
}
VectorScale ( normal , - 1 , projection ) ;
// get the fragments
numFragments = trap_CM_MarkFragments ( 4 , ( const float ( * ) [ 3 ] ) originalPoints ,
projection , MAX_MARK_POINTS , markPoints [ 0 ] , MAX_MARK_FRAGMENTS , markFragments ) ;
for ( i = 0 , mf = markFragments ; i < numFragments ; i + + , mf + + )
{
// 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 ;
// Set up our texture coords, this may need some work
VectorCopy ( markPoints [ mf - > firstPoint + j ] , v - > xyz ) ;
VectorAdd ( end , start , mid ) ;
VectorScale ( mid , 0.5f , mid ) ;
VectorSubtract ( v - > xyz , mid , delta ) ;
v - > st [ 0 ] = 0.5 + DotProduct ( delta , axis [ 1 ] ) * ( 0.05f + random ( ) * 0.03f ) ;
v - > st [ 1 ] = 0.5 + DotProduct ( delta , axis [ 2 ] ) * ( 0.15f + random ( ) * 0.05f ) ;
}
if ( cg_saberDynamicMarks . integer )
{
int i = 0 ;
int i_2 = 0 ;
addpolyArgStruct_t apArgs ;
vec3_t x ;
memset ( & apArgs , 0 , sizeof ( apArgs ) ) ;
while ( i < 4 )
{
while ( i_2 < 3 )
{
apArgs . p [ i ] [ i_2 ] = verts [ i ] . xyz [ i_2 ] ;
i_2 + + ;
}
i_2 = 0 ;
i + + ;
}
i = 0 ;
i_2 = 0 ;
while ( i < 4 )
{
while ( i_2 < 2 )
{
apArgs . ev [ i ] [ i_2 ] = verts [ i ] . st [ i_2 ] ;
i_2 + + ;
}
i_2 = 0 ;
i + + ;
}
//When using addpoly, having a situation like this tends to cause bad results.
//(I assume it doesn't like trying to draw a polygon over two planes and extends
//the vertex out to some odd value)
VectorSubtract ( apArgs . p [ 0 ] , apArgs . p [ 3 ] , x ) ;
if ( VectorLength ( x ) > 3.0f )
{
return ;
}
apArgs . numVerts = mf - > numPoints ;
VectorCopy ( vec3_origin , apArgs . vel ) ;
VectorCopy ( vec3_origin , apArgs . accel ) ;
apArgs . alpha1 = 1.0f ;
apArgs . alpha2 = 0.0f ;
apArgs . alphaParm = 255.0f ;
VectorSet ( apArgs . rgb1 , 0.0f , 0.0f , 0.0f ) ;
VectorSet ( apArgs . rgb2 , 0.0f , 0.0f , 0.0f ) ;
apArgs . rgbParm = 0.0f ;
apArgs . bounce = 0 ;
apArgs . motionDelay = 0 ;
apArgs . killTime = cg_saberDynamicMarkTime . integer ;
apArgs . shader = cgs . media . rivetMarkShader ;
apArgs . flags = 0x08000000 | 0x00000004 ;
trap_FX_AddPoly ( & apArgs ) ;
apArgs . shader = cgs . media . mSaberDamageGlow ;
apArgs . rgb1 [ 0 ] = 215 + random ( ) * 40.0f ;
apArgs . rgb1 [ 1 ] = 96 + random ( ) * 32.0f ;
apArgs . rgb1 [ 2 ] = apArgs . alphaParm = random ( ) * 15.0f ;
apArgs . rgb1 [ 0 ] / = 255 ;
apArgs . rgb1 [ 1 ] / = 255 ;
apArgs . rgb1 [ 2 ] / = 255 ;
VectorCopy ( apArgs . rgb1 , apArgs . rgb2 ) ;
apArgs . killTime = 100 ;
trap_FX_AddPoly ( & apArgs ) ;
}
else
{
// save it persistantly, do burn first
mark = CG_AllocMark ( ) ;
mark - > time = cg . time ;
mark - > alphaFade = qtrue ;
mark - > markShader = cgs . media . rivetMarkShader ;
mark - > poly . numVerts = mf - > numPoints ;
mark - > color [ 0 ] = mark - > color [ 1 ] = mark - > color [ 2 ] = mark - > color [ 3 ] = 255 ;
memcpy ( mark - > verts , verts , mf - > numPoints * sizeof ( verts [ 0 ] ) ) ;
// And now do a glow pass
// by moving the start time back, we can hack it to fade out way before the burn does
mark = CG_AllocMark ( ) ;
mark - > time = cg . time - 8500 ;
mark - > alphaFade = qfalse ;
mark - > markShader = cgs . media . mSaberDamageGlow ;
mark - > poly . numVerts = mf - > numPoints ;
mark - > color [ 0 ] = 215 + random ( ) * 40.0f ;
mark - > color [ 1 ] = 96 + random ( ) * 32.0f ;
mark - > color [ 2 ] = mark - > color [ 3 ] = random ( ) * 15.0f ;
memcpy ( mark - > verts , verts , mf - > numPoints * sizeof ( verts [ 0 ] ) ) ;
}
}
}
qboolean CG_G2TraceCollide ( trace_t * tr , vec3_t const mins , vec3_t const maxs , const vec3_t lastValidStart , const vec3_t lastValidEnd )
{
G2Trace_t G2Trace ;
centity_t * g2Hit ;
vec3_t angles ;
int tN = 0 ;
float fRadius = 0.0f ;
if ( mins & & maxs & &
( mins [ 0 ] | | maxs [ 0 ] ) )
{
fRadius = ( maxs [ 0 ] - mins [ 0 ] ) / 2.0f ;
}
memset ( & G2Trace , 0 , sizeof ( G2Trace ) ) ;
while ( tN < MAX_G2_COLLISIONS )
{
G2Trace [ tN ] . mEntityNum = - 1 ;
tN + + ;
}
g2Hit = & cg_entities [ tr - > entityNum ] ;
if ( g2Hit & & g2Hit - > ghoul2 )
{
angles [ ROLL ] = angles [ PITCH ] = 0 ;
angles [ YAW ] = g2Hit - > lerpAngles [ YAW ] ;
if ( cg_optvehtrace . integer & &
g2Hit - > currentState . eType = = ET_NPC & &
g2Hit - > currentState . NPC_class = = CLASS_VEHICLE & &
g2Hit - > m_pVehicle )
{
trap_G2API_CollisionDetectCache ( G2Trace , g2Hit - > ghoul2 , angles , g2Hit - > lerpOrigin , cg . time , g2Hit - > currentState . number , lastValidStart , lastValidEnd , g2Hit - > modelScale , 0 , cg_g2TraceLod . integer , fRadius ) ;
}
else
{
trap_G2API_CollisionDetect ( G2Trace , g2Hit - > ghoul2 , angles , g2Hit - > lerpOrigin , cg . time , g2Hit - > currentState . number , lastValidStart , lastValidEnd , g2Hit - > modelScale , 0 , cg_g2TraceLod . integer , fRadius ) ;
}
if ( G2Trace [ 0 ] . mEntityNum ! = g2Hit - > currentState . number )
{
tr - > fraction = 1.0f ;
tr - > entityNum = ENTITYNUM_NONE ;
tr - > startsolid = 0 ;
tr - > allsolid = 0 ;
return qfalse ;
}
else
{ //Yay!
VectorCopy ( G2Trace [ 0 ] . mCollisionPosition , tr - > endpos ) ;
VectorCopy ( G2Trace [ 0 ] . mCollisionNormal , tr - > plane . normal ) ;
return qtrue ;
}
}
return qfalse ;
}
void CG_G2SaberEffects ( vec3_t start , vec3_t end , centity_t * owner )
{
trace_t trace ;
vec3_t startTr ;
vec3_t endTr ;
qboolean backWards = qfalse ;
qboolean doneWithTraces = qfalse ;
while ( ! doneWithTraces )
{
if ( ! backWards )
{
VectorCopy ( start , startTr ) ;
VectorCopy ( end , endTr ) ;
}
else
{
VectorCopy ( end , startTr ) ;
VectorCopy ( start , endTr ) ;
}
CG_Trace ( & trace , startTr , NULL , NULL , endTr , owner - > currentState . number , MASK_PLAYERSOLID ) ;
if ( trace . entityNum < MAX_CLIENTS )
{ //hit a client..
CG_G2TraceCollide ( & trace , NULL , NULL , startTr , endTr ) ;
if ( trace . entityNum ! = ENTITYNUM_NONE )
{ //it succeeded with the ghoul2 trace
trap_FX_PlayEffectID ( cgs . effects . mSaberBloodSparks , trace . endpos , trace . plane . normal , - 1 , - 1 ) ;
trap_S_StartSound ( trace . endpos , trace . entityNum , CHAN_AUTO , trap_S_RegisterSound ( va ( " sound/weapons/saber/saberhit%i.wav " , Q_irand ( 1 , 3 ) ) ) ) ;
}
}
if ( ! backWards )
{
backWards = qtrue ;
}
else
{
doneWithTraces = qtrue ;
}
}
}
# define CG_MAX_SABER_COMP_TIME 400 //last registered saber entity hit must match within this many ms for the client effect to take place.
void CG_AddGhoul2Mark ( int shader , float size , vec3_t start , vec3_t end , int entnum ,
vec3_t entposition , float entangle , void * ghoul2 , vec3_t scale , int lifeTime )
{
SSkinGoreData goreSkin ;
assert ( ghoul2 ) ;
memset ( & goreSkin , 0 , sizeof ( goreSkin ) ) ;
if ( trap_G2API_GetNumGoreMarks ( ghoul2 , 0 ) > = cg_ghoul2Marks . integer )
{ //you've got too many marks already
return ;
}
goreSkin . growDuration = - 1 ; // default expandy time
goreSkin . goreScaleStartFraction = 1.0 ; // default start scale
goreSkin . frontFaces = qtrue ;
goreSkin . backFaces = qtrue ;
goreSkin . lifeTime = lifeTime ; //last randomly 10-20 seconds
/*
if ( lifeTime )
{
goreSkin . fadeOutTime = lifeTime * 0.1 ; //default fade duration is relative to lifetime.
}
goreSkin . fadeRGB = qtrue ; //fade on RGB instead of alpha (this depends on the shader really, modify if needed)
*/
//rwwFIXMEFIXME: fade has sorting issues with other non-fading decals, disabled until fixed
goreSkin . baseModelOnly = qfalse ;
goreSkin . currentTime = cg . time ;
goreSkin . entNum = entnum ;
goreSkin . SSize = size ;
goreSkin . TSize = size ;
goreSkin . theta = flrand ( 0.0f , 6.28f ) ;
goreSkin . shader = shader ;
if ( ! scale [ 0 ] & & ! scale [ 1 ] & & ! scale [ 2 ] )
{
VectorSet ( goreSkin . scale , 1.0f , 1.0f , 1.0f ) ;
}
else
{
VectorCopy ( goreSkin . scale , scale ) ;
}
VectorCopy ( start , goreSkin . hitLocation ) ;
VectorSubtract ( end , start , goreSkin . rayDirection ) ;
if ( VectorNormalize ( goreSkin . rayDirection ) < .1f )
{
return ;
}
VectorCopy ( entposition , goreSkin . position ) ;
goreSkin . angles [ YAW ] = entangle ;
trap_G2API_AddSkinGore ( ghoul2 , & goreSkin ) ;
}
void CG_SaberCompWork ( vec3_t start , vec3_t end , centity_t * owner , int saberNum , int bladeNum )
{
trace_t trace ;
vec3_t startTr ;
vec3_t endTr ;
qboolean backWards = qfalse ;
qboolean doneWithTraces = qfalse ;
qboolean doEffect = qfalse ;
clientInfo_t * client = NULL ;
if ( ( cg . time - owner - > serverSaberHitTime ) > CG_MAX_SABER_COMP_TIME )
{
return ;
}
if ( cg . time = = owner - > serverSaberHitTime )
{ //don't want to do it the same frame as the server hit, to avoid burst effect concentrations every x ms.
return ;
}
while ( ! doneWithTraces )
{
if ( ! backWards )
{
VectorCopy ( start , startTr ) ;
VectorCopy ( end , endTr ) ;
}
else
{
VectorCopy ( end , startTr ) ;
VectorCopy ( start , endTr ) ;
}
CG_Trace ( & trace , startTr , NULL , NULL , endTr , owner - > currentState . number , MASK_PLAYERSOLID ) ;
if ( trace . entityNum = = owner - > serverSaberHitIndex )
{ //this is the guy the server says we last hit, so continue.
if ( cg_entities [ trace . entityNum ] . ghoul2 )
{ //If it has a g2 instance, do the proper ghoul2 checks
CG_G2TraceCollide ( & trace , NULL , NULL , startTr , endTr ) ;
if ( trace . entityNum ! = ENTITYNUM_NONE )
{ //it succeeded with the ghoul2 trace
doEffect = qtrue ;
if ( cg_ghoul2Marks . integer )
{
vec3_t ePos ;
centity_t * trEnt = & cg_entities [ trace . entityNum ] ;
if ( trEnt - > ghoul2 )
{
if ( trEnt - > currentState . eType ! = ET_NPC | |
trEnt - > currentState . NPC_class ! = CLASS_VEHICLE | |
! trEnt - > m_pVehicle | |
trEnt - > m_pVehicle - > m_pVehicleInfo - > type ! = VH_FIGHTER )
{ //don't do on fighters cause they have crazy full axial angles
int weaponMarkShader = 0 , markShader = cgs . media . bdecal_saberglow ;
VectorSubtract ( endTr , trace . endpos , ePos ) ;
VectorNormalize ( ePos ) ;
VectorMA ( trace . endpos , 4.0f , ePos , ePos ) ;
if ( owner - > currentState . eType = = ET_NPC )
{
client = owner - > npcClient ;
}
else
{
client = & cgs . clientinfo [ owner - > currentState . clientNum ] ;
}
if ( client
& & client - > infoValid )
{
if ( WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum ) )
{
if ( client - > saber [ saberNum ] . g2MarksShader2 )
{ //we have a shader to use instead of the standard mark shader
markShader = client - > saber [ saberNum ] . g2MarksShader2 ;
}
if ( client - > saber [ saberNum ] . g2WeaponMarkShader2 )
{ //we have a shader to use as a splashback onto the weapon model
weaponMarkShader = client - > saber [ saberNum ] . g2WeaponMarkShader2 ;
}
}
else
{
if ( client - > saber [ saberNum ] . g2MarksShader )
{ //we have a shader to use instead of the standard mark shader
markShader = client - > saber [ saberNum ] . g2MarksShader ;
}
if ( client - > saber [ saberNum ] . g2WeaponMarkShader )
{ //we have a shader to use as a splashback onto the weapon model
weaponMarkShader = client - > saber [ saberNum ] . g2WeaponMarkShader ;
}
}
}
CG_AddGhoul2Mark ( markShader , flrand ( 3.0f , 4.0f ) ,
trace . endpos , ePos , trace . entityNum , trEnt - > lerpOrigin , trEnt - > lerpAngles [ YAW ] ,
trEnt - > ghoul2 , trEnt - > modelScale , Q_irand ( 5000 , 10000 ) ) ;
if ( weaponMarkShader )
{
vec3_t splashBackDir ;
VectorScale ( ePos , - 1 , splashBackDir ) ;
CG_AddGhoul2Mark ( weaponMarkShader , flrand ( 0.5f , 2.0f ) ,
trace . endpos , splashBackDir , owner - > currentState . clientNum , owner - > lerpOrigin , owner - > lerpAngles [ YAW ] ,
owner - > ghoul2 , owner - > modelScale , Q_irand ( 5000 , 10000 ) ) ;
}
}
}
}
}
}
else
{ //otherwise, we're all set.
doEffect = qtrue ;
}
if ( doEffect )
{
int hitPersonFxID = cgs . effects . mSaberBloodSparks ;
int hitOtherFxID = cgs . effects . mSaberCut ;
if ( owner - > currentState . eType = = ET_NPC )
{
client = owner - > npcClient ;
}
else
{
client = & cgs . clientinfo [ owner - > currentState . clientNum ] ;
}
if ( client & & client - > infoValid )
{
if ( WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum ) )
{ //use second blade style values
if ( client - > saber [ saberNum ] . hitPersonEffect2 )
{
hitPersonFxID = client - > saber [ saberNum ] . hitPersonEffect2 ;
}
if ( client - > saber [ saberNum ] . hitOtherEffect2 )
{ //custom hit other effect
hitOtherFxID = client - > saber [ saberNum ] . hitOtherEffect2 ;
}
}
else
{ //use first blade style values
if ( client - > saber [ saberNum ] . hitPersonEffect )
{
hitPersonFxID = client - > saber [ saberNum ] . hitPersonEffect ;
}
if ( client - > saber [ saberNum ] . hitOtherEffect )
{ //custom hit other effect
hitOtherFxID = client - > saber [ saberNum ] . hitOtherEffect ;
}
}
}
if ( ! trace . plane . normal [ 0 ] & & ! trace . plane . normal [ 1 ] & & ! trace . plane . normal [ 2 ] )
{ //who cares, just shoot it somewhere.
trace . plane . normal [ 1 ] = 1 ;
}
if ( owner - > serverSaberFleshImpact )
{ //do standard player/live ent hit sparks
trap_FX_PlayEffectID ( hitPersonFxID , trace . endpos , trace . plane . normal , - 1 , - 1 ) ;
//trap_S_StartSound(trace.endpos, trace.entityNum, CHAN_AUTO, trap_S_RegisterSound(va("sound/weapons/saber/saberhit%i.wav", Q_irand(1, 3))));
}
else
{ //do the cut effect
trap_FX_PlayEffectID ( hitOtherFxID , trace . endpos , trace . plane . normal , - 1 , - 1 ) ;
}
doEffect = qfalse ;
}
}
/*
if ( ! backWards )
{
backWards = qtrue ;
}
else
{
doneWithTraces = qtrue ;
}
*/
doneWithTraces = qtrue ; //disabling backwards tr for now, sometimes it just makes too many effects.
}
}
# define SABER_TRAIL_TIME 40.0f
# define FX_USE_ALPHA 0x08000000
# include "../namespace_begin.h"
qboolean BG_SuperBreakWinAnim ( int anim ) ;
# include "../namespace_end.h"
void CG_AddSaberBlade ( centity_t * cent , centity_t * scent , refEntity_t * saber , int renderfx , int modelIndex , int saberNum , int bladeNum , vec3_t origin , vec3_t angles , qboolean fromSaber , qboolean dontDraw )
{
vec3_t org_ , end , v ,
axis_ [ 3 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; // shut the compiler up
trace_t trace ;
int i = 0 ;
int trailDur ;
float saberLen ;
float diff ;
clientInfo_t * client ;
centity_t * saberEnt ;
saberTrail_t * saberTrail ;
mdxaBone_t boltMatrix ;
vec3_t futureAngles ;
effectTrailArgStruct_t fx ;
int scolor = 0 ;
int useModelIndex = 0 ;
if ( cent - > currentState . eType = = ET_NPC )
{
client = cent - > npcClient ;
assert ( client ) ;
}
else
{
client = & cgs . clientinfo [ cent - > currentState . number ] ;
}
saberEnt = & cg_entities [ cent - > currentState . saberEntityNum ] ;
saberLen = client - > saber [ saberNum ] . blade [ bladeNum ] . length ;
if ( saberLen < = 0 & & ! dontDraw )
{ //don't bother then.
return ;
}
futureAngles [ YAW ] = angles [ YAW ] ;
futureAngles [ PITCH ] = angles [ PITCH ] ;
futureAngles [ ROLL ] = angles [ ROLL ] ;
if ( fromSaber )
{
useModelIndex = 0 ;
}
else
{
useModelIndex = saberNum + 1 ;
}
//Assume bladeNum is equal to the bolt index because bolts should be added in order of the blades.
//if there is an effect on this blade, play it
if ( ! WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum )
& & client - > saber [ saberNum ] . bladeEffect )
{
trap_FX_PlayBoltedEffectID ( client - > saber [ saberNum ] . bladeEffect , scent - > lerpOrigin ,
scent - > ghoul2 , bladeNum , scent - > currentState . number , useModelIndex , - 1 , qfalse ) ;
}
else if ( WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum )
& & client - > saber [ saberNum ] . bladeEffect2 )
{
trap_FX_PlayBoltedEffectID ( client - > saber [ saberNum ] . bladeEffect2 , scent - > lerpOrigin ,
scent - > ghoul2 , bladeNum , scent - > currentState . number , useModelIndex , - 1 , qfalse ) ;
}
//get the boltMatrix
trap_G2API_GetBoltMatrix ( scent - > ghoul2 , useModelIndex , bladeNum , & boltMatrix , futureAngles , origin , cg . time , cgs . gameModels , scent - > modelScale ) ;
// work the matrix axis stuff into the original axis and origins used.
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , org_ ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_Y , axis_ [ 0 ] ) ;
if ( ! fromSaber & & saberEnt & & ! cent - > currentState . saberInFlight )
{
VectorCopy ( org_ , saberEnt - > currentState . pos . trBase ) ;
VectorCopy ( axis_ [ 0 ] , saberEnt - > currentState . apos . trBase ) ;
}
VectorMA ( org_ , saberLen , axis_ [ 0 ] , end ) ;
VectorAdd ( end , axis_ [ 0 ] , end ) ;
if ( cent - > currentState . eType = = ET_NPC )
{
scolor = client - > saber [ saberNum ] . blade [ bladeNum ] . color ;
}
else
{
if ( saberNum = = 0 )
{
scolor = client - > icolor1 ;
}
else
{
scolor = client - > icolor2 ;
}
}
if ( cgs . gametype > = GT_TEAM & &
cgs . gametype ! = GT_SIEGE & &
! cgs . jediVmerc & &
cent - > currentState . eType ! = ET_NPC )
{
if ( client - > team = = TEAM_RED )
{
scolor = SABER_RED ;
}
else if ( client - > team = = TEAM_BLUE )
{
scolor = SABER_BLUE ;
}
}
if ( ! cg_saberContact . integer )
{ //if we don't have saber contact enabled, just add the blade and don't care what it's touching
goto CheckTrail ;
}
if ( ! dontDraw )
{
if ( cg_saberModelTraceEffect . integer )
{
CG_G2SaberEffects ( org_ , end , cent ) ;
}
else if ( cg_saberClientVisualCompensation . integer )
{
CG_Trace ( & trace , org_ , NULL , NULL , end , ENTITYNUM_NONE , MASK_SOLID ) ;
if ( trace . fraction ! = 1 )
{ //nudge the endpos a very small amount from the beginning to the end, so the comp trace hits at the end.
//I'm only bothering with this because I want to do a backwards trace too in the comp trace, so if the
//blade is sticking through a player or something the standard trace doesn't it, it will make sparks
//on each side.
vec3_t seDif ;
VectorSubtract ( trace . endpos , org_ , seDif ) ;
VectorNormalize ( seDif ) ;
trace . endpos [ 0 ] + = seDif [ 0 ] * 0.1f ;
trace . endpos [ 1 ] + = seDif [ 1 ] * 0.1f ;
trace . endpos [ 2 ] + = seDif [ 2 ] * 0.1f ;
}
if ( client - > saber [ saberNum ] . blade [ bladeNum ] . storageTime < cg . time )
{ //debounce it in case our framerate is absurdly high. Using storageTime since it's not used for anything else in the client.
CG_SaberCompWork ( org_ , trace . endpos , cent , saberNum , bladeNum ) ;
client - > saber [ saberNum ] . blade [ bladeNum ] . storageTime = cg . time + 5 ;
}
}
for ( i = 0 ; i < 1 ; i + + ) //was 2 because it would go through architecture and leave saber trails on either side of the brush - but still looks bad if we hit a corner, blade is still 8 longer than hit
{
if ( i )
{ //tracing from end to base
CG_Trace ( & trace , end , NULL , NULL , org_ , ENTITYNUM_NONE , MASK_SOLID ) ;
}
else
{ //tracing from base to end
CG_Trace ( & trace , org_ , NULL , NULL , end , ENTITYNUM_NONE , MASK_SOLID ) ;
}
if ( trace . fraction < 1.0f )
{
vec3_t trDir ;
VectorCopy ( trace . plane . normal , trDir ) ;
if ( ! trDir [ 0 ] & & ! trDir [ 1 ] & & ! trDir [ 2 ] )
{
trDir [ 1 ] = 1 ;
}
if ( ( client - > saber [ saberNum ] . saberFlags2 & SFL2_NO_WALL_MARKS ) )
{ //don't actually draw the marks/impact effects
}
else
{
if ( ! ( trace . surfaceFlags & SURF_NOIMPACT ) ) // never spark on sky
{
trap_FX_PlayEffectID ( cgs . effects . mSparks , trace . endpos , trDir , - 1 , - 1 ) ;
}
}
//Stop saber? (it wouldn't look right if it was stuck through a thin wall and unable to hurt players on the other side)
VectorSubtract ( org_ , trace . endpos , v ) ;
saberLen = VectorLength ( v ) ;
VectorCopy ( trace . endpos , end ) ;
if ( ( client - > saber [ saberNum ] . saberFlags2 & SFL2_NO_WALL_MARKS ) )
{ //don't actually draw the marks
}
else
{ //draw marks if we hit a wall
// All I need is a bool to mark whether I have a previous point to work with.
//....come up with something better..
if ( client - > saber [ saberNum ] . blade [ bladeNum ] . trail . haveOldPos [ i ] )
{
if ( trace . entityNum = = ENTITYNUM_WORLD | | cg_entities [ trace . entityNum ] . currentState . eType = = ET_TERRAIN | | ( cg_entities [ trace . entityNum ] . currentState . eFlags & EF_PERMANENT ) )
{ //only put marks on architecture
// Let's do some cool burn/glowing mark bits!!!
CG_CreateSaberMarks ( client - > saber [ saberNum ] . blade [ bladeNum ] . trail . oldPos [ i ] , trace . endpos , trace . plane . normal ) ;
//make a sound
if ( cg . time - client - > saber [ saberNum ] . blade [ bladeNum ] . hitWallDebounceTime > = 100 )
{ //ugh, need to have a real sound debouncer... or do this game-side
client - > saber [ saberNum ] . blade [ bladeNum ] . hitWallDebounceTime = cg . time ;
trap_S_StartSound ( trace . endpos , - 1 , CHAN_WEAPON , trap_S_RegisterSound ( va ( " sound/weapons/saber/saberhitwall%i " , Q_irand ( 1 , 3 ) ) ) ) ;
}
}
}
else
{
// if we impact next frame, we'll mark a slash mark
client - > saber [ saberNum ] . blade [ bladeNum ] . trail . haveOldPos [ i ] = qtrue ;
// CG_ImpactMark( cgs.media.rivetMarkShader, client->saber[saberNum].blade[bladeNum].trail.oldPos[i], client->saber[saberNum].blade[bladeNum].trail.oldNormal[i],
// 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse );
}
}
// stash point so we can connect-the-dots later
VectorCopy ( trace . endpos , client - > saber [ saberNum ] . blade [ bladeNum ] . trail . oldPos [ i ] ) ;
VectorCopy ( trace . plane . normal , client - > saber [ saberNum ] . blade [ bladeNum ] . trail . oldNormal [ i ] ) ;
}
else
{
if ( client - > saber [ saberNum ] . blade [ bladeNum ] . trail . haveOldPos [ i ] )
{
// Hmmm, no impact this frame, but we have an old point
// Let's put the mark there, we should use an endcap mark to close the line, but we
// can probably just get away with a round mark
// CG_ImpactMark( cgs.media.rivetMarkShader, client->saber[saberNum].blade[bladeNum].trail.oldPos[i], client->saber[saberNum].blade[bladeNum].trail.oldNormal[i],
// 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse );
}
// we aren't impacting, so turn off our mark tracking mechanism
client - > saber [ saberNum ] . blade [ bladeNum ] . trail . haveOldPos [ i ] = qfalse ;
}
}
}
CheckTrail :
if ( ! cg_saberTrail . integer )
{ //don't do the trail in this case
goto JustDoIt ;
}
if ( ( ! WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum ) & & client - > saber [ saberNum ] . trailStyle > 1 )
| | ( WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum ) & & client - > saber [ saberNum ] . trailStyle2 > 1 ) )
{ //don't actually draw the trail at all
goto JustDoIt ;
}
//FIXME: if trailStyle is 1, use the motion blur instead
saberTrail = & client - > saber [ saberNum ] . blade [ bladeNum ] . trail ;
saberTrail - > duration = saberMoveData [ cent - > currentState . saberMove ] . trailLength ;
trailDur = ( saberTrail - > duration / 5.0f ) ;
if ( ! trailDur )
{ //hmm.. ok, default
if ( BG_SuperBreakWinAnim ( cent - > currentState . torsoAnim ) )
{
trailDur = 150 ;
}
else
{
trailDur = SABER_TRAIL_TIME ;
}
}
// if we happen to be timescaled or running in a high framerate situation, we don't want to flood
// the system with very small trail slices...but perhaps doing it by distance would yield better results?
if ( cg . time > saberTrail - > lastTime + 2 | | cg_saberTrail . integer = = 2 ) // 2ms
{
if ( ! dontDraw )
{
if ( ( BG_SuperBreakWinAnim ( cent - > currentState . torsoAnim ) | | saberMoveData [ cent - > currentState . saberMove ] . trailLength > 0 | | ( ( cent - > currentState . powerups & ( 1 < < PW_SPEED ) & & cg_speedTrail . integer ) ) | | ( cent - > currentState . saberInFlight & & saberNum = = 0 ) ) & & cg . time < saberTrail - > lastTime + 2000 ) // if we have a stale segment, don't draw until we have a fresh one
{
#if 0
if ( cg_saberTrail . integer = = 2 & & cg_shadows . integer ! = 2 & & cgs . glconfig . stencilBits > = 4 )
{
polyVert_t verts [ 4 ] ;
VectorCopy ( org_ , verts [ 0 ] . xyz ) ;
VectorMA ( end , 3.0f , axis_ [ 0 ] , verts [ 1 ] . xyz ) ;
VectorCopy ( saberTrail - > tip , verts [ 2 ] . xyz ) ;
VectorCopy ( saberTrail - > base , verts [ 3 ] . xyz ) ;
//tc doesn't even matter since we're just gonna stencil an outline, but whatever.
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 ;
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 ;
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 ;
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 ;
//don't capture postrender objects (now we'll postrender the saber so it doesn't get in the capture)
trap_R_SetRefractProp ( 1.0f , 0.0f , qtrue , qtrue ) ;
//shader 2 is always the crazy refractive shader.
trap_R_AddPolyToScene ( 2 , 4 , verts ) ;
}
else
# endif
{
vec3_t rgb1 = { 255.0f , 255.0f , 255.0f } ;
switch ( scolor )
{
case SABER_RED :
VectorSet ( rgb1 , 255.0f , 0.0f , 0.0f ) ;
break ;
case SABER_ORANGE :
VectorSet ( rgb1 , 255.0f , 64.0f , 0.0f ) ;
break ;
case SABER_YELLOW :
VectorSet ( rgb1 , 255.0f , 255.0f , 0.0f ) ;
break ;
case SABER_GREEN :
VectorSet ( rgb1 , 0.0f , 255.0f , 0.0f ) ;
break ;
case SABER_BLUE :
VectorSet ( rgb1 , 0.0f , 64.0f , 255.0f ) ;
break ;
case SABER_PURPLE :
VectorSet ( rgb1 , 220.0f , 0.0f , 255.0f ) ;
break ;
default :
VectorSet ( rgb1 , 0.0f , 64.0f , 255.0f ) ;
break ;
}
//Here we will use the happy process of filling a struct in with arguments and passing it to a trap function
//so that we can take the struct and fill in an actual CTrail type using the data within it once we get it
//into the effects area
// Go from new muzzle to new end...then to old end...back down to old muzzle...finally
// connect back to the new muzzle...this is our trail quad
VectorCopy ( org_ , fx . mVerts [ 0 ] . origin ) ;
VectorMA ( end , 3.0f , axis_ [ 0 ] , fx . mVerts [ 1 ] . origin ) ;
VectorCopy ( saberTrail - > tip , fx . mVerts [ 2 ] . origin ) ;
VectorCopy ( saberTrail - > base , fx . mVerts [ 3 ] . origin ) ;
diff = cg . time - saberTrail - > lastTime ;
// I'm not sure that clipping this is really the best idea
//This prevents the trail from showing at all in low framerate situations.
//if ( diff <= SABER_TRAIL_TIME * 2 )
if ( diff < = 10000 )
{ //don't draw it if the last time is way out of date
float oldAlpha = 1.0f - ( diff / trailDur ) ;
if ( cg_saberTrail . integer = = 2 & & cg_shadows . integer ! = 2 & & cgs . glconfig . stencilBits > = 4 )
{ //does other stuff below
}
else
{
if ( ( ! WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum ) & & client - > saber [ saberNum ] . trailStyle = = 1 )
| | ( WP_SaberBladeUseSecondBladeStyle ( & client - > saber [ saberNum ] , bladeNum ) & & client - > saber [ saberNum ] . trailStyle2 = = 1 ) )
{ //motion trail
fx . mShader = cgs . media . swordTrailShader ;
VectorSet ( rgb1 , 32.0f , 32.0f , 32.0f ) ; // make the sith sword trail pretty faint
trailDur * = 2.0f ; // stay around twice as long?
}
else
{
fx . mShader = cgs . media . saberBlurShader ;
}
fx . mKillTime = trailDur ;
fx . mSetFlags = FX_USE_ALPHA ;
}
// New muzzle
VectorCopy ( rgb1 , fx . mVerts [ 0 ] . rgb ) ;
fx . mVerts [ 0 ] . alpha = 255.0f ;
fx . mVerts [ 0 ] . ST [ 0 ] = 0.0f ;
fx . mVerts [ 0 ] . ST [ 1 ] = 1.0f ;
fx . mVerts [ 0 ] . destST [ 0 ] = 1.0f ;
fx . mVerts [ 0 ] . destST [ 1 ] = 1.0f ;
// new tip
VectorCopy ( rgb1 , fx . mVerts [ 1 ] . rgb ) ;
fx . mVerts [ 1 ] . alpha = 255.0f ;
fx . mVerts [ 1 ] . ST [ 0 ] = 0.0f ;
fx . mVerts [ 1 ] . ST [ 1 ] = 0.0f ;
fx . mVerts [ 1 ] . destST [ 0 ] = 1.0f ;
fx . mVerts [ 1 ] . destST [ 1 ] = 0.0f ;
// old tip
VectorCopy ( rgb1 , fx . mVerts [ 2 ] . rgb ) ;
fx . mVerts [ 2 ] . alpha = 255.0f ;
fx . mVerts [ 2 ] . ST [ 0 ] = 1.0f - oldAlpha ; // NOTE: this just happens to contain the value I want
fx . mVerts [ 2 ] . ST [ 1 ] = 0.0f ;
fx . mVerts [ 2 ] . destST [ 0 ] = 1.0f + fx . mVerts [ 2 ] . ST [ 0 ] ;
fx . mVerts [ 2 ] . destST [ 1 ] = 0.0f ;
// old muzzle
VectorCopy ( rgb1 , fx . mVerts [ 3 ] . rgb ) ;
fx . mVerts [ 3 ] . alpha = 255.0f ;
fx . mVerts [ 3 ] . ST [ 0 ] = 1.0f - oldAlpha ; // NOTE: this just happens to contain the value I want
fx . mVerts [ 3 ] . ST [ 1 ] = 1.0f ;
fx . mVerts [ 3 ] . destST [ 0 ] = 1.0f + fx . mVerts [ 2 ] . ST [ 0 ] ;
fx . mVerts [ 3 ] . destST [ 1 ] = 1.0f ;
if ( cg_saberTrail . integer = = 2 & & cg_shadows . integer ! = 2 & & cgs . glconfig . stencilBits > = 4 )
{
trap_R_SetRefractProp ( 1.0f , 0.0f , qtrue , qtrue ) ; //don't need to do this every frame.. but..
if ( BG_SaberInAttack ( cent - > currentState . saberMove )
| | BG_SuperBreakWinAnim ( cent - > currentState . torsoAnim ) )
{ //in attack, strong trail
fx . mKillTime = 300 ;
}
else
{ //faded trail
fx . mKillTime = 40 ;
}
fx . mShader = 2 ; //2 is always refractive shader
fx . mSetFlags = FX_USE_ALPHA ;
}
/*
else
{
fx . mShader = cgs . media . saberBlurShader ;
fx . mKillTime = trailDur ;
fx . mSetFlags = FX_USE_ALPHA ;
}
*/
trap_FX_AddPrimitive ( & fx ) ;
}
}
}
}
// we must always do this, even if we aren't active..otherwise we won't know where to pick up from
VectorCopy ( org_ , saberTrail - > base ) ;
VectorMA ( end , 3.0f , axis_ [ 0 ] , saberTrail - > tip ) ;
saberTrail - > lastTime = cg . time ;
}
JustDoIt :
if ( dontDraw )
{
return ;
}
if ( ( client - > saber [ saberNum ] . saberFlags2 & SFL2_NO_BLADE ) )
{ //don't actually draw the blade at all
if ( client - > saber [ saberNum ] . numBlades < 3
& & ! ( client - > saber [ saberNum ] . saberFlags2 & SFL2_NO_DLIGHT ) )
{ //hmm, but still add the dlight
CG_DoSaberLight ( & client - > saber [ saberNum ] ) ;
}
return ;
}
// Pass in the renderfx flags attached to the saber weapon model...this is done so that saber glows
// will get rendered properly in a mirror...not sure if this is necessary??
//CG_DoSaber( org_, axis_[0], saberLen, client->saber[saberNum].blade[bladeNum].lengthMax, client->saber[saberNum].blade[bladeNum].radius,
// scolor, renderfx, (qboolean)(saberNum==0&&bladeNum==0) );
CG_DoSaber ( org_ , axis_ [ 0 ] , saberLen , client - > saber [ saberNum ] . blade [ bladeNum ] . lengthMax , client - > saber [ saberNum ] . blade [ bladeNum ] . radius ,
scolor , renderfx , ( qboolean ) ( client - > saber [ saberNum ] . numBlades < 3 & & ! ( client - > saber [ saberNum ] . saberFlags2 & SFL2_NO_DLIGHT ) ) ) ;
}
int CG_IsMindTricked ( int trickIndex1 , int trickIndex2 , int trickIndex3 , int trickIndex4 , int client )
{
int checkIn ;
int sub = 0 ;
if ( cg_entities [ client ] . currentState . forcePowersActive & ( 1 < < FP_SEE ) )
{
return 0 ;
}
if ( client > 47 )
{
checkIn = trickIndex4 ;
sub = 48 ;
}
else if ( client > 31 )
{
checkIn = trickIndex3 ;
sub = 32 ;
}
else if ( client > 15 )
{
checkIn = trickIndex2 ;
sub = 16 ;
}
else
{
checkIn = trickIndex1 ;
}
if ( checkIn & ( 1 < < ( client - sub ) ) )
{
return 1 ;
}
return 0 ;
}
# define SPEED_TRAIL_DISTANCE 6
void CG_DrawPlayerSphere ( centity_t * cent , vec3_t origin , float scale , int shader )
{
refEntity_t ent ;
vec3_t ang ;
float vLen ;
vec3_t viewDir ;
// Don't draw the shield when the player is dead.
if ( cent - > currentState . eFlags & EF_DEAD )
{
return ;
}
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( origin , ent . origin ) ;
ent . origin [ 2 ] + = 9.0 ;
VectorSubtract ( ent . origin , cg . refdef . vieworg , ent . axis [ 0 ] ) ;
vLen = VectorLength ( ent . axis [ 0 ] ) ;
if ( vLen < = 0.1f )
{ // Entity is right on vieworg. quit.
return ;
}
VectorCopy ( ent . axis [ 0 ] , viewDir ) ;
VectorInverse ( viewDir ) ;
VectorNormalize ( viewDir ) ;
vectoangles ( ent . axis [ 0 ] , ang ) ;
ang [ ROLL ] + = 180.0f ;
ang [ PITCH ] + = 180.0f ;
AnglesToAxis ( ang , ent . axis ) ;
VectorScale ( ent . axis [ 0 ] , scale , ent . axis [ 0 ] ) ;
VectorScale ( ent . axis [ 1 ] , scale , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 2 ] , scale , ent . axis [ 2 ] ) ;
ent . nonNormalizedAxes = qtrue ;
ent . hModel = cgs . media . halfShieldModel ;
ent . customShader = shader ;
trap_R_AddRefEntityToScene ( & ent ) ;
if ( ! cg . renderingThirdPerson & & cent - > currentState . number = = cg . predictedPlayerState . clientNum )
{ //don't do the rest then
return ;
}
if ( ! cg_renderToTextureFX . integer )
{
return ;
}
ang [ PITCH ] - = 180.0f ;
AnglesToAxis ( ang , ent . axis ) ;
VectorScale ( ent . axis [ 0 ] , scale * 0.5f , ent . axis [ 0 ] ) ;
VectorScale ( ent . axis [ 1 ] , scale * 0.5f , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 2 ] , scale * 0.5f , ent . axis [ 2 ] ) ;
ent . renderfx = ( RF_DISTORTION | RF_FORCE_ENT_ALPHA ) ;
if ( shader = = cgs . media . invulnerabilityShader )
{ //ok, ok, this is a little hacky. sorry!
ent . shaderRGBA [ 0 ] = 0 ;
ent . shaderRGBA [ 1 ] = 255 ;
ent . shaderRGBA [ 2 ] = 0 ;
ent . shaderRGBA [ 3 ] = 100 ;
}
else if ( shader = = cgs . media . ysalimariShader )
{
ent . shaderRGBA [ 0 ] = 255 ;
ent . shaderRGBA [ 1 ] = 255 ;
ent . shaderRGBA [ 2 ] = 0 ;
ent . shaderRGBA [ 3 ] = 100 ;
}
else if ( shader = = cgs . media . endarkenmentShader )
{
ent . shaderRGBA [ 0 ] = 100 ;
ent . shaderRGBA [ 1 ] = 0 ;
ent . shaderRGBA [ 2 ] = 0 ;
ent . shaderRGBA [ 3 ] = 20 ;
}
else if ( shader = = cgs . media . enlightenmentShader )
{
ent . shaderRGBA [ 0 ] = 255 ;
ent . shaderRGBA [ 1 ] = 255 ;
ent . shaderRGBA [ 2 ] = 255 ;
ent . shaderRGBA [ 3 ] = 20 ;
}
else
{ //ysal red/blue, boon
ent . shaderRGBA [ 0 ] = 255.0f ;
ent . shaderRGBA [ 1 ] = 255.0f ;
ent . shaderRGBA [ 2 ] = 255.0f ;
ent . shaderRGBA [ 3 ] = 20 ;
}
ent . radius = 256 ;
VectorMA ( ent . origin , 40.0f , viewDir , ent . origin ) ;
ent . customShader = trap_R_RegisterShader ( " effects/refract_2 " ) ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
void CG_AddLightningBeam ( vec3_t start , vec3_t end )
{
vec3_t dir , chaos ,
c1 , c2 ,
v1 , v2 ;
float len ,
s1 , s2 , s3 ;
addbezierArgStruct_t b ;
VectorCopy ( start , b . start ) ;
VectorCopy ( end , b . end ) ;
VectorSubtract ( b . end , b . start , dir ) ;
len = VectorNormalize ( dir ) ;
// Get the base control points, we'll work from there
VectorMA ( b . start , 0.3333f * len , dir , c1 ) ;
VectorMA ( b . start , 0.6666f * len , dir , c2 ) ;
// get some chaos values that really aren't very chaotic :)
s1 = sin ( cg . time * 0.005f ) * 2 + crandom ( ) * 0.2f ;
s2 = sin ( cg . time * 0.001f ) ;
s3 = sin ( cg . time * 0.011f ) ;
VectorSet ( chaos , len * 0.01f * s1 ,
len * 0.02f * s2 ,
len * 0.04f * ( s1 + s2 + s3 ) ) ;
VectorAdd ( c1 , chaos , c1 ) ;
VectorScale ( chaos , 4.0f , v1 ) ;
VectorSet ( chaos , - len * 0.02f * s3 ,
len * 0.01f * ( s1 * s2 ) ,
- len * 0.02f * ( s1 + s2 * s3 ) ) ;
VectorAdd ( c2 , chaos , c2 ) ;
VectorScale ( chaos , 2.0f , v2 ) ;
VectorSet ( chaos , 1.0f , 1.0f , 1.0f ) ;
VectorCopy ( c1 , b . control1 ) ;
VectorCopy ( vec3_origin , b . control1Vel ) ;
VectorCopy ( c2 , b . control2 ) ;
VectorCopy ( vec3_origin , b . control2Vel ) ;
b . size1 = 6.0f ;
b . size2 = 6.0f ;
b . sizeParm = 0.0f ;
b . alpha1 = 0.0f ;
b . alpha2 = 0.2f ;
b . alphaParm = 0.5f ;
/*
VectorCopy ( WHITE , b . sRGB ) ;
VectorCopy ( WHITE , b . eRGB ) ;
*/
b . sRGB [ 0 ] = 255 ;
b . sRGB [ 1 ] = 255 ;
b . sRGB [ 2 ] = 255 ;
VectorCopy ( b . sRGB , b . eRGB ) ;
b . rgbParm = 0.0f ;
b . killTime = 50 ;
b . shader = trap_R_RegisterShader ( " gfx/misc/electric2 " ) ;
b . flags = 0x00000001 ; //FX_ALPHA_LINEAR
trap_FX_AddBezier ( & b ) ;
}
void CG_AddRandomLightning ( vec3_t start , vec3_t end )
{
vec3_t inOrg , outOrg ;
VectorCopy ( start , inOrg ) ;
VectorCopy ( end , outOrg ) ;
if ( rand ( ) & 1 )
{
outOrg [ 0 ] + = Q_irand ( 0 , 24 ) ;
inOrg [ 0 ] + = Q_irand ( 0 , 8 ) ;
}
else
{
outOrg [ 0 ] - = Q_irand ( 0 , 24 ) ;
inOrg [ 0 ] - = Q_irand ( 0 , 8 ) ;
}
if ( rand ( ) & 1 )
{
outOrg [ 1 ] + = Q_irand ( 0 , 24 ) ;
inOrg [ 1 ] + = Q_irand ( 0 , 8 ) ;
}
else
{
outOrg [ 1 ] - = Q_irand ( 0 , 24 ) ;
inOrg [ 1 ] - = Q_irand ( 0 , 8 ) ;
}
if ( rand ( ) & 1 )
{
outOrg [ 2 ] + = Q_irand ( 0 , 50 ) ;
inOrg [ 2 ] + = Q_irand ( 0 , 40 ) ;
}
else
{
outOrg [ 2 ] - = Q_irand ( 0 , 64 ) ;
inOrg [ 2 ] - = Q_irand ( 0 , 40 ) ;
}
CG_AddLightningBeam ( inOrg , outOrg ) ;
}
extern char * forceHolocronModels [ ] ;
qboolean CG_ThereIsAMaster ( void )
{
int i = 0 ;
centity_t * cent ;
while ( i < MAX_CLIENTS )
{
cent = & cg_entities [ i ] ;
if ( cent & & cent - > currentState . isJediMaster )
{
return qtrue ;
}
i + + ;
}
return qfalse ;
}
#if 0
void CG_DrawNoForceSphere ( centity_t * cent , vec3_t origin , float scale , int shader )
{
refEntity_t ent ;
// Don't draw the shield when the player is dead.
if ( cent - > currentState . eFlags & EF_DEAD )
{
return ;
}
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( origin , ent . origin ) ;
ent . origin [ 2 ] + = 9.0 ;
VectorSubtract ( cg . refdef . vieworg , ent . origin , ent . axis [ 0 ] ) ;
if ( VectorNormalize ( ent . axis [ 0 ] ) < = 0.1f )
{ // Entity is right on vieworg. quit.
return ;
}
VectorCopy ( cg . refdef . viewaxis [ 2 ] , ent . axis [ 2 ] ) ;
CrossProduct ( ent . axis [ 0 ] , ent . axis [ 2 ] , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 0 ] , scale , ent . axis [ 0 ] ) ;
VectorScale ( ent . axis [ 1 ] , scale , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 2 ] , - scale , ent . axis [ 2 ] ) ;
ent . shaderRGBA [ 3 ] = ( cent - > currentState . genericenemyindex - cg . time ) / 8 ;
ent . renderfx | = RF_RGB_TINT ;
if ( ent . shaderRGBA [ 3 ] > 200 )
{
ent . shaderRGBA [ 3 ] = 200 ;
}
if ( ent . shaderRGBA [ 3 ] < 1 )
{
ent . shaderRGBA [ 3 ] = 1 ;
}
ent . shaderRGBA [ 2 ] = 0 ;
ent . shaderRGBA [ 0 ] = ent . shaderRGBA [ 1 ] = ent . shaderRGBA [ 3 ] ;
ent . hModel = cgs . media . halfShieldModel ;
ent . customShader = shader ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
# endif
//Checks to see if the model string has a * appended with a custom skin name after.
//If so, it terminates the model string correctly, parses the skin name out, and returns
//the handle of the registered skin.
int CG_HandleAppendedSkin ( char * modelName )
{
char skinName [ MAX_QPATH ] ;
char * p ;
qhandle_t skinID = 0 ;
int i = 0 ;
//see if it has a skin name
p = Q_strrchr ( modelName , ' * ' ) ;
if ( p )
{ //found a *, we should have a model name before it and a skin name after it.
* p = 0 ; //terminate the modelName string at this point, then go ahead and parse to the next 0 for the skin.
p + + ;
while ( p & & * p )
{
skinName [ i ] = * p ;
i + + ;
p + + ;
}
skinName [ i ] = 0 ;
if ( skinName [ 0 ] )
{ //got it, register the skin under the model path.
char baseFolder [ MAX_QPATH ] ;
strcpy ( baseFolder , modelName ) ;
p = Q_strrchr ( baseFolder , ' / ' ) ; //go back to the first /, should be the path point
if ( p )
{ //got it.. terminate at the slash and register.
char * useSkinName ;
* p = 0 ;
if ( strchr ( skinName , ' | ' ) )
{ //three part skin
useSkinName = va ( " %s/|%s " , baseFolder , skinName ) ;
}
else
{
useSkinName = va ( " %s/model_%s.skin " , baseFolder , skinName ) ;
}
skinID = trap_R_RegisterSkin ( useSkinName ) ;
}
}
}
return skinID ;
}
//Create a temporary ghoul2 instance and get the gla name so we can try loading animation data and sounds.
# include "../namespace_begin.h"
void BG_GetVehicleModelName ( char * modelname ) ;
void BG_GetVehicleSkinName ( char * skinname ) ;
# include "../namespace_end.h"
void CG_CacheG2AnimInfo ( char * modelName )
{
void * g2 = NULL ;
char * slash ;
char useModel [ MAX_QPATH ] ;
char useSkin [ MAX_QPATH ] ;
int animIndex ;
strcpy ( useModel , modelName ) ;
strcpy ( useSkin , modelName ) ;
if ( modelName [ 0 ] = = ' $ ' )
{ //it's a vehicle name actually, let's precache the whole vehicle
BG_GetVehicleModelName ( useModel ) ;
BG_GetVehicleSkinName ( useSkin ) ;
if ( useSkin [ 0 ] )
{ //use a custom skin
trap_R_RegisterSkin ( va ( " models/players/%s/model_%s.skin " , useModel , useSkin ) ) ;
}
else
{
trap_R_RegisterSkin ( va ( " models/players/%s/model_default.skin " , useModel ) ) ;
}
strcpy ( useModel , va ( " models/players/%s/model.glm " , useModel ) ) ;
}
trap_G2API_InitGhoul2Model ( & g2 , useModel , 0 , 0 , 0 , 0 , 0 ) ;
if ( g2 )
{
char GLAName [ MAX_QPATH ] ;
char originalModelName [ MAX_QPATH ] ;
animIndex = - 1 ;
GLAName [ 0 ] = 0 ;
trap_G2API_GetGLAName ( g2 , 0 , GLAName ) ;
strcpy ( originalModelName , useModel ) ;
slash = Q_strrchr ( GLAName , ' / ' ) ;
if ( slash )
{
strcpy ( slash , " /animation.cfg " ) ;
animIndex = BG_ParseAnimationFile ( GLAName , NULL , qfalse ) ;
}
if ( animIndex ! = - 1 )
{
slash = Q_strrchr ( originalModelName , ' / ' ) ;
if ( slash )
{
slash + + ;
* slash = 0 ;
}
BG_ParseAnimationEvtFile ( originalModelName , animIndex , bgNumAnimEvents ) ;
}
//Now free the temp instance
trap_G2API_CleanGhoul2Models ( & g2 ) ;
}
}
static void CG_RegisterVehicleAssets ( Vehicle_t * pVeh )
{
/*
if ( pVeh - > m_pVehicleInfo - > exhaustFX )
{
pVeh - > m_pVehicleInfo - > iExhaustFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > exhaustFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > trailFX )
{
pVeh - > m_pVehicleInfo - > iTrailFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > trailFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > impactFX )
{
pVeh - > m_pVehicleInfo - > iImpactFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > impactFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > explodeFX )
{
pVeh - > m_pVehicleInfo - > iExplodeFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > explodeFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > wakeFX )
{
pVeh - > m_pVehicleInfo - > iWakeFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > wakeFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > dmgFX )
{
pVeh - > m_pVehicleInfo - > iDmgFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > dmgFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > wpn1FX )
{
pVeh - > m_pVehicleInfo - > iWpn1FX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > wpn1FX ) ;
}
if ( pVeh - > m_pVehicleInfo - > wpn2FX )
{
pVeh - > m_pVehicleInfo - > iWpn2FX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > wpn2FX ) ;
}
if ( pVeh - > m_pVehicleInfo - > wpn1FireFX )
{
pVeh - > m_pVehicleInfo - > iWpn1FireFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > wpn1FireFX ) ;
}
if ( pVeh - > m_pVehicleInfo - > wpn2FireFX )
{
pVeh - > m_pVehicleInfo - > iWpn2FireFX = trap_FX_RegisterEffect ( pVeh - > m_pVehicleInfo - > wpn2FireFX ) ;
}
*/
}
extern void CG_HandleNPCSounds ( centity_t * cent ) ;
# include "../namespace_begin.h"
extern void G_CreateAnimalNPC ( Vehicle_t * * pVeh , const char * strAnimalType ) ;
extern void G_CreateSpeederNPC ( Vehicle_t * * pVeh , const char * strType ) ;
extern void G_CreateWalkerNPC ( Vehicle_t * * pVeh , const char * strAnimalType ) ;
extern void G_CreateFighterNPC ( Vehicle_t * * pVeh , const char * strType ) ;
# include "../namespace_end.h"
extern playerState_t * cgSendPS [ MAX_GENTITIES ] ;
void CG_G2AnimEntModelLoad ( centity_t * cent )
{
const char * cModelName = CG_ConfigString ( CS_MODELS + cent - > currentState . modelindex ) ;
if ( ! cent - > npcClient )
{ //have not init'd client yet
return ;
}
if ( cModelName & & cModelName [ 0 ] )
{
char modelName [ MAX_QPATH ] ;
int skinID ;
char * slash ;
strcpy ( modelName , cModelName ) ;
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE & & modelName [ 0 ] = = ' $ ' )
{ //vehicles pass their veh names over as model names, then we get the model name from the veh type
//create a vehicle object clientside for this type
char * vehType = & modelName [ 1 ] ;
int iVehIndex = BG_VehicleGetIndex ( vehType ) ;
switch ( g_vehicleInfo [ iVehIndex ] . type )
{
case VH_ANIMAL :
// Create the animal (making sure all it's data is initialized).
G_CreateAnimalNPC ( & cent - > m_pVehicle , vehType ) ;
break ;
case VH_SPEEDER :
// Create the speeder (making sure all it's data is initialized).
G_CreateSpeederNPC ( & cent - > m_pVehicle , vehType ) ;
break ;
case VH_FIGHTER :
// Create the fighter (making sure all it's data is initialized).
G_CreateFighterNPC ( & cent - > m_pVehicle , vehType ) ;
break ;
case VH_WALKER :
// Create the walker (making sure all it's data is initialized).
G_CreateWalkerNPC ( & cent - > m_pVehicle , vehType ) ;
break ;
default :
assert ( ! " vehicle with an unknown type - couldn't create vehicle_t " ) ;
break ;
}
//set up my happy prediction hack
cent - > m_pVehicle - > m_vOrientation = & cgSendPS [ cent - > currentState . number ] - > vehOrientation [ 0 ] ;
cent - > m_pVehicle - > m_pParentEntity = ( bgEntity_t * ) cent ;
//attach the handles for fx cgame-side
CG_RegisterVehicleAssets ( cent - > m_pVehicle ) ;
BG_GetVehicleModelName ( modelName ) ;
if ( cent - > m_pVehicle - > m_pVehicleInfo - > skin & &
cent - > m_pVehicle - > m_pVehicleInfo - > skin [ 0 ] )
{ //use a custom skin
skinID = trap_R_RegisterSkin ( va ( " models/players/%s/model_%s.skin " , modelName , cent - > m_pVehicle - > m_pVehicleInfo - > skin ) ) ;
}
else
{
skinID = trap_R_RegisterSkin ( va ( " models/players/%s/model_default.skin " , modelName ) ) ;
}
strcpy ( modelName , va ( " models/players/%s/model.glm " , modelName ) ) ;
//this sound is *only* used for vehicles now
cgs . media . noAmmoSound = trap_S_RegisterSound ( " sound/weapons/noammo.wav " ) ;
}
else
{
skinID = CG_HandleAppendedSkin ( modelName ) ; //get the skin if there is one.
}
if ( cent - > ghoul2 )
{ //clean it first!
trap_G2API_CleanGhoul2Models ( & cent - > ghoul2 ) ;
}
trap_G2API_InitGhoul2Model ( & cent - > ghoul2 , modelName , 0 , skinID , 0 , 0 , 0 ) ;
if ( cent - > ghoul2 )
{
char GLAName [ MAX_QPATH ] ;
char originalModelName [ MAX_QPATH ] ;
char * saber ;
int j = 0 ;
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE & &
cent - > m_pVehicle )
{ //do special vehicle stuff
char strTemp [ 128 ] ;
int i ;
// Setup the default first bolt
i = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " model_root " ) ;
// Setup the droid unit.
cent - > m_pVehicle - > m_iDroidUnitTag = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *droidunit " ) ;
// Setup the Exhausts.
for ( i = 0 ; i < MAX_VEHICLE_EXHAUSTS ; i + + )
{
Com_sprintf ( strTemp , 128 , " *exhaust%i " , i + 1 ) ;
cent - > m_pVehicle - > m_iExhaustTag [ i ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , strTemp ) ;
}
// Setup the Muzzles.
for ( i = 0 ; i < MAX_VEHICLE_MUZZLES ; i + + )
{
Com_sprintf ( strTemp , 128 , " *muzzle%i " , i + 1 ) ;
cent - > m_pVehicle - > m_iMuzzleTag [ i ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , strTemp ) ;
if ( cent - > m_pVehicle - > m_iMuzzleTag [ i ] = = - 1 )
{ //ergh, try *flash?
Com_sprintf ( strTemp , 128 , " *flash%i " , i + 1 ) ;
cent - > m_pVehicle - > m_iMuzzleTag [ i ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , strTemp ) ;
}
}
// Setup the Turrets.
for ( i = 0 ; i < MAX_VEHICLE_TURRETS ; i + + )
{
if ( cent - > m_pVehicle - > m_pVehicleInfo - > turret [ i ] . gunnerViewTag )
{
cent - > m_pVehicle - > m_iGunnerViewTag [ i ] = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , cent - > m_pVehicle - > m_pVehicleInfo - > turret [ i ] . gunnerViewTag ) ;
}
else
{
cent - > m_pVehicle - > m_iGunnerViewTag [ i ] = - 1 ;
}
}
}
if ( cent - > currentState . npcSaber1 )
{
saber = ( char * ) CG_ConfigString ( CS_MODELS + cent - > currentState . npcSaber1 ) ;
assert ( ! saber | | ! saber [ 0 ] | | saber [ 0 ] = = ' @ ' ) ;
//valid saber names should always start with '@' for NPCs
if ( saber & & saber [ 0 ] )
{
saber + + ; //skip over the @
WP_SetSaber ( cent - > currentState . number , cent - > npcClient - > saber , 0 , saber ) ;
}
}
if ( cent - > currentState . npcSaber2 )
{
saber = ( char * ) CG_ConfigString ( CS_MODELS + cent - > currentState . npcSaber2 ) ;
assert ( ! saber | | ! saber [ 0 ] | | saber [ 0 ] = = ' @ ' ) ;
//valid saber names should always start with '@' for NPCs
if ( saber & & saber [ 0 ] )
{
saber + + ; //skip over the @
WP_SetSaber ( cent - > currentState . number , cent - > npcClient - > saber , 1 , saber ) ;
}
}
// If this is a not vehicle, give it saber stuff...
if ( cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{
while ( j < MAX_SABERS )
{
if ( cent - > npcClient - > saber [ j ] . model [ 0 ] )
{
if ( cent - > npcClient - > ghoul2Weapons [ j ] )
{ //free the old instance(s)
trap_G2API_CleanGhoul2Models ( & cent - > npcClient - > ghoul2Weapons [ j ] ) ;
cent - > npcClient - > ghoul2Weapons [ j ] = 0 ;
}
CG_InitG2SaberData ( j , cent - > npcClient ) ;
}
j + + ;
}
}
trap_G2API_SetSkin ( cent - > ghoul2 , 0 , skinID , skinID ) ;
cent - > localAnimIndex = - 1 ;
GLAName [ 0 ] = 0 ;
trap_G2API_GetGLAName ( cent - > ghoul2 , 0 , GLAName ) ;
strcpy ( originalModelName , modelName ) ;
if ( GLAName [ 0 ] & &
! strstr ( GLAName , " players/_humanoid/ " ) /*&&
! strstr ( GLAName , " players/rockettrooper/ " ) */ )
{ //it doesn't use humanoid anims.
slash = Q_strrchr ( GLAName , ' / ' ) ;
if ( slash )
{
strcpy ( slash , " /animation.cfg " ) ;
cent - > localAnimIndex = BG_ParseAnimationFile ( GLAName , NULL , qfalse ) ;
}
}
else
{ //humanoid index.
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_hand " ) ;
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_hand " ) ;
//rhand must always be first bolt. lhand always second. Whichever you want the
//jetpack bolted to must always be third.
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *chestg " ) ;
//claw bolts
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_hand_cap_r_arm " ) ;
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_hand_cap_l_arm " ) ;
if ( strstr ( GLAName , " players/rockettrooper/ " ) )
{
cent - > localAnimIndex = 1 ;
}
else
{
cent - > localAnimIndex = 0 ;
}
if ( trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *head_top " ) = = - 1 )
{
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " ceyebrow " ) ;
}
trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " Motion " ) ;
}
// If this is a not vehicle...
if ( cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{
if ( trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " lower_lumbar " ) = = - 1 )
{ //check now to see if we have this bone for setting anims and such
cent - > noLumbar = qtrue ;
}
if ( trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " face " ) = = - 1 )
{ //check now to see if we have this bone for setting anims and such
cent - > noFace = qtrue ;
}
}
else
{
cent - > noLumbar = qtrue ;
cent - > noFace = qtrue ;
}
if ( cent - > localAnimIndex ! = - 1 )
{
slash = Q_strrchr ( originalModelName , ' / ' ) ;
if ( slash )
{
slash + + ;
* slash = 0 ;
}
cent - > eventAnimIndex = BG_ParseAnimationEvtFile ( originalModelName , cent - > localAnimIndex , bgNumAnimEvents ) ;
}
}
}
trap_S_ShutUp ( qtrue ) ;
CG_HandleNPCSounds ( cent ) ; //handle sound loading here as well.
trap_S_ShutUp ( qfalse ) ;
}
//for now this is just gonna create a big explosion on the area of the surface,
//because I am lazy.
static void CG_CreateSurfaceDebris ( centity_t * cent , int surfNum , int fxID , qboolean throwPart )
{
int lostPartFX = 0 ;
int b = - 1 ;
vec3_t v , d ;
mdxaBone_t boltMatrix ;
const char * surfName = NULL ;
if ( surfNum > 0 )
{
surfName = bgToggleableSurfaces [ surfNum ] ;
}
if ( ! cent - > ghoul2 )
{ //oh no
return ;
}
//let's add the surface as a bolt so we can get the base point of it
if ( bgToggleableSurfaceDebris [ surfNum ] = = 3 )
{ //right wing flame
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_wingdamage " ) ;
if ( throwPart
& & cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo )
{
lostPartFX = cent - > m_pVehicle - > m_pVehicleInfo - > iRWingFX ;
}
}
else if ( bgToggleableSurfaceDebris [ surfNum ] = = 4 )
{ //left wing flame
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_wingdamage " ) ;
if ( throwPart
& & cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo )
{
lostPartFX = cent - > m_pVehicle - > m_pVehicleInfo - > iLWingFX ;
}
}
else if ( bgToggleableSurfaceDebris [ surfNum ] = = 5 )
{ //right wing flame 2
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_wingdamage " ) ;
if ( throwPart
& & cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo )
{
lostPartFX = cent - > m_pVehicle - > m_pVehicleInfo - > iRWingFX ;
}
}
else if ( bgToggleableSurfaceDebris [ surfNum ] = = 6 )
{ //left wing flame 2
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_wingdamage " ) ;
if ( throwPart
& & cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo )
{
lostPartFX = cent - > m_pVehicle - > m_pVehicleInfo - > iLWingFX ;
}
}
else if ( bgToggleableSurfaceDebris [ surfNum ] = = 7 )
{ //nose flame
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *nosedamage " ) ;
if ( cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo )
{
lostPartFX = cent - > m_pVehicle - > m_pVehicleInfo - > iNoseFX ;
}
}
else if ( surfName )
{
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , surfName ) ;
}
if ( b = = - 1 | | surfNum = = - 1 )
{ //couldn't find this surface apparently, so play on origin?
VectorCopy ( cent - > lerpOrigin , v ) ;
AngleVectors ( cent - > lerpAngles , d , NULL , NULL ) ;
VectorNormalize ( d ) ;
}
else
{
//now let's get the position and direction of this surface and make a big explosion
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , b , & boltMatrix , cent - > lerpAngles , cent - > lerpOrigin , cg . time ,
cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , v ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , POSITIVE_Z , d ) ;
}
trap_FX_PlayEffectID ( fxID , v , d , - 1 , - 1 ) ;
if ( throwPart & & lostPartFX )
{ //throw off a ship part, too
vec3_t fxFwd ;
AngleVectors ( cent - > lerpAngles , fxFwd , NULL , NULL ) ;
trap_FX_PlayEffectID ( lostPartFX , v , fxFwd , - 1 , - 1 ) ;
}
}
//for now this is just gonna create a big explosion on the area of the surface,
//because I am lazy.
static void CG_CreateSurfaceSmoke ( centity_t * cent , int shipSurf , int fxID )
{
int b = - 1 ;
vec3_t v , d ;
mdxaBone_t boltMatrix ;
const char * surfName = NULL ;
if ( ! cent - > ghoul2 )
{ //oh no
return ;
}
//let's add the surface as a bolt so we can get the base point of it
if ( shipSurf = = SHIPSURF_FRONT )
{ //front flame/smoke
surfName = " *nosedamage " ;
}
else if ( shipSurf = = SHIPSURF_BACK )
{ //back flame/smoke
surfName = " *exhaust1 " ; //FIXME: random? Some point in-between?
}
else if ( shipSurf = = SHIPSURF_RIGHT )
{ //right wing flame/smoke
surfName = " *r_wingdamage " ;
}
else if ( shipSurf = = SHIPSURF_LEFT )
{ //left wing flame/smoke
surfName = " *l_wingdamage " ;
}
else
{ //unknown surf!
return ;
}
b = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , surfName ) ;
if ( b = = - 1 )
{ //couldn't find this surface apparently
return ;
}
//now let's get the position and direction of this surface and make a big explosion
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , b , & boltMatrix , cent - > lerpAngles , cent - > lerpOrigin , cg . time ,
cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , v ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , POSITIVE_Z , d ) ;
trap_FX_PlayEffectID ( fxID , v , d , - 1 , - 1 ) ;
}
# define SMOOTH_G2ANIM_LERPANGLES
qboolean CG_VehicleShouldDrawShields ( centity_t * vehCent )
{
if ( vehCent - > damageTime > cg . time //ship shields currently taking damage
& & vehCent - > currentState . NPC_class = = CLASS_VEHICLE
& & vehCent - > m_pVehicle
& & vehCent - > m_pVehicle - > m_pVehicleInfo )
{
return qtrue ;
}
return qfalse ;
}
/*
extern vmCvar_t cg_showVehBounds ;
extern void BG_VehicleAdjustBBoxForOrientation ( Vehicle_t * veh , vec3_t origin , vec3_t mins , vec3_t maxs ,
int clientNum , int tracemask ,
void ( * localTrace ) ( trace_t * results , const vec3_t start , const vec3_t mins , const vec3_t maxs , const vec3_t end , int passEntityNum , int contentMask ) ) ; // bg_pmove.c
*/
qboolean CG_VehicleAttachDroidUnit ( centity_t * droidCent , refEntity_t * legs )
{
if ( droidCent
& & droidCent - > currentState . owner
& & droidCent - > currentState . clientNum > = MAX_CLIENTS )
{ //the only NPCs that can ride a vehicle are droids...???
centity_t * vehCent = & cg_entities [ droidCent - > currentState . owner ] ;
if ( vehCent
& & vehCent - > m_pVehicle
& & vehCent - > ghoul2
& & vehCent - > m_pVehicle - > m_iDroidUnitTag ! = - 1 )
{
mdxaBone_t boltMatrix ;
vec3_t fwd , rt , tempAng ;
trap_G2API_GetBoltMatrix ( vehCent - > ghoul2 , 0 , vehCent - > m_pVehicle - > m_iDroidUnitTag , & boltMatrix , vehCent - > lerpAngles , vehCent - > lerpOrigin , cg . time ,
cgs . gameModels , vehCent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , droidCent - > lerpOrigin ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , POSITIVE_X , fwd ) ; //WTF???
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_Y , rt ) ; //WTF???
vectoangles ( fwd , droidCent - > lerpAngles ) ;
vectoangles ( rt , tempAng ) ;
droidCent - > lerpAngles [ ROLL ] = tempAng [ PITCH ] ;
return qtrue ;
}
}
return qfalse ;
}
void CG_G2Animated ( centity_t * cent )
{
# ifdef SMOOTH_G2ANIM_LERPANGLES
float angSmoothFactor = 0.7f ;
# endif
if ( ! cent - > ghoul2 )
{ //Initialize this g2 anim ent, then return (will start rendering next frame)
CG_G2AnimEntModelLoad ( cent ) ;
cent - > npcLocalSurfOff = 0 ;
cent - > npcLocalSurfOn = 0 ;
return ;
}
if ( cent - > npcLocalSurfOff ! = cent - > currentState . surfacesOff | |
cent - > npcLocalSurfOn ! = cent - > currentState . surfacesOn )
{ //looks like it's time for an update.
int i = 0 ;
while ( i < BG_NUM_TOGGLEABLE_SURFACES & & bgToggleableSurfaces [ i ] )
{
if ( ! ( cent - > npcLocalSurfOff & ( 1 < < i ) ) & &
( cent - > currentState . surfacesOff & ( 1 < < i ) ) )
{ //it wasn't off before but it's off now, so reflect this change in the g2 instance.
if ( bgToggleableSurfaceDebris [ i ] > 0 )
{ //make some local debris of this thing?
//FIXME: throw off the proper model effect, too
CG_CreateSurfaceDebris ( cent , i , cgs . effects . mShipDestDestroyed , qtrue ) ;
}
trap_G2API_SetSurfaceOnOff ( cent - > ghoul2 , bgToggleableSurfaces [ i ] , TURN_OFF ) ;
}
if ( ! ( cent - > npcLocalSurfOn & ( 1 < < i ) ) & &
( cent - > currentState . surfacesOn & ( 1 < < i ) ) )
{ //same as above, but on instead of off.
trap_G2API_SetSurfaceOnOff ( cent - > ghoul2 , bgToggleableSurfaces [ i ] , TURN_ON ) ;
}
i + + ;
}
cent - > npcLocalSurfOff = cent - > currentState . surfacesOff ;
cent - > npcLocalSurfOn = cent - > currentState . surfacesOn ;
}
/*
if ( cent - > currentState . weapon & &
! trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > ghoul2 ) , 1 ) & &
! ( cent - > currentState . eFlags & EF_DEAD ) )
{ //if the server says we have a weapon and we haven't copied one onto ourselves yet, then do so.
trap_G2API_CopySpecificGhoul2Model ( g2WeaponInstances [ cent - > currentState . weapon ] , 0 , cent - > ghoul2 , 1 ) ;
if ( cent - > currentState . weapon = = WP_SABER )
{
trap_S_StartSound ( cent - > lerpOrigin , cent - > currentState . number , CHAN_AUTO , trap_S_RegisterSound ( " sound/weapons/saber/saberon.wav " ) ) ;
}
}
*/
if ( cent - > torsoBolt & & ! ( cent - > currentState . eFlags & EF_DEAD ) )
{ //he's alive and has a limb missing still, reattach it and reset the weapon
CG_ReattachLimb ( cent ) ;
}
if ( ( ( cent - > currentState . eFlags & EF_DEAD ) | | ( cent - > currentState . eFlags & EF_RAG ) ) & & ! cent - > localAnimIndex )
{
vec3_t forcedAngles ;
VectorClear ( forcedAngles ) ;
forcedAngles [ YAW ] = cent - > lerpAngles [ YAW ] ;
CG_RagDoll ( cent , forcedAngles ) ;
}
# ifdef SMOOTH_G2ANIM_LERPANGLES
if ( ( cent - > lerpAngles [ YAW ] > 0 & & cent - > smoothYaw < 0 ) | |
( cent - > lerpAngles [ YAW ] < 0 & & cent - > smoothYaw > 0 ) )
{ //keep it from snapping around on the threshold
cent - > smoothYaw = - cent - > smoothYaw ;
}
cent - > lerpAngles [ YAW ] = cent - > smoothYaw + ( cent - > lerpAngles [ YAW ] - cent - > smoothYaw ) * angSmoothFactor ;
cent - > smoothYaw = cent - > lerpAngles [ YAW ] ;
# endif
//now just render as a player
CG_Player ( cent ) ;
/*
if ( cg_showVehBounds . integer )
{ //show vehicle bboxes
if ( cent - > currentState . clientNum > = MAX_CLIENTS
& & cent - > currentState . NPC_class = = CLASS_VEHICLE
& & cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo
& & cent - > currentState . clientNum ! = cg . predictedVehicleState . clientNum )
{ //not the predicted vehicle
vec3_t NPCDEBUG_RED = { 1.0 , 0.0 , 0.0 } ;
vec3_t absmin , absmax ;
vec3_t bmins , bmaxs ;
float * old = cent - > m_pVehicle - > m_vOrientation ;
cent - > m_pVehicle - > m_vOrientation = & cent - > lerpAngles [ 0 ] ;
BG_VehicleAdjustBBoxForOrientation ( cent - > m_pVehicle , cent - > lerpOrigin , bmins , bmaxs ,
cent - > currentState . number , MASK_PLAYERSOLID , NULL ) ;
cent - > m_pVehicle - > m_vOrientation = old ;
VectorAdd ( cent - > lerpOrigin , bmins , absmin ) ;
VectorAdd ( cent - > lerpOrigin , bmaxs , absmax ) ;
CG_Cube ( absmin , absmax , NPCDEBUG_RED , 0.25 ) ;
}
}
*/
}
//rww - here ends the majority of my g2animent stuff.
//Disabled for now, I'm too lazy to keep it working with all the stuff changing around.
#if 0
int cgFPLSState = 0 ;
void CG_ForceFPLSPlayerModel ( centity_t * cent , clientInfo_t * ci )
{
animation_t * anim ;
if ( cg_fpls . integer & & ! cg . renderingThirdPerson )
{
int skinHandle ;
skinHandle = trap_R_RegisterSkin ( " models/players/kyle/model_fpls2.skin " ) ;
trap_G2API_CleanGhoul2Models ( & ( ci - > ghoul2Model ) ) ;
ci - > torsoSkin = skinHandle ;
trap_G2API_InitGhoul2Model ( & ci - > ghoul2Model , " models/players/kyle/model.glm " , 0 , ci - > torsoSkin , 0 , 0 , 0 ) ;
ci - > bolt_rhand = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *r_hand " ) ;
trap_G2API_SetBoneAnim ( ci - > ghoul2Model , 0 , " model_root " , 0 , 12 , BONE_ANIM_OVERRIDE_LOOP , 1.0f , cg . time , - 1 , - 1 ) ;
trap_G2API_SetBoneAngles ( ci - > ghoul2Model , 0 , " upper_lumbar " , vec3_origin , BONE_ANGLES_POSTMULT , POSITIVE_X , NEGATIVE_Y , NEGATIVE_Z , NULL , 0 , cg . time ) ;
trap_G2API_SetBoneAngles ( ci - > ghoul2Model , 0 , " cranium " , vec3_origin , BONE_ANGLES_POSTMULT , POSITIVE_Z , NEGATIVE_Y , POSITIVE_X , NULL , 0 , cg . time ) ;
ci - > bolt_lhand = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *l_hand " ) ;
//rhand must always be first bolt. lhand always second. Whichever you want the
//jetpack bolted to must always be third.
trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *chestg " ) ;
//claw bolts
trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *r_hand_cap_r_arm " ) ;
trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *l_hand_cap_l_arm " ) ;
ci - > bolt_head = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " *head_top " ) ;
if ( ci - > bolt_head = = - 1 )
{
ci - > bolt_head = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " ceyebrow " ) ;
}
ci - > bolt_motion = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " Motion " ) ;
//We need a lower lumbar bolt for footsteps
ci - > bolt_llumbar = trap_G2API_AddBolt ( ci - > ghoul2Model , 0 , " lower_lumbar " ) ;
CG_CopyG2WeaponInstance ( cent , cent - > currentState . weapon , ci - > ghoul2Model ) ;
}
else
{
CG_RegisterClientModelname ( ci , ci - > modelName , ci - > skinName , ci - > teamName , cent - > currentState . number ) ;
}
anim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ cent - > currentState . legsAnim ] ;
if ( anim )
{
int flags = BONE_ANIM_OVERRIDE_FREEZE ;
int firstFrame = anim - > firstFrame ;
int setFrame = - 1 ;
float animSpeed = 50.0f / anim - > frameLerp ;
if ( anim - > loopFrames ! = - 1 )
{
flags = BONE_ANIM_OVERRIDE_LOOP ;
}
if ( cent - > pe . legs . frame > = anim - > firstFrame & & cent - > pe . legs . frame < = ( anim - > firstFrame + anim - > numFrames ) )
{
setFrame = cent - > pe . legs . frame ;
}
trap_G2API_SetBoneAnim ( ci - > ghoul2Model , 0 , " model_root " , firstFrame , anim - > firstFrame + anim - > numFrames , flags , animSpeed , cg . time , setFrame , 150 ) ;
cent - > currentState . legsAnim = 0 ;
}
anim = & bgAllAnims [ cent - > localAnimIndex ] . anims [ cent - > currentState . torsoAnim ] ;
if ( anim )
{
int flags = BONE_ANIM_OVERRIDE_FREEZE ;
int firstFrame = anim - > firstFrame ;
int setFrame = - 1 ;
float animSpeed = 50.0f / anim - > frameLerp ;
if ( anim - > loopFrames ! = - 1 )
{
flags = BONE_ANIM_OVERRIDE_LOOP ;
}
if ( cent - > pe . torso . frame > = anim - > firstFrame & & cent - > pe . torso . frame < = ( anim - > firstFrame + anim - > numFrames ) )
{
setFrame = cent - > pe . torso . frame ;
}
trap_G2API_SetBoneAnim ( ci - > ghoul2Model , 0 , " lower_lumbar " , firstFrame , anim - > firstFrame + anim - > numFrames , flags , animSpeed , cg . time , setFrame , 150 ) ;
cent - > currentState . torsoAnim = 0 ;
}
trap_G2API_CleanGhoul2Models ( & ( cent - > ghoul2 ) ) ;
trap_G2API_DuplicateGhoul2Instance ( ci - > ghoul2Model , & cent - > ghoul2 ) ;
//Attach the instance to this entity num so we can make use of client-server
//shared operations if possible.
trap_G2API_AttachInstanceToEntNum ( cent - > ghoul2 , cent - > currentState . number , qfalse ) ;
}
# endif
//for allocating and freeing npc clientinfo structures.
//Remember to free this before game shutdown no matter what
//and don't stomp over it, as it is dynamic memory from the
//exe.
void CG_CreateNPCClient ( clientInfo_t * * ci )
{
//trap_TrueMalloc((void **)ci, sizeof(clientInfo_t));
* ci = ( clientInfo_t * ) BG_Alloc ( sizeof ( clientInfo_t ) ) ;
}
void CG_DestroyNPCClient ( clientInfo_t * * ci )
{
memset ( * ci , 0 , sizeof ( clientInfo_t ) ) ;
//trap_TrueFree((void **)ci);
}
static void CG_ForceElectrocution ( centity_t * cent , const vec3_t origin , vec3_t tempAngles , qhandle_t shader , qboolean alwaysDo )
{
// Undoing for now, at least this code should compile if I ( or anyone else ) decides to work on this effect
qboolean found = qfalse ;
vec3_t fxOrg , fxOrg2 , dir ;
vec3_t rgb ;
mdxaBone_t boltMatrix ;
trace_t tr ;
int bolt = - 1 ;
int iter = 0 ;
int torsoBolt = - 1 ;
int crotchBolt = - 1 ;
int elbowLBolt = - 1 ;
int elbowRBolt = - 1 ;
int handLBolt = - 1 ;
int handRBolt = - 1 ;
int kneeLBolt = - 1 ;
int kneeRBolt = - 1 ;
int footLBolt = - 1 ;
int footRBolt = - 1 ;
VectorSet ( rgb , 1 , 1 , 1 ) ;
if ( cent - > localAnimIndex < = 1 )
{ //humanoid
torsoBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " lower_lumbar " ) ;
crotchBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " pelvis " ) ;
elbowLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_arm_elbow " ) ;
elbowRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_arm_elbow " ) ;
handLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_hand " ) ;
handRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_hand " ) ;
kneeLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *hips_l_knee " ) ;
kneeRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *hips_r_knee " ) ;
footLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *l_leg_foot " ) ;
footRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *r_leg_foot " ) ;
}
else if ( cent - > currentState . NPC_class = = CLASS_PROTOCOL )
{ //any others that can use these bolts too?
torsoBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " lower_lumbar " ) ;
crotchBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " pelvis " ) ;
elbowLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *bicep_lg " ) ;
elbowRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *bicep_rg " ) ;
handLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *hand_l " ) ;
handRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *weapon " ) ;
kneeLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *thigh_lg " ) ;
kneeRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *thigh_rg " ) ;
footLBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *foot_lg " ) ;
footRBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *foot_rg " ) ;
}
// Pick a random start point
while ( bolt < 0 )
{
int test ;
if ( iter > 5 )
{
test = iter - 5 ;
}
else
{
test = Q_irand ( 0 , 6 ) ;
}
switch ( test )
{
case 0 :
// Right Elbow
bolt = elbowRBolt ;
break ;
case 1 :
// Left Hand
bolt = handLBolt ;
break ;
case 2 :
// Right hand
bolt = handRBolt ;
break ;
case 3 :
// Left Foot
bolt = footLBolt ;
break ;
case 4 :
// Right foot
bolt = footRBolt ;
break ;
case 5 :
// Torso
bolt = torsoBolt ;
break ;
case 6 :
default :
// Left Elbow
bolt = elbowLBolt ;
break ;
}
if ( + + iter = = 20 )
break ;
}
if ( bolt > = 0 )
{
found = trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , bolt ,
& boltMatrix , tempAngles , origin , cg . time ,
cgs . gameModels , cent - > modelScale ) ;
}
// Make sure that it's safe to even try and get these values out of the Matrix, otherwise the values could be garbage
if ( found )
{
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , fxOrg ) ;
if ( random ( ) > 0.5f )
{
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_X , dir ) ;
}
else
{
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_Y , dir ) ;
}
// Add some fudge, makes us not normalized, but that isn't really important
dir [ 0 ] + = crandom ( ) * 0.4f ;
dir [ 1 ] + = crandom ( ) * 0.4f ;
dir [ 2 ] + = crandom ( ) * 0.4f ;
}
else
{
// Just use the lerp Origin and a random direction
VectorCopy ( cent - > lerpOrigin , fxOrg ) ;
VectorSet ( dir , crandom ( ) , crandom ( ) , crandom ( ) ) ; // Not normalized, but who cares.
switch ( cent - > currentState . NPC_class )
{
case CLASS_PROBE :
fxOrg [ 2 ] + = 50 ;
break ;
case CLASS_MARK1 :
fxOrg [ 2 ] + = 50 ;
break ;
case CLASS_ATST :
fxOrg [ 2 ] + = 120 ;
break ;
default :
break ;
}
}
VectorMA ( fxOrg , random ( ) * 40 + 40 , dir , fxOrg2 ) ;
CG_Trace ( & tr , fxOrg , NULL , NULL , fxOrg2 , - 1 , CONTENTS_SOLID ) ;
if ( tr . fraction < 1.0f | | random ( ) > 0.94f | | alwaysDo )
{
addElectricityArgStruct_t p ;
VectorCopy ( fxOrg , p . start ) ;
VectorCopy ( tr . endpos , p . end ) ;
p . size1 = 1.5f ;
p . size2 = 4.0f ;
p . sizeParm = 0.0f ;
p . alpha1 = 1.0f ;
p . alpha2 = 0.5f ;
p . alphaParm = 0.0f ;
VectorCopy ( rgb , p . sRGB ) ;
VectorCopy ( rgb , p . eRGB ) ;
p . rgbParm = 0.0f ;
p . chaos = 5.0f ;
p . killTime = ( random ( ) * 50 + 100 ) ;
p . shader = shader ;
p . flags = ( 0x00000001 | 0x00000100 | 0x02000000 | 0x04000000 | 0x01000000 ) ;
trap_FX_AddElectricity ( & p ) ;
//In other words:
/*
FX_AddElectricity ( fxOrg , tr . endpos ,
1.5f , 4.0f , 0.0f ,
1.0f , 0.5f , 0.0f ,
rgb , rgb , 0.0f ,
5.5f , random ( ) * 50 + 100 , shader , FX_ALPHA_LINEAR | FX_SIZE_LINEAR | FX_BRANCH | FX_GROW | FX_TAPER ) ;
*/
}
}
void * cg_g2JetpackInstance = NULL ;
# define JETPACK_MODEL "models / weapons2 / jetpack / model.glm"
void CG_InitJetpackGhoul2 ( void )
{
if ( cg_g2JetpackInstance )
{
assert ( ! " Tried to init jetpack inst, already init'd " ) ;
return ;
}
trap_G2API_InitGhoul2Model ( & cg_g2JetpackInstance , JETPACK_MODEL , 0 , 0 , 0 , 0 , 0 ) ;
assert ( cg_g2JetpackInstance ) ;
//Indicate which bolt on the player we will be attached to
//In this case bolt 0 is rhand, 1 is lhand, and 2 is the bolt
//for the jetpack (*chestg)
trap_G2API_SetBoltInfo ( cg_g2JetpackInstance , 0 , 2 ) ;
//Add the bolts jet effects will be played from
trap_G2API_AddBolt ( cg_g2JetpackInstance , 0 , " torso_ljet " ) ;
trap_G2API_AddBolt ( cg_g2JetpackInstance , 0 , " torso_rjet " ) ;
}
void CG_CleanJetpackGhoul2 ( void )
{
if ( cg_g2JetpackInstance )
{
trap_G2API_CleanGhoul2Models ( & cg_g2JetpackInstance ) ;
cg_g2JetpackInstance = NULL ;
}
}
# define RARMBIT (1 << (G2_MODELPART_RARM-10))
# define RHANDBIT (1 << (G2_MODELPART_RHAND-10))
# define WAISTBIT (1 << (G2_MODELPART_WAIST-10))
#if 0
static void CG_VehicleHeatEffect ( vec3_t org , centity_t * cent )
{
refEntity_t ent ;
vec3_t ang ;
float scale ;
float vLen ;
float alpha ;
if ( ! cg_renderToTextureFX . integer )
{
return ;
}
scale = 0.1f ;
alpha = 200.0f ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( org , ent . origin ) ;
VectorSubtract ( ent . origin , cg . refdef . vieworg , ent . axis [ 0 ] ) ;
vLen = VectorLength ( ent . axis [ 0 ] ) ;
if ( VectorNormalize ( ent . axis [ 0 ] ) < = 0.1f )
{ // Entity is right on vieworg. quit.
return ;
}
vectoangles ( ent . axis [ 0 ] , ang ) ;
AnglesToAxis ( ang , ent . axis ) ;
//radius must be a power of 2, and is the actual captured texture size
ent . radius = 32 ;
VectorScale ( ent . axis [ 0 ] , scale , ent . axis [ 0 ] ) ;
VectorScale ( ent . axis [ 1 ] , scale , ent . axis [ 1 ] ) ;
VectorScale ( ent . axis [ 2 ] , - scale , ent . axis [ 2 ] ) ;
ent . hModel = cgs . media . halfShieldModel ;
ent . customShader = cgs . media . cloakedShader ;
//make it partially transparent so it blends with the background
ent . renderfx = ( RF_DISTORTION | RF_FORCE_ENT_ALPHA ) ;
ent . shaderRGBA [ 0 ] = 255.0f ;
ent . shaderRGBA [ 1 ] = 255.0f ;
ent . shaderRGBA [ 2 ] = 255.0f ;
ent . shaderRGBA [ 3 ] = alpha ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
# endif
static int lastFlyBySound [ MAX_GENTITIES ] = { 0 } ;
# define FLYBYSOUNDTIME 2000
int cg_lastHyperSpaceEffectTime = 0 ;
static CGAME_INLINE void CG_VehicleEffects ( centity_t * cent )
{
Vehicle_t * pVehNPC ;
if ( cent - > currentState . eType ! = ET_NPC | |
cent - > currentState . NPC_class ! = CLASS_VEHICLE | |
! cent - > m_pVehicle )
{
return ;
}
pVehNPC = cent - > m_pVehicle ;
if ( cent - > currentState . clientNum = = cg . predictedPlayerState . m_iVehicleNum //my vehicle
& & ( cent - > currentState . eFlags2 & EF2_HYPERSPACE ) ) //hyperspacing
{ //in hyperspace!
if ( cg . predictedVehicleState . hyperSpaceTime
& & ( cg . time - cg . predictedVehicleState . hyperSpaceTime ) < HYPERSPACE_TIME )
{
if ( ! cg_lastHyperSpaceEffectTime
| | ( cg . time - cg_lastHyperSpaceEffectTime ) > HYPERSPACE_TIME + 500 )
{ //can't be from the last time we were in hyperspace, so play the effect!
trap_FX_PlayBoltedEffectID ( cgs . effects . mHyperspaceStars , cent - > lerpOrigin , cent - > ghoul2 , 0 ,
cent - > currentState . number , 0 , 0 , qtrue ) ;
cg_lastHyperSpaceEffectTime = cg . time ;
}
}
}
//FLYBY sound
if ( cent - > currentState . clientNum ! = cg . predictedPlayerState . m_iVehicleNum
& & ( pVehNPC - > m_pVehicleInfo - > soundFlyBy | | pVehNPC - > m_pVehicleInfo - > soundFlyBy2 ) )
{ //not my vehicle
if ( cent - > currentState . speed & & cg . predictedPlayerState . speed + cent - > currentState . speed > 500 )
{ //he's moving and between the two of us, we're moving fast
vec3_t diff ;
VectorSubtract ( cent - > lerpOrigin , cg . predictedPlayerState . origin , diff ) ;
if ( VectorLength ( diff ) < 2048 )
{ //close
vec3_t myFwd , theirFwd ;
AngleVectors ( cg . predictedPlayerState . viewangles , myFwd , NULL , NULL ) ;
VectorScale ( myFwd , cg . predictedPlayerState . speed , myFwd ) ;
AngleVectors ( cent - > lerpAngles , theirFwd , NULL , NULL ) ;
VectorScale ( theirFwd , cent - > currentState . speed , theirFwd ) ;
if ( lastFlyBySound [ cent - > currentState . clientNum ] + FLYBYSOUNDTIME < cg . time )
{ //okay to do a flyby sound on this vehicle
if ( DotProduct ( myFwd , theirFwd ) < 500 )
{
int flyBySound = 0 ;
if ( pVehNPC - > m_pVehicleInfo - > soundFlyBy & & pVehNPC - > m_pVehicleInfo - > soundFlyBy2 )
{
flyBySound = Q_irand ( 0 , 1 ) ? pVehNPC - > m_pVehicleInfo - > soundFlyBy : pVehNPC - > m_pVehicleInfo - > soundFlyBy2 ;
}
else if ( pVehNPC - > m_pVehicleInfo - > soundFlyBy )
{
flyBySound = pVehNPC - > m_pVehicleInfo - > soundFlyBy ;
}
else //if ( pVehNPC->m_pVehicleInfo->soundFlyBy2 )
{
flyBySound = pVehNPC - > m_pVehicleInfo - > soundFlyBy2 ;
}
trap_S_StartSound ( NULL , cent - > currentState . clientNum , CHAN_LESS_ATTEN , flyBySound ) ;
lastFlyBySound [ cent - > currentState . clientNum ] = cg . time ;
}
}
}
}
}
if ( ! cent - > currentState . speed //was stopped
& & cent - > nextState . speed > 0 //now moving forward
& & cent - > m_pVehicle - > m_pVehicleInfo - > soundEngineStart )
{ //engines rev up for the first time
trap_S_StartSound ( NULL , cent - > currentState . clientNum , CHAN_LESS_ATTEN , cent - > m_pVehicle - > m_pVehicleInfo - > soundEngineStart ) ;
}
// Animals don't exude any effects...
if ( pVehNPC - > m_pVehicleInfo - > type ! = VH_ANIMAL )
{
qboolean didFireTrail = qfalse ;
if ( pVehNPC - > m_pVehicleInfo - > surfDestruction & & cent - > ghoul2 )
{ //see if anything has been blown off
int i = 0 ;
qboolean surfDmg = qfalse ;
while ( i < BG_NUM_TOGGLEABLE_SURFACES )
{
if ( bgToggleableSurfaceDebris [ i ] > 1 )
{ //this is decidedly a destroyable surface, let's check its status
int surfTest = trap_G2API_GetSurfaceRenderStatus ( cent - > ghoul2 , 0 , bgToggleableSurfaces [ i ] ) ;
if ( surfTest ! = - 1
& & ( surfTest & TURN_OFF ) )
{ //it exists, but it's off...
surfDmg = qtrue ;
//create some flames
CG_CreateSurfaceDebris ( cent , i , cgs . effects . mShipDestBurning , qfalse ) ;
didFireTrail = qtrue ;
}
}
i + + ;
}
if ( surfDmg )
{ //if any surface are damaged, neglect exhaust etc effects (so we don't have exhaust trails coming out of invisible surfaces)
return ;
}
}
if ( ! didFireTrail & & ( cent - > currentState . eFlags & EF_DEAD ) )
{ //spiralling out of control anyway
CG_CreateSurfaceDebris ( cent , - 1 , cgs . effects . mShipDestBurning , qfalse ) ;
}
if ( pVehNPC - > m_iLastFXTime < = cg . time )
{ //until we attach it, we need to debounce this
vec3_t fwd , rt , up ;
vec3_t flat ;
float nextFXDelay = 50 ;
VectorSet ( flat , 0 , cent - > lerpAngles [ 1 ] , cent - > lerpAngles [ 2 ] ) ;
AngleVectors ( flat , fwd , rt , up ) ;
if ( cent - > currentState . speed > 0 )
{ //FIXME: only do this when accelerator is being pressed! (must have a driver?)
vec3_t org ;
qboolean doExhaust = qfalse ;
VectorMA ( cent - > lerpOrigin , - 16 , up , org ) ;
VectorMA ( org , - 42 , fwd , org ) ;
// Play damage effects.
//if ( pVehNPC->m_iArmor <= 75 )
if ( 0 )
{ //hurt
trap_FX_PlayEffectID ( cgs . effects . mBlackSmoke , org , fwd , - 1 , - 1 ) ;
}
else if ( pVehNPC - > m_pVehicleInfo - > iTrailFX )
{ //okay, do normal trail
trap_FX_PlayEffectID ( pVehNPC - > m_pVehicleInfo - > iTrailFX , org , fwd , - 1 , - 1 ) ;
}
//=====================================================================
//EXHAUST FX
//=====================================================================
//do exhaust
if ( ( cent - > currentState . eFlags & EF_JETPACK_ACTIVE ) )
{ //cheap way of telling us the vehicle is in "turbo" mode
doExhaust = ( pVehNPC - > m_pVehicleInfo - > iTurboFX ! = 0 ) ;
}
else
{
doExhaust = ( pVehNPC - > m_pVehicleInfo - > iExhaustFX ! = 0 ) ;
}
if ( doExhaust & & cent - > ghoul2 )
{
int i ;
int fx ;
for ( i = 0 ; i < MAX_VEHICLE_EXHAUSTS ; i + + )
{
// We hit an invalid tag, we quit (they should be created in order so tough luck if not).
if ( pVehNPC - > m_iExhaustTag [ i ] = = - 1 )
{
break ;
}
if ( ( cent - > currentState . brokenLimbs & ( 1 < < SHIPSURF_DAMAGE_BACK_HEAVY ) ) )
{ //engine has taken heavy damage
if ( ! Q_irand ( 0 , 1 ) )
{ //50% chance of not drawing this engine glow this frame
continue ;
}
}
else if ( ( cent - > currentState . brokenLimbs & ( 1 < < SHIPSURF_DAMAGE_BACK_LIGHT ) ) )
{ //engine has taken light damage
if ( ! Q_irand ( 0 , 4 ) )
{ //20% chance of not drawing this engine glow this frame
continue ;
}
}
if ( ( cent - > currentState . eFlags & EF_JETPACK_ACTIVE ) //cheap way of telling us the vehicle is in "turbo" mode
& & pVehNPC - > m_pVehicleInfo - > iTurboFX ) //they have a valid turbo exhaust effect to play
{
fx = pVehNPC - > m_pVehicleInfo - > iTurboFX ;
}
else
{ //play the normal one
fx = pVehNPC - > m_pVehicleInfo - > iExhaustFX ;
}
if ( pVehNPC - > m_pVehicleInfo - > type = = VH_FIGHTER )
{
trap_FX_PlayBoltedEffectID ( fx , cent - > lerpOrigin , cent - > ghoul2 , pVehNPC - > m_iExhaustTag [ i ] ,
cent - > currentState . number , 0 , 0 , qtrue ) ;
}
else
{ //fixme: bolt these too
mdxaBone_t boltMatrix ;
vec3_t boltOrg , boltDir ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , pVehNPC - > m_iExhaustTag [ i ] , & boltMatrix , flat ,
cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltOrg ) ;
VectorCopy ( fwd , boltDir ) ; //fixme?
trap_FX_PlayEffectID ( fx , boltOrg , boltDir , - 1 , - 1 ) ;
}
}
}
//=====================================================================
//WING TRAIL FX
//=====================================================================
//do trail
//FIXME: not in space!!!
if ( pVehNPC - > m_pVehicleInfo - > iTrailFX ! = 0 & & cent - > ghoul2 )
{
int i ;
vec3_t boltOrg , boltDir ;
mdxaBone_t boltMatrix ;
vec3_t getBoltAngles ;
VectorCopy ( cent - > lerpAngles , getBoltAngles ) ;
if ( pVehNPC - > m_pVehicleInfo - > type ! = VH_FIGHTER )
{ //only fighters use pitch/roll in refent axis
getBoltAngles [ PITCH ] = getBoltAngles [ ROLL ] = 0.0f ;
}
for ( i = 1 ; i < 5 ; i + + )
{
int trailBolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , va ( " *trail%d " , i ) ) ;
// We hit an invalid tag, we quit (they should be created in order so tough luck if not).
if ( trailBolt = = - 1 )
{
break ;
}
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , trailBolt , & boltMatrix , getBoltAngles ,
cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , boltOrg ) ;
VectorCopy ( fwd , boltDir ) ; //fixme?
trap_FX_PlayEffectID ( pVehNPC - > m_pVehicleInfo - > iTrailFX , boltOrg , boltDir , - 1 , - 1 ) ;
}
}
}
//FIXME armor needs to be sent over network
{
if ( ( cent - > currentState . eFlags & EF_DEAD ) )
{ //just plain dead, use flames
vec3_t up = { 0 , 0 , 1 } ;
vec3_t boltOrg ;
//if ( pVehNPC->m_iDriverTag == -1 )
{ //doh! no tag
VectorCopy ( cent - > lerpOrigin , boltOrg ) ;
}
//else
//{
// mdxaBone_t boltMatrix;
// vec3_t getBoltAngles;
// VectorCopy(cent->lerpAngles, getBoltAngles);
// if (pVehNPC->m_pVehicleInfo->type != VH_FIGHTER)
// { //only fighters use pitch/roll in refent axis
// getBoltAngles[PITCH] = getBoltAngles[ROLL] = 0.0f;
// }
// trap_G2API_GetBoltMatrix(cent->ghoul2, 0, pVehNPC->m_iDriverTag, &boltMatrix, getBoltAngles,
// cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
// BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrg);
//}
trap_FX_PlayEffectID ( cgs . effects . mShipDestBurning , boltOrg , up , - 1 , - 1 ) ;
}
}
if ( cent - > currentState . brokenLimbs )
{
int i ;
if ( ! Q_irand ( 0 , 5 ) )
{
for ( i = SHIPSURF_FRONT ; i < = SHIPSURF_LEFT ; i + + )
{
if ( ( cent - > currentState . brokenLimbs & ( 1 < < ( ( i - SHIPSURF_FRONT ) + SHIPSURF_DAMAGE_FRONT_HEAVY ) ) ) )
{ //heavy damage, do both effects
if ( pVehNPC - > m_pVehicleInfo - > iInjureFX )
{
CG_CreateSurfaceSmoke ( cent , i , pVehNPC - > m_pVehicleInfo - > iInjureFX ) ;
}
if ( pVehNPC - > m_pVehicleInfo - > iDmgFX )
{
CG_CreateSurfaceSmoke ( cent , i , pVehNPC - > m_pVehicleInfo - > iDmgFX ) ;
}
}
else if ( ( cent - > currentState . brokenLimbs & ( 1 < < ( ( i - SHIPSURF_FRONT ) + SHIPSURF_DAMAGE_FRONT_LIGHT ) ) ) )
{ //only light damage
if ( pVehNPC - > m_pVehicleInfo - > iInjureFX )
{
CG_CreateSurfaceSmoke ( cent , i , pVehNPC - > m_pVehicleInfo - > iInjureFX ) ;
}
}
}
}
}
/*
if ( pVehNPC - > m_iArmor < = 50 )
{ //FIXME: use as a proportion of max armor?
VectorMA ( cent - > lerpOrigin , 64 , fwd , org ) ;
VectorScale ( fwd , - 1 , fwd ) ;
trap_FX_PlayEffectID ( cgs . effects . mBlackSmoke , org , fwd , - 1 , - 1 ) ;
}
if ( pVehNPC - > m_iArmor < = 0 )
{ //FIXME: should use something attached.. but want it to build up over time, so...
if ( flrand ( 0 , cg . time - pVehNPC - > m_iDieTime ) < 1000 )
{ //flaming!
VectorMA ( cent - > lerpOrigin , flrand ( - 64 , 64 ) , fwd , org ) ;
VectorScale ( fwd , - 1 , fwd ) ;
trap_FX_PlayEffectID ( trap_FX_RegisterEffect ( " ships/fire " ) , org , fwd , - 1 , - 1 ) ;
nextFXDelay = 50 ;
}
}
*/
pVehNPC - > m_iLastFXTime = cg . time + nextFXDelay ;
}
}
}
/*
= = = = = = = = = = = = = = =
CG_Player
= = = = = = = = = = = = = = =
*/
# include "../namespace_begin.h"
int BG_EmplacedView ( vec3_t baseAngles , vec3_t angles , float * newYaw , float constraint ) ;
# include "../namespace_end.h"
float CG_RadiusForCent ( centity_t * cent )
{
if ( cent - > currentState . eType = = ET_NPC )
{
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE & &
cent - > m_pVehicle & &
cent - > m_pVehicle - > m_pVehicleInfo - > g2radius )
{ //has override
return cent - > m_pVehicle - > m_pVehicleInfo - > g2radius ;
}
else if ( cent - > currentState . g2radius )
{
return cent - > currentState . g2radius ;
}
}
else if ( cent - > currentState . g2radius )
{
return cent - > currentState . g2radius ;
}
return 64.0f ;
}
static float cg_vehThirdPersonAlpha = 1.0f ;
extern vec3_t cg_crosshairPos ;
extern vec3_t cameraCurLoc ;
void CG_CheckThirdPersonAlpha ( centity_t * cent , refEntity_t * legs )
{
float alpha = 1.0f ;
int setFlags = 0 ;
if ( cent - > m_pVehicle )
{ //a vehicle
if ( cg . predictedPlayerState . m_iVehicleNum ! = cent - > currentState . clientNum //not mine
& & cent - > m_pVehicle - > m_pVehicleInfo
& & cent - > m_pVehicle - > m_pVehicleInfo - > cameraOverride
& & cent - > m_pVehicle - > m_pVehicleInfo - > cameraAlpha ) //it has alpha
{ //make sure it's not using any alpha
legs - > renderfx | = RF_FORCE_ENT_ALPHA ;
legs - > shaderRGBA [ 3 ] = 255 ;
return ;
}
}
if ( ! cg . renderingThirdPerson )
{
return ;
}
if ( cg . predictedPlayerState . m_iVehicleNum )
{ //in a vehicle
if ( cg . predictedPlayerState . m_iVehicleNum = = cent - > currentState . clientNum )
{ //this is my vehicle
if ( cent - > m_pVehicle
& & cent - > m_pVehicle - > m_pVehicleInfo
& & cent - > m_pVehicle - > m_pVehicleInfo - > cameraOverride
& & cent - > m_pVehicle - > m_pVehicleInfo - > cameraAlpha )
{ //vehicle has auto third-person alpha on
trace_t trace ;
vec3_t dir2Crosshair , end ;
VectorSubtract ( cg_crosshairPos , cameraCurLoc , dir2Crosshair ) ;
VectorNormalize ( dir2Crosshair ) ;
VectorMA ( cameraCurLoc , cent - > m_pVehicle - > m_pVehicleInfo - > cameraRange * 2.0f , dir2Crosshair , end ) ;
CG_G2Trace ( & trace , cameraCurLoc , vec3_origin , vec3_origin , end , ENTITYNUM_NONE , CONTENTS_BODY ) ;
if ( trace . entityNum = = cent - > currentState . clientNum
| | trace . entityNum = = cg . predictedPlayerState . clientNum )
{ //hit me or the vehicle I'm in
cg_vehThirdPersonAlpha - = 0.1f * cg . frametime / 50.0f ;
if ( cg_vehThirdPersonAlpha < cent - > m_pVehicle - > m_pVehicleInfo - > cameraAlpha )
{
cg_vehThirdPersonAlpha = cent - > m_pVehicle - > m_pVehicleInfo - > cameraAlpha ;
}
}
else
{
cg_vehThirdPersonAlpha + = 0.1f * cg . frametime / 50.0f ;
if ( cg_vehThirdPersonAlpha > 1.0f )
{
cg_vehThirdPersonAlpha = 1.0f ;
}
}
alpha = cg_vehThirdPersonAlpha ;
}
else
{ //use the cvar
//reset this
cg_vehThirdPersonAlpha = 1.0f ;
//use the cvar
alpha = cg_thirdPersonAlpha . value ;
}
}
}
else if ( cg . predictedPlayerState . clientNum = = cent - > currentState . clientNum )
{ //it's me
//reset this
cg_vehThirdPersonAlpha = 1.0f ;
//use the cvar
setFlags = RF_FORCE_ENT_ALPHA ;
alpha = cg_thirdPersonAlpha . value ;
}
if ( alpha < 1.0f )
{
legs - > renderfx | = setFlags ;
legs - > shaderRGBA [ 3 ] = ( unsigned char ) ( alpha * 255.0f ) ;
}
}
void CG_Player ( centity_t * cent ) {
clientInfo_t * ci ;
refEntity_t legs ;
refEntity_t torso ;
int clientNum ;
int renderfx ;
qboolean shadow = qfalse ;
float shadowPlane = 0 ;
qboolean dead = qfalse ;
vec3_t rootAngles ;
float angle ;
vec3_t angles , dir , elevated , enang , seekorg ;
int iwantout = 0 , successchange = 0 ;
int team ;
mdxaBone_t boltMatrix , lHandMatrix ;
int doAlpha = 0 ;
qboolean gotLHandMatrix = qfalse ;
qboolean g2HasWeapon = qfalse ;
qboolean drawPlayerSaber = qfalse ;
qboolean checkDroidShields = qfalse ;
//first if we are not an npc and we are using an emplaced gun then make sure our
//angles are visually capped to the constraints (otherwise it's possible to lerp
//a little outside and look kind of twitchy)
if ( cent - > currentState . weapon = = WP_EMPLACED_GUN & &
cent - > currentState . otherEntityNum2 )
{
float empYaw ;
if ( BG_EmplacedView ( cent - > lerpAngles , cg_entities [ cent - > currentState . otherEntityNum2 ] . currentState . angles , & empYaw , cg_entities [ cent - > currentState . otherEntityNum2 ] . currentState . origin2 [ 0 ] ) )
{
cent - > lerpAngles [ YAW ] = empYaw ;
}
}
if ( cent - > currentState . iModelScale )
{ //if the server says we have a custom scale then set it now.
cent - > modelScale [ 0 ] = cent - > modelScale [ 1 ] = cent - > modelScale [ 2 ] = cent - > currentState . iModelScale / 100.0f ;
if ( cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{
if ( cent - > modelScale [ 2 ] & & cent - > modelScale [ 2 ] ! = 1.0f )
{
cent - > lerpOrigin [ 2 ] + = 24 * ( cent - > modelScale [ 2 ] - 1 ) ;
}
}
}
else
{
VectorClear ( cent - > modelScale ) ;
}
if ( ( cg_smoothClients . integer | | cent - > currentState . heldByClient ) & & ( cent - > currentState . groundEntityNum > = ENTITYNUM_WORLD | | cent - > currentState . eType = = ET_TERRAIN ) & &
! ( cent - > currentState . eFlags2 & EF2_HYPERSPACE ) & & cg . predictedPlayerState . m_iVehicleNum ! = cent - > currentState . number )
{ //always smooth when being thrown
vec3_t posDif ;
float smoothFactor ;
int k = 0 ;
float fTolerance = 20000.0f ;
if ( cent - > currentState . heldByClient )
{ //smooth the origin more when in this state, because movement is origin-based on server.
smoothFactor = 0.2f ;
}
else if ( ( cent - > currentState . powerups & ( 1 < < PW_SPEED ) ) | |
( cent - > currentState . forcePowersActive & ( 1 < < FP_RAGE ) ) )
{ //we're moving fast so don't smooth as much
smoothFactor = 0.6f ;
}
else if ( cent - > currentState . eType = = ET_NPC & & cent - > currentState . NPC_class = = CLASS_VEHICLE & &
cent - > m_pVehicle & & cent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //greater smoothing for flying vehicles, since they move so fast
fTolerance = 6000000.0f ; //500000.0f; //yeah, this is so wrong..but..
smoothFactor = 0.5f ;
}
else
{
smoothFactor = 0.5f ;
}
if ( DistanceSquared ( cent - > beamEnd , cent - > lerpOrigin ) > smoothFactor * fTolerance ) //10000
{
VectorCopy ( cent - > lerpOrigin , cent - > beamEnd ) ;
}
VectorSubtract ( cent - > lerpOrigin , cent - > beamEnd , posDif ) ;
for ( k = 0 ; k < 3 ; k + + )
{
cent - > beamEnd [ k ] = ( cent - > beamEnd [ k ] + posDif [ k ] * smoothFactor ) ;
cent - > lerpOrigin [ k ] = cent - > beamEnd [ k ] ;
}
}
else
{
VectorCopy ( cent - > lerpOrigin , cent - > beamEnd ) ;
}
if ( cent - > currentState . m_iVehicleNum & &
cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{ //this player is riding a vehicle
centity_t * veh = & cg_entities [ cent - > currentState . m_iVehicleNum ] ;
cent - > lerpAngles [ YAW ] = veh - > lerpAngles [ YAW ] ;
//Attach ourself to the vehicle
if ( veh - > m_pVehicle & &
cent - > playerState & &
veh - > playerState & &
cent - > ghoul2 & &
veh - > ghoul2 )
{
if ( veh - > currentState . owner ! = cent - > currentState . clientNum )
{ //FIXME: what about visible passengers?
if ( CG_VehicleAttachDroidUnit ( cent , & legs ) )
{
checkDroidShields = qtrue ;
}
}
else if ( veh - > currentState . owner ! = ENTITYNUM_NONE )
{ //has a pilot...???
vec3_t oldPSOrg ;
//make sure it has its pilot and parent set
veh - > m_pVehicle - > m_pPilot = ( bgEntity_t * ) & cg_entities [ veh - > currentState . owner ] ;
veh - > m_pVehicle - > m_pParentEntity = ( bgEntity_t * ) veh ;
VectorCopy ( veh - > playerState - > origin , oldPSOrg ) ;
//update the veh's playerstate org for getting the bolt
VectorCopy ( veh - > lerpOrigin , veh - > playerState - > origin ) ;
VectorCopy ( cent - > lerpOrigin , cent - > playerState - > origin ) ;
//Now do the attach
VectorCopy ( veh - > lerpAngles , veh - > playerState - > viewangles ) ;
veh - > m_pVehicle - > m_pVehicleInfo - > AttachRiders ( veh - > m_pVehicle ) ;
//copy the "playerstate origin" to the lerpOrigin since that's what we use to display
VectorCopy ( cent - > playerState - > origin , cent - > lerpOrigin ) ;
VectorCopy ( oldPSOrg , veh - > playerState - > origin ) ;
}
}
}
// 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
if ( cent - > currentState . eType ! = ET_NPC )
{
clientNum = cent - > currentState . clientNum ;
if ( clientNum < 0 | | clientNum > = MAX_CLIENTS ) {
CG_Error ( " Bad clientNum on player entity " ) ;
}
ci = & cgs . clientinfo [ clientNum ] ;
}
else
{
if ( ! cent - > npcClient )
{
CG_CreateNPCClient ( & cent - > npcClient ) ; //allocate memory for it
if ( ! cent - > npcClient )
{
assert ( 0 ) ;
return ;
}
memset ( cent - > npcClient , 0 , sizeof ( clientInfo_t ) ) ;
cent - > npcClient - > ghoul2Model = NULL ;
}
assert ( cent - > npcClient ) ;
if ( cent - > npcClient - > ghoul2Model ! = cent - > ghoul2 & & cent - > ghoul2 )
{
cent - > npcClient - > ghoul2Model = cent - > ghoul2 ;
if ( cent - > localAnimIndex < = 1 )
{
cent - > npcClient - > bolt_rhand = trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " *r_hand " ) ;
cent - > npcClient - > bolt_lhand = trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " *l_hand " ) ;
//rhand must always be first bolt. lhand always second. Whichever you want the
//jetpack bolted to must always be third.
trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " *chestg " ) ;
//claw bolts
trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " *r_hand_cap_r_arm " ) ;
trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " *l_hand_cap_l_arm " ) ;
cent - > npcClient - > bolt_head = trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " *head_top " ) ;
if ( cent - > npcClient - > bolt_head = = - 1 )
{
cent - > npcClient - > bolt_head = trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " ceyebrow " ) ;
}
cent - > npcClient - > bolt_motion = trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " Motion " ) ;
cent - > npcClient - > bolt_llumbar = trap_G2API_AddBolt ( cent - > npcClient - > ghoul2Model , 0 , " lower_lumbar " ) ;
}
else
{
cent - > npcClient - > bolt_rhand = - 1 ;
cent - > npcClient - > bolt_lhand = - 1 ;
cent - > npcClient - > bolt_head = - 1 ;
cent - > npcClient - > bolt_motion = - 1 ;
cent - > npcClient - > bolt_llumbar = - 1 ;
}
cent - > npcClient - > team = TEAM_FREE ;
cent - > npcClient - > infoValid = qtrue ;
}
ci = cent - > npcClient ;
}
// it is possible to see corpses from disconnected players that may
// not have valid clientinfo
if ( ! ci - > infoValid ) {
return ;
}
// Add the player to the radar if on the same team and its a team game
if ( cgs . gametype > = GT_TEAM )
{
if ( cent - > currentState . eType ! = ET_NPC & &
cg . snap - > ps . clientNum ! = cent - > currentState . number & &
ci - > team = = cg . snap - > ps . persistant [ PERS_TEAM ] )
{
CG_AddRadarEnt ( cent ) ;
}
}
if ( cent - > currentState . eType = = ET_NPC & &
cent - > currentState . NPC_class = = CLASS_VEHICLE )
{ //add vehicles
CG_AddRadarEnt ( cent ) ;
if ( CG_InFighter ( ) )
{ //this is a vehicle, bracket it
if ( cg . predictedPlayerState . m_iVehicleNum ! = cent - > currentState . clientNum )
{ //don't add the vehicle I'm in... :)
CG_AddBracketedEnt ( cent ) ;
}
}
}
if ( ! cent - > ghoul2 )
{ //not ready yet?
# ifdef _DEBUG
Com_Printf ( " WARNING: Client %i has a null ghoul2 instance \n " , cent - > currentState . number ) ;
# endif
trap_G2API_ClearAttachedInstance ( cent - > currentState . number ) ;
if ( ci - > ghoul2Model & &
trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{
# ifdef _DEBUG
Com_Printf ( " Clientinfo instance was valid, duplicating for cent \n " ) ;
# endif
trap_G2API_DuplicateGhoul2Instance ( ci - > ghoul2Model , & cent - > ghoul2 ) ;
//Attach the instance to this entity num so we can make use of client-server
//shared operations if possible.
trap_G2API_AttachInstanceToEntNum ( cent - > ghoul2 , cent - > currentState . number , qfalse ) ;
if ( trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " face " ) = = - 1 )
{ //check now to see if we have this bone for setting anims and such
cent - > noFace = qtrue ;
}
cent - > localAnimIndex = CG_G2SkelForModel ( cent - > ghoul2 ) ;
cent - > eventAnimIndex = CG_G2EvIndexForModel ( cent - > ghoul2 , cent - > localAnimIndex ) ;
}
return ;
}
if ( ci - > superSmoothTime )
{ //do crazy smoothing
if ( ci - > superSmoothTime > cg . time )
{ //do it
trap_G2API_AbsurdSmoothing ( cent - > ghoul2 , qtrue ) ;
}
else
{ //turn it off
ci - > superSmoothTime = 0 ;
trap_G2API_AbsurdSmoothing ( cent - > ghoul2 , qfalse ) ;
}
}
if ( cg . predictedPlayerState . pm_type = = PM_INTERMISSION )
{ //don't show all this shit during intermission
if ( cent - > currentState . eType = = ET_NPC
& & cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{ //NPC in intermission
}
else
{ //don't render players or vehicles in intermissions, allow other NPCs for scripts
return ;
}
}
CG_VehicleEffects ( cent ) ;
if ( ( cent - > currentState . eFlags & EF_JETPACK ) & & ! ( cent - > currentState . eFlags & EF_DEAD ) & &
cg_g2JetpackInstance )
{ //should have a jetpack attached
//1 is rhand weap, 2 is lhand weap (akimbo sabs), 3 is jetpack
if ( ! trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > ghoul2 ) , 3 ) )
{
trap_G2API_CopySpecificGhoul2Model ( cg_g2JetpackInstance , 0 , cent - > ghoul2 , 3 ) ;
}
if ( cent - > currentState . eFlags & EF_JETPACK_ACTIVE )
{
mdxaBone_t mat ;
vec3_t flamePos , flameDir ;
int n = 0 ;
while ( n < 2 )
{
//Get the position/dir of the flame bolt on the jetpack model bolted to the player
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 3 , n , & mat , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & mat , ORIGIN , flamePos ) ;
if ( n = = 0 )
{
BG_GiveMeVectorFromMatrix ( & mat , NEGATIVE_Y , flameDir ) ;
VectorMA ( flamePos , - 9.5f , flameDir , flamePos ) ;
BG_GiveMeVectorFromMatrix ( & mat , POSITIVE_X , flameDir ) ;
VectorMA ( flamePos , - 13.5f , flameDir , flamePos ) ;
}
else
{
BG_GiveMeVectorFromMatrix ( & mat , POSITIVE_X , flameDir ) ;
VectorMA ( flamePos , - 9.5f , flameDir , flamePos ) ;
BG_GiveMeVectorFromMatrix ( & mat , NEGATIVE_Y , flameDir ) ;
VectorMA ( flamePos , - 13.5f , flameDir , flamePos ) ;
}
if ( cent - > currentState . eFlags & EF_JETPACK_FLAMING )
{ //create effects
//FIXME: Just one big effect
//Play the effect
trap_FX_PlayEffectID ( cgs . effects . mBobaJet , flamePos , flameDir , - 1 , - 1 ) ;
trap_FX_PlayEffectID ( cgs . effects . mBobaJet , flamePos , flameDir , - 1 , - 1 ) ;
//Keep the jet fire sound looping
trap_S_AddLoopingSound ( cent - > currentState . number , cent - > lerpOrigin , vec3_origin ,
trap_S_RegisterSound ( " sound/effects/fire_lp " ) ) ;
}
else
{ //just idling
//FIXME: Different smaller effect for idle
//Play the effect
trap_FX_PlayEffectID ( cgs . effects . mBobaJet , flamePos , flameDir , - 1 , - 1 ) ;
}
n + + ;
}
trap_S_AddLoopingSound ( cent - > currentState . number , cent - > lerpOrigin , vec3_origin ,
trap_S_RegisterSound ( " sound/boba/JETHOVER " ) ) ;
}
}
else if ( trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > ghoul2 ) , 3 ) )
{ //fixme: would be good if this could be done not every frame
trap_G2API_RemoveGhoul2Model ( & ( cent - > ghoul2 ) , 3 ) ;
}
g2HasWeapon = trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > ghoul2 ) , 1 ) ;
if ( ! g2HasWeapon )
{ //force a redup of the weapon instance onto the client instance
cent - > ghoul2weapon = NULL ;
cent - > weapon = 0 ;
}
if ( cent - > torsoBolt & & ! ( cent - > currentState . eFlags & EF_DEAD ) )
{ //he's alive and has a limb missing still, reattach it and reset the weapon
CG_ReattachLimb ( cent ) ;
}
if ( cent - > isRagging & & ! ( cent - > currentState . eFlags & EF_DEAD ) & & ! ( cent - > currentState . eFlags & EF_RAG ) )
{ //make sure we don't ragdoll ever while alive unless directly told to with eFlags
cent - > isRagging = qfalse ;
trap_G2API_SetRagDoll ( cent - > ghoul2 , NULL ) ; //calling with null parms resets to no ragdoll.
}
if ( cent - > ghoul2 & & cent - > torsoBolt & & ( ( cent - > torsoBolt & RARMBIT ) | | ( cent - > torsoBolt & RHANDBIT ) | | ( cent - > torsoBolt & WAISTBIT ) ) & & g2HasWeapon )
{ //kill the weapon if the limb holding it is no longer on the model
trap_G2API_RemoveGhoul2Model ( & ( cent - > ghoul2 ) , 1 ) ;
g2HasWeapon = qfalse ;
}
if ( ! cent - > trickAlphaTime | | ( cg . time - cent - > trickAlphaTime ) > 1000 )
{ //things got out of sync, perhaps a new client is trying to fill in this slot
cent - > trickAlpha = 255 ;
cent - > trickAlphaTime = cg . time ;
}
if ( cent - > currentState . eFlags & EF_NODRAW )
{ //If nodraw, return here
return ;
}
else if ( cent - > currentState . eFlags2 & EF2_SHIP_DEATH )
{ //died in ship, don't draw, we were "obliterated"
return ;
}
//If this client has tricked you.
if ( CG_IsMindTricked ( cent - > currentState . trickedentindex ,
cent - > currentState . trickedentindex2 ,
cent - > currentState . trickedentindex3 ,
cent - > currentState . trickedentindex4 ,
cg . snap - > ps . clientNum ) )
{
if ( cent - > trickAlpha > 1 )
{
cent - > trickAlpha - = ( cg . time - cent - > trickAlphaTime ) * 0.5 ;
cent - > trickAlphaTime = cg . time ;
if ( cent - > trickAlpha < 0 )
{
cent - > trickAlpha = 0 ;
}
doAlpha = 1 ;
}
else
{
doAlpha = 1 ;
cent - > trickAlpha = 1 ;
cent - > trickAlphaTime = cg . time ;
iwantout = 1 ;
}
}
else
{
if ( cent - > trickAlpha < 255 )
{
cent - > trickAlpha + = ( cg . time - cent - > trickAlphaTime ) ;
cent - > trickAlphaTime = cg . time ;
if ( cent - > trickAlpha > 255 )
{
cent - > trickAlpha = 255 ;
}
doAlpha = 1 ;
}
else
{
cent - > trickAlpha = 255 ;
cent - > trickAlphaTime = cg . time ;
}
}
// get the player model information
renderfx = 0 ;
if ( cent - > currentState . number = = cg . snap - > ps . clientNum ) {
if ( ! cg . renderingThirdPerson ) {
#if 0
if ( ! cg_fpls . integer | | cent - > currentState . weapon ! = WP_SABER )
# else
if ( cent - > currentState . weapon ! = WP_SABER )
# endif
{
renderfx = RF_THIRD_PERSON ; // only draw in mirrors
}
} else {
if ( cg_cameraMode . integer ) {
iwantout = 1 ;
// goto minimal_add;
// NOTENOTE Temporary
return ;
}
}
}
// Update the player's client entity information regarding weapons.
// Explanation: The entitystate has a weapond defined on it. The cliententity does as well.
// The cliententity's weapon tells us what the ghoul2 instance on the cliententity has bolted to it.
// If the entitystate and cliententity weapons differ, then the state's needs to be copied to the client.
// Save the old weapon, to verify that it is or is not the same as the new weapon.
// rww - Make sure weapons don't get set BEFORE cent->ghoul2 is initialized or else we'll have no
// weapon bolted on
if ( cent - > currentState . saberInFlight )
{
cent - > ghoul2weapon = CG_G2WeaponInstance ( cent , WP_SABER ) ;
}
if ( cent - > ghoul2 & &
( cent - > currentState . eType ! = ET_NPC | | ( cent - > currentState . NPC_class ! = CLASS_VEHICLE & & cent - > currentState . NPC_class ! = CLASS_REMOTE & & cent - > currentState . NPC_class ! = CLASS_SEEKER ) ) & & //don't add weapon models to NPCs that have no bolt for them!
cent - > ghoul2weapon ! = CG_G2WeaponInstance ( cent , cent - > currentState . weapon ) & &
! ( cent - > currentState . eFlags & EF_DEAD ) & & ! cent - > torsoBolt & &
cg . snap & & ( cent - > currentState . number ! = cg . snap - > ps . clientNum | | ( cg . snap - > ps . pm_flags & PMF_FOLLOW ) ) )
{
if ( ci - > team = = TEAM_SPECTATOR )
{
cent - > ghoul2weapon = NULL ;
cent - > weapon = 0 ;
}
else
{
CG_CopyG2WeaponInstance ( cent , cent - > currentState . weapon , cent - > ghoul2 ) ;
if ( cent - > currentState . eType ! = ET_NPC )
{
if ( cent - > weapon = = WP_SABER
& & cent - > weapon ! = cent - > currentState . weapon
& & ! cent - > currentState . saberHolstered )
{ //switching away from the saber
//trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/saber/saberoffquick.wav" ));
if ( ci - > saber [ 0 ] . soundOff
& & ! cent - > currentState . saberHolstered )
{
trap_S_StartSound ( cent - > lerpOrigin , cent - > currentState . number , CHAN_AUTO , ci - > saber [ 0 ] . soundOff ) ;
}
if ( ci - > saber [ 1 ] . soundOff & &
ci - > saber [ 1 ] . model [ 0 ] & &
! cent - > currentState . saberHolstered )
{
trap_S_StartSound ( cent - > lerpOrigin , cent - > currentState . number , CHAN_AUTO , ci - > saber [ 1 ] . soundOff ) ;
}
}
else if ( cent - > currentState . weapon = = WP_SABER
& & cent - > weapon ! = cent - > currentState . weapon
& & ! cent - > saberWasInFlight )
{ //switching to the saber
//trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/saber/saberon.wav" ));
if ( ci - > saber [ 0 ] . soundOn )
{
trap_S_StartSound ( cent - > lerpOrigin , cent - > currentState . number , CHAN_AUTO , ci - > saber [ 0 ] . soundOn ) ;
}
if ( ci - > saber [ 1 ] . soundOn )
{
trap_S_StartSound ( cent - > lerpOrigin , cent - > currentState . number , CHAN_AUTO , ci - > saber [ 1 ] . soundOn ) ;
}
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
}
}
cent - > weapon = cent - > currentState . weapon ;
cent - > ghoul2weapon = CG_G2WeaponInstance ( cent , cent - > currentState . weapon ) ;
}
}
else if ( ( cent - > currentState . eFlags & EF_DEAD ) | | cent - > torsoBolt )
{
cent - > ghoul2weapon = NULL ; //be sure to update after respawning/getting limb regrown
}
if ( cent - > saberWasInFlight & & g2HasWeapon )
{
cent - > saberWasInFlight = qfalse ;
}
memset ( & legs , 0 , sizeof ( legs ) ) ;
CG_SetGhoul2Info ( & legs , cent ) ;
VectorCopy ( cent - > modelScale , legs . modelScale ) ;
legs . radius = CG_RadiusForCent ( cent ) ;
VectorClear ( legs . angles ) ;
if ( ci - > colorOverride [ 0 ] ! = 0.0f | |
ci - > colorOverride [ 1 ] ! = 0.0f | |
ci - > colorOverride [ 2 ] ! = 0.0f )
{
legs . shaderRGBA [ 0 ] = ci - > colorOverride [ 0 ] * 255.0f ;
legs . shaderRGBA [ 1 ] = ci - > colorOverride [ 1 ] * 255.0f ;
legs . shaderRGBA [ 2 ] = ci - > colorOverride [ 2 ] * 255.0f ;
legs . shaderRGBA [ 3 ] = cent - > currentState . customRGBA [ 3 ] ;
}
else
{
legs . shaderRGBA [ 0 ] = cent - > currentState . customRGBA [ 0 ] ;
legs . shaderRGBA [ 1 ] = cent - > currentState . customRGBA [ 1 ] ;
legs . shaderRGBA [ 2 ] = cent - > currentState . customRGBA [ 2 ] ;
legs . shaderRGBA [ 3 ] = cent - > currentState . customRGBA [ 3 ] ;
}
// minimal_add:
team = ci - > team ;
if ( cgs . gametype > = GT_TEAM & & cg_drawFriend . integer & &
cent - > currentState . number ! = cg . snap - > ps . clientNum & &
cent - > currentState . eType ! = ET_NPC )
{ // If the view is either a spectator or on the same team as this character, show a symbol above their head.
if ( ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_SPECTATOR | | cg . snap - > ps . persistant [ PERS_TEAM ] = = team ) & &
! ( cent - > currentState . eFlags & EF_DEAD ) )
{
if ( cgs . gametype = = GT_SIEGE )
{ //check for per-map team shaders
if ( team = = SIEGETEAM_TEAM1 )
{
if ( cgSiegeTeam1PlShader )
{
CG_PlayerFloatSprite ( cent , cgSiegeTeam1PlShader ) ;
}
else
{ //if there isn't one fallback to default
CG_PlayerFloatSprite ( cent , cgs . media . teamRedShader ) ;
}
}
else
{
if ( cgSiegeTeam2PlShader )
{
CG_PlayerFloatSprite ( cent , cgSiegeTeam2PlShader ) ;
}
else
{ //if there isn't one fallback to default
CG_PlayerFloatSprite ( cent , cgs . media . teamBlueShader ) ;
}
}
}
else
{ //generic teamplay
if ( team = = TEAM_RED )
{
CG_PlayerFloatSprite ( cent , cgs . media . teamRedShader ) ;
}
else // if (team == TEAM_BLUE)
{
CG_PlayerFloatSprite ( cent , cgs . media . teamBlueShader ) ;
}
}
}
}
else if ( cgs . gametype = = GT_POWERDUEL & & cg_drawFriend . integer & &
cent - > currentState . number ! = cg . snap - > ps . clientNum )
{
if ( cg . predictedPlayerState . persistant [ PERS_TEAM ] ! = TEAM_SPECTATOR & &
cent - > currentState . number < MAX_CLIENTS & &
! ( cent - > currentState . eFlags & EF_DEAD ) & &
ci & &
cgs . clientinfo [ cg . snap - > ps . clientNum ] . duelTeam = = ci - > duelTeam )
{ //ally in powerduel, so draw the icon
CG_PlayerFloatSprite ( cent , cgs . media . powerDuelAllyShader ) ;
}
else if ( cg . predictedPlayerState . persistant [ PERS_TEAM ] = = TEAM_SPECTATOR & &
cent - > currentState . number < MAX_CLIENTS & &
! ( cent - > currentState . eFlags & EF_DEAD ) & &
ci - > duelTeam = = DUELTEAM_DOUBLE )
{
CG_PlayerFloatSprite ( cent , cgs . media . powerDuelAllyShader ) ;
}
}
if ( cgs . gametype = = GT_JEDIMASTER & & cg_drawFriend . integer & &
cent - > currentState . number ! = cg . snap - > ps . clientNum ) // Don't show a sprite above a player's own head in 3rd person.
{ // If the view is either a spectator or on the same team as this character, show a symbol above their head.
if ( ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_SPECTATOR | | cg . snap - > ps . persistant [ PERS_TEAM ] = = team ) & &
! ( cent - > currentState . eFlags & EF_DEAD ) )
{
if ( CG_ThereIsAMaster ( ) )
{
if ( ! cg . snap - > ps . isJediMaster )
{
if ( ! cent - > currentState . isJediMaster )
{
CG_PlayerFloatSprite ( cent , cgs . media . teamRedShader ) ;
}
}
}
}
}
// add the shadow
shadow = CG_PlayerShadow ( cent , & shadowPlane ) ;
if ( ( ( cent - > currentState . eFlags & EF_SEEKERDRONE ) | | cent - > currentState . genericenemyindex ! = - 1 ) & & cent - > currentState . eType ! = ET_NPC )
{
refEntity_t seeker ;
memset ( & seeker , 0 , sizeof ( seeker ) ) ;
VectorCopy ( cent - > lerpOrigin , elevated ) ;
elevated [ 2 ] + = 40 ;
VectorCopy ( elevated , seeker . lightingOrigin ) ;
seeker . shadowPlane = shadowPlane ;
seeker . renderfx = 0 ; //renderfx;
//don't show in first person?
angle = ( ( cg . time / 12 ) & 255 ) * ( M_PI * 2 ) / 255 ;
dir [ 0 ] = cos ( angle ) * 20 ;
dir [ 1 ] = sin ( angle ) * 20 ;
dir [ 2 ] = cos ( angle ) * 5 ;
VectorAdd ( elevated , dir , seeker . origin ) ;
VectorCopy ( seeker . origin , seekorg ) ;
if ( cent - > currentState . genericenemyindex > MAX_GENTITIES )
{
float prefig = ( cent - > currentState . genericenemyindex - cg . time ) / 80 ;
if ( prefig > 55 )
{
prefig = 55 ;
}
else if ( prefig < 1 )
{
prefig = 1 ;
}
elevated [ 2 ] - = 55 - prefig ;
angle = ( ( cg . time / 12 ) & 255 ) * ( M_PI * 2 ) / 255 ;
dir [ 0 ] = cos ( angle ) * 20 ;
dir [ 1 ] = sin ( angle ) * 20 ;
dir [ 2 ] = cos ( angle ) * 5 ;
VectorAdd ( elevated , dir , seeker . origin ) ;
}
else if ( cent - > currentState . genericenemyindex ! = ENTITYNUM_NONE & & cent - > currentState . genericenemyindex ! = - 1 )
{
centity_t * enent = & cg_entities [ cent - > currentState . genericenemyindex ] ;
if ( enent )
{
VectorSubtract ( enent - > lerpOrigin , seekorg , enang ) ;
VectorNormalize ( enang ) ;
vectoangles ( enang , angles ) ;
successchange = 1 ;
}
}
if ( ! successchange )
{
angles [ 0 ] = sin ( angle ) * 30 ;
angles [ 1 ] = ( angle * 180 / M_PI ) + 90 ;
if ( angles [ 1 ] > 360 )
angles [ 1 ] - = 360 ;
angles [ 2 ] = 0 ;
}
AnglesToAxis ( angles , seeker . axis ) ;
seeker . hModel = trap_R_RegisterModel ( " models/items/remote.md3 " ) ;
trap_R_AddRefEntityToScene ( & seeker ) ;
}
// add a water splash if partially in and out of water
CG_PlayerSplash ( cent ) ;
if ( ( cg_shadows . integer = = 3 | | cg_shadows . integer = = 2 ) & & shadow ) {
renderfx | = RF_SHADOW_PLANE ;
}
renderfx | = RF_LIGHTING_ORIGIN ; // use the same origin for all
// if we've been hit, display proper fullscreen fx
CG_PlayerHitFX ( cent ) ;
VectorCopy ( cent - > lerpOrigin , legs . origin ) ;
VectorCopy ( cent - > lerpOrigin , legs . lightingOrigin ) ;
legs . shadowPlane = shadowPlane ;
legs . renderfx = renderfx ;
if ( cg_shadows . integer = = 2 & & ( renderfx & RF_THIRD_PERSON ) )
{ //can see own shadow
legs . renderfx | = RF_SHADOW_ONLY ;
}
VectorCopy ( legs . origin , legs . oldorigin ) ; // don't positionally lerp at all
CG_G2PlayerAngles ( cent , legs . axis , rootAngles ) ;
CG_G2PlayerHeadAnims ( cent ) ;
if ( ( cent - > currentState . eFlags2 & EF2_HELD_BY_MONSTER )
& & cent - > currentState . hasLookTarget ) //NOTE: lookTarget is an entity number, so this presumes that client 0 is NOT a Rancor...
{
centity_t * rancor = & cg_entities [ cent - > currentState . lookTarget ] ;
if ( rancor )
{
BG_AttachToRancor ( rancor - > ghoul2 , //ghoul2 info
rancor - > lerpAngles [ YAW ] ,
rancor - > lerpOrigin ,
cg . time ,
cgs . gameModels ,
rancor - > modelScale ,
( rancor - > currentState . eFlags2 & EF2_GENERIC_NPC_FLAG ) ,
legs . origin ,
legs . angles ,
NULL ) ;
if ( cent - > isRagging )
{ //hack, ragdoll has you way at bottom of bounding box
VectorMA ( legs . origin , 32 , legs . axis [ 2 ] , legs . origin ) ;
}
VectorCopy ( legs . origin , legs . oldorigin ) ;
VectorCopy ( legs . origin , legs . lightingOrigin ) ;
VectorCopy ( legs . angles , cent - > lerpAngles ) ;
VectorCopy ( cent - > lerpAngles , rootAngles ) ; //??? tempAngles );//tempAngles is needed a lot below
VectorCopy ( cent - > lerpAngles , cent - > turAngles ) ;
VectorCopy ( legs . origin , cent - > lerpOrigin ) ;
}
}
//This call is mainly just to reconstruct the skeleton. But we'll get the left hand matrix while we're at it.
//If we don't reconstruct the skeleton after setting the bone angles, we will get bad bolt points on the model
//(e.g. the weapon model bolt will look "lagged") if there's no other GetBoltMatrix call for the rest of the
//frame. Yes, this is stupid and needs to be fixed properly.
//The current solution is to force it not to reconstruct the skeleton for the first GBM call in G2PlayerAngles.
//It works and we end up only reconstructing it once, but it doesn't seem like the best solution.
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_lhand , & lHandMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
gotLHandMatrix = qtrue ;
#if 0
if ( cg . renderingThirdPerson )
{
if ( cgFPLSState ! = 0 )
{
CG_ForceFPLSPlayerModel ( cent , ci ) ;
cgFPLSState = 0 ;
return ;
}
}
else if ( ci - > team = = TEAM_SPECTATOR | | ( cg . snap & & ( cg . snap - > ps . pm_flags & PMF_FOLLOW ) ) )
{ //don't allow this when spectating
if ( cgFPLSState ! = 0 )
{
trap_Cvar_Set ( " cg_fpls " , " 0 " ) ;
cg_fpls . integer = 0 ;
CG_ForceFPLSPlayerModel ( cent , ci ) ;
cgFPLSState = 0 ;
return ;
}
if ( cg_fpls . integer )
{
trap_Cvar_Set ( " cg_fpls " , " 0 " ) ;
}
}
else
{
if ( cg_fpls . integer & & cent - > currentState . weapon = = WP_SABER & & cg . snap & & cent - > currentState . number = = cg . snap - > ps . clientNum )
{
if ( cgFPLSState ! = cg_fpls . integer )
{
CG_ForceFPLSPlayerModel ( cent , ci ) ;
cgFPLSState = cg_fpls . integer ;
return ;
}
/*
mdxaBone_t headMatrix ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_head , & headMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & headMatrix , ORIGIN , cg . refdef . vieworg ) ;
*/
}
else if ( ! cg_fpls . integer & & cgFPLSState )
{
if ( cgFPLSState ! = cg_fpls . integer )
{
CG_ForceFPLSPlayerModel ( cent , ci ) ;
cgFPLSState = cg_fpls . integer ;
return ;
}
}
}
# endif
if ( cent - > currentState . eFlags & EF_DEAD )
{
dead = qtrue ;
//rww - since our angles are fixed when we're dead this shouldn't be an issue anyway
//we need to render the dying/dead player because we are now spawning the body on respawn instead of death
//return;
}
ScaleModelAxis ( & legs ) ;
memset ( & torso , 0 , sizeof ( torso ) ) ;
//rww - force speed "trail" effect
if ( ! ( cent - > currentState . powerups & ( 1 < < PW_SPEED ) ) | | doAlpha | | ! cg_speedTrail . integer )
{
cent - > frame_minus1_refreshed = 0 ;
cent - > frame_minus2_refreshed = 0 ;
}
if ( cent - > frame_minus1_refreshed | |
cent - > frame_minus2_refreshed )
{
vec3_t tDir ;
int distVelBase ;
VectorCopy ( cent - > currentState . pos . trDelta , tDir ) ;
distVelBase = SPEED_TRAIL_DISTANCE * ( VectorNormalize ( tDir ) * 0.004 ) ;
if ( cent - > frame_minus1_refreshed )
{
refEntity_t reframe_minus1 = legs ;
reframe_minus1 . renderfx | = RF_FORCE_ENT_ALPHA ;
reframe_minus1 . shaderRGBA [ 0 ] = legs . shaderRGBA [ 0 ] ;
reframe_minus1 . shaderRGBA [ 1 ] = legs . shaderRGBA [ 1 ] ;
reframe_minus1 . shaderRGBA [ 2 ] = legs . shaderRGBA [ 2 ] ;
reframe_minus1 . shaderRGBA [ 3 ] = 100 ;
//rww - if the client gets a bad framerate we will only receive frame positions
//once per frame anyway, so we might end up with speed trails very spread out.
//in order to avoid that, we'll get the direction of the last trail from the player
//and place the trail refent a set distance from the player location this frame
VectorSubtract ( cent - > frame_minus1 , legs . origin , tDir ) ;
VectorNormalize ( tDir ) ;
cent - > frame_minus1 [ 0 ] = legs . origin [ 0 ] + tDir [ 0 ] * distVelBase ;
cent - > frame_minus1 [ 1 ] = legs . origin [ 1 ] + tDir [ 1 ] * distVelBase ;
cent - > frame_minus1 [ 2 ] = legs . origin [ 2 ] + tDir [ 2 ] * distVelBase ;
VectorCopy ( cent - > frame_minus1 , reframe_minus1 . origin ) ;
//reframe_minus1.customShader = 2;
trap_R_AddRefEntityToScene ( & reframe_minus1 ) ;
}
if ( cent - > frame_minus2_refreshed )
{
refEntity_t reframe_minus2 = legs ;
reframe_minus2 . renderfx | = RF_FORCE_ENT_ALPHA ;
reframe_minus2 . shaderRGBA [ 0 ] = legs . shaderRGBA [ 0 ] ;
reframe_minus2 . shaderRGBA [ 1 ] = legs . shaderRGBA [ 1 ] ;
reframe_minus2 . shaderRGBA [ 2 ] = legs . shaderRGBA [ 2 ] ;
reframe_minus2 . shaderRGBA [ 3 ] = 50 ;
//Same as above but do it between trail points instead of the player and first trail entry
VectorSubtract ( cent - > frame_minus2 , cent - > frame_minus1 , tDir ) ;
VectorNormalize ( tDir ) ;
cent - > frame_minus2 [ 0 ] = cent - > frame_minus1 [ 0 ] + tDir [ 0 ] * distVelBase ;
cent - > frame_minus2 [ 1 ] = cent - > frame_minus1 [ 1 ] + tDir [ 1 ] * distVelBase ;
cent - > frame_minus2 [ 2 ] = cent - > frame_minus1 [ 2 ] + tDir [ 2 ] * distVelBase ;
VectorCopy ( cent - > frame_minus2 , reframe_minus2 . origin ) ;
//reframe_minus2.customShader = 2;
trap_R_AddRefEntityToScene ( & reframe_minus2 ) ;
}
}
//trigger animation-based sounds, done before next lerp frame.
CG_TriggerAnimSounds ( cent ) ;
// get the animation state (after rotation, to allow feet shuffle)
CG_PlayerAnimation ( cent , & legs . oldframe , & legs . frame , & legs . backlerp ,
& torso . oldframe , & torso . frame , & torso . backlerp ) ;
// add the talk baloon or disconnect icon
CG_PlayerSprites ( cent ) ;
if ( cent - > currentState . eFlags & EF_DEAD )
{ //keep track of death anim frame for when we copy off the bodyqueue
ci - > frame = cent - > pe . torso . frame ;
}
if ( cent - > currentState . activeForcePass > FORCE_LEVEL_3
& & cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{
vec3_t axis [ 3 ] ;
vec3_t tAng , fAng , fxDir ;
vec3_t efOrg ;
int realForceLev = ( cent - > currentState . activeForcePass - FORCE_LEVEL_3 ) ;
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
VectorSet ( fAng , cent - > pe . torso . pitchAngle , cent - > pe . torso . yawAngle , 0 ) ;
AngleVectors ( fAng , fxDir , NULL , NULL ) ;
if ( cent - > currentState . torsoAnim = = BOTH_FORCE_2HANDEDLIGHTNING_HOLD
& & Q_irand ( 0 , 1 ) )
{ //alternate back and forth between left and right
mdxaBone_t rHandMatrix ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_rhand , & rHandMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
efOrg [ 0 ] = rHandMatrix . matrix [ 0 ] [ 3 ] ;
efOrg [ 1 ] = rHandMatrix . matrix [ 1 ] [ 3 ] ;
efOrg [ 2 ] = rHandMatrix . matrix [ 2 ] [ 3 ] ;
}
else
{
//trap_G2API_GetBoltMatrix(cent->ghoul2, 0, ci->bolt_lhand, &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
if ( ! gotLHandMatrix )
{
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_lhand , & lHandMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
gotLHandMatrix = qtrue ;
}
efOrg [ 0 ] = lHandMatrix . matrix [ 0 ] [ 3 ] ;
efOrg [ 1 ] = lHandMatrix . matrix [ 1 ] [ 3 ] ;
efOrg [ 2 ] = lHandMatrix . matrix [ 2 ] [ 3 ] ;
}
AnglesToAxis ( fAng , axis ) ;
if ( realForceLev > FORCE_LEVEL_2 )
{ //arc
//trap_FX_PlayEffectID( cgs.effects.forceLightningWide, efOrg, fxDir );
//trap_FX_PlayEntityEffectID(cgs.effects.forceDrainWide, efOrg, axis, cent->boltInfo, cent->currentState.number, -1, -1);
trap_FX_PlayEntityEffectID ( cgs . effects . forceDrainWide , efOrg , axis , - 1 , - 1 , - 1 , - 1 ) ;
}
else
{ //line
//trap_FX_PlayEffectID( cgs.effects.forceLightning, efOrg, fxDir );
//trap_FX_PlayEntityEffectID(cgs.effects.forceDrain, efOrg, axis, cent->boltInfo, cent->currentState.number, -1, -1);
trap_FX_PlayEntityEffectID ( cgs . effects . forceDrain , efOrg , axis , - 1 , - 1 , - 1 , - 1 ) ;
}
/*
if ( cent - > bolt4 < cg . time )
{
cent - > bolt4 = cg . time + 100 ;
trap_S_StartSound ( NULL , cent - > currentState . number , CHAN_AUTO , trap_S_RegisterSound ( " sound/weapons/force/drain.wav " ) ) ;
}
*/
}
else if ( cent - > currentState . activeForcePass
& & cent - > currentState . NPC_class ! = CLASS_VEHICLE )
{ //doing the electrocuting
vec3_t axis [ 3 ] ;
vec3_t tAng , fAng , fxDir ;
vec3_t efOrg ;
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
VectorSet ( fAng , cent - > pe . torso . pitchAngle , cent - > pe . torso . yawAngle , 0 ) ;
AngleVectors ( fAng , fxDir , NULL , NULL ) ;
//trap_G2API_GetBoltMatrix(cent->ghoul2, 0, ci->bolt_lhand, &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
if ( ! gotLHandMatrix )
{
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_lhand , & lHandMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
gotLHandMatrix = qtrue ;
}
efOrg [ 0 ] = lHandMatrix . matrix [ 0 ] [ 3 ] ;
efOrg [ 1 ] = lHandMatrix . matrix [ 1 ] [ 3 ] ;
efOrg [ 2 ] = lHandMatrix . matrix [ 2 ] [ 3 ] ;
AnglesToAxis ( fAng , axis ) ;
if ( cent - > currentState . activeForcePass > FORCE_LEVEL_2 )
{ //arc
//trap_FX_PlayEffectID( cgs.effects.forceLightningWide, efOrg, fxDir );
//trap_FX_PlayEntityEffectID(cgs.effects.forceLightningWide, efOrg, axis, cent->boltInfo, cent->currentState.number, -1, -1);
trap_FX_PlayEntityEffectID ( cgs . effects . forceLightningWide , efOrg , axis , - 1 , - 1 , - 1 , - 1 ) ;
}
else
{ //line
//trap_FX_PlayEffectID( cgs.effects.forceLightning, efOrg, fxDir );
//trap_FX_PlayEntityEffectID(cgs.effects.forceLightning, efOrg, axis, cent->boltInfo, cent->currentState.number, -1, -1);
trap_FX_PlayEntityEffectID ( cgs . effects . forceLightning , efOrg , axis , - 1 , - 1 , - 1 , - 1 ) ;
}
/*
if ( cent - > bolt4 < cg . time )
{
cent - > bolt4 = cg . time + 100 ;
trap_S_StartSound ( NULL , cent - > currentState . number , CHAN_AUTO , trap_S_RegisterSound ( " sound/weapons/force/lightning.wav " ) ) ;
}
*/
}
//fullbody push effect
if ( cent - > currentState . eFlags & EF_BODYPUSH )
{
CG_ForcePushBodyBlur ( cent ) ;
}
if ( cent - > currentState . powerups & ( 1 < < PW_DISINT_4 ) )
{
vec3_t tAng ;
vec3_t efOrg ;
//VectorSet( tAng, 0, cent->pe.torso.yawAngle, 0 );
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
//trap_G2API_GetBoltMatrix(cent->ghoul2, 0, ci->bolt_lhand, &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
if ( ! gotLHandMatrix )
{
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_lhand , & lHandMatrix , cent - > turAngles , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
gotLHandMatrix = qtrue ;
}
efOrg [ 0 ] = lHandMatrix . matrix [ 0 ] [ 3 ] ;
efOrg [ 1 ] = lHandMatrix . matrix [ 1 ] [ 3 ] ;
efOrg [ 2 ] = lHandMatrix . matrix [ 2 ] [ 3 ] ;
if ( ( cent - > currentState . forcePowersActive & ( 1 < < FP_GRIP ) ) & &
( cg . renderingThirdPerson | | cent - > currentState . number ! = cg . snap - > ps . clientNum ) )
{
vec3_t boltDir ;
vec3_t origBolt ;
VectorCopy ( efOrg , origBolt ) ;
BG_GiveMeVectorFromMatrix ( & lHandMatrix , NEGATIVE_Y , boltDir ) ;
CG_ForceGripEffect ( efOrg ) ;
CG_ForceGripEffect ( efOrg ) ;
/*
//Render a scaled version of the model's hand with a n337 looking shader
{
const char * rotateBone ;
char * limbName ;
char * limbCapName ;
vec3_t armAng ;
refEntity_t regrip_arm ;
float wv = sin ( cg . time * 0.003f ) * 0.08f + 0.1f ;
//rotateBone = "lradius";
rotateBone = " lradiusX " ;
limbName = " l_arm " ;
limbCapName = " l_arm_cap_torso " ;
if ( cent - > grip_arm & & trap_G2_HaveWeGhoul2Models ( cent - > grip_arm ) )
{
trap_G2API_CleanGhoul2Models ( & ( cent - > grip_arm ) ) ;
}
memset ( & regrip_arm , 0 , sizeof ( regrip_arm ) ) ;
VectorCopy ( origBolt , efOrg ) ;
//efOrg[2] += 8;
efOrg [ 2 ] - = 4 ;
VectorCopy ( efOrg , regrip_arm . origin ) ;
VectorCopy ( regrip_arm . origin , regrip_arm . lightingOrigin ) ;
//VectorCopy(cent->lerpAngles, armAng);
VectorAdd ( vec3_origin , rootAngles , armAng ) ;
//armAng[ROLL] = -90;
armAng [ ROLL ] = 0 ;
armAng [ PITCH ] = 0 ;
AnglesToAxis ( armAng , regrip_arm . axis ) ;
trap_G2API_DuplicateGhoul2Instance ( cent - > ghoul2 , & cent - > grip_arm ) ;
//remove all other models
if ( trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > grip_arm ) , 1 ) )
{ //weapon right
trap_G2API_RemoveGhoul2Model ( & ( cent - > grip_arm ) , 1 ) ;
}
if ( trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > grip_arm ) , 2 ) )
{ //weapon left
trap_G2API_RemoveGhoul2Model ( & ( cent - > grip_arm ) , 2 ) ;
}
if ( trap_G2API_HasGhoul2ModelOnIndex ( & ( cent - > grip_arm ) , 3 ) )
{ //jetpack
trap_G2API_RemoveGhoul2Model ( & ( cent - > grip_arm ) , 3 ) ;
}
trap_G2API_SetRootSurface ( cent - > grip_arm , 0 , limbName ) ;
trap_G2API_SetNewOrigin ( cent - > grip_arm , trap_G2API_AddBolt ( cent - > grip_arm , 0 , rotateBone ) ) ;
trap_G2API_SetSurfaceOnOff ( cent - > grip_arm , limbCapName , 0 ) ;
regrip_arm . modelScale [ 0 ] = 1 ; //+(wv*6);
regrip_arm . modelScale [ 1 ] = 1 ; //+(wv*6);
regrip_arm . modelScale [ 2 ] = 1 ; //+(wv*6);
ScaleModelAxis ( & regrip_arm ) ;
regrip_arm . radius = 64 ;
regrip_arm . customShader = trap_R_RegisterShader ( " gfx/misc/red_portashield " ) ;
regrip_arm . renderfx | = RF_RGB_TINT ;
regrip_arm . shaderRGBA [ 0 ] = 255 - ( wv * 900 ) ;
if ( regrip_arm . shaderRGBA [ 0 ] < 30 )
{
regrip_arm . shaderRGBA [ 0 ] = 30 ;
}
if ( regrip_arm . shaderRGBA [ 0 ] > 255 )
{
regrip_arm . shaderRGBA [ 0 ] = 255 ;
}
regrip_arm . shaderRGBA [ 1 ] = regrip_arm . shaderRGBA [ 2 ] = regrip_arm . shaderRGBA [ 0 ] ;
regrip_arm . ghoul2 = cent - > grip_arm ;
trap_R_AddRefEntityToScene ( & regrip_arm ) ;
}
*/
}
else if ( ! ( cent - > currentState . forcePowersActive & ( 1 < < FP_GRIP ) ) )
{
//use refractive effect
CG_ForcePushBlur ( efOrg , cent ) ;
}
}
else if ( cent - > bodyFadeTime )
{ //reset the counter for keeping track of push refraction effect state
cent - > bodyFadeTime = 0 ;
}
if ( cent - > currentState . weapon = = WP_STUN_BATON & & cent - > currentState . number = = cg . snap - > ps . clientNum )
{
trap_S_AddLoopingSound ( cent - > currentState . number , cg . refdef . vieworg , vec3_origin ,
trap_S_RegisterSound ( " sound/weapons/baton/idle.wav " ) ) ;
}
//NOTE: All effects that should be visible during mindtrick should go above here
if ( iwantout )
{
goto stillDoSaber ;
//return;
}
else if ( doAlpha )
{
legs . renderfx | = RF_FORCE_ENT_ALPHA ;
legs . shaderRGBA [ 3 ] = cent - > trickAlpha ;
if ( legs . shaderRGBA [ 3 ] < 1 )
{ //don't cancel it out even if it's < 1
legs . shaderRGBA [ 3 ] = 1 ;
}
}
if ( cent - > teamPowerEffectTime > cg . time )
{
if ( cent - > teamPowerType = = 3 )
{ //absorb is a somewhat different effect entirely
//Guess I'll take care of it where it's always been, just checking these values instead.
}
else
{
vec4_t preCol ;
int preRFX ;
preRFX = legs . renderfx ;
legs . renderfx | = RF_RGB_TINT ;
legs . renderfx | = RF_FORCE_ENT_ALPHA ;
preCol [ 0 ] = legs . shaderRGBA [ 0 ] ;
preCol [ 1 ] = legs . shaderRGBA [ 1 ] ;
preCol [ 2 ] = legs . shaderRGBA [ 2 ] ;
preCol [ 3 ] = legs . shaderRGBA [ 3 ] ;
if ( cent - > teamPowerType = = 1 )
{ //heal
legs . shaderRGBA [ 0 ] = 0 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 0 ;
}
else if ( cent - > teamPowerType = = 0 )
{ //regen
legs . shaderRGBA [ 0 ] = 0 ;
legs . shaderRGBA [ 1 ] = 0 ;
legs . shaderRGBA [ 2 ] = 255 ;
}
else
{ //drain
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 0 ;
legs . shaderRGBA [ 2 ] = 0 ;
}
legs . shaderRGBA [ 3 ] = ( ( cent - > teamPowerEffectTime - cg . time ) / 8 ) ;
legs . customShader = trap_R_RegisterShader ( " powerups/ysalimarishell " ) ;
trap_R_AddRefEntityToScene ( & legs ) ;
legs . customShader = 0 ;
legs . renderfx = preRFX ;
legs . shaderRGBA [ 0 ] = preCol [ 0 ] ;
legs . shaderRGBA [ 1 ] = preCol [ 1 ] ;
legs . shaderRGBA [ 2 ] = preCol [ 2 ] ;
legs . shaderRGBA [ 3 ] = preCol [ 3 ] ;
}
}
//If you've tricked this client.
if ( CG_IsMindTricked ( cg . snap - > ps . fd . forceMindtrickTargetIndex ,
cg . snap - > ps . fd . forceMindtrickTargetIndex2 ,
cg . snap - > ps . fd . forceMindtrickTargetIndex3 ,
cg . snap - > ps . fd . forceMindtrickTargetIndex4 ,
cent - > currentState . number ) )
{
if ( cent - > ghoul2 )
{
vec3_t efOrg ;
vec3_t tAng , fxAng ;
vec3_t axis [ 3 ] ;
//VectorSet( tAng, 0, cent->pe.torso.yawAngle, 0 );
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_head , & boltMatrix , tAng , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , efOrg ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_Y , fxAng ) ;
axis [ 0 ] [ 0 ] = boltMatrix . matrix [ 0 ] [ 0 ] ;
axis [ 0 ] [ 1 ] = boltMatrix . matrix [ 1 ] [ 0 ] ;
axis [ 0 ] [ 2 ] = boltMatrix . matrix [ 2 ] [ 0 ] ;
axis [ 1 ] [ 0 ] = boltMatrix . matrix [ 0 ] [ 1 ] ;
axis [ 1 ] [ 1 ] = boltMatrix . matrix [ 1 ] [ 1 ] ;
axis [ 1 ] [ 2 ] = boltMatrix . matrix [ 2 ] [ 1 ] ;
axis [ 2 ] [ 0 ] = boltMatrix . matrix [ 0 ] [ 2 ] ;
axis [ 2 ] [ 1 ] = boltMatrix . matrix [ 1 ] [ 2 ] ;
axis [ 2 ] [ 2 ] = boltMatrix . matrix [ 2 ] [ 2 ] ;
//trap_FX_PlayEntityEffectID(trap_FX_RegisterEffect("force/confusion.efx"), efOrg, axis, cent->boltInfo, cent->currentState.number);
trap_FX_PlayEntityEffectID ( cgs . effects . mForceConfustionOld , efOrg , axis , - 1 , - 1 , - 1 , - 1 ) ;
}
}
if ( cgs . gametype = = GT_HOLOCRON & & cent - > currentState . time2 & & ( cg . renderingThirdPerson | | cg . snap - > ps . clientNum ! = cent - > currentState . number ) )
{
int i = 0 ;
int renderedHolos = 0 ;
refEntity_t holoRef ;
while ( i < NUM_FORCE_POWERS & & renderedHolos < 3 )
{
if ( cent - > currentState . time2 & ( 1 < < i ) )
{
memset ( & holoRef , 0 , sizeof ( holoRef ) ) ;
VectorCopy ( cent - > lerpOrigin , elevated ) ;
elevated [ 2 ] + = 8 ;
VectorCopy ( elevated , holoRef . lightingOrigin ) ;
holoRef . shadowPlane = shadowPlane ;
holoRef . renderfx = 0 ; //RF_THIRD_PERSON;
if ( renderedHolos = = 0 )
{
angle = ( ( cg . time / 8 ) & 255 ) * ( M_PI * 2 ) / 255 ;
dir [ 0 ] = cos ( angle ) * 20 ;
dir [ 1 ] = sin ( angle ) * 20 ;
dir [ 2 ] = cos ( angle ) * 20 ;
VectorAdd ( elevated , dir , holoRef . origin ) ;
angles [ 0 ] = sin ( angle ) * 30 ;
angles [ 1 ] = ( angle * 180 / M_PI ) + 90 ;
if ( angles [ 1 ] > 360 )
angles [ 1 ] - = 360 ;
angles [ 2 ] = 0 ;
AnglesToAxis ( angles , holoRef . axis ) ;
}
else if ( renderedHolos = = 1 )
{
angle = ( ( cg . time / 8 ) & 255 ) * ( M_PI * 2 ) / 255 + M_PI ;
if ( angle > M_PI * 2 )
angle - = ( float ) M_PI * 2 ;
dir [ 0 ] = sin ( angle ) * 20 ;
dir [ 1 ] = cos ( angle ) * 20 ;
dir [ 2 ] = cos ( angle ) * 20 ;
VectorAdd ( elevated , dir , holoRef . origin ) ;
angles [ 0 ] = cos ( angle - 0.5 * M_PI ) * 30 ;
angles [ 1 ] = 360 - ( angle * 180 / M_PI ) ;
if ( angles [ 1 ] > 360 )
angles [ 1 ] - = 360 ;
angles [ 2 ] = 0 ;
AnglesToAxis ( angles , holoRef . axis ) ;
}
else
{
angle = ( ( cg . time / 6 ) & 255 ) * ( M_PI * 2 ) / 255 + 0.5 * M_PI ;
if ( angle > M_PI * 2 )
angle - = ( float ) M_PI * 2 ;
dir [ 0 ] = sin ( angle ) * 20 ;
dir [ 1 ] = cos ( angle ) * 20 ;
dir [ 2 ] = 0 ;
VectorAdd ( elevated , dir , holoRef . origin ) ;
VectorCopy ( dir , holoRef . axis [ 1 ] ) ;
VectorNormalize ( holoRef . axis [ 1 ] ) ;
VectorSet ( holoRef . axis [ 2 ] , 0 , 0 , 1 ) ;
CrossProduct ( holoRef . axis [ 1 ] , holoRef . axis [ 2 ] , holoRef . axis [ 0 ] ) ;
}
holoRef . modelScale [ 0 ] = 0.5 ;
holoRef . modelScale [ 1 ] = 0.5 ;
holoRef . modelScale [ 2 ] = 0.5 ;
ScaleModelAxis ( & holoRef ) ;
{
float wv ;
addspriteArgStruct_t fxSArgs ;
vec3_t holoCenter ;
holoCenter [ 0 ] = holoRef . origin [ 0 ] + holoRef . axis [ 2 ] [ 0 ] * 18 ;
holoCenter [ 1 ] = holoRef . origin [ 1 ] + holoRef . axis [ 2 ] [ 1 ] * 18 ;
holoCenter [ 2 ] = holoRef . origin [ 2 ] + holoRef . axis [ 2 ] [ 2 ] * 18 ;
wv = sin ( cg . time * 0.004f ) * 0.08f + 0.1f ;
VectorCopy ( holoCenter , fxSArgs . origin ) ;
VectorClear ( fxSArgs . vel ) ;
VectorClear ( fxSArgs . accel ) ;
fxSArgs . scale = wv * 60 ;
fxSArgs . dscale = wv * 60 ;
fxSArgs . sAlpha = wv * 12 ;
fxSArgs . eAlpha = wv * 12 ;
fxSArgs . rotation = 0.0f ;
fxSArgs . bounce = 0.0f ;
fxSArgs . life = 1.0f ;
fxSArgs . flags = 0x08000000 | 0x00000001 ;
if ( forcePowerDarkLight [ i ] = = FORCE_DARKSIDE )
{ //dark
fxSArgs . sAlpha * = 3 ;
fxSArgs . eAlpha * = 3 ;
fxSArgs . shader = cgs . media . redSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
}
else if ( forcePowerDarkLight [ i ] = = FORCE_LIGHTSIDE )
{ //light
fxSArgs . sAlpha * = 1.5 ;
fxSArgs . eAlpha * = 1.5 ;
fxSArgs . shader = cgs . media . redSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
fxSArgs . shader = cgs . media . greenSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
fxSArgs . shader = cgs . media . blueSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
}
else
{ //neutral
if ( i = = FP_SABER_OFFENSE | |
i = = FP_SABER_DEFENSE | |
i = = FP_SABERTHROW )
{ //saber power
fxSArgs . sAlpha * = 1.5 ;
fxSArgs . eAlpha * = 1.5 ;
fxSArgs . shader = cgs . media . greenSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
}
else
{
fxSArgs . sAlpha * = 0.5 ;
fxSArgs . eAlpha * = 0.5 ;
fxSArgs . shader = cgs . media . greenSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
fxSArgs . shader = cgs . media . blueSaberGlowShader ;
trap_FX_AddSprite ( & fxSArgs ) ;
}
}
}
holoRef . hModel = trap_R_RegisterModel ( forceHolocronModels [ i ] ) ;
trap_R_AddRefEntityToScene ( & holoRef ) ;
renderedHolos + + ;
}
i + + ;
}
}
if ( ( cent - > currentState . powerups & ( 1 < < PW_YSALAMIRI ) ) | |
( cgs . gametype = = GT_CTY & & ( ( cent - > currentState . powerups & ( 1 < < PW_REDFLAG ) ) | | ( cent - > currentState . powerups & ( 1 < < PW_BLUEFLAG ) ) ) ) )
{
if ( cgs . gametype = = GT_CTY & & ( cent - > currentState . powerups & ( 1 < < PW_REDFLAG ) ) )
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 1.4f , cgs . media . ysaliredShader ) ;
}
else if ( cgs . gametype = = GT_CTY & & ( cent - > currentState . powerups & ( 1 < < PW_BLUEFLAG ) ) )
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 1.4f , cgs . media . ysaliblueShader ) ;
}
else
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 1.4f , cgs . media . ysalimariShader ) ;
}
}
if ( cent - > currentState . powerups & ( 1 < < PW_FORCE_BOON ) )
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 2.0f , cgs . media . boonShader ) ;
}
if ( cent - > currentState . powerups & ( 1 < < PW_FORCE_ENLIGHTENED_DARK ) )
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 2.0f , cgs . media . endarkenmentShader ) ;
}
else if ( cent - > currentState . powerups & ( 1 < < PW_FORCE_ENLIGHTENED_LIGHT ) )
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 2.0f , cgs . media . enlightenmentShader ) ;
}
if ( cent - > currentState . eFlags & EF_INVULNERABLE )
{
CG_DrawPlayerSphere ( cent , cent - > lerpOrigin , 1.0f , cgs . media . invulnerabilityShader ) ;
}
stillDoSaber :
if ( ( cent - > currentState . eFlags & EF_DEAD ) & & cent - > currentState . weapon = = WP_SABER )
{
//cent->saberLength = 0;
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
drawPlayerSaber = qtrue ;
}
else if ( cent - > currentState . weapon = = WP_SABER
& & cent - > currentState . saberHolstered < 2 )
{
if ( ( ! cent - > currentState . saberInFlight //saber not in flight
| | ci - > saber [ 1 ] . soundLoop ) //???
& & ! ( cent - > currentState . eFlags & EF_DEAD ) ) //still alive
{
vec3_t soundSpot ;
qboolean didFirstSound = qfalse ;
if ( cg . snap - > ps . clientNum = = cent - > currentState . number )
{
//trap_S_AddLoopingSound( cent->currentState.number, cg.refdef.vieworg, vec3_origin,
// trap_S_RegisterSound( "sound/weapons/saber/saberhum1.wav" ) );
VectorCopy ( cg . refdef . vieworg , soundSpot ) ;
}
else
{
//trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
// trap_S_RegisterSound( "sound/weapons/saber/saberhum1.wav" ) );
VectorCopy ( cent - > lerpOrigin , soundSpot ) ;
}
if ( ci - > saber [ 0 ] . model [ 0 ]
& & ci - > saber [ 0 ] . soundLoop
& & ! cent - > currentState . saberInFlight )
{
int i = 0 ;
qboolean hasLen = qfalse ;
while ( i < ci - > saber [ 0 ] . numBlades )
{
if ( ci - > saber [ 0 ] . blade [ i ] . length )
{
hasLen = qtrue ;
break ;
}
i + + ;
}
if ( hasLen )
{
trap_S_AddLoopingSound ( cent - > currentState . number , soundSpot , vec3_origin ,
ci - > saber [ 0 ] . soundLoop ) ;
didFirstSound = qtrue ;
}
}
if ( ci - > saber [ 1 ] . model [ 0 ]
& & ci - > saber [ 1 ] . soundLoop
& & ( ! didFirstSound | | ci - > saber [ 0 ] . soundLoop ! = ci - > saber [ 1 ] . soundLoop ) )
{
int i = 0 ;
qboolean hasLen = qfalse ;
while ( i < ci - > saber [ 1 ] . numBlades )
{
if ( ci - > saber [ 1 ] . blade [ i ] . length )
{
hasLen = qtrue ;
break ;
}
i + + ;
}
if ( hasLen )
{
trap_S_AddLoopingSound ( cent - > currentState . number , soundSpot , vec3_origin ,
ci - > saber [ 1 ] . soundLoop ) ;
}
}
}
if ( iwantout
& & ! cent - > currentState . saberInFlight )
{
if ( cent - > currentState . eFlags & EF_DEAD )
{
if ( cent - > ghoul2
& & cent - > currentState . saberInFlight
& & g2HasWeapon )
{ //special case, kill the saber on a freshly dead player if another source says to.
trap_G2API_RemoveGhoul2Model ( & ( cent - > ghoul2 ) , 1 ) ;
g2HasWeapon = qfalse ;
}
}
return ;
//goto endOfCall;
}
if ( g2HasWeapon
& & cent - > currentState . saberInFlight )
{ //keep this set, so we don't re-unholster the thing when we get it back, even if it's knocked away.
cent - > saberWasInFlight = qtrue ;
}
if ( cent - > currentState . saberInFlight
& & cent - > currentState . saberEntityNum )
{
centity_t * saberEnt ;
saberEnt = & cg_entities [ cent - > currentState . saberEntityNum ] ;
if ( /*!cent->bolt4 &&*/ g2HasWeapon | | ! cent - > bolt3 | |
saberEnt - > serverSaberHitIndex ! = saberEnt - > currentState . modelindex /*|| !cent->saberLength*/ )
{ //saber is in flight, do not have it as a standard weapon model
qboolean addBolts = qfalse ;
mdxaBone_t boltMat ;
if ( g2HasWeapon )
{
//ah well, just stick it over the right hand right now.
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_rhand , & boltMat , cent - > turAngles , cent - > lerpOrigin ,
cg . time , cgs . gameModels , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMat , ORIGIN , saberEnt - > currentState . pos . trBase ) ;
trap_G2API_RemoveGhoul2Model ( & ( cent - > ghoul2 ) , 1 ) ;
g2HasWeapon = qfalse ;
}
//cent->bolt4 = 1;
saberEnt - > currentState . pos . trTime = cg . time ;
saberEnt - > currentState . apos . trTime = cg . time ;
VectorCopy ( saberEnt - > currentState . pos . trBase , saberEnt - > lerpOrigin ) ;
VectorCopy ( saberEnt - > currentState . apos . trBase , saberEnt - > lerpAngles ) ;
cent - > bolt3 = saberEnt - > currentState . apos . trBase [ 0 ] ;
if ( ! cent - > bolt3 )
{
cent - > bolt3 = 1 ;
}
cent - > bolt2 = 0 ;
saberEnt - > currentState . bolt2 = 123 ;
if ( saberEnt - > ghoul2 & &
saberEnt - > serverSaberHitIndex = = saberEnt - > currentState . modelindex )
{
// now set up the gun bolt on it
addBolts = qtrue ;
}
else
{
const char * saberModel = CG_ConfigString ( CS_MODELS + saberEnt - > currentState . modelindex ) ;
saberEnt - > serverSaberHitIndex = saberEnt - > currentState . modelindex ;
if ( saberEnt - > ghoul2 )
{ //clean if we already have one (because server changed model string index)
trap_G2API_CleanGhoul2Models ( & ( saberEnt - > ghoul2 ) ) ;
saberEnt - > ghoul2 = 0 ;
}
if ( saberModel & & saberModel [ 0 ] )
{
trap_G2API_InitGhoul2Model ( & saberEnt - > ghoul2 , saberModel , 0 , 0 , 0 , 0 , 0 ) ;
}
else if ( ci - > saber [ 0 ] . model [ 0 ] )
{
trap_G2API_InitGhoul2Model ( & saberEnt - > ghoul2 , ci - > saber [ 0 ] . model , 0 , 0 , 0 , 0 , 0 ) ;
}
else
{
trap_G2API_InitGhoul2Model ( & saberEnt - > ghoul2 , " models/weapons2/saber/saber_w.glm " , 0 , 0 , 0 , 0 , 0 ) ;
}
//trap_G2API_DuplicateGhoul2Instance(cent->ghoul2, &saberEnt->ghoul2);
if ( saberEnt - > ghoul2 )
{
addBolts = qtrue ;
//cent->bolt4 = 2;
VectorCopy ( saberEnt - > currentState . pos . trBase , saberEnt - > lerpOrigin ) ;
VectorCopy ( saberEnt - > currentState . apos . trBase , saberEnt - > lerpAngles ) ;
saberEnt - > currentState . pos . trTime = cg . time ;
saberEnt - > currentState . apos . trTime = cg . time ;
}
}
if ( addBolts )
{
int m = 0 ;
int tagBolt ;
char * tagName ;
while ( m < ci - > saber [ 0 ] . numBlades )
{
tagName = va ( " *blade%i " , m + 1 ) ;
tagBolt = trap_G2API_AddBolt ( saberEnt - > ghoul2 , 0 , tagName ) ;
if ( tagBolt = = - 1 )
{
if ( m = = 0 )
{ //guess this is an 0ldsk3wl saber
tagBolt = trap_G2API_AddBolt ( saberEnt - > ghoul2 , 0 , " *flash " ) ;
if ( tagBolt = = - 1 )
{
assert ( 0 ) ;
}
break ;
}
if ( tagBolt = = - 1 )
{
assert ( 0 ) ;
break ;
}
}
m + + ;
}
}
}
/*else if (cent->bolt4 != 2)
{
if ( saberEnt - > ghoul2 )
{
trap_G2API_AddBolt ( saberEnt - > ghoul2 , 0 , " *flash " ) ;
cent - > bolt4 = 2 ;
}
} */
if ( saberEnt & & saberEnt - > ghoul2 /*&& cent->bolt4 == 2*/ )
{
vec3_t bladeAngles ;
vec3_t tAng ;
vec3_t efOrg ;
float wv ;
int k = 0 ;
int l = 0 ;
addspriteArgStruct_t fxSArgs ;
if ( ! cent - > bolt2 )
{
cent - > bolt2 = cg . time ;
}
if ( cent - > bolt3 ! = 90 )
{
if ( cent - > bolt3 < 90 )
{
cent - > bolt3 + = ( cg . time - cent - > bolt2 ) * 0.5 ;
if ( cent - > bolt3 > 90 )
{
cent - > bolt3 = 90 ;
}
}
else if ( cent - > bolt3 > 90 )
{
cent - > bolt3 - = ( cg . time - cent - > bolt2 ) * 0.5 ;
if ( cent - > bolt3 < 90 )
{
cent - > bolt3 = 90 ;
}
}
}
cent - > bolt2 = cg . time ;
saberEnt - > currentState . apos . trBase [ 0 ] = cent - > bolt3 ;
saberEnt - > lerpAngles [ 0 ] = cent - > bolt3 ;
if ( ! saberEnt - > currentState . saberInFlight & & saberEnt - > currentState . bolt2 ! = 123 )
{ //owner is pulling is back
if ( ! ( ci - > saber [ 0 ] . saberFlags & SFL_RETURN_DAMAGE )
| | cent - > currentState . saberHolstered )
{
vec3_t owndir ;
VectorSubtract ( saberEnt - > lerpOrigin , cent - > lerpOrigin , owndir ) ;
VectorNormalize ( owndir ) ;
vectoangles ( owndir , owndir ) ;
owndir [ 0 ] + = 90 ;
VectorCopy ( owndir , saberEnt - > currentState . apos . trBase ) ;
VectorCopy ( owndir , saberEnt - > lerpAngles ) ;
VectorClear ( saberEnt - > currentState . apos . trDelta ) ;
}
}
//We don't actually want to rely entirely on server updates to render the position of the saber, because we actually know generally where
//it's going to be before the first position update even gets here, and it needs to start getting rendered the instant the saber model is
//removed from the player hand. So we'll just render it manually and let normal rendering for the entity be ignored.
if ( ! saberEnt - > currentState . saberInFlight & & saberEnt - > currentState . bolt2 ! = 123 )
{ //tell it that we're a saber and to render the glow around our handle because we're being pulled back
saberEnt - > bolt3 = 999 ;
}
saberEnt - > currentState . modelGhoul2 = 1 ;
CG_ManualEntityRender ( saberEnt ) ;
saberEnt - > bolt3 = 0 ;
saberEnt - > currentState . modelGhoul2 = 127 ;
VectorCopy ( saberEnt - > lerpAngles , bladeAngles ) ;
bladeAngles [ ROLL ] = 0 ;
if ( ci - > saber [ 0 ] . numBlades > 1 //staff
& & cent - > currentState . saberHolstered = = 1 ) //extra blades off
{ //only first blade should be on
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , - 1 , 0 ) ;
}
else
{
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , - 1 , - 1 ) ;
}
if ( ci - > saber [ 1 ] . model //dual sabers
& & cent - > currentState . saberHolstered = = 1 ) //second one off
{
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
}
else
{
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , - 1 , - 1 ) ;
}
//while (l < MAX_SABERS)
//Only want to do for the first saber actually, it's the one in flight.
while ( l < 1 )
{
if ( ! ci - > saber [ l ] . model [ 0 ] )
{
break ;
}
k = 0 ;
while ( k < ci - > saber [ l ] . numBlades )
{
if ( //cent->currentState.fireflag == SS_STAFF&& //in saberstaff style
l = = 0 //first saber
& & cent - > currentState . saberHolstered = = 1 //extra blades should be off
& & k > 0 ) //this is an extra blade
{ //extra blades off
//don't draw them
CG_AddSaberBlade ( cent , saberEnt , NULL , 0 , 0 , l , k , saberEnt - > lerpOrigin , bladeAngles , qtrue , qtrue ) ;
}
else
{
CG_AddSaberBlade ( cent , saberEnt , NULL , 0 , 0 , l , k , saberEnt - > lerpOrigin , bladeAngles , qtrue , qfalse ) ;
}
k + + ;
}
if ( ci - > saber [ l ] . numBlades > 2 )
{ //add a single glow for the saber based on all the blade colors combined
CG_DoSaberLight ( & ci - > saber [ l ] ) ;
}
l + + ;
}
//Make the player's hand glow while guiding the saber
VectorSet ( tAng , cent - > turAngles [ PITCH ] , cent - > turAngles [ YAW ] , cent - > turAngles [ ROLL ] ) ;
trap_G2API_GetBoltMatrix ( cent - > ghoul2 , 0 , ci - > bolt_rhand , & boltMatrix , tAng , cent - > lerpOrigin , cg . time , cgs . gameModels , cent - > modelScale ) ;
efOrg [ 0 ] = boltMatrix . matrix [ 0 ] [ 3 ] ;
efOrg [ 1 ] = boltMatrix . matrix [ 1 ] [ 3 ] ;
efOrg [ 2 ] = boltMatrix . matrix [ 2 ] [ 3 ] ;
wv = sin ( cg . time * 0.003f ) * 0.08f + 0.1f ;
//trap_FX_AddSprite( NULL, efOrg, NULL, NULL, 8.0f, 8.0f, wv, wv, 0.0f, 0.0f, 1.0f, cgs.media.yellowSaberGlowShader, 0x08000000 );
VectorCopy ( efOrg , fxSArgs . origin ) ;
VectorClear ( fxSArgs . vel ) ;
VectorClear ( fxSArgs . accel ) ;
fxSArgs . scale = 8.0f ;
fxSArgs . dscale = 8.0f ;
fxSArgs . sAlpha = wv ;
fxSArgs . eAlpha = wv ;
fxSArgs . rotation = 0.0f ;
fxSArgs . bounce = 0.0f ;
fxSArgs . life = 1.0f ;
fxSArgs . shader = cgs . media . yellowDroppedSaberShader ;
fxSArgs . flags = 0x08000000 ;
trap_FX_AddSprite ( & fxSArgs ) ;
}
}
else
{
if ( ci - > saber [ 0 ] . numBlades > 1 //staff
& & cent - > currentState . saberHolstered = = 1 ) //extra blades off
{ //only first blade should be on
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , - 1 , 0 ) ;
}
else
{
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , - 1 , - 1 ) ;
}
if ( ci - > saber [ 1 ] . model //dual sabers
& & cent - > currentState . saberHolstered = = 1 ) //second one off
{
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
}
else
{
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , - 1 , - 1 ) ;
}
}
//If the arm the saber is in is broken, turn it off.
/*
if ( cent - > currentState . brokenLimbs & ( 1 < < BROKENLIMB_RARM ) )
{
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
}
*/
//Leaving right arm on, at least for now.
if ( cent - > currentState . brokenLimbs & ( 1 < < BROKENLIMB_LARM ) )
{
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
}
if ( ! cent - > currentState . saberEntityNum )
{
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
//BG_SI_SetDesiredLength(&ci->saber[1], 0, -1);
}
/*
else
{
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
}
*/
drawPlayerSaber = qtrue ;
}
else if ( cent - > currentState . weapon = = WP_SABER )
{
//cent->saberLength = 0;
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
drawPlayerSaber = qtrue ;
}
else
{
//cent->saberLength = 0;
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
BG_SI_SetLength ( & ci - > saber [ 0 ] , 0 ) ;
BG_SI_SetLength ( & ci - > saber [ 1 ] , 0 ) ;
}
# ifdef _RAG_BOLT_TESTING
if ( cent - > currentState . eFlags & EF_RAG )
{
CG_TempTestFunction ( cent , cent - > turAngles ) ;
}
# endif
if ( cent - > currentState . weapon = = WP_SABER )
{
BG_SI_SetLengthGradual ( & ci - > saber [ 0 ] , cg . time ) ;
BG_SI_SetLengthGradual ( & ci - > saber [ 1 ] , cg . time ) ;
}
if ( drawPlayerSaber )
{
centity_t * saberEnt ;
int k = 0 ;
int l = 0 ;
if ( ! cent - > currentState . saberEntityNum )
{
l = 1 ; //The "primary" saber is missing or in flight or something, so only try to draw in the second one
}
else if ( ! cent - > currentState . saberInFlight )
{
saberEnt = & cg_entities [ cent - > currentState . saberEntityNum ] ;
if ( /*cent->bolt4 && */ ! g2HasWeapon )
{
trap_G2API_CopySpecificGhoul2Model ( CG_G2WeaponInstance ( cent , WP_SABER ) , 0 , cent - > ghoul2 , 1 ) ;
if ( saberEnt & & saberEnt - > ghoul2 )
{
trap_G2API_CleanGhoul2Models ( & ( saberEnt - > ghoul2 ) ) ;
}
saberEnt - > currentState . modelindex = 0 ;
saberEnt - > ghoul2 = NULL ;
VectorClear ( saberEnt - > currentState . pos . trBase ) ;
}
cent - > bolt3 = 0 ;
cent - > bolt2 = 0 ;
}
else
{
l = 1 ; //The "primary" saber is missing or in flight or something, so only try to draw in the second one
}
while ( l < MAX_SABERS )
{
k = 0 ;
if ( ! ci - > saber [ l ] . model [ 0 ] )
{
break ;
}
if ( cent - > currentState . eFlags2 & EF2_HELD_BY_MONSTER )
{
//vectoangles(legs.axis[0], rootAngles);
#if 0
if ( cent - > currentState . hasLookTarget ) //NOTE: lookTarget is an entity number, so this presumes that client 0 is NOT a Rancor...
{
centity_t * rancor = & cg_entities [ cent - > currentState . lookTarget ] ;
if ( rancor & & rancor - > ghoul2 )
{
BG_AttachToRancor ( rancor - > ghoul2 , //ghoul2 info
rancor - > lerpAngles [ YAW ] ,
rancor - > lerpOrigin ,
cg . time ,
cgs . gameModels ,
rancor - > modelScale ,
( rancor - > currentState . eFlags2 & EF2_GENERIC_NPC_FLAG ) ,
legs . origin ,
rootAngles ,
NULL ) ;
}
}
# else
vectoangles ( legs . axis [ 0 ] , rootAngles ) ;
# endif
}
while ( k < ci - > saber [ l ] . numBlades )
{
if ( //cent->currentState.fireflag == SS_STAFF&& //in saberstaff style
cent - > currentState . saberHolstered = = 1 //extra blades should be off
& & k > 0 //this is an extra blade
& & ci - > saber [ l ] . blade [ k ] . length < = 0 ) //it's completely off
{ //extra blades off
//don't draw them
CG_AddSaberBlade ( cent , cent , NULL , 0 , 0 , l , k , legs . origin , rootAngles , qfalse , qtrue ) ;
}
else if ( ci - > saber [ 1 ] . model [ 0 ] //we have a second saber
& & cent - > currentState . saberHolstered = = 1 //it should be off
& & l > 0 //and this is the second one
& & ci - > saber [ l ] . blade [ k ] . length < = 0 ) //it's completely off
{ //second saber is turned off and this blade is done with turning off
CG_AddSaberBlade ( cent , cent , NULL , 0 , 0 , l , k , legs . origin , rootAngles , qfalse , qtrue ) ;
}
else
{
CG_AddSaberBlade ( cent , cent , NULL , 0 , 0 , l , k , legs . origin , rootAngles , qfalse , qfalse ) ;
}
k + + ;
}
if ( ci - > saber [ l ] . numBlades > 2 )
{ //add a single glow for the saber based on all the blade colors combined
CG_DoSaberLight ( & ci - > saber [ l ] ) ;
}
l + + ;
}
}
if ( cent - > currentState . saberInFlight & & ! cent - > currentState . saberEntityNum )
{ //reset the length if the saber is knocked away
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
if ( g2HasWeapon )
{ //and remember to kill the bolton model in case we didn't get a thrown saber update first
trap_G2API_RemoveGhoul2Model ( & ( cent - > ghoul2 ) , 1 ) ;
g2HasWeapon = qfalse ;
}
cent - > bolt3 = 0 ;
cent - > bolt2 = 0 ;
}
if ( cent - > currentState . eFlags & EF_DEAD )
{
if ( cent - > ghoul2 & & cent - > currentState . saberInFlight & & g2HasWeapon )
{ //special case, kill the saber on a freshly dead player if another source says to.
trap_G2API_RemoveGhoul2Model ( & ( cent - > ghoul2 ) , 1 ) ;
g2HasWeapon = qfalse ;
}
}
if ( iwantout )
{
return ;
//goto endOfCall;
}
if ( ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_SEE ) ) & & cg . snap - > ps . clientNum ! = cent - > currentState . number )
{
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 0 ;
legs . renderfx | = RF_MINLIGHT ;
}
if ( cg . snap - > ps . duelInProgress /*&& cent->currentState.number != cg.snap->ps.clientNum*/ )
{ //I guess go ahead and glow your own client too in a duel
if ( cent - > currentState . number ! = cg . snap - > ps . duelIndex & &
cent - > currentState . number ! = cg . snap - > ps . clientNum )
{ //everyone not involved in the duel is drawn very dark
legs . shaderRGBA [ 0 ] / = 5.0f ;
legs . shaderRGBA [ 1 ] / = 5.0f ;
legs . shaderRGBA [ 2 ] / = 5.0f ;
legs . renderfx | = RF_RGB_TINT ;
}
else
{ //adjust the glow by how far away you are from your dueling partner
centity_t * duelEnt ;
duelEnt = & cg_entities [ cg . snap - > ps . duelIndex ] ;
if ( duelEnt )
{
vec3_t vecSub ;
float subLen = 0 ;
VectorSubtract ( duelEnt - > lerpOrigin , cg . snap - > ps . origin , vecSub ) ;
subLen = VectorLength ( vecSub ) ;
if ( subLen < 1 )
{
subLen = 1 ;
}
if ( subLen > 1020 )
{
subLen = 1020 ;
}
{
const unsigned char savRGBA [ 3 ] = { legs . shaderRGBA [ 0 ] , legs . shaderRGBA [ 1 ] , legs . shaderRGBA [ 2 ] } ;
legs . shaderRGBA [ 0 ] = max ( 255 - subLen / 4 , 1 ) ;
legs . shaderRGBA [ 1 ] = max ( 255 - subLen / 4 , 1 ) ;
legs . shaderRGBA [ 2 ] = max ( 255 - subLen / 4 , 1 ) ;
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . customShader = cgs . media . forceShell ;
trap_R_AddRefEntityToScene ( & legs ) ; //draw the shell
legs . customShader = 0 ; //reset to player model
legs . shaderRGBA [ 0 ] = max ( savRGBA [ 0 ] - subLen / 8 , 1 ) ;
legs . shaderRGBA [ 1 ] = max ( savRGBA [ 1 ] - subLen / 8 , 1 ) ;
legs . shaderRGBA [ 2 ] = max ( savRGBA [ 2 ] - subLen / 8 , 1 ) ;
}
if ( subLen < = 1024 )
{
legs . renderfx | = RF_RGB_TINT ;
}
}
}
}
else
{
if ( cent - > currentState . bolt1 & & ! ( cent - > currentState . eFlags & EF_DEAD ) & & cent - > currentState . number ! = cg . snap - > ps . clientNum & & ( ! cg . snap - > ps . duelInProgress | | cg . snap - > ps . duelIndex ! = cent - > currentState . number ) )
{
legs . shaderRGBA [ 0 ] = 50 ;
legs . shaderRGBA [ 1 ] = 50 ;
legs . shaderRGBA [ 2 ] = 50 ;
legs . renderfx | = RF_RGB_TINT ;
}
}
if ( cent - > currentState . eFlags & EF_DISINTEGRATION )
{
if ( ! cent - > dustTrailTime )
{
cent - > dustTrailTime = cg . time ;
cent - > miscTime = legs . frame ;
}
if ( ( cg . time - cent - > dustTrailTime ) > 1500 )
{ //avoid rendering the entity after disintegration has finished anyway
//goto endOfCall;
return ;
}
trap_G2API_SetBoneAnim ( legs . ghoul2 , 0 , " model_root " , cent - > miscTime , cent - > miscTime , BONE_ANIM_OVERRIDE_FREEZE , 1.0f , cg . time , cent - > miscTime , - 1 ) ;
if ( ! cent - > noLumbar )
{
trap_G2API_SetBoneAnim ( legs . ghoul2 , 0 , " lower_lumbar " , cent - > miscTime , cent - > miscTime , BONE_ANIM_OVERRIDE_FREEZE , 1.0f , cg . time , cent - > miscTime , - 1 ) ;
if ( cent - > localAnimIndex < = 1 )
{
trap_G2API_SetBoneAnim ( legs . ghoul2 , 0 , " Motion " , cent - > miscTime , cent - > miscTime , BONE_ANIM_OVERRIDE_FREEZE , 1.0f , cg . time , cent - > miscTime , - 1 ) ;
}
}
CG_Disintegration ( cent , & legs ) ;
//goto endOfCall;
return ;
}
else
{
cent - > dustTrailTime = 0 ;
cent - > miscTime = 0 ;
}
if ( cent - > currentState . powerups & ( 1 < < PW_CLOAKED ) )
{
if ( ! cent - > cloaked )
{
cent - > cloaked = qtrue ;
cent - > uncloaking = cg . time + 2000 ;
}
}
else if ( cent - > cloaked )
{
cent - > cloaked = qfalse ;
cent - > uncloaking = cg . time + 2000 ;
}
if ( cent - > uncloaking > cg . time )
{ //in the middle of cloaking
if ( ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_SEE ) )
& & cg . snap - > ps . clientNum ! = cent - > currentState . number )
{ //just draw him
trap_R_AddRefEntityToScene ( & legs ) ;
}
else
{
float perc = ( float ) ( cent - > uncloaking - cg . time ) / 2000.0f ;
if ( ( cent - > currentState . powerups & ( 1 < < PW_CLOAKED ) ) )
{ //actually cloaking, so reverse it
perc = 1.0f - perc ;
}
if ( perc > = 0.0f & & perc < = 1.0f )
{
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . renderfx | = RF_RGB_TINT ;
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = 255.0f * perc ;
legs . shaderRGBA [ 3 ] = 0 ;
legs . customShader = cgs . media . cloakedShader ;
trap_R_AddRefEntityToScene ( & legs ) ;
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = 255 ;
legs . shaderRGBA [ 3 ] = 255 * ( 1.0f - perc ) ; // let model alpha in
legs . customShader = 0 ; // use regular skin
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx | = RF_FORCE_ENT_ALPHA ;
trap_R_AddRefEntityToScene ( & legs ) ;
}
}
}
else if ( ( cent - > currentState . powerups & ( 1 < < PW_CLOAKED ) ) )
{ //fully cloaked
if ( ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_SEE ) )
& & cg . snap - > ps . clientNum ! = cent - > currentState . number )
{ //just draw him
trap_R_AddRefEntityToScene ( & legs ) ;
}
else
{
if ( cg . renderingThirdPerson | | cent - > currentState . number ! = cg . predictedPlayerState . clientNum )
{
/*
legs . renderfx = 0 ; //&= ~(RF_RGB_TINT|RF_ALPHA_FADE);
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = legs . shaderRGBA [ 3 ] = 255 ;
legs . customShader = cgs . media . cloakedShader ;
legs . nonNormalizedAxes = qtrue ;
legs . modelScale [ 0 ] = 1.02f ;
legs . modelScale [ 1 ] = 1.02f ;
legs . modelScale [ 2 ] = 1.02f ;
VectorScale ( legs . axis [ 0 ] , legs . modelScale [ 0 ] , legs . axis [ 0 ] ) ;
VectorScale ( legs . axis [ 1 ] , legs . modelScale [ 1 ] , legs . axis [ 1 ] ) ;
VectorScale ( legs . axis [ 2 ] , legs . modelScale [ 2 ] , legs . axis [ 2 ] ) ;
ScaleModelAxis ( & legs ) ;
trap_R_AddRefEntityToScene ( & legs ) ;
legs . modelScale [ 0 ] = 0.98f ;
legs . modelScale [ 1 ] = 0.98f ;
legs . modelScale [ 2 ] = 0.98f ;
VectorScale ( legs . axis [ 0 ] , legs . modelScale [ 0 ] , legs . axis [ 0 ] ) ;
VectorScale ( legs . axis [ 1 ] , legs . modelScale [ 1 ] , legs . axis [ 1 ] ) ;
VectorScale ( legs . axis [ 2 ] , legs . modelScale [ 2 ] , legs . axis [ 2 ] ) ;
ScaleModelAxis ( & legs ) ;
*/
if ( cg_shadows . integer ! = 2 & & cgs . glconfig . stencilBits > = 4 & & cg_renderToTextureFX . integer )
{
trap_R_SetRefractProp ( 1.0f , 0.0f , qfalse , qfalse ) ; //don't need to do this every frame.. but..
legs . customShader = 2 ; //crazy "refractive" shader
trap_R_AddRefEntityToScene ( & legs ) ;
legs . customShader = 0 ;
}
else
{ //stencil buffer's in use, sorry
legs . renderfx = 0 ; //&= ~(RF_RGB_TINT|RF_ALPHA_FADE);
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = legs . shaderRGBA [ 3 ] = 255 ;
legs . customShader = cgs . media . cloakedShader ;
trap_R_AddRefEntityToScene ( & legs ) ;
legs . customShader = 0 ;
}
}
}
}
if ( ! ( cent - > currentState . powerups & ( 1 < < PW_CLOAKED ) ) )
{ //don't add the normal model if cloaked
CG_CheckThirdPersonAlpha ( cent , & legs ) ;
trap_R_AddRefEntityToScene ( & legs ) ;
}
//cent->frame_minus2 = cent->frame_minus1;
VectorCopy ( cent - > frame_minus1 , cent - > frame_minus2 ) ;
if ( cent - > frame_minus1_refreshed )
{
cent - > frame_minus2_refreshed = 1 ;
}
//cent->frame_minus1 = legs;
VectorCopy ( legs . origin , cent - > frame_minus1 ) ;
cent - > frame_minus1_refreshed = 1 ;
if ( ! cent - > frame_hold_refreshed & & ( cent - > currentState . powerups & ( 1 < < PW_SPEEDBURST ) ) )
{
cent - > frame_hold_time = cg . time + 254 ;
}
if ( cent - > frame_hold_time > = cg . time )
{
refEntity_t reframe_hold ;
if ( ! cent - > frame_hold_refreshed )
{ //We're taking the ghoul2 instance from the original refent and duplicating it onto our refent alias so that we can then freeze the frame and fade it for the effect
if ( cent - > frame_hold & & trap_G2_HaveWeGhoul2Models ( cent - > frame_hold ) & &
cent - > frame_hold ! = cent - > ghoul2 )
{
trap_G2API_CleanGhoul2Models ( & ( cent - > frame_hold ) ) ;
}
reframe_hold = legs ;
cent - > frame_hold_refreshed = 1 ;
reframe_hold . ghoul2 = NULL ;
trap_G2API_DuplicateGhoul2Instance ( cent - > ghoul2 , & cent - > frame_hold ) ;
//Set the animation to the current frame and freeze on end
//trap_G2API_SetBoneAnim(cent->frame_hold.ghoul2, 0, "model_root", cent->frame_hold.frame, cent->frame_hold.frame, BONE_ANIM_OVERRIDE_FREEZE, 1.0f, cg.time, cent->frame_hold.frame, -1);
trap_G2API_SetBoneAnim ( cent - > frame_hold , 0 , " model_root " , legs . frame , legs . frame , 0 , 1.0f , cg . time , legs . frame , - 1 ) ;
}
else
{
reframe_hold = legs ;
reframe_hold . ghoul2 = cent - > frame_hold ;
}
reframe_hold . renderfx | = RF_FORCE_ENT_ALPHA ;
reframe_hold . shaderRGBA [ 3 ] = ( cent - > frame_hold_time - cg . time ) ;
if ( reframe_hold . shaderRGBA [ 3 ] > 254 )
{
reframe_hold . shaderRGBA [ 3 ] = 254 ;
}
if ( reframe_hold . shaderRGBA [ 3 ] < 1 )
{
reframe_hold . shaderRGBA [ 3 ] = 1 ;
}
reframe_hold . ghoul2 = cent - > frame_hold ;
trap_R_AddRefEntityToScene ( & reframe_hold ) ;
}
else
{
cent - > frame_hold_refreshed = 0 ;
}
//
// add the gun / barrel / flash
//
if ( cent - > currentState . weapon ! = WP_EMPLACED_GUN )
{
CG_AddPlayerWeapon ( & legs , NULL , cent , ci - > team , rootAngles , qtrue ) ;
}
// add powerups floating behind the player
CG_PlayerPowerups ( cent , & legs ) ;
if ( ( cent - > currentState . forcePowersActive & ( 1 < < FP_RAGE ) ) & &
( cg . renderingThirdPerson | | cent - > currentState . number ! = cg . snap - > ps . clientNum ) )
{
//legs.customShader = cgs.media.rageShader;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . renderfx & = ~ RF_MINLIGHT ;
legs . renderfx | = RF_RGB_TINT ;
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = 0 ;
legs . shaderRGBA [ 3 ] = 255 ;
if ( rand ( ) & 1 )
{
legs . customShader = cgs . media . electricBodyShader ;
}
else
{
legs . customShader = cgs . media . electricBody2Shader ;
}
trap_R_AddRefEntityToScene ( & legs ) ;
}
if ( ! cg . snap - > ps . duelInProgress & & cent - > currentState . bolt1 & & ! ( cent - > currentState . eFlags & EF_DEAD ) & & cent - > currentState . number ! = cg . snap - > ps . clientNum & & ( ! cg . snap - > ps . duelInProgress | | cg . snap - > ps . duelIndex ! = cent - > currentState . number ) )
{
legs . shaderRGBA [ 0 ] = 50 ;
legs . shaderRGBA [ 1 ] = 50 ;
legs . shaderRGBA [ 2 ] = 255 ;
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . customShader = cgs . media . forceSightBubble ;
trap_R_AddRefEntityToScene ( & legs ) ;
}
if ( CG_VehicleShouldDrawShields ( cent ) //vehicle
| | ( checkDroidShields & & CG_VehicleShouldDrawShields ( & cg_entities [ cent - > currentState . m_iVehicleNum ] ) ) ) //droid in vehicle
{ //Vehicles have form-fitting shields
Vehicle_t * pVeh = cent - > m_pVehicle ;
if ( checkDroidShields )
{
pVeh = cg_entities [ cent - > currentState . m_iVehicleNum ] . m_pVehicle ;
}
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 255 ;
legs . shaderRGBA [ 3 ] = 10.0f + ( sin ( ( float ) ( cg . time / 4 ) ) * 128.0f ) ; //112.0 * ((cent->damageTime - cg.time) / MIN_SHIELD_TIME) + random()*16;
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
if ( pVeh
& & pVeh - > m_pVehicleInfo
& & pVeh - > m_pVehicleInfo - > shieldShaderHandle )
{ //use the vehicle-specific shader
legs . customShader = pVeh - > m_pVehicleInfo - > shieldShaderHandle ;
}
else
{
legs . customShader = cgs . media . playerShieldDamage ;
}
trap_R_AddRefEntityToScene ( & legs ) ;
}
//For now, these two are using the old shield shader. This is just so that you
//can tell it apart from the JM/duel shaders, but it's still very obvious.
if ( cent - > currentState . forcePowersActive & ( 1 < < FP_PROTECT ) )
{ //aborb is represented by green..
refEntity_t prot ;
memcpy ( & prot , & legs , sizeof ( prot ) ) ;
prot . shaderRGBA [ 0 ] = 0 ;
prot . shaderRGBA [ 1 ] = 128 ;
prot . shaderRGBA [ 2 ] = 0 ;
prot . shaderRGBA [ 3 ] = 254 ;
prot . renderfx & = ~ RF_RGB_TINT ;
prot . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
prot . customShader = cgs . media . protectShader ;
/*
if ( ! prot . modelScale [ 0 ] & & ! prot . modelScale [ 1 ] & & ! prot . modelScale [ 2 ] )
{
prot . modelScale [ 0 ] = prot . modelScale [ 1 ] = prot . modelScale [ 2 ] = 1.0f ;
}
VectorScale ( prot . modelScale , 1.1f , prot . modelScale ) ;
prot . origin [ 2 ] - = 2.0f ;
ScaleModelAxis ( & prot ) ;
*/
trap_R_AddRefEntityToScene ( & prot ) ;
}
//if (cent->currentState.forcePowersActive & (1 << FP_ABSORB))
//Showing only when the power has been active (absorbed something) recently now, instead of always.
//AND
//always show if it is you with the absorb on
if ( ( cent - > currentState . number = = cg . predictedPlayerState . clientNum & & ( cg . predictedPlayerState . fd . forcePowersActive & ( 1 < < FP_ABSORB ) ) ) | |
( cent - > teamPowerEffectTime > cg . time & & cent - > teamPowerType = = 3 ) )
{ //aborb is represented by blue..
legs . shaderRGBA [ 0 ] = 0 ;
legs . shaderRGBA [ 1 ] = 0 ;
legs . shaderRGBA [ 2 ] = 255 ;
legs . shaderRGBA [ 3 ] = 254 ;
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . customShader = cgs . media . playerShieldDamage ;
trap_R_AddRefEntityToScene ( & legs ) ;
}
if ( cent - > currentState . isJediMaster & & cg . snap - > ps . clientNum ! = cent - > currentState . number )
{
legs . shaderRGBA [ 0 ] = 100 ;
legs . shaderRGBA [ 1 ] = 100 ;
legs . shaderRGBA [ 2 ] = 255 ;
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . renderfx | = RF_NODEPTH ;
legs . customShader = cgs . media . forceShell ;
trap_R_AddRefEntityToScene ( & legs ) ;
legs . renderfx & = ~ RF_NODEPTH ;
}
if ( ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_SEE ) ) & & cg . snap - > ps . clientNum ! = cent - > currentState . number & & cg_auraShell . integer )
{
if ( cgs . gametype = = GT_SIEGE )
{ // A team game
if ( ci - > team = = TEAM_SPECTATOR | | ci - > team = = TEAM_FREE )
{ //yellow
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 0 ;
}
else if ( ci - > team ! = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team )
{ //red
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 50 ;
legs . shaderRGBA [ 2 ] = 50 ;
}
else
{ //green
legs . shaderRGBA [ 0 ] = 50 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 50 ;
}
}
else if ( cgs . gametype > = GT_TEAM )
{ // A team game
switch ( ci - > team )
{
case TEAM_RED :
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 50 ;
legs . shaderRGBA [ 2 ] = 50 ;
break ;
case TEAM_BLUE :
legs . shaderRGBA [ 0 ] = 75 ;
legs . shaderRGBA [ 1 ] = 75 ;
legs . shaderRGBA [ 2 ] = 255 ;
break ;
default :
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 0 ;
break ;
}
}
else
{ // Not a team game
legs . shaderRGBA [ 0 ] = 255 ;
legs . shaderRGBA [ 1 ] = 255 ;
legs . shaderRGBA [ 2 ] = 0 ;
}
/* if (cg.snap->ps.fd.forcePowerLevel[FP_SEE] <= FORCE_LEVEL_1)
{
legs . renderfx | = RF_MINLIGHT ;
}
else
*/ { // See through walls.
legs . renderfx | = RF_MINLIGHT | RF_NODEPTH ;
if ( cg . snap - > ps . fd . forcePowerLevel [ FP_SEE ] < FORCE_LEVEL_2 )
{ //only level 2+ can see players through walls
legs . renderfx & = ~ RF_NODEPTH ;
}
}
legs . renderfx & = ~ RF_RGB_TINT ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . customShader = cgs . media . sightShell ;
trap_R_AddRefEntityToScene ( & legs ) ;
}
// Electricity
//------------------------------------------------
if ( cent - > currentState . emplacedOwner > cg . time )
{
int dif = cent - > currentState . emplacedOwner - cg . time ;
vec3_t tempAngles ;
if ( dif > 0 & & random ( ) > 0.4f )
{
// fade out over the last 500 ms
int brightness = 255 ;
if ( dif < 500 )
{
brightness = floor ( ( dif - 500.0f ) / 500.0f * 255.0f ) ;
}
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . renderfx & = ~ RF_MINLIGHT ;
legs . renderfx | = RF_RGB_TINT ;
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = brightness ;
legs . shaderRGBA [ 3 ] = 255 ;
if ( rand ( ) & 1 )
{
legs . customShader = cgs . media . electricBodyShader ;
}
else
{
legs . customShader = cgs . media . electricBody2Shader ;
}
trap_R_AddRefEntityToScene ( & legs ) ;
if ( random ( ) > 0.9f )
trap_S_StartSound ( NULL , cent - > currentState . number , CHAN_AUTO , cgs . media . crackleSound ) ;
}
VectorSet ( tempAngles , 0 , cent - > lerpAngles [ YAW ] , 0 ) ;
CG_ForceElectrocution ( cent , legs . origin , tempAngles , cgs . media . boltShader , qfalse ) ;
}
if ( cent - > currentState . powerups & ( 1 < < PW_SHIELDHIT ) )
{
/*
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = 255.0f * 0.5f ; //t;
legs . shaderRGBA [ 3 ] = 255 ;
legs . renderfx & = ~ RF_ALPHA_FADE ;
legs . renderfx | = RF_RGB_TINT ;
*/
legs . shaderRGBA [ 0 ] = legs . shaderRGBA [ 1 ] = legs . shaderRGBA [ 2 ] = Q_irand ( 1 , 255 ) ;
legs . renderfx & = ~ RF_FORCE_ENT_ALPHA ;
legs . renderfx & = ~ RF_MINLIGHT ;
legs . renderfx & = ~ RF_RGB_TINT ;
legs . customShader = cgs . media . playerShieldDamage ;
trap_R_AddRefEntityToScene ( & legs ) ;
}
#if 0
endOfCall :
if ( cgBoneAnglePostSet . refreshSet )
{
trap_G2API_SetBoneAngles ( cgBoneAnglePostSet . ghoul2 , cgBoneAnglePostSet . modelIndex , cgBoneAnglePostSet . boneName ,
cgBoneAnglePostSet . angles , cgBoneAnglePostSet . flags , cgBoneAnglePostSet . up , cgBoneAnglePostSet . right ,
cgBoneAnglePostSet . forward , cgBoneAnglePostSet . modelList , cgBoneAnglePostSet . blendTime , cgBoneAnglePostSet . currentTime ) ;
cgBoneAnglePostSet . refreshSet = qfalse ;
}
# endif
}
//=====================================================================
/*
= = = = = = = = = = = = = = =
CG_ResetPlayerEntity
A player just came into view or teleported , so reset all animation info
= = = = = = = = = = = = = = =
*/
void CG_ResetPlayerEntity ( centity_t * cent )
{
clientInfo_t * ci ;
int i = 0 ;
int j = 0 ;
// cent->errorTime = -99999; // guarantee no error decay added
// cent->extrapolated = qfalse;
if ( cent - > currentState . eType = = ET_NPC )
{
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE & &
cent - > m_pVehicle & &
cent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER & &
cg . predictedPlayerState . m_iVehicleNum & &
cent - > currentState . number = = cg . predictedPlayerState . m_iVehicleNum )
{ //holy hackery, batman!
//I don't think this will break anything. But really, do I ever?
return ;
}
if ( ! cent - > npcClient )
{
CG_CreateNPCClient ( & cent - > npcClient ) ; //allocate memory for it
if ( ! cent - > npcClient )
{
assert ( 0 ) ;
return ;
}
memset ( cent - > npcClient , 0 , sizeof ( clientInfo_t ) ) ;
cent - > npcClient - > ghoul2Model = NULL ;
}
ci = cent - > npcClient ;
assert ( ci ) ;
//just force these guys to be set again, it won't hurt anything if they're
//already set.
cent - > npcLocalSurfOff = 0 ;
cent - > npcLocalSurfOn = 0 ;
}
else
{
ci = & cgs . clientinfo [ cent - > currentState . clientNum ] ;
}
while ( i < MAX_SABERS )
{
j = 0 ;
while ( j < ci - > saber [ i ] . numBlades )
{
ci - > saber [ i ] . blade [ j ] . trail . lastTime = - 20000 ;
j + + ;
}
i + + ;
}
ci - > facial_blink = - 1 ;
ci - > facial_frown = 0 ;
ci - > facial_aux = 0 ;
ci - > superSmoothTime = 0 ;
//reset lerp origin smooth point
VectorCopy ( cent - > lerpOrigin , cent - > beamEnd ) ;
if ( cent - > currentState . eType ! = ET_NPC | |
! ( cent - > currentState . eFlags & EF_DEAD ) )
{
CG_ClearLerpFrame ( cent , ci , & cent - > pe . legs , cent - > currentState . legsAnim , qfalse ) ;
CG_ClearLerpFrame ( cent , ci , & cent - > pe . torso , cent - > currentState . torsoAnim , qtrue ) ;
BG_EvaluateTrajectory ( & cent - > currentState . pos , cg . time , cent - > lerpOrigin ) ;
BG_EvaluateTrajectory ( & cent - > currentState . apos , cg . time , cent - > lerpAngles ) ;
// VectorCopy( cent->lerpOrigin, cent->rawOrigin );
VectorCopy ( cent - > lerpAngles , cent - > rawAngles ) ;
memset ( & cent - > pe . legs , 0 , sizeof ( cent - > pe . legs ) ) ;
cent - > pe . legs . yawAngle = cent - > rawAngles [ YAW ] ;
cent - > pe . legs . yawing = qfalse ;
cent - > pe . legs . pitchAngle = 0 ;
cent - > pe . legs . pitching = qfalse ;
memset ( & cent - > pe . torso , 0 , sizeof ( cent - > pe . legs ) ) ;
cent - > pe . torso . yawAngle = cent - > rawAngles [ YAW ] ;
cent - > pe . torso . yawing = qfalse ;
cent - > pe . torso . pitchAngle = cent - > rawAngles [ PITCH ] ;
cent - > pe . torso . pitching = qfalse ;
if ( cent - > currentState . eType = = ET_NPC )
{ //just start them off at 0 pitch
cent - > pe . torso . pitchAngle = 0 ;
}
if ( ( cent - > ghoul2 = = NULL ) & & ci - > ghoul2Model & & trap_G2_HaveWeGhoul2Models ( ci - > ghoul2Model ) )
{
trap_G2API_DuplicateGhoul2Instance ( ci - > ghoul2Model , & cent - > ghoul2 ) ;
cent - > weapon = 0 ;
cent - > ghoul2weapon = NULL ;
//Attach the instance to this entity num so we can make use of client-server
//shared operations if possible.
trap_G2API_AttachInstanceToEntNum ( cent - > ghoul2 , cent - > currentState . number , qfalse ) ;
if ( trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " face " ) = = - 1 )
{ //check now to see if we have this bone for setting anims and such
cent - > noFace = qtrue ;
}
cent - > localAnimIndex = CG_G2SkelForModel ( cent - > ghoul2 ) ;
cent - > eventAnimIndex = CG_G2EvIndexForModel ( cent - > ghoul2 , cent - > localAnimIndex ) ;
//CG_CopyG2WeaponInstance(cent->currentState.weapon, ci->ghoul2Model);
//cent->weapon = cent->currentState.weapon;
}
}
//do this to prevent us from making a saber unholster sound the first time we enter the pvs
if ( cent - > currentState . number ! = cg . predictedPlayerState . clientNum & &
cent - > currentState . weapon = = WP_SABER & &
cent - > weapon ! = cent - > currentState . weapon )
{
cent - > weapon = cent - > currentState . weapon ;
if ( cent - > ghoul2 & & ci - > ghoul2Model )
{
CG_CopyG2WeaponInstance ( cent , cent - > currentState . weapon , cent - > ghoul2 ) ;
cent - > ghoul2weapon = CG_G2WeaponInstance ( cent , cent - > currentState . weapon ) ;
}
if ( ! cent - > currentState . saberHolstered )
{ //if not holstered set length and desired length for both blades to full right now.
BG_SI_SetDesiredLength ( & ci - > saber [ 0 ] , 0 , - 1 ) ;
BG_SI_SetDesiredLength ( & ci - > saber [ 1 ] , 0 , - 1 ) ;
i = 0 ;
while ( i < MAX_SABERS )
{
j = 0 ;
while ( j < ci - > saber [ i ] . numBlades )
{
ci - > saber [ i ] . blade [ j ] . length = ci - > saber [ i ] . blade [ j ] . lengthMax ;
j + + ;
}
i + + ;
}
}
}
if ( cg_debugPosition . integer ) {
CG_Printf ( " %i ResetPlayerEntity yaw=%i \n " , cent - > currentState . number , cent - > pe . torso . yawAngle ) ;
}
}