📄 cg_ents.c
字号:
s1 = ¢->currentState;
if ( s1->weapon > WP_NUM_WEAPONS ) {
s1->weapon = 0;
}
weapon = &cg_weapons[s1->weapon];
// calculate the axis
VectorCopy( s1->angles, cent->lerpAngles);
#if 0 // FIXME add grapple pull sound here..?
// add missile sound
if ( weapon->missileSound ) {
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->missileSound );
}
#endif
// Will draw cable if needed
CG_GrappleTrail ( cent, weapon );
// create the render entity
memset (&ent, 0, sizeof(ent));
VectorCopy( cent->lerpOrigin, ent.origin);
VectorCopy( cent->lerpOrigin, ent.oldorigin);
// flicker between two skins
ent.skinNum = cg.clientFrame & 1;
ent.hModel = weapon->missileModel;
ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
// convert direction of travel into axis
if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
ent.axis[0][2] = 1;
}
trap_R_AddRefEntityToScene( &ent );
}
/*
===============
CG_Mover
===============
*/
static void CG_Mover( centity_t *cent ) {
refEntity_t ent;
entityState_t *s1;
s1 = ¢->currentState;
// create the render entity
memset (&ent, 0, sizeof(ent));
VectorCopy( cent->lerpOrigin, ent.origin);
VectorCopy( cent->lerpOrigin, ent.oldorigin);
AnglesToAxis( cent->lerpAngles, ent.axis );
ent.renderfx = RF_NOSHADOW;
// flicker between two skins (FIXME?)
ent.skinNum = ( cg.time >> 6 ) & 1;
// get the model, either as a bmodel or a modelindex
if ( s1->solid == SOLID_BMODEL ) {
ent.hModel = cgs.inlineDrawModel[s1->modelindex];
} else {
ent.hModel = cgs.gameModels[s1->modelindex];
}
// add to refresh list
trap_R_AddRefEntityToScene(&ent);
// add the secondary model
if ( s1->modelindex2 ) {
ent.skinNum = 0;
ent.hModel = cgs.gameModels[s1->modelindex2];
trap_R_AddRefEntityToScene(&ent);
}
}
/*
===============
CG_Beam
Also called as an event
===============
*/
void CG_Beam( centity_t *cent ) {
refEntity_t ent;
entityState_t *s1;
s1 = ¢->currentState;
// create the render entity
memset (&ent, 0, sizeof(ent));
VectorCopy( s1->pos.trBase, ent.origin );
VectorCopy( s1->origin2, ent.oldorigin );
AxisClear( ent.axis );
ent.reType = RT_BEAM;
ent.renderfx = RF_NOSHADOW;
// add to refresh list
trap_R_AddRefEntityToScene(&ent);
}
/*
===============
CG_Portal
===============
*/
static void CG_Portal( centity_t *cent ) {
refEntity_t ent;
entityState_t *s1;
s1 = ¢->currentState;
// create the render entity
memset (&ent, 0, sizeof(ent));
VectorCopy( cent->lerpOrigin, ent.origin );
VectorCopy( s1->origin2, ent.oldorigin );
ByteToDir( s1->eventParm, ent.axis[0] );
PerpendicularVector( ent.axis[1], ent.axis[0] );
// negating this tends to get the directions like they want
// we really should have a camera roll value
VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
ent.reType = RT_PORTALSURFACE;
ent.oldframe = s1->powerups;
ent.frame = s1->frame; // rotation speed
ent.skinNum = s1->clientNum/256.0 * 360; // roll offset
// add to refresh list
trap_R_AddRefEntityToScene(&ent);
}
/*
=========================
CG_AdjustPositionForMover
Also called by client movement prediction code
=========================
*/
void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
centity_t *cent;
vec3_t oldOrigin, origin, deltaOrigin;
vec3_t oldAngles, angles, deltaAngles;
if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
VectorCopy( in, out );
return;
}
cent = &cg_entities[ moverNum ];
if ( cent->currentState.eType != ET_MOVER ) {
VectorCopy( in, out );
return;
}
BG_EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin );
BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles );
BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin );
BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles );
VectorSubtract( origin, oldOrigin, deltaOrigin );
VectorSubtract( angles, oldAngles, deltaAngles );
VectorAdd( in, deltaOrigin, out );
// FIXME: origin change when on a rotating object
}
/*
=============================
CG_InterpolateEntityPosition
=============================
*/
static void CG_InterpolateEntityPosition( centity_t *cent ) {
vec3_t current, next;
float f;
// it would be an internal error to find an entity that interpolates without
// a snapshot ahead of the current one
if ( cg.nextSnap == NULL ) {
CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
}
f = cg.frameInterpolation;
// this will linearize a sine or parabolic curve, but it is important
// to not extrapolate player positions if more recent data is available
BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current );
BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next );
cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current );
BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next );
cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
}
/*
===============
CG_CalcEntityLerpPositions
===============
*/
static void CG_CalcEntityLerpPositions( centity_t *cent ) {
// if this player does not want to see extrapolated players
if ( !cg_smoothClients.integer ) {
// make sure the clients use TR_INTERPOLATE
if ( cent->currentState.number < MAX_CLIENTS ) {
cent->currentState.pos.trType = TR_INTERPOLATE;
cent->nextState.pos.trType = TR_INTERPOLATE;
}
}
if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
CG_InterpolateEntityPosition( cent );
return;
}
// first see if we can interpolate between two snaps for
// linear extrapolated clients
if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
cent->currentState.number < MAX_CLIENTS) {
CG_InterpolateEntityPosition( cent );
return;
}
// just use the current frame and evaluate as best we can
BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
// adjust for riding a mover if it wasn't rolled into the predicted
// player state
if ( cent != &cg.predictedPlayerEntity ) {
CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum,
cg.snap->serverTime, cg.time, cent->lerpOrigin );
}
}
/*
===============
CG_TeamBase
===============
*/
static void CG_TeamBase( centity_t *cent ) {
refEntity_t model;
#ifdef MISSIONPACK
vec3_t angles;
int t, h;
float c;
if ( cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF ) {
#else
if ( cgs.gametype == GT_CTF) {
#endif
// show the flag base
memset(&model, 0, sizeof(model));
model.reType = RT_MODEL;
VectorCopy( cent->lerpOrigin, model.lightingOrigin );
VectorCopy( cent->lerpOrigin, model.origin );
AnglesToAxis( cent->currentState.angles, model.axis );
if ( cent->currentState.modelindex == TEAM_RED ) {
model.hModel = cgs.media.redFlagBaseModel;
}
else if ( cent->currentState.modelindex == TEAM_BLUE ) {
model.hModel = cgs.media.blueFlagBaseModel;
}
else {
model.hModel = cgs.media.neutralFlagBaseModel;
}
trap_R_AddRefEntityToScene( &model );
}
#ifdef MISSIONPACK
else if ( cgs.gametype == GT_OBELISK ) {
// show the obelisk
memset(&model, 0, sizeof(model));
model.reType = RT_MODEL;
VectorCopy( cent->lerpOrigin, model.lightingOrigin );
VectorCopy( cent->lerpOrigin, model.origin );
AnglesToAxis( cent->currentState.angles, model.axis );
model.hModel = cgs.media.overloadBaseModel;
trap_R_AddRefEntityToScene( &model );
// if hit
if ( cent->currentState.frame == 1) {
// show hit model
// modelindex2 is the health value of the obelisk
c = cent->currentState.modelindex2;
model.shaderRGBA[0] = 0xff;
model.shaderRGBA[1] = c;
model.shaderRGBA[2] = c;
model.shaderRGBA[3] = 0xff;
//
model.hModel = cgs.media.overloadEnergyModel;
trap_R_AddRefEntityToScene( &model );
}
// if respawning
if ( cent->currentState.frame == 2) {
if ( !cent->miscTime ) {
cent->miscTime = cg.time;
}
t = cg.time - cent->miscTime;
h = (cg_obeliskRespawnDelay.integer - 5) * 1000;
//
if (t > h) {
c = (float) (t - h) / h;
if (c > 1)
c = 1;
}
else {
c = 0;
}
// show the lights
AnglesToAxis( cent->currentState.angles, model.axis );
//
model.shaderRGBA[0] = c * 0xff;
model.shaderRGBA[1] = c * 0xff;
model.shaderRGBA[2] = c * 0xff;
model.shaderRGBA[3] = c * 0xff;
model.hModel = cgs.media.overloadLightsModel;
trap_R_AddRefEntityToScene( &model );
// show the target
if (t > h) {
if ( !cent->muzzleFlashTime ) {
trap_S_StartSound (cent->lerpOrigin, ENTITYNUM_NONE, CHAN_BODY, cgs.media.obeliskRespawnSound);
cent->muzzleFlashTime = 1;
}
VectorCopy(cent->currentState.angles, angles);
angles[YAW] += (float) 16 * acos(1-c) * 180 / M_PI;
AnglesToAxis( angles, model.axis );
VectorScale( model.axis[0], c, model.axis[0]);
VectorScale( model.axis[1], c, model.axis[1]);
VectorScale( model.axis[2], c, model.axis[2]);
model.shaderRGBA[0] = 0xff;
model.shaderRGBA[1] = 0xff;
model.shaderRGBA[2] = 0xff;
model.shaderRGBA[3] = 0xff;
//
model.origin[2] += 56;
model.hModel = cgs.media.overloadTargetModel;
trap_R_AddRefEntityToScene( &model );
}
else {
//FIXME: show animated smoke
}
}
else {
cent->miscTime = 0;
cent->muzzleFlashTime = 0;
// modelindex2 is the health value of the obelisk
c = cent->currentState.modelindex2;
model.shaderRGBA[0] = 0xff;
model.shaderRGBA[1] = c;
model.shaderRGBA[2] = c;
model.shaderRGBA[3] = 0xff;
// show the lights
model.hModel = cgs.media.overloadLightsModel;
trap_R_AddRefEntityToScene( &model );
// show the target
model.origin[2] += 56;
model.hModel = cgs.media.overloadTargetModel;
trap_R_AddRefEntityToScene( &model );
}
}
else if ( cgs.gametype == GT_HARVESTER ) {
// show harvester model
memset(&model, 0, sizeof(model));
model.reType = RT_MODEL;
VectorCopy( cent->lerpOrigin, model.lightingOrigin );
VectorCopy( cent->lerpOrigin, model.origin );
AnglesToAxis( cent->currentState.angles, model.axis );
if ( cent->currentState.modelindex == TEAM_RED ) {
model.hModel = cgs.media.harvesterModel;
model.customSkin = cgs.media.harvesterRedSkin;
}
else if ( cent->currentState.modelindex == TEAM_BLUE ) {
model.hModel = cgs.media.harvesterModel;
model.customSkin = cgs.media.harvesterBlueSkin;
}
else {
model.hModel = cgs.media.harvesterNeutralModel;
model.customSkin = 0;
}
trap_R_AddRefEntityToScene( &model );
}
#endif
}
/*
===============
CG_AddCEntity
===============
*/
static void CG_AddCEntity( centity_t *cent ) {
// event-only entities will have been dealt with already
if ( cent->currentState.eType >= ET_EVENTS ) {
return;
}
// calculate the current origin
CG_CalcEntityLerpPositions( cent );
// add automatic effects
CG_EntityEffects( cent );
switch ( cent->currentState.eType ) {
default:
CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
break;
case ET_INVISIBLE:
case ET_PUSH_TRIGGER:
case ET_TELEPORT_TRIGGER:
break;
case ET_GENERAL:
CG_General( cent );
break;
case ET_PLAYER:
CG_Player( cent );
break;
case ET_ITEM:
CG_Item( cent );
break;
case ET_MISSILE:
CG_Missile( cent );
break;
case ET_MOVER:
CG_Mover( cent );
break;
case ET_BEAM:
CG_Beam( cent );
break;
case ET_PORTAL:
CG_Portal( cent );
break;
case ET_SPEAKER:
CG_Speaker( cent );
break;
case ET_GRAPPLE:
CG_Grapple( cent );
break;
case ET_TEAM:
CG_TeamBase( cent );
break;
}
}
/*
===============
CG_AddPacketEntities
===============
*/
void CG_AddPacketEntities( void ) {
int num;
centity_t *cent;
playerState_t *ps;
// set cg.frameInterpolation
if ( cg.nextSnap ) {
int delta;
delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
if ( delta == 0 ) {
cg.frameInterpolation = 0;
} else {
cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
}
} else {
cg.frameInterpolation = 0; // actually, it should never be used, because
// no entities should be marked as interpolating
}
// the auto-rotating items will all have the same axis
cg.autoAngles[0] = 0;
cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
cg.autoAngles[2] = 0;
cg.autoAnglesFast[0] = 0;
cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
cg.autoAnglesFast[2] = 0;
AnglesToAxis( cg.autoAngles, cg.autoAxis );
AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
// generate and add the entity from the playerstate
ps = &cg.predictedPlayerState;
BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse );
CG_AddCEntity( &cg.predictedPlayerEntity );
// lerp the non-predicted value for lightning gun origins
CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
// add each entity sent over by the server
for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
cent = &cg_entities[ cg.snap->entities[ num ].number ];
CG_AddCEntity( cent );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -