Changed line endings to UNIX.

This commit is contained in:
Paradox460 committed 2008-01-05 21:51:54 +00:00
1 parent 7acbb8c956
commit fc0f4ac57c
52 files changed
+53864 -53864

No files matched your search

+227 -227
View File
@@ -1,227 +1,227 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
/*
===============
CG_DoorAnimation
===============
*/
static void CG_DoorAnimation( centity_t *cent, int *old, int *now, float *backLerp )
{
CG_RunLerpFrame( &cent->lerpFrame );
*old = cent->lerpFrame.oldFrame;
*now = cent->lerpFrame.frame;
*backLerp = cent->lerpFrame.backlerp;
}
/*
===============
CG_ModelDoor
===============
*/
void CG_ModelDoor( centity_t *cent )
{
refEntity_t ent;
entityState_t *es;
animation_t anim;
lerpFrame_t *lf = &cent->lerpFrame;
es = &cent->currentState;
if( !es->modelindex )
return;
//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;
//add the door model
ent.skinNum = 0;
ent.hModel = cgs.gameModels[ es->modelindex ];
//scale the door
VectorScale( ent.axis[ 0 ], es->origin2[ 0 ], ent.axis[ 0 ] );
VectorScale( ent.axis[ 1 ], es->origin2[ 1 ], ent.axis[ 1 ] );
VectorScale( ent.axis[ 2 ], es->origin2[ 2 ], ent.axis[ 2 ] );
ent.nonNormalizedAxes = qtrue;
//setup animation
anim.firstFrame = es->powerups;
anim.numFrames = es->weapon;
anim.reversed = !es->legsAnim;
anim.flipflop = qfalse;
anim.loopFrames = 0;
anim.frameLerp = 1000 / es->torsoAnim;
anim.initialLerp = 1000 / es->torsoAnim;
//door changed state
if( es->legsAnim != cent->doorState )
{
lf->animationTime = lf->frameTime + anim.initialLerp;
cent->doorState = es->legsAnim;
}
lf->animation = &anim;
//run animation
CG_DoorAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
trap_R_AddRefEntityToScene( &ent );
}
/*
===============
CG_AMOAnimation
===============
*/
static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLerp )
{
if( !( cent->currentState.eFlags & EF_MOVER_STOP ) || cent->animPlaying )
{
int delta = cg.time - cent->miscTime;
//hack to prevent "pausing" mucking up the lerping
if( delta > 900 )
{
cent->lerpFrame.oldFrameTime += delta;
cent->lerpFrame.frameTime += delta;
}
CG_RunLerpFrame( &cent->lerpFrame );
cent->miscTime = cg.time;
}
*old = cent->lerpFrame.oldFrame;
*now = cent->lerpFrame.frame;
*backLerp = cent->lerpFrame.backlerp;
}
/*
==================
CG_animMapObj
==================
*/
void CG_AnimMapObj( centity_t *cent )
{
refEntity_t ent;
entityState_t *es;
float scale;
animation_t anim;
es = &cent->currentState;
// if set to invisible, skip
if( !es->modelindex || ( es->eFlags & EF_NODRAW ) )
return;
memset( &ent, 0, sizeof( ent ) );
VectorCopy( es->angles, cent->lerpAngles );
AnglesToAxis( cent->lerpAngles, ent.axis );
ent.hModel = cgs.gameModels[ es->modelindex ];
VectorCopy( cent->lerpOrigin, ent.origin);
VectorCopy( cent->lerpOrigin, ent.oldorigin);
ent.nonNormalizedAxes = qfalse;
//scale the model
if( es->angles2[ 0 ] )
{
scale = es->angles2[ 0 ];
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;
}
//setup animation
anim.firstFrame = es->powerups;
anim.numFrames = es->weapon;
anim.reversed = qfalse;
anim.flipflop = qfalse;
// if numFrames is negative the animation is reversed
if( anim.numFrames < 0 )
{
anim.numFrames = -anim.numFrames;
anim.reversed = qtrue;
}
anim.loopFrames = es->torsoAnim;
if( !es->legsAnim )
{
anim.frameLerp = 1000;
anim.initialLerp = 1000;
}
else
{
anim.frameLerp = 1000 / es->legsAnim;
anim.initialLerp = 1000 / es->legsAnim;
}
cent->lerpFrame.animation = &anim;
if( !anim.loopFrames )
{
// add one frame to allow the animation to play the last frame
// add another to get it to stop playing at the first frame
anim.numFrames += 2;
if( !cent->animInit )
{
cent->animInit = qtrue;
cent->animPlaying = !( cent->currentState.eFlags & EF_MOVER_STOP );
}
else
{
if( cent->animLastState !=
!( cent->currentState.eFlags & EF_MOVER_STOP ) )
{
cent->animPlaying = qtrue;
cent->lerpFrame.animationTime = cg.time;
cent->lerpFrame.frameTime = cg.time;
}
}
cent->animLastState = !( cent->currentState.eFlags & EF_MOVER_STOP );
}
//run animation
CG_AMOAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
// add to refresh list
trap_R_AddRefEntityToScene(&ent);
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
/*
===============
CG_DoorAnimation
===============
*/
static void CG_DoorAnimation( centity_t *cent, int *old, int *now, float *backLerp )
{
CG_RunLerpFrame( &cent->lerpFrame );
*old = cent->lerpFrame.oldFrame;
*now = cent->lerpFrame.frame;
*backLerp = cent->lerpFrame.backlerp;
}
/*
===============
CG_ModelDoor
===============
*/
void CG_ModelDoor( centity_t *cent )
{
refEntity_t ent;
entityState_t *es;
animation_t anim;
lerpFrame_t *lf = &cent->lerpFrame;
es = &cent->currentState;
if( !es->modelindex )
return;
//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;
//add the door model
ent.skinNum = 0;
ent.hModel = cgs.gameModels[ es->modelindex ];
//scale the door
VectorScale( ent.axis[ 0 ], es->origin2[ 0 ], ent.axis[ 0 ] );
VectorScale( ent.axis[ 1 ], es->origin2[ 1 ], ent.axis[ 1 ] );
VectorScale( ent.axis[ 2 ], es->origin2[ 2 ], ent.axis[ 2 ] );
ent.nonNormalizedAxes = qtrue;
//setup animation
anim.firstFrame = es->powerups;
anim.numFrames = es->weapon;
anim.reversed = !es->legsAnim;
anim.flipflop = qfalse;
anim.loopFrames = 0;
anim.frameLerp = 1000 / es->torsoAnim;
anim.initialLerp = 1000 / es->torsoAnim;
//door changed state
if( es->legsAnim != cent->doorState )
{
lf->animationTime = lf->frameTime + anim.initialLerp;
cent->doorState = es->legsAnim;
}
lf->animation = &anim;
//run animation
CG_DoorAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
trap_R_AddRefEntityToScene( &ent );
}
/*
===============
CG_AMOAnimation
===============
*/
static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLerp )
{
if( !( cent->currentState.eFlags & EF_MOVER_STOP ) || cent->animPlaying )
{
int delta = cg.time - cent->miscTime;
//hack to prevent "pausing" mucking up the lerping
if( delta > 900 )
{
cent->lerpFrame.oldFrameTime += delta;
cent->lerpFrame.frameTime += delta;
}
CG_RunLerpFrame( &cent->lerpFrame );
cent->miscTime = cg.time;
}
*old = cent->lerpFrame.oldFrame;
*now = cent->lerpFrame.frame;
*backLerp = cent->lerpFrame.backlerp;
}
/*
==================
CG_animMapObj
==================
*/
void CG_AnimMapObj( centity_t *cent )
{
refEntity_t ent;
entityState_t *es;
float scale;
animation_t anim;
es = &cent->currentState;
// if set to invisible, skip
if( !es->modelindex || ( es->eFlags & EF_NODRAW ) )
return;
memset( &ent, 0, sizeof( ent ) );
VectorCopy( es->angles, cent->lerpAngles );
AnglesToAxis( cent->lerpAngles, ent.axis );
ent.hModel = cgs.gameModels[ es->modelindex ];
VectorCopy( cent->lerpOrigin, ent.origin);
VectorCopy( cent->lerpOrigin, ent.oldorigin);
ent.nonNormalizedAxes = qfalse;
//scale the model
if( es->angles2[ 0 ] )
{
scale = es->angles2[ 0 ];
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;
}
//setup animation
anim.firstFrame = es->powerups;
anim.numFrames = es->weapon;
anim.reversed = qfalse;
anim.flipflop = qfalse;
// if numFrames is negative the animation is reversed
if( anim.numFrames < 0 )
{
anim.numFrames = -anim.numFrames;
anim.reversed = qtrue;
}
anim.loopFrames = es->torsoAnim;
if( !es->legsAnim )
{
anim.frameLerp = 1000;
anim.initialLerp = 1000;
}
else
{
anim.frameLerp = 1000 / es->legsAnim;
anim.initialLerp = 1000 / es->legsAnim;
}
cent->lerpFrame.animation = &anim;
if( !anim.loopFrames )
{
// add one frame to allow the animation to play the last frame
// add another to get it to stop playing at the first frame
anim.numFrames += 2;
if( !cent->animInit )
{
cent->animInit = qtrue;
cent->animPlaying = !( cent->currentState.eFlags & EF_MOVER_STOP );
}
else
{
if( cent->animLastState !=
!( cent->currentState.eFlags & EF_MOVER_STOP ) )
{
cent->animPlaying = qtrue;
cent->lerpFrame.animationTime = cg.time;
cent->lerpFrame.frameTime = cg.time;
}
}
cent->animLastState = !( cent->currentState.eFlags & EF_MOVER_STOP );
}
//run animation
CG_AMOAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
// add to refresh list
trap_R_AddRefEntityToScene(&ent);
}
+404 -404
View File
@@ -1,404 +1,404 @@
/*
===========================================================================
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_attachment.c -- an abstract attachment system
#include "cg_local.h"
/*
===============
CG_AttachmentPoint
Return the attachment point
===============
*/
qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v )
{
centity_t *cent;
if( !a )
return qfalse;
// if it all breaks, then use the last point we know was correct
VectorCopy( a->lastValidAttachmentPoint, v );
switch( a->type )
{
case AT_STATIC:
if( !a->staticValid )
return qfalse;
VectorCopy( a->origin, v );
break;
case AT_TAG:
if( !a->tagValid )
return qfalse;
AxisCopy( axisDefault, a->re.axis );
CG_PositionRotatedEntityOnTag( &a->re, &a->parent,
a->model, a->tagName );
VectorCopy( a->re.origin, v );
break;
case AT_CENT:
if( !a->centValid )
return qfalse;
if( a->centNum == cg.predictedPlayerState.clientNum )
{
// this is smoother if it's the local client
VectorCopy( cg.predictedPlayerState.origin, v );
}
else
{
cent = &cg_entities[ a->centNum ];
VectorCopy( cent->lerpOrigin, v );
}
break;
case AT_PARTICLE:
if( !a->particleValid )
return qfalse;
if( !a->particle->valid )
{
a->particleValid = qfalse;
return qfalse;
}
else
VectorCopy( a->particle->origin, v );
break;
default:
CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
break;
}
if( a->hasOffset )
VectorAdd( v, a->offset, v );
VectorCopy( v, a->lastValidAttachmentPoint );
return qtrue;
}
/*
===============
CG_AttachmentDir
Return the attachment direction
===============
*/
qboolean CG_AttachmentDir( attachment_t *a, vec3_t v )
{
vec3_t forward;
centity_t *cent;
if( !a )
return qfalse;
switch( a->type )
{
case AT_STATIC:
return qfalse;
break;
case AT_TAG:
if( !a->tagValid )
return qfalse;
VectorCopy( a->re.axis[ 0 ], v );
break;
case AT_CENT:
if( !a->centValid )
return qfalse;
cent = &cg_entities[ a->centNum ];
AngleVectors( cent->lerpAngles, forward, NULL, NULL );
VectorCopy( forward, v );
break;
case AT_PARTICLE:
if( !a->particleValid )
return qfalse;
if( !a->particle->valid )
{
a->particleValid = qfalse;
return qfalse;
}
else
VectorCopy( a->particle->velocity, v );
break;
default:
CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
break;
}
VectorNormalize( v );
return qtrue;
}
/*
===============
CG_AttachmentAxis
Return the attachment axis
===============
*/
qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] )
{
centity_t *cent;
if( !a )
return qfalse;
switch( a->type )
{
case AT_STATIC:
return qfalse;
break;
case AT_TAG:
if( !a->tagValid )
return qfalse;
AxisCopy( a->re.axis, axis );
break;
case AT_CENT:
if( !a->centValid )
return qfalse;
cent = &cg_entities[ a->centNum ];
AnglesToAxis( cent->lerpAngles, axis );
break;
case AT_PARTICLE:
return qfalse;
break;
default:
CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
break;
}
return qtrue;
}
/*
===============
CG_AttachmentVelocity
If the attachment can have velocity, return it
===============
*/
qboolean CG_AttachmentVelocity( attachment_t *a, vec3_t v )
{
if( !a )
return qfalse;
if( a->particleValid && a->particle->valid )
{
VectorCopy( a->particle->velocity, v );
return qtrue;
}
else if( a->centValid )
{
centity_t *cent = &cg_entities[ a->centNum ];
VectorCopy( cent->currentState.pos.trDelta, v );
return qtrue;
}
return qfalse;
}
/*
===============
CG_AttachmentCentNum
If the attachment has a centNum, return it
===============
*/
int CG_AttachmentCentNum( attachment_t *a )
{
if( !a || !a->centValid )
return -1;
return a->centNum;
}
/*
===============
CG_Attached
If the attachment is valid, return qtrue
===============
*/
qboolean CG_Attached( attachment_t *a )
{
if( !a )
return qfalse;
return a->attached;
}
/*
===============
CG_AttachToPoint
Attach to a point in space
===============
*/
void CG_AttachToPoint( attachment_t *a )
{
if( !a || !a->staticValid )
return;
a->type = AT_STATIC;
a->attached = qtrue;
}
/*
===============
CG_AttachToCent
Attach to a centity_t
===============
*/
void CG_AttachToCent( attachment_t *a )
{
if( !a || !a->centValid )
return;
a->type = AT_CENT;
a->attached = qtrue;
}
/*
===============
CG_AttachToTag
Attach to a model tag
===============
*/
void CG_AttachToTag( attachment_t *a )
{
if( !a || !a->tagValid )
return;
a->type = AT_TAG;
a->attached = qtrue;
}
/*
===============
CG_AttachToParticle
Attach to a particle
===============
*/
void CG_AttachToParticle( attachment_t *a )
{
if( !a || !a->particleValid )
return;
a->type = AT_PARTICLE;
a->attached = qtrue;
}
/*
===============
CG_SetAttachmentPoint
===============
*/
void CG_SetAttachmentPoint( attachment_t *a, vec3_t v )
{
if( !a )
return;
VectorCopy( v, a->origin );
a->staticValid = qtrue;
}
/*
===============
CG_SetAttachmentCent
===============
*/
void CG_SetAttachmentCent( attachment_t *a, centity_t *cent )
{
if( !a || !cent )
return;
a->centNum = cent->currentState.number;
a->centValid = qtrue;
}
/*
===============
CG_SetAttachmentTag
===============
*/
void CG_SetAttachmentTag( attachment_t *a, refEntity_t parent,
qhandle_t model, char *tagName )
{
if( !a )
return;
a->parent = parent;
a->model = model;
strncpy( a->tagName, tagName, MAX_STRING_CHARS );
a->tagValid = qtrue;
}
/*
===============
CG_SetAttachmentParticle
===============
*/
void CG_SetAttachmentParticle( attachment_t *a, particle_t *p )
{
if( !a )
return;
a->particle = p;
a->particleValid = qtrue;
}
/*
===============
CG_SetAttachmentOffset
===============
*/
void CG_SetAttachmentOffset( attachment_t *a, vec3_t v )
{
if( !a )
return;
VectorCopy( v, a->offset );
a->hasOffset = qtrue;
}
/*
===========================================================================
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_attachment.c -- an abstract attachment system
#include "cg_local.h"
/*
===============
CG_AttachmentPoint
Return the attachment point
===============
*/
qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v )
{
centity_t *cent;
if( !a )
return qfalse;
// if it all breaks, then use the last point we know was correct
VectorCopy( a->lastValidAttachmentPoint, v );
switch( a->type )
{
case AT_STATIC:
if( !a->staticValid )
return qfalse;
VectorCopy( a->origin, v );
break;
case AT_TAG:
if( !a->tagValid )
return qfalse;
AxisCopy( axisDefault, a->re.axis );
CG_PositionRotatedEntityOnTag( &a->re, &a->parent,
a->model, a->tagName );
VectorCopy( a->re.origin, v );
break;
case AT_CENT:
if( !a->centValid )
return qfalse;
if( a->centNum == cg.predictedPlayerState.clientNum )
{
// this is smoother if it's the local client
VectorCopy( cg.predictedPlayerState.origin, v );
}
else
{
cent = &cg_entities[ a->centNum ];
VectorCopy( cent->lerpOrigin, v );
}
break;
case AT_PARTICLE:
if( !a->particleValid )
return qfalse;
if( !a->particle->valid )
{
a->particleValid = qfalse;
return qfalse;
}
else
VectorCopy( a->particle->origin, v );
break;
default:
CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
break;
}
if( a->hasOffset )
VectorAdd( v, a->offset, v );
VectorCopy( v, a->lastValidAttachmentPoint );
return qtrue;
}
/*
===============
CG_AttachmentDir
Return the attachment direction
===============
*/
qboolean CG_AttachmentDir( attachment_t *a, vec3_t v )
{
vec3_t forward;
centity_t *cent;
if( !a )
return qfalse;
switch( a->type )
{
case AT_STATIC:
return qfalse;
break;
case AT_TAG:
if( !a->tagValid )
return qfalse;
VectorCopy( a->re.axis[ 0 ], v );
break;
case AT_CENT:
if( !a->centValid )
return qfalse;
cent = &cg_entities[ a->centNum ];
AngleVectors( cent->lerpAngles, forward, NULL, NULL );
VectorCopy( forward, v );
break;
case AT_PARTICLE:
if( !a->particleValid )
return qfalse;
if( !a->particle->valid )
{
a->particleValid = qfalse;
return qfalse;
}
else
VectorCopy( a->particle->velocity, v );
break;
default:
CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
break;
}
VectorNormalize( v );
return qtrue;
}
/*
===============
CG_AttachmentAxis
Return the attachment axis
===============
*/
qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] )
{
centity_t *cent;
if( !a )
return qfalse;
switch( a->type )
{
case AT_STATIC:
return qfalse;
break;
case AT_TAG:
if( !a->tagValid )
return qfalse;
AxisCopy( a->re.axis, axis );
break;
case AT_CENT:
if( !a->centValid )
return qfalse;
cent = &cg_entities[ a->centNum ];
AnglesToAxis( cent->lerpAngles, axis );
break;
case AT_PARTICLE:
return qfalse;
break;
default:
CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
break;
}
return qtrue;
}
/*
===============
CG_AttachmentVelocity
If the attachment can have velocity, return it
===============
*/
qboolean CG_AttachmentVelocity( attachment_t *a, vec3_t v )
{
if( !a )
return qfalse;
if( a->particleValid && a->particle->valid )
{
VectorCopy( a->particle->velocity, v );
return qtrue;
}
else if( a->centValid )
{
centity_t *cent = &cg_entities[ a->centNum ];
VectorCopy( cent->currentState.pos.trDelta, v );
return qtrue;
}
return qfalse;
}
/*
===============
CG_AttachmentCentNum
If the attachment has a centNum, return it
===============
*/
int CG_AttachmentCentNum( attachment_t *a )
{
if( !a || !a->centValid )
return -1;
return a->centNum;
}
/*
===============
CG_Attached
If the attachment is valid, return qtrue
===============
*/
qboolean CG_Attached( attachment_t *a )
{
if( !a )
return qfalse;
return a->attached;
}
/*
===============
CG_AttachToPoint
Attach to a point in space
===============
*/
void CG_AttachToPoint( attachment_t *a )
{
if( !a || !a->staticValid )
return;
a->type = AT_STATIC;
a->attached = qtrue;
}
/*
===============
CG_AttachToCent
Attach to a centity_t
===============
*/
void CG_AttachToCent( attachment_t *a )
{
if( !a || !a->centValid )
return;
a->type = AT_CENT;
a->attached = qtrue;
}
/*
===============
CG_AttachToTag
Attach to a model tag
===============
*/
void CG_AttachToTag( attachment_t *a )
{
if( !a || !a->tagValid )
return;
a->type = AT_TAG;
a->attached = qtrue;
}
/*
===============
CG_AttachToParticle
Attach to a particle
===============
*/
void CG_AttachToParticle( attachment_t *a )
{
if( !a || !a->particleValid )
return;
a->type = AT_PARTICLE;
a->attached = qtrue;
}
/*
===============
CG_SetAttachmentPoint
===============
*/
void CG_SetAttachmentPoint( attachment_t *a, vec3_t v )
{
if( !a )
return;
VectorCopy( v, a->origin );
a->staticValid = qtrue;
}
/*
===============
CG_SetAttachmentCent
===============
*/
void CG_SetAttachmentCent( attachment_t *a, centity_t *cent )
{
if( !a || !cent )
return;
a->centNum = cent->currentState.number;
a->centValid = qtrue;
}
/*
===============
CG_SetAttachmentTag
===============
*/
void CG_SetAttachmentTag( attachment_t *a, refEntity_t parent,
qhandle_t model, char *tagName )
{
if( !a )
return;
a->parent = parent;
a->model = model;
strncpy( a->tagName, tagName, MAX_STRING_CHARS );
a->tagValid = qtrue;
}
/*
===============
CG_SetAttachmentParticle
===============
*/
void CG_SetAttachmentParticle( attachment_t *a, particle_t *p )
{
if( !a )
return;
a->particle = p;
a->particleValid = qtrue;
}
/*
===============
CG_SetAttachmentOffset
===============
*/
void CG_SetAttachmentOffset( attachment_t *a, vec3_t v )
{
if( !a )
return;
VectorCopy( v, a->offset );
a->hasOffset = qtrue;
}
+1423 -1423
View File
File diff suppressed because it is too large. Load diff
+325 -325
View File
@@ -1,325 +1,325 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_consolecmds.c -- text commands typed in at the local console, or
// executed by a key binding
#include "cg_local.h"
void CG_TargetCommand_f( void )
{
int targetNum;
char test[ 4 ];
targetNum = CG_CrosshairPlayer( );
if( !targetNum )
return;
trap_Argv( 1, test, 4 );
trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
}
/*
=================
CG_SizeUp_f
Keybinding command
=================
*/
static void CG_SizeUp_f( void )
{
trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer + 10 ) ) );
}
/*
=================
CG_SizeDown_f
Keybinding command
=================
*/
static void CG_SizeDown_f( void )
{
trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer - 10 ) ) );
}
/*
=============
CG_Viewpos_f
Debugging command to print the current position
=============
*/
static void CG_Viewpos_f( void )
{
CG_Printf( "(%i %i %i) : %i\n", (int)cg.refdef.vieworg[ 0 ],
(int)cg.refdef.vieworg[ 1 ], (int)cg.refdef.vieworg[ 2 ],
(int)cg.refdefViewAngles[ YAW ] );
}
qboolean CG_RequestScores( void )
{
if( cg.scoresRequestTime + 2000 < cg.time )
{
// the scores are more than two seconds out of data,
// so request new ones
cg.scoresRequestTime = cg.time;
//TA: added \n SendClientCommand doesn't call flush( )?
trap_SendClientCommand( "score\n" );
return qtrue;
}
else
return qfalse;
}
extern menuDef_t *menuScoreboard;
static void CG_scrollScoresDown_f( void )
{
if( menuScoreboard && cg.scoreBoardShowing )
{
Menu_ScrollFeeder( menuScoreboard, FEEDER_ALIENTEAM_LIST, qtrue );
Menu_ScrollFeeder( menuScoreboard, FEEDER_HUMANTEAM_LIST, qtrue );
}
}
static void CG_scrollScoresUp_f( void )
{
if( menuScoreboard && cg.scoreBoardShowing )
{
Menu_ScrollFeeder( menuScoreboard, FEEDER_ALIENTEAM_LIST, qfalse );
Menu_ScrollFeeder( menuScoreboard, FEEDER_HUMANTEAM_LIST, qfalse );
}
}
static void CG_ScoresDown_f( void )
{
if( !cg.showScores )
{
Menu_SetFeederSelection( menuScoreboard, FEEDER_ALIENTEAM_LIST, 0, NULL );
Menu_SetFeederSelection( menuScoreboard, FEEDER_HUMANTEAM_LIST, 0, NULL );
}
if( CG_RequestScores( ) )
{
// leave the current scores up if they were already
// displayed, but if this is the first hit, clear them out
if( !cg.showScores )
{
if( cg_debugRandom.integer )
CG_Printf( "CG_ScoresDown_f: scores out of date\n" );
cg.showScores = qtrue;
cg.numScores = 0;
}
}
else
{
// show the cached contents even if they just pressed if it
// is within two seconds
cg.showScores = qtrue;
}
}
static void CG_ScoresUp_f( void )
{
if( cg.showScores )
{
cg.showScores = qfalse;
cg.scoreFadeTime = cg.time;
}
}
static void CG_TellTarget_f( void )
{
int clientNum;
char command[ 128 ];
char message[ 128 ];
clientNum = CG_CrosshairPlayer( );
if( clientNum == -1 )
return;
trap_Args( message, 128 );
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
trap_SendClientCommand( command );
}
static void CG_TellAttacker_f( void )
{
int clientNum;
char command[ 128 ];
char message[ 128 ];
clientNum = CG_LastAttacker( );
if( clientNum == -1 )
return;
trap_Args( message, 128 );
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
trap_SendClientCommand( command );
}
typedef struct
{
char *cmd;
void (*function)( void );
} consoleCommand_t;
static consoleCommand_t commands[ ] =
{
{ "testgun", CG_TestGun_f },
{ "testmodel", CG_TestModel_f },
{ "nextframe", CG_TestModelNextFrame_f },
{ "prevframe", CG_TestModelPrevFrame_f },
{ "nextskin", CG_TestModelNextSkin_f },
{ "prevskin", CG_TestModelPrevSkin_f },
{ "viewpos", CG_Viewpos_f },
{ "+scores", CG_ScoresDown_f },
{ "-scores", CG_ScoresUp_f },
{ "scoresUp", CG_scrollScoresUp_f },
{ "scoresDown", CG_scrollScoresDown_f },
{ "sizeup", CG_SizeUp_f },
{ "sizedown", CG_SizeDown_f },
{ "weapnext", CG_NextWeapon_f },
{ "weapprev", CG_PrevWeapon_f },
{ "weapon", CG_Weapon_f },
{ "tell_target", CG_TellTarget_f },
{ "tell_attacker", CG_TellAttacker_f },
{ "tcmd", CG_TargetCommand_f },
{ "testPS", CG_TestPS_f },
{ "destroyTestPS", CG_DestroyTestPS_f },
{ "testTS", CG_TestTS_f },
{ "destroyTestTS", CG_DestroyTestTS_f },
};
/*
=================
CG_ConsoleCommand
The string has been tokenized and can be retrieved with
Cmd_Argc() / Cmd_Argv()
=================
*/
qboolean CG_ConsoleCommand( void )
{
const char *cmd;
const char *arg1;
int i;
cmd = CG_Argv( 0 );
//TA: ugly hacky special case
if( !Q_stricmp( cmd, "ui_menu" ) )
{
arg1 = CG_Argv( 1 );
trap_SendConsoleCommand( va( "menu %s\n", arg1 ) );
return qtrue;
}
for( i = 0; i < sizeof( commands ) / sizeof( commands[ 0 ] ); i++ )
{
if( !Q_stricmp( cmd, commands[ i ].cmd ) )
{
commands[ i ].function( );
return qtrue;
}
}
return qfalse;
}
/*
=================
CG_InitConsoleCommands
Let the client system know about all of our commands
so it can perform tab completion
=================
*/
void CG_InitConsoleCommands( void )
{
int i;
for( i = 0 ; i < sizeof( commands ) / sizeof( commands[ 0 ] ) ; i++ )
trap_AddCommand( commands[ i ].cmd );
//
// the game server will interpret these commands, which will be automatically
// forwarded to the server after they are not recognized locally
//
trap_AddCommand( "kill" );
trap_AddCommand( "say" );
trap_AddCommand( "say_team" );
trap_AddCommand( "tell" );
trap_AddCommand( "vsay" );
trap_AddCommand( "vsay_team" );
trap_AddCommand( "vtell" );
trap_AddCommand( "vtaunt" );
trap_AddCommand( "vosay" );
trap_AddCommand( "vosay_team" );
trap_AddCommand( "votell" );
trap_AddCommand( "give" );
trap_AddCommand( "god" );
trap_AddCommand( "notarget" );
trap_AddCommand( "noclip" );
trap_AddCommand( "team" );
trap_AddCommand( "follow" );
trap_AddCommand( "levelshot" );
trap_AddCommand( "addbot" );
trap_AddCommand( "setviewpos" );
trap_AddCommand( "callvote" );
trap_AddCommand( "vote" );
trap_AddCommand( "callteamvote" );
trap_AddCommand( "teamvote" );
trap_AddCommand( "stats" );
trap_AddCommand( "teamtask" );
trap_AddCommand( "class" );
trap_AddCommand( "build" );
trap_AddCommand( "buy" );
trap_AddCommand( "sell" );
trap_AddCommand( "reload" );
trap_AddCommand( "itemact" );
trap_AddCommand( "itemdeact" );
trap_AddCommand( "itemtoggle" );
trap_AddCommand( "destroy" );
trap_AddCommand( "deconstruct" );
trap_AddCommand( "menu" );
trap_AddCommand( "ui_menu" );
trap_AddCommand( "mapRotation" );
trap_AddCommand( "stopMapRotation" );
trap_AddCommand( "advanceMapRotation" );
trap_AddCommand( "alienWin" );
trap_AddCommand( "humanWin" );
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_consolecmds.c -- text commands typed in at the local console, or
// executed by a key binding
#include "cg_local.h"
void CG_TargetCommand_f( void )
{
int targetNum;
char test[ 4 ];
targetNum = CG_CrosshairPlayer( );
if( !targetNum )
return;
trap_Argv( 1, test, 4 );
trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
}
/*
=================
CG_SizeUp_f
Keybinding command
=================
*/
static void CG_SizeUp_f( void )
{
trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer + 10 ) ) );
}
/*
=================
CG_SizeDown_f
Keybinding command
=================
*/
static void CG_SizeDown_f( void )
{
trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer - 10 ) ) );
}
/*
=============
CG_Viewpos_f
Debugging command to print the current position
=============
*/
static void CG_Viewpos_f( void )
{
CG_Printf( "(%i %i %i) : %i\n", (int)cg.refdef.vieworg[ 0 ],
(int)cg.refdef.vieworg[ 1 ], (int)cg.refdef.vieworg[ 2 ],
(int)cg.refdefViewAngles[ YAW ] );
}
qboolean CG_RequestScores( void )
{
if( cg.scoresRequestTime + 2000 < cg.time )
{
// the scores are more than two seconds out of data,
// so request new ones
cg.scoresRequestTime = cg.time;
//TA: added \n SendClientCommand doesn't call flush( )?
trap_SendClientCommand( "score\n" );
return qtrue;
}
else
return qfalse;
}
extern menuDef_t *menuScoreboard;
static void CG_scrollScoresDown_f( void )
{
if( menuScoreboard && cg.scoreBoardShowing )
{
Menu_ScrollFeeder( menuScoreboard, FEEDER_ALIENTEAM_LIST, qtrue );
Menu_ScrollFeeder( menuScoreboard, FEEDER_HUMANTEAM_LIST, qtrue );
}
}
static void CG_scrollScoresUp_f( void )
{
if( menuScoreboard && cg.scoreBoardShowing )
{
Menu_ScrollFeeder( menuScoreboard, FEEDER_ALIENTEAM_LIST, qfalse );
Menu_ScrollFeeder( menuScoreboard, FEEDER_HUMANTEAM_LIST, qfalse );
}
}
static void CG_ScoresDown_f( void )
{
if( !cg.showScores )
{
Menu_SetFeederSelection( menuScoreboard, FEEDER_ALIENTEAM_LIST, 0, NULL );
Menu_SetFeederSelection( menuScoreboard, FEEDER_HUMANTEAM_LIST, 0, NULL );
}
if( CG_RequestScores( ) )
{
// leave the current scores up if they were already
// displayed, but if this is the first hit, clear them out
if( !cg.showScores )
{
if( cg_debugRandom.integer )
CG_Printf( "CG_ScoresDown_f: scores out of date\n" );
cg.showScores = qtrue;
cg.numScores = 0;
}
}
else
{
// show the cached contents even if they just pressed if it
// is within two seconds
cg.showScores = qtrue;
}
}
static void CG_ScoresUp_f( void )
{
if( cg.showScores )
{
cg.showScores = qfalse;
cg.scoreFadeTime = cg.time;
}
}
static void CG_TellTarget_f( void )
{
int clientNum;
char command[ 128 ];
char message[ 128 ];
clientNum = CG_CrosshairPlayer( );
if( clientNum == -1 )
return;
trap_Args( message, 128 );
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
trap_SendClientCommand( command );
}
static void CG_TellAttacker_f( void )
{
int clientNum;
char command[ 128 ];
char message[ 128 ];
clientNum = CG_LastAttacker( );
if( clientNum == -1 )
return;
trap_Args( message, 128 );
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
trap_SendClientCommand( command );
}
typedef struct
{
char *cmd;
void (*function)( void );
} consoleCommand_t;
static consoleCommand_t commands[ ] =
{
{ "testgun", CG_TestGun_f },
{ "testmodel", CG_TestModel_f },
{ "nextframe", CG_TestModelNextFrame_f },
{ "prevframe", CG_TestModelPrevFrame_f },
{ "nextskin", CG_TestModelNextSkin_f },
{ "prevskin", CG_TestModelPrevSkin_f },
{ "viewpos", CG_Viewpos_f },
{ "+scores", CG_ScoresDown_f },
{ "-scores", CG_ScoresUp_f },
{ "scoresUp", CG_scrollScoresUp_f },
{ "scoresDown", CG_scrollScoresDown_f },
{ "sizeup", CG_SizeUp_f },
{ "sizedown", CG_SizeDown_f },
{ "weapnext", CG_NextWeapon_f },
{ "weapprev", CG_PrevWeapon_f },
{ "weapon", CG_Weapon_f },
{ "tell_target", CG_TellTarget_f },
{ "tell_attacker", CG_TellAttacker_f },
{ "tcmd", CG_TargetCommand_f },
{ "testPS", CG_TestPS_f },
{ "destroyTestPS", CG_DestroyTestPS_f },
{ "testTS", CG_TestTS_f },
{ "destroyTestTS", CG_DestroyTestTS_f },
};
/*
=================
CG_ConsoleCommand
The string has been tokenized and can be retrieved with
Cmd_Argc() / Cmd_Argv()
=================
*/
qboolean CG_ConsoleCommand( void )
{
const char *cmd;
const char *arg1;
int i;
cmd = CG_Argv( 0 );
//TA: ugly hacky special case
if( !Q_stricmp( cmd, "ui_menu" ) )
{
arg1 = CG_Argv( 1 );
trap_SendConsoleCommand( va( "menu %s\n", arg1 ) );
return qtrue;
}
for( i = 0; i < sizeof( commands ) / sizeof( commands[ 0 ] ); i++ )
{
if( !Q_stricmp( cmd, commands[ i ].cmd ) )
{
commands[ i ].function( );
return qtrue;
}
}
return qfalse;
}
/*
=================
CG_InitConsoleCommands
Let the client system know about all of our commands
so it can perform tab completion
=================
*/
void CG_InitConsoleCommands( void )
{
int i;
for( i = 0 ; i < sizeof( commands ) / sizeof( commands[ 0 ] ) ; i++ )
trap_AddCommand( commands[ i ].cmd );
//
// the game server will interpret these commands, which will be automatically
// forwarded to the server after they are not recognized locally
//
trap_AddCommand( "kill" );
trap_AddCommand( "say" );
trap_AddCommand( "say_team" );
trap_AddCommand( "tell" );
trap_AddCommand( "vsay" );
trap_AddCommand( "vsay_team" );
trap_AddCommand( "vtell" );
trap_AddCommand( "vtaunt" );
trap_AddCommand( "vosay" );
trap_AddCommand( "vosay_team" );
trap_AddCommand( "votell" );
trap_AddCommand( "give" );
trap_AddCommand( "god" );
trap_AddCommand( "notarget" );
trap_AddCommand( "noclip" );
trap_AddCommand( "team" );
trap_AddCommand( "follow" );
trap_AddCommand( "levelshot" );
trap_AddCommand( "addbot" );
trap_AddCommand( "setviewpos" );
trap_AddCommand( "callvote" );
trap_AddCommand( "vote" );
trap_AddCommand( "callteamvote" );
trap_AddCommand( "teamvote" );
trap_AddCommand( "stats" );
trap_AddCommand( "teamtask" );
trap_AddCommand( "class" );
trap_AddCommand( "build" );
trap_AddCommand( "buy" );
trap_AddCommand( "sell" );
trap_AddCommand( "reload" );
trap_AddCommand( "itemact" );
trap_AddCommand( "itemdeact" );
trap_AddCommand( "itemtoggle" );
trap_AddCommand( "destroy" );
trap_AddCommand( "deconstruct" );
trap_AddCommand( "menu" );
trap_AddCommand( "ui_menu" );
trap_AddCommand( "mapRotation" );
trap_AddCommand( "stopMapRotation" );
trap_AddCommand( "advanceMapRotation" );
trap_AddCommand( "alienWin" );
trap_AddCommand( "humanWin" );
}
+3524 -3524
View File
File diff suppressed because it is too large. Load diff
+378 -378
View File
@@ -1,378 +1,378 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
#include "cg_local.h"
/*
===============
CG_DrawPlane
Draw a quad in 3 space - basically CG_DrawPic in 3 space
===============
*/
void CG_DrawPlane( vec3_t origin, vec3_t down, vec3_t right, qhandle_t shader )
{
polyVert_t verts[ 4 ];
vec3_t temp;
VectorCopy( origin, verts[ 0 ].xyz );
verts[ 0 ].st[ 0 ] = 0;
verts[ 0 ].st[ 1 ] = 0;
verts[ 0 ].modulate[ 0 ] = 255;
verts[ 0 ].modulate[ 1 ] = 255;
verts[ 0 ].modulate[ 2 ] = 255;
verts[ 0 ].modulate[ 3 ] = 255;
VectorAdd( origin, right, temp );
VectorCopy( temp, verts[ 1 ].xyz );
verts[ 1 ].st[ 0 ] = 1;
verts[ 1 ].st[ 1 ] = 0;
verts[ 1 ].modulate[ 0 ] = 255;
verts[ 1 ].modulate[ 1 ] = 255;
verts[ 1 ].modulate[ 2 ] = 255;
verts[ 1 ].modulate[ 3 ] = 255;
VectorAdd( origin, right, temp );
VectorAdd( temp, down, temp );
VectorCopy( temp, verts[ 2 ].xyz );
verts[ 2 ].st[ 0 ] = 1;
verts[ 2 ].st[ 1 ] = 1;
verts[ 2 ].modulate[ 0 ] = 255;
verts[ 2 ].modulate[ 1 ] = 255;
verts[ 2 ].modulate[ 2 ] = 255;
verts[ 2 ].modulate[ 3 ] = 255;
VectorAdd( origin, down, temp );
VectorCopy( temp, verts[ 3 ].xyz );
verts[ 3 ].st[ 0 ] = 0;
verts[ 3 ].st[ 1 ] = 1;
verts[ 3 ].modulate[ 0 ] = 255;
verts[ 3 ].modulate[ 1 ] = 255;
verts[ 3 ].modulate[ 2 ] = 255;
verts[ 3 ].modulate[ 3 ] = 255;
trap_R_AddPolyToScene( shader, 4, verts );
}
/*
================
CG_AdjustFrom640
Adjusted for resolution and screen aspect ratio
================
*/
void CG_AdjustFrom640( float *x, float *y, float *w, float *h )
{
#if 0
// adjust for wide screens
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
}
#endif
// scale for screen sizes
*x *= cgs.screenXScale;
*y *= cgs.screenYScale;
*w *= cgs.screenXScale;
*h *= cgs.screenYScale;
}
/*
================
CG_FillRect
Coordinates are 640*480 virtual values
=================
*/
void CG_FillRect( float x, float y, float width, float height, const float *color )
{
trap_R_SetColor( color );
CG_AdjustFrom640( &x, &y, &width, &height );
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
trap_R_SetColor( NULL );
}
/*
================
CG_DrawSides
Coords are virtual 640x480
================
*/
void CG_DrawSides( float x, float y, float w, float h, float size )
{
CG_AdjustFrom640( &x, &y, &w, &h );
size *= cgs.screenXScale;
trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
}
void CG_DrawTopBottom( float x, float y, float w, float h, float size )
{
CG_AdjustFrom640( &x, &y, &w, &h );
size *= cgs.screenYScale;
trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
}
/*
================
CG_DrawRect
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawRect( float x, float y, float width, float height, float size, const float *color )
{
trap_R_SetColor( color );
CG_DrawTopBottom( x, y, width, height, size );
CG_DrawSides( x, y, width, height, size );
trap_R_SetColor( NULL );
}
/*
================
CG_DrawPic
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader )
{
CG_AdjustFrom640( &x, &y, &width, &height );
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}
/*
================
CG_DrawFadePic
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor,
vec4_t tcolor, float amount, qhandle_t hShader )
{
vec4_t finalcolor;
float inverse;
inverse = 100 - amount;
CG_AdjustFrom640( &x, &y, &width, &height );
finalcolor[ 0 ] = ( ( inverse * fcolor[ 0 ] ) + ( amount * tcolor[ 0 ] ) ) / 100;
finalcolor[ 1 ] = ( ( inverse * fcolor[ 1 ] ) + ( amount * tcolor[ 1 ] ) ) / 100;
finalcolor[ 2 ] = ( ( inverse * fcolor[ 2 ] ) + ( amount * tcolor[ 2 ] ) ) / 100;
finalcolor[ 3 ] = ( ( inverse * fcolor[ 3 ] ) + ( amount * tcolor[ 3 ] ) ) / 100;
trap_R_SetColor( finalcolor );
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
trap_R_SetColor( NULL );
}
/*
=================
CG_DrawStrlen
Returns character count, skiping color escape codes
=================
*/
int CG_DrawStrlen( const char *str )
{
const char *s = str;
int count = 0;
while( *s )
{
if( Q_IsColorString( s ) )
s += 2;
else
{
count++;
s++;
}
}
return count;
}
/*
=============
CG_TileClearBox
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader )
{
float s1, t1, s2, t2;
s1 = x / 64.0;
t1 = y / 64.0;
s2 = ( x + w ) / 64.0;
t2 = ( y + h ) / 64.0;
trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
}
/*
==============
CG_TileClear
Clear around a sized down screen
==============
*/
void CG_TileClear( void )
{
int top, bottom, left, right;
int w, h;
w = cgs.glconfig.vidWidth;
h = cgs.glconfig.vidHeight;
if( cg.refdef.x == 0 && cg.refdef.y == 0 &&
cg.refdef.width == w && cg.refdef.height == h )
return; // full screen rendering
top = cg.refdef.y;
bottom = top + cg.refdef.height - 1;
left = cg.refdef.x;
right = left + cg.refdef.width - 1;
// clear above view screen
CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
// clear below view screen
CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
// clear left of view screen
CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
// clear right of view screen
CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
}
/*
================
CG_FadeColor
================
*/
float *CG_FadeColor( int startMsec, int totalMsec )
{
static vec4_t color;
int t;
if( startMsec == 0 )
return NULL;
t = cg.time - startMsec;
if( t >= totalMsec )
return NULL;
// fade out
if( totalMsec - t < FADE_TIME )
color[ 3 ] = ( totalMsec - t ) * 1.0 / FADE_TIME;
else
color[ 3 ] = 1.0;
color[ 0 ] = color[ 1 ] = color[ 2 ] = 1;
return color;
}
/*
================
CG_WorldToScreen
================
*/
qboolean CG_WorldToScreen( vec3_t point, float *x, float *y )
{
vec3_t trans;
float xc, yc;
float px, py;
float z;
px = tan( cg.refdef.fov_x * M_PI / 360.0 );
py = tan( cg.refdef.fov_y * M_PI / 360.0 );
VectorSubtract( point, cg.refdef.vieworg, trans );
xc = 640.0f / 2.0f;
yc = 480.0f / 2.0f;
z = DotProduct( trans, cg.refdef.viewaxis[ 0 ] );
if( z <= 0.001f )
return qfalse;
if( x )
*x = xc - DotProduct( trans, cg.refdef.viewaxis[ 1 ] ) * xc / ( z * px );
if( y )
*y = yc - DotProduct( trans, cg.refdef.viewaxis[ 2 ] ) * yc / ( z * py );
return qtrue;
}
/*
================
CG_KeyBinding
================
*/
char *CG_KeyBinding( const char *bind )
{
static char key[ 32 ];
char bindbuff[ MAX_CVAR_VALUE_STRING ];
int i;
key[ 0 ] = '\0';
// NOTE: change K_LAST_KEY to MAX_KEYS for full key support (eventually)
for( i = 0; i < K_LAST_KEY; i++ )
{
trap_Key_GetBindingBuf( i, bindbuff, sizeof( bindbuff ) );
if( !Q_stricmp( bindbuff, bind ) )
{
trap_Key_KeynumToStringBuf( i, key, sizeof( key ) );
break;
}
}
if( !key[ 0 ] )
{
Q_strncpyz( key, "\\", sizeof( key ) );
Q_strcat( key, sizeof( key ), bind );
}
return key;
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
#include "cg_local.h"
/*
===============
CG_DrawPlane
Draw a quad in 3 space - basically CG_DrawPic in 3 space
===============
*/
void CG_DrawPlane( vec3_t origin, vec3_t down, vec3_t right, qhandle_t shader )
{
polyVert_t verts[ 4 ];
vec3_t temp;
VectorCopy( origin, verts[ 0 ].xyz );
verts[ 0 ].st[ 0 ] = 0;
verts[ 0 ].st[ 1 ] = 0;
verts[ 0 ].modulate[ 0 ] = 255;
verts[ 0 ].modulate[ 1 ] = 255;
verts[ 0 ].modulate[ 2 ] = 255;
verts[ 0 ].modulate[ 3 ] = 255;
VectorAdd( origin, right, temp );
VectorCopy( temp, verts[ 1 ].xyz );
verts[ 1 ].st[ 0 ] = 1;
verts[ 1 ].st[ 1 ] = 0;
verts[ 1 ].modulate[ 0 ] = 255;
verts[ 1 ].modulate[ 1 ] = 255;
verts[ 1 ].modulate[ 2 ] = 255;
verts[ 1 ].modulate[ 3 ] = 255;
VectorAdd( origin, right, temp );
VectorAdd( temp, down, temp );
VectorCopy( temp, verts[ 2 ].xyz );
verts[ 2 ].st[ 0 ] = 1;
verts[ 2 ].st[ 1 ] = 1;
verts[ 2 ].modulate[ 0 ] = 255;
verts[ 2 ].modulate[ 1 ] = 255;
verts[ 2 ].modulate[ 2 ] = 255;
verts[ 2 ].modulate[ 3 ] = 255;
VectorAdd( origin, down, temp );
VectorCopy( temp, verts[ 3 ].xyz );
verts[ 3 ].st[ 0 ] = 0;
verts[ 3 ].st[ 1 ] = 1;
verts[ 3 ].modulate[ 0 ] = 255;
verts[ 3 ].modulate[ 1 ] = 255;
verts[ 3 ].modulate[ 2 ] = 255;
verts[ 3 ].modulate[ 3 ] = 255;
trap_R_AddPolyToScene( shader, 4, verts );
}
/*
================
CG_AdjustFrom640
Adjusted for resolution and screen aspect ratio
================
*/
void CG_AdjustFrom640( float *x, float *y, float *w, float *h )
{
#if 0
// adjust for wide screens
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
}
#endif
// scale for screen sizes
*x *= cgs.screenXScale;
*y *= cgs.screenYScale;
*w *= cgs.screenXScale;
*h *= cgs.screenYScale;
}
/*
================
CG_FillRect
Coordinates are 640*480 virtual values
=================
*/
void CG_FillRect( float x, float y, float width, float height, const float *color )
{
trap_R_SetColor( color );
CG_AdjustFrom640( &x, &y, &width, &height );
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
trap_R_SetColor( NULL );
}
/*
================
CG_DrawSides
Coords are virtual 640x480
================
*/
void CG_DrawSides( float x, float y, float w, float h, float size )
{
CG_AdjustFrom640( &x, &y, &w, &h );
size *= cgs.screenXScale;
trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
}
void CG_DrawTopBottom( float x, float y, float w, float h, float size )
{
CG_AdjustFrom640( &x, &y, &w, &h );
size *= cgs.screenYScale;
trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
}
/*
================
CG_DrawRect
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawRect( float x, float y, float width, float height, float size, const float *color )
{
trap_R_SetColor( color );
CG_DrawTopBottom( x, y, width, height, size );
CG_DrawSides( x, y, width, height, size );
trap_R_SetColor( NULL );
}
/*
================
CG_DrawPic
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader )
{
CG_AdjustFrom640( &x, &y, &width, &height );
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}
/*
================
CG_DrawFadePic
Coordinates are 640*480 virtual values
=================
*/
void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor,
vec4_t tcolor, float amount, qhandle_t hShader )
{
vec4_t finalcolor;
float inverse;
inverse = 100 - amount;
CG_AdjustFrom640( &x, &y, &width, &height );
finalcolor[ 0 ] = ( ( inverse * fcolor[ 0 ] ) + ( amount * tcolor[ 0 ] ) ) / 100;
finalcolor[ 1 ] = ( ( inverse * fcolor[ 1 ] ) + ( amount * tcolor[ 1 ] ) ) / 100;
finalcolor[ 2 ] = ( ( inverse * fcolor[ 2 ] ) + ( amount * tcolor[ 2 ] ) ) / 100;
finalcolor[ 3 ] = ( ( inverse * fcolor[ 3 ] ) + ( amount * tcolor[ 3 ] ) ) / 100;
trap_R_SetColor( finalcolor );
trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
trap_R_SetColor( NULL );
}
/*
=================
CG_DrawStrlen
Returns character count, skiping color escape codes
=================
*/
int CG_DrawStrlen( const char *str )
{
const char *s = str;
int count = 0;
while( *s )
{
if( Q_IsColorString( s ) )
s += 2;
else
{
count++;
s++;
}
}
return count;
}
/*
=============
CG_TileClearBox
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader )
{
float s1, t1, s2, t2;
s1 = x / 64.0;
t1 = y / 64.0;
s2 = ( x + w ) / 64.0;
t2 = ( y + h ) / 64.0;
trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
}
/*
==============
CG_TileClear
Clear around a sized down screen
==============
*/
void CG_TileClear( void )
{
int top, bottom, left, right;
int w, h;
w = cgs.glconfig.vidWidth;
h = cgs.glconfig.vidHeight;
if( cg.refdef.x == 0 && cg.refdef.y == 0 &&
cg.refdef.width == w && cg.refdef.height == h )
return; // full screen rendering
top = cg.refdef.y;
bottom = top + cg.refdef.height - 1;
left = cg.refdef.x;
right = left + cg.refdef.width - 1;
// clear above view screen
CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
// clear below view screen
CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
// clear left of view screen
CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
// clear right of view screen
CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
}
/*
================
CG_FadeColor
================
*/
float *CG_FadeColor( int startMsec, int totalMsec )
{
static vec4_t color;
int t;
if( startMsec == 0 )
return NULL;
t = cg.time - startMsec;
if( t >= totalMsec )
return NULL;
// fade out
if( totalMsec - t < FADE_TIME )
color[ 3 ] = ( totalMsec - t ) * 1.0 / FADE_TIME;
else
color[ 3 ] = 1.0;
color[ 0 ] = color[ 1 ] = color[ 2 ] = 1;
return color;
}
/*
================
CG_WorldToScreen
================
*/
qboolean CG_WorldToScreen( vec3_t point, float *x, float *y )
{
vec3_t trans;
float xc, yc;
float px, py;
float z;
px = tan( cg.refdef.fov_x * M_PI / 360.0 );
py = tan( cg.refdef.fov_y * M_PI / 360.0 );
VectorSubtract( point, cg.refdef.vieworg, trans );
xc = 640.0f / 2.0f;
yc = 480.0f / 2.0f;
z = DotProduct( trans, cg.refdef.viewaxis[ 0 ] );
if( z <= 0.001f )
return qfalse;
if( x )
*x = xc - DotProduct( trans, cg.refdef.viewaxis[ 1 ] ) * xc / ( z * px );
if( y )
*y = yc - DotProduct( trans, cg.refdef.viewaxis[ 2 ] ) * yc / ( z * py );
return qtrue;
}
/*
================
CG_KeyBinding
================
*/
char *CG_KeyBinding( const char *bind )
{
static char key[ 32 ];
char bindbuff[ MAX_CVAR_VALUE_STRING ];
int i;
key[ 0 ] = '\0';
// NOTE: change K_LAST_KEY to MAX_KEYS for full key support (eventually)
for( i = 0; i < K_LAST_KEY; i++ )
{
trap_Key_GetBindingBuf( i, bindbuff, sizeof( bindbuff ) );
if( !Q_stricmp( bindbuff, bind ) )
{
trap_Key_KeynumToStringBuf( i, key, sizeof( key ) );
break;
}
}
if( !key[ 0 ] )
{
Q_strncpyz( key, "\\", sizeof( key ) );
Q_strcat( key, sizeof( key ), bind );
}
return key;
}
+1256 -1256
View File
File diff suppressed because it is too large. Load diff
+1034 -1034
View File
File diff suppressed because it is too large. Load diff
+2071 -2071
View File
File diff suppressed because it is too large. Load diff
+1840 -1840
View File
File diff suppressed because it is too large. Load diff
+289 -289
View File
@@ -1,289 +1,289 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_marks.c -- wall marks
#include "cg_local.h"
/*
===================================================================
MARK POLYS
===================================================================
*/
markPoly_t cg_activeMarkPolys; // double linked list
markPoly_t *cg_freeMarkPolys; // single linked list
markPoly_t cg_markPolys[ MAX_MARK_POLYS ];
static int markTotal;
/*
===================
CG_InitMarkPolys
This is called at startup and for tournement restarts
===================
*/
void CG_InitMarkPolys( void )
{
int i;
memset( cg_markPolys, 0, sizeof( cg_markPolys ) );
cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
cg_freeMarkPolys = cg_markPolys;
for( i = 0; i < MAX_MARK_POLYS - 1; i++ )
cg_markPolys[ i ].nextMark = &cg_markPolys[ i + 1 ];
}
/*
==================
CG_FreeMarkPoly
==================
*/
void CG_FreeMarkPoly( markPoly_t *le )
{
if( !le->prevMark )
CG_Error( "CG_FreeLocalEntity: not active" );
// remove from the doubly linked active list
le->prevMark->nextMark = le->nextMark;
le->nextMark->prevMark = le->prevMark;
// the free list is only singly linked
le->nextMark = cg_freeMarkPolys;
cg_freeMarkPolys = le;
}
/*
===================
CG_AllocMark
Will allways succeed, even if it requires freeing an old active mark
===================
*/
markPoly_t *CG_AllocMark( void )
{
markPoly_t *le;
int time;
if( !cg_freeMarkPolys )
{
// no free entities, so free the one at the end of the chain
// remove the oldest active entity
time = cg_activeMarkPolys.prevMark->time;
while( cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time )
CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
}
le = cg_freeMarkPolys;
cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
memset( le, 0, sizeof( *le ) );
// link into the active list
le->nextMark = cg_activeMarkPolys.nextMark;
le->prevMark = &cg_activeMarkPolys;
cg_activeMarkPolys.nextMark->prevMark = le;
cg_activeMarkPolys.nextMark = le;
return le;
}
/*
=================
CG_ImpactMark
origin should be a point within a unit of the plane
dir should be the plane normal
temporary marks will not be stored or randomly oriented, but immediately
passed to the renderer.
=================
*/
#define MAX_MARK_FRAGMENTS 128
#define MAX_MARK_POINTS 384
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
float orientation, float red, float green, float blue, float alpha,
qboolean alphaFade, float radius, qboolean temporary )
{
vec3_t axis[ 3 ];
float texCoordScale;
vec3_t originalPoints[ 4 ];
byte colors[ 4 ];
int i, j;
int numFragments;
markFragment_t markFragments[ MAX_MARK_FRAGMENTS ], *mf;
vec3_t markPoints[ MAX_MARK_POINTS ];
vec3_t projection;
if( !cg_addMarks.integer )
return;
if( radius <= 0 )
CG_Error( "CG_ImpactMark called with <= 0 radius" );
//if ( markTotal >= MAX_MARK_POLYS ) {
// return;
//}
// create the texture axis
VectorNormalize2( dir, axis[ 0 ] );
PerpendicularVector( axis[ 1 ], axis[ 0 ] );
RotatePointAroundVector( axis[ 2 ], axis[ 0 ], axis[ 1 ], orientation );
CrossProduct( axis[ 0 ], axis[ 2 ], axis[ 1 ] );
texCoordScale = 0.5 * 1.0 / radius;
// create the full polygon
for( i = 0; i < 3; i++ )
{
originalPoints[ 0 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ];
originalPoints[ 1 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ];
originalPoints[ 2 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ];
originalPoints[ 3 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ];
}
// get the fragments
VectorScale( dir, -20, projection );
numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
projection, MAX_MARK_POINTS, markPoints[ 0 ],
MAX_MARK_FRAGMENTS, markFragments );
colors[ 0 ] = red * 255;
colors[ 1 ] = green * 255;
colors[ 2 ] = blue * 255;
colors[ 3 ] = alpha * 255;
for( i = 0, mf = markFragments; i < numFragments; i++, mf++ )
{
polyVert_t *v;
polyVert_t verts[ MAX_VERTS_ON_POLY ];
markPoly_t *mark;
// we have an upper limit on the complexity of polygons
// that we store persistantly
if( mf->numPoints > MAX_VERTS_ON_POLY )
mf->numPoints = MAX_VERTS_ON_POLY;
for( j = 0, v = verts; j < mf->numPoints; j++, v++ )
{
vec3_t delta;
VectorCopy( markPoints[ mf->firstPoint + j ], v->xyz );
VectorSubtract( v->xyz, origin, delta );
v->st[ 0 ] = 0.5 + DotProduct( delta, axis[ 1 ] ) * texCoordScale;
v->st[ 1 ] = 0.5 + DotProduct( delta, axis[ 2 ] ) * texCoordScale;
*(int *)v->modulate = *(int *)colors;
}
// if it is a temporary (shadow) mark, add it immediately and forget about it
if( temporary )
{
trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
continue;
}
// otherwise save it persistantly
mark = CG_AllocMark( );
mark->time = cg.time;
mark->alphaFade = alphaFade;
mark->markShader = markShader;
mark->poly.numVerts = mf->numPoints;
mark->color[ 0 ] = red;
mark->color[ 1 ] = green;
mark->color[ 2 ] = blue;
mark->color[ 3 ] = alpha;
memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[ 0 ] ) );
markTotal++;
}
}
/*
===============
CG_AddMarks
===============
*/
#define MARK_TOTAL_TIME 10000
#define MARK_FADE_TIME 1000
void CG_AddMarks( void )
{
int j;
markPoly_t *mp, *next;
int t;
int fade;
if( !cg_addMarks.integer )
return;
mp = cg_activeMarkPolys.nextMark;
for ( ; mp != &cg_activeMarkPolys; mp = next )
{
// grab next now, so if the local entity is freed we
// still have it
next = mp->nextMark;
// see if it is time to completely remove it
if( cg.time > mp->time + MARK_TOTAL_TIME )
{
CG_FreeMarkPoly( mp );
continue;
}
// fade all marks out with time
t = mp->time + MARK_TOTAL_TIME - cg.time;
if( t < MARK_FADE_TIME )
{
fade = 255 * t / MARK_FADE_TIME;
if( mp->alphaFade )
{
for( j = 0; j < mp->poly.numVerts; j++ )
mp->verts[ j ].modulate[ 3 ] = fade;
}
else
{
for( j = 0; j < mp->poly.numVerts; j++ )
{
mp->verts[ j ].modulate[ 0 ] = mp->color[ 0 ] * fade;
mp->verts[ j ].modulate[ 1 ] = mp->color[ 1 ] * fade;
mp->verts[ j ].modulate[ 2 ] = mp->color[ 2 ] * fade;
}
}
}
trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
}
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_marks.c -- wall marks
#include "cg_local.h"
/*
===================================================================
MARK POLYS
===================================================================
*/
markPoly_t cg_activeMarkPolys; // double linked list
markPoly_t *cg_freeMarkPolys; // single linked list
markPoly_t cg_markPolys[ MAX_MARK_POLYS ];
static int markTotal;
/*
===================
CG_InitMarkPolys
This is called at startup and for tournement restarts
===================
*/
void CG_InitMarkPolys( void )
{
int i;
memset( cg_markPolys, 0, sizeof( cg_markPolys ) );
cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
cg_freeMarkPolys = cg_markPolys;
for( i = 0; i < MAX_MARK_POLYS - 1; i++ )
cg_markPolys[ i ].nextMark = &cg_markPolys[ i + 1 ];
}
/*
==================
CG_FreeMarkPoly
==================
*/
void CG_FreeMarkPoly( markPoly_t *le )
{
if( !le->prevMark )
CG_Error( "CG_FreeLocalEntity: not active" );
// remove from the doubly linked active list
le->prevMark->nextMark = le->nextMark;
le->nextMark->prevMark = le->prevMark;
// the free list is only singly linked
le->nextMark = cg_freeMarkPolys;
cg_freeMarkPolys = le;
}
/*
===================
CG_AllocMark
Will allways succeed, even if it requires freeing an old active mark
===================
*/
markPoly_t *CG_AllocMark( void )
{
markPoly_t *le;
int time;
if( !cg_freeMarkPolys )
{
// no free entities, so free the one at the end of the chain
// remove the oldest active entity
time = cg_activeMarkPolys.prevMark->time;
while( cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time )
CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
}
le = cg_freeMarkPolys;
cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
memset( le, 0, sizeof( *le ) );
// link into the active list
le->nextMark = cg_activeMarkPolys.nextMark;
le->prevMark = &cg_activeMarkPolys;
cg_activeMarkPolys.nextMark->prevMark = le;
cg_activeMarkPolys.nextMark = le;
return le;
}
/*
=================
CG_ImpactMark
origin should be a point within a unit of the plane
dir should be the plane normal
temporary marks will not be stored or randomly oriented, but immediately
passed to the renderer.
=================
*/
#define MAX_MARK_FRAGMENTS 128
#define MAX_MARK_POINTS 384
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir,
float orientation, float red, float green, float blue, float alpha,
qboolean alphaFade, float radius, qboolean temporary )
{
vec3_t axis[ 3 ];
float texCoordScale;
vec3_t originalPoints[ 4 ];
byte colors[ 4 ];
int i, j;
int numFragments;
markFragment_t markFragments[ MAX_MARK_FRAGMENTS ], *mf;
vec3_t markPoints[ MAX_MARK_POINTS ];
vec3_t projection;
if( !cg_addMarks.integer )
return;
if( radius <= 0 )
CG_Error( "CG_ImpactMark called with <= 0 radius" );
//if ( markTotal >= MAX_MARK_POLYS ) {
// return;
//}
// create the texture axis
VectorNormalize2( dir, axis[ 0 ] );
PerpendicularVector( axis[ 1 ], axis[ 0 ] );
RotatePointAroundVector( axis[ 2 ], axis[ 0 ], axis[ 1 ], orientation );
CrossProduct( axis[ 0 ], axis[ 2 ], axis[ 1 ] );
texCoordScale = 0.5 * 1.0 / radius;
// create the full polygon
for( i = 0; i < 3; i++ )
{
originalPoints[ 0 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ];
originalPoints[ 1 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ];
originalPoints[ 2 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ];
originalPoints[ 3 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ];
}
// get the fragments
VectorScale( dir, -20, projection );
numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
projection, MAX_MARK_POINTS, markPoints[ 0 ],
MAX_MARK_FRAGMENTS, markFragments );
colors[ 0 ] = red * 255;
colors[ 1 ] = green * 255;
colors[ 2 ] = blue * 255;
colors[ 3 ] = alpha * 255;
for( i = 0, mf = markFragments; i < numFragments; i++, mf++ )
{
polyVert_t *v;
polyVert_t verts[ MAX_VERTS_ON_POLY ];
markPoly_t *mark;
// we have an upper limit on the complexity of polygons
// that we store persistantly
if( mf->numPoints > MAX_VERTS_ON_POLY )
mf->numPoints = MAX_VERTS_ON_POLY;
for( j = 0, v = verts; j < mf->numPoints; j++, v++ )
{
vec3_t delta;
VectorCopy( markPoints[ mf->firstPoint + j ], v->xyz );
VectorSubtract( v->xyz, origin, delta );
v->st[ 0 ] = 0.5 + DotProduct( delta, axis[ 1 ] ) * texCoordScale;
v->st[ 1 ] = 0.5 + DotProduct( delta, axis[ 2 ] ) * texCoordScale;
*(int *)v->modulate = *(int *)colors;
}
// if it is a temporary (shadow) mark, add it immediately and forget about it
if( temporary )
{
trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
continue;
}
// otherwise save it persistantly
mark = CG_AllocMark( );
mark->time = cg.time;
mark->alphaFade = alphaFade;
mark->markShader = markShader;
mark->poly.numVerts = mf->numPoints;
mark->color[ 0 ] = red;
mark->color[ 1 ] = green;
mark->color[ 2 ] = blue;
mark->color[ 3 ] = alpha;
memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[ 0 ] ) );
markTotal++;
}
}
/*
===============
CG_AddMarks
===============
*/
#define MARK_TOTAL_TIME 10000
#define MARK_FADE_TIME 1000
void CG_AddMarks( void )
{
int j;
markPoly_t *mp, *next;
int t;
int fade;
if( !cg_addMarks.integer )
return;
mp = cg_activeMarkPolys.nextMark;
for ( ; mp != &cg_activeMarkPolys; mp = next )
{
// grab next now, so if the local entity is freed we
// still have it
next = mp->nextMark;
// see if it is time to completely remove it
if( cg.time > mp->time + MARK_TOTAL_TIME )
{
CG_FreeMarkPoly( mp );
continue;
}
// fade all marks out with time
t = mp->time + MARK_TOTAL_TIME - cg.time;
if( t < MARK_FADE_TIME )
{
fade = 255 * t / MARK_FADE_TIME;
if( mp->alphaFade )
{
for( j = 0; j < mp->poly.numVerts; j++ )
mp->verts[ j ].modulate[ 3 ] = fade;
}
else
{
for( j = 0; j < mp->poly.numVerts; j++ )
{
mp->verts[ j ].modulate[ 0 ] = mp->color[ 0 ] * fade;
mp->verts[ j ].modulate[ 1 ] = mp->color[ 1 ] * fade;
mp->verts[ j ].modulate[ 2 ] = mp->color[ 2 ] * fade;
}
}
}
trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
}
}
+202 -202
View File
@@ -1,202 +1,202 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
#define POOLSIZE (256 * 1024)
#define FREEMEMCOOKIE ((int)0xDEADBE3F) // Any unlikely to be used value
#define ROUNDBITS 31 // Round to 32 bytes
struct freememnode
{
// Size of ROUNDBITS
int cookie, size; // Size includes node (obviously)
struct freememnode *prev, *next;
};
static char memoryPool[ POOLSIZE ];
static struct freememnode *freehead;
static int freemem;
void *CG_Alloc( int size )
{
// Find a free block and allocate.
// Does two passes, attempts to fill same-sized free slot first.
struct freememnode *fmn, *prev, *next, *smallest;
int allocsize, smallestsize;
char *endptr;
int *ptr;
allocsize = ( size + sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
ptr = NULL;
smallest = NULL;
smallestsize = POOLSIZE + 1; // Guaranteed not to miss any slots :)
for( fmn = freehead; fmn; fmn = fmn->next )
{
if( fmn->cookie != FREEMEMCOOKIE )
CG_Error( "CG_Alloc: Memory corruption detected!\n" );
if( fmn->size >= allocsize )
{
// We've got a block
if( fmn->size == allocsize )
{
// Same size, just remove
prev = fmn->prev;
next = fmn->next;
if( prev )
prev->next = next; // Point previous node to next
if( next )
next->prev = prev; // Point next node to previous
if( fmn == freehead )
freehead = next; // Set head pointer to next
ptr = (int *) fmn;
break; // Stop the loop, this is fine
}
else
{
// Keep track of the smallest free slot
if( fmn->size < smallestsize )
{
smallest = fmn;
smallestsize = fmn->size;
}
}
}
}
if( !ptr && smallest )
{
// We found a slot big enough
smallest->size -= allocsize;
endptr = (char *) smallest + smallest->size;
ptr = (int *) endptr;
}
if( ptr )
{
freemem -= allocsize;
if( cg_debugAlloc.integer )
CG_Printf( "CG_Alloc of %i bytes (%i left)\n", allocsize, freemem );
memset( ptr, 0, allocsize );
*ptr++ = allocsize; // Store a copy of size for deallocation
return( (void *) ptr );
}
CG_Error( "CG_Alloc: failed on allocation of %i bytes\n", size );
return( NULL );
}
void CG_Free( void *ptr )
{
// Release allocated memory, add it to the free list.
struct freememnode *fmn;
char *freeend;
int *freeptr;
freeptr = ptr;
freeptr--;
freemem += *freeptr;
if( cg_debugAlloc.integer )
CG_Printf( "CG_Free of %i bytes (%i left)\n", *freeptr, freemem );
for( fmn = freehead; fmn; fmn = fmn->next )
{
freeend = ((char *) fmn) + fmn->size;
if( freeend == (char *) freeptr )
{
// Released block can be merged to an existing node
fmn->size += *freeptr; // Add size of node.
return;
}
}
// No merging, add to head of list
fmn = (struct freememnode *) freeptr;
fmn->size = *freeptr; // Set this first to avoid corrupting *freeptr
fmn->cookie = FREEMEMCOOKIE;
fmn->prev = NULL;
fmn->next = freehead;
freehead->prev = fmn;
freehead = fmn;
}
void CG_InitMemory( void )
{
// Set up the initial node
freehead = (struct freememnode *) memoryPool;
freehead->cookie = FREEMEMCOOKIE;
freehead->size = POOLSIZE;
freehead->next = NULL;
freehead->prev = NULL;
freemem = sizeof(memoryPool);
}
void CG_DefragmentMemory( void )
{
// If there's a frenzy of deallocation and we want to
// allocate something big, this is useful. Otherwise...
// not much use.
struct freememnode *startfmn, *endfmn, *fmn;
for( startfmn = freehead; startfmn; )
{
endfmn = (struct freememnode *)(((char *) startfmn) + startfmn->size);
for( fmn = freehead; fmn; )
{
if( fmn->cookie != FREEMEMCOOKIE )
CG_Error( "CG_DefragmentMemory: Memory corruption detected!\n" );
if( fmn == endfmn )
{
// We can add fmn onto startfmn.
if( fmn->prev )
fmn->prev->next = fmn->next;
if( fmn->next )
{
if( !(fmn->next->prev = fmn->prev) )
freehead = fmn->next; // We're removing the head node
}
startfmn->size += fmn->size;
memset( fmn, 0, sizeof(struct freememnode) ); // A redundant call, really.
startfmn = freehead;
endfmn = fmn = NULL; // Break out of current loop
}
else
fmn = fmn->next;
}
if( endfmn )
startfmn = startfmn->next; // endfmn acts as a 'restart' flag here
}
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
#define POOLSIZE (256 * 1024)
#define FREEMEMCOOKIE ((int)0xDEADBE3F) // Any unlikely to be used value
#define ROUNDBITS 31 // Round to 32 bytes
struct freememnode
{
// Size of ROUNDBITS
int cookie, size; // Size includes node (obviously)
struct freememnode *prev, *next;
};
static char memoryPool[ POOLSIZE ];
static struct freememnode *freehead;
static int freemem;
void *CG_Alloc( int size )
{
// Find a free block and allocate.
// Does two passes, attempts to fill same-sized free slot first.
struct freememnode *fmn, *prev, *next, *smallest;
int allocsize, smallestsize;
char *endptr;
int *ptr;
allocsize = ( size + sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
ptr = NULL;
smallest = NULL;
smallestsize = POOLSIZE + 1; // Guaranteed not to miss any slots :)
for( fmn = freehead; fmn; fmn = fmn->next )
{
if( fmn->cookie != FREEMEMCOOKIE )
CG_Error( "CG_Alloc: Memory corruption detected!\n" );
if( fmn->size >= allocsize )
{
// We've got a block
if( fmn->size == allocsize )
{
// Same size, just remove
prev = fmn->prev;
next = fmn->next;
if( prev )
prev->next = next; // Point previous node to next
if( next )
next->prev = prev; // Point next node to previous
if( fmn == freehead )
freehead = next; // Set head pointer to next
ptr = (int *) fmn;
break; // Stop the loop, this is fine
}
else
{
// Keep track of the smallest free slot
if( fmn->size < smallestsize )
{
smallest = fmn;
smallestsize = fmn->size;
}
}
}
}
if( !ptr && smallest )
{
// We found a slot big enough
smallest->size -= allocsize;
endptr = (char *) smallest + smallest->size;
ptr = (int *) endptr;
}
if( ptr )
{
freemem -= allocsize;
if( cg_debugAlloc.integer )
CG_Printf( "CG_Alloc of %i bytes (%i left)\n", allocsize, freemem );
memset( ptr, 0, allocsize );
*ptr++ = allocsize; // Store a copy of size for deallocation
return( (void *) ptr );
}
CG_Error( "CG_Alloc: failed on allocation of %i bytes\n", size );
return( NULL );
}
void CG_Free( void *ptr )
{
// Release allocated memory, add it to the free list.
struct freememnode *fmn;
char *freeend;
int *freeptr;
freeptr = ptr;
freeptr--;
freemem += *freeptr;
if( cg_debugAlloc.integer )
CG_Printf( "CG_Free of %i bytes (%i left)\n", *freeptr, freemem );
for( fmn = freehead; fmn; fmn = fmn->next )
{
freeend = ((char *) fmn) + fmn->size;
if( freeend == (char *) freeptr )
{
// Released block can be merged to an existing node
fmn->size += *freeptr; // Add size of node.
return;
}
}
// No merging, add to head of list
fmn = (struct freememnode *) freeptr;
fmn->size = *freeptr; // Set this first to avoid corrupting *freeptr
fmn->cookie = FREEMEMCOOKIE;
fmn->prev = NULL;
fmn->next = freehead;
freehead->prev = fmn;
freehead = fmn;
}
void CG_InitMemory( void )
{
// Set up the initial node
freehead = (struct freememnode *) memoryPool;
freehead->cookie = FREEMEMCOOKIE;
freehead->size = POOLSIZE;
freehead->next = NULL;
freehead->prev = NULL;
freemem = sizeof(memoryPool);
}
void CG_DefragmentMemory( void )
{
// If there's a frenzy of deallocation and we want to
// allocate something big, this is useful. Otherwise...
// not much use.
struct freememnode *startfmn, *endfmn, *fmn;
for( startfmn = freehead; startfmn; )
{
endfmn = (struct freememnode *)(((char *) startfmn) + startfmn->size);
for( fmn = freehead; fmn; )
{
if( fmn->cookie != FREEMEMCOOKIE )
CG_Error( "CG_DefragmentMemory: Memory corruption detected!\n" );
if( fmn == endfmn )
{
// We can add fmn onto startfmn.
if( fmn->prev )
fmn->prev->next = fmn->next;
if( fmn->next )
{
if( !(fmn->next->prev = fmn->prev) )
freehead = fmn->next; // We're removing the head node
}
startfmn->size += fmn->size;
memset( fmn, 0, sizeof(struct freememnode) ); // A redundant call, really.
startfmn = freehead;
endfmn = fmn = NULL; // Break out of current loop
}
else
fmn = fmn->next;
}
if( endfmn )
startfmn = startfmn->next; // endfmn acts as a 'restart' flag here
}
}
+2567 -2567
View File
File diff suppressed because it is too large. Load diff
+2565 -2565
View File
File diff suppressed because it is too large. Load diff
+317 -317
View File
@@ -1,317 +1,317 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_playerstate.c -- this file acts on changes in a new playerState_t
// With normal play, this will be done after local prediction, but when
// following another player or playing back a demo, it will be checked
// when the snapshot transitions like all the other entities
#include "cg_local.h"
/*
==============
CG_DamageFeedback
==============
*/
void CG_DamageFeedback( int yawByte, int pitchByte, int damage )
{
float left, front, up;
float kick;
int health;
float scale;
vec3_t dir;
vec3_t angles;
float dist;
float yaw, pitch;
// show the attacking player's head and name in corner
cg.attackerTime = cg.time;
// the lower on health you are, the greater the view kick will be
health = cg.snap->ps.stats[STAT_HEALTH];
if( health < 40 )
scale = 1;
else
scale = 40.0 / health;
kick = damage * scale;
if( kick < 5 )
kick = 5;
if( kick > 10 )
kick = 10;
// if yaw and pitch are both 255, make the damage always centered (falling, etc)
if( yawByte == 255 && pitchByte == 255 )
{
cg.damageX = 0;
cg.damageY = 0;
cg.v_dmg_roll = 0;
cg.v_dmg_pitch = -kick;
}
else
{
// positional
pitch = pitchByte / 255.0 * 360;
yaw = yawByte / 255.0 * 360;
angles[ PITCH ] = pitch;
angles[ YAW ] = yaw;
angles[ ROLL ] = 0;
AngleVectors( angles, dir, NULL, NULL );
VectorSubtract( vec3_origin, dir, dir );
front = DotProduct( dir, cg.refdef.viewaxis[ 0 ] );
left = DotProduct( dir, cg.refdef.viewaxis[ 1 ] );
up = DotProduct( dir, cg.refdef.viewaxis[ 2 ] );
dir[ 0 ] = front;
dir[ 1 ] = left;
dir[ 2 ] = 0;
dist = VectorLength( dir );
if( dist < 0.1f )
dist = 0.1f;
cg.v_dmg_roll = kick * left;
cg.v_dmg_pitch = -kick * front;
if( front <= 0.1 )
front = 0.1f;
cg.damageX = -left / front;
cg.damageY = up / dist;
}
// clamp the position
if( cg.damageX > 1.0 )
cg.damageX = 1.0;
if( cg.damageX < - 1.0 )
cg.damageX = -1.0;
if( cg.damageY > 1.0 )
cg.damageY = 1.0;
if( cg.damageY < - 1.0 )
cg.damageY = -1.0;
// don't let the screen flashes vary as much
if( kick > 10 )
kick = 10;
cg.damageValue = kick;
cg.v_dmg_time = cg.time + DAMAGE_TIME;
cg.damageTime = cg.snap->serverTime;
}
/*
================
CG_Respawn
A respawn happened this snapshot
================
*/
void CG_Respawn( void )
{
// no error decay on player movement
cg.thisFrameTeleport = qtrue;
// display weapons available
cg.weaponSelectTime = cg.time;
// select the weapon the server says we are using
cg.weaponSelect = cg.snap->ps.weapon;
CG_ResetPainBlend( );
}
/*
==============
CG_CheckPlayerstateEvents
==============
*/
void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops )
{
int i;
int event;
centity_t *cent;
if( ps->externalEvent && ps->externalEvent != ops->externalEvent )
{
cent = &cg_entities[ ps->clientNum ];
cent->currentState.event = ps->externalEvent;
cent->currentState.eventParm = ps->externalEventParm;
CG_EntityEvent( cent, cent->lerpOrigin );
}
cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
// go through the predictable events buffer
for( i = ps->eventSequence - MAX_PS_EVENTS; i < ps->eventSequence; i++ )
{
// if we have a new predictable event
if( i >= ops->eventSequence ||
// or the server told us to play another event instead of a predicted event we already issued
// or something the server told us changed our prediction causing a different event
( i > ops->eventSequence - MAX_PS_EVENTS && ps->events[ i & ( MAX_PS_EVENTS - 1 ) ] !=
ops->events[ i & ( MAX_PS_EVENTS - 1 ) ] ) )
{
event = ps->events[ i & ( MAX_PS_EVENTS - 1 ) ];
cent->currentState.event = event;
cent->currentState.eventParm = ps->eventParms[ i & ( MAX_PS_EVENTS - 1 ) ];
CG_EntityEvent( cent, cent->lerpOrigin );
cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] = event;
cg.eventSequence++;
}
}
}
/*
==================
CG_CheckChangedPredictableEvents
==================
*/
void CG_CheckChangedPredictableEvents( playerState_t *ps )
{
int i;
int event;
centity_t *cent;
cent = &cg.predictedPlayerEntity;
for( i = ps->eventSequence - MAX_PS_EVENTS; i < ps->eventSequence; i++ )
{
//
if( i >= cg.eventSequence )
continue;
// if this event is not further back in than the maximum predictable events we remember
if( i > cg.eventSequence - MAX_PREDICTED_EVENTS )
{
// if the new playerstate event is different from a previously predicted one
if( ps->events[ i & ( MAX_PS_EVENTS - 1 ) ] != cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] )
{
event = ps->events[ i & ( MAX_PS_EVENTS - 1 ) ];
cent->currentState.event = event;
cent->currentState.eventParm = ps->eventParms[ i & ( MAX_PS_EVENTS - 1 ) ];
CG_EntityEvent( cent, cent->lerpOrigin );
cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] = event;
if( cg_showmiss.integer )
CG_Printf( "WARNING: changed predicted event\n" );
}
}
}
}
/*
==================
CG_CheckLocalSounds
==================
*/
void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops )
{
int reward;
// don't play the sounds if the player just changed teams
if( ps->persistant[ PERS_TEAM ] != ops->persistant[ PERS_TEAM ] )
return;
// health changes of more than -1 should make pain sounds
if( ps->stats[ STAT_HEALTH ] < ops->stats[ STAT_HEALTH ] - 1 )
{
if( ps->stats[ STAT_HEALTH ] > 0 )
CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[ STAT_HEALTH ] );
}
// if we are going into the intermission, don't start any voices
if( cg.intermissionStarted )
return;
// reward sounds
reward = qfalse;
}
/*
===============
CG_TransitionPlayerState
===============
*/
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops )
{
// check for changing follow mode
if( ps->clientNum != ops->clientNum )
{
cg.thisFrameTeleport = qtrue;
// make sure we don't get any unwanted transition effects
*ops = *ps;
CG_ResetPainBlend( );
}
// damage events (player is getting wounded)
if( ps->damageEvent != ops->damageEvent && ps->damageCount )
CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
// respawning
if( ps->persistant[ PERS_SPAWN_COUNT ] != ops->persistant[ PERS_SPAWN_COUNT ] )
CG_Respawn( );
if( cg.mapRestart )
{
CG_Respawn( );
cg.mapRestart = qfalse;
}
if( cg.snap->ps.pm_type != PM_INTERMISSION &&
ps->persistant[ PERS_TEAM ] != TEAM_SPECTATOR )
CG_CheckLocalSounds( ps, ops );
// run events
CG_CheckPlayerstateEvents( ps, ops );
// smooth the ducking viewheight change
if( ps->viewheight != ops->viewheight )
{
cg.duckChange = ps->viewheight - ops->viewheight;
cg.duckTime = cg.time;
}
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_playerstate.c -- this file acts on changes in a new playerState_t
// With normal play, this will be done after local prediction, but when
// following another player or playing back a demo, it will be checked
// when the snapshot transitions like all the other entities
#include "cg_local.h"
/*
==============
CG_DamageFeedback
==============
*/
void CG_DamageFeedback( int yawByte, int pitchByte, int damage )
{
float left, front, up;
float kick;
int health;
float scale;
vec3_t dir;
vec3_t angles;
float dist;
float yaw, pitch;
// show the attacking player's head and name in corner
cg.attackerTime = cg.time;
// the lower on health you are, the greater the view kick will be
health = cg.snap->ps.stats[STAT_HEALTH];
if( health < 40 )
scale = 1;
else
scale = 40.0 / health;
kick = damage * scale;
if( kick < 5 )
kick = 5;
if( kick > 10 )
kick = 10;
// if yaw and pitch are both 255, make the damage always centered (falling, etc)
if( yawByte == 255 && pitchByte == 255 )
{
cg.damageX = 0;
cg.damageY = 0;
cg.v_dmg_roll = 0;
cg.v_dmg_pitch = -kick;
}
else
{
// positional
pitch = pitchByte / 255.0 * 360;
yaw = yawByte / 255.0 * 360;
angles[ PITCH ] = pitch;
angles[ YAW ] = yaw;
angles[ ROLL ] = 0;
AngleVectors( angles, dir, NULL, NULL );
VectorSubtract( vec3_origin, dir, dir );
front = DotProduct( dir, cg.refdef.viewaxis[ 0 ] );
left = DotProduct( dir, cg.refdef.viewaxis[ 1 ] );
up = DotProduct( dir, cg.refdef.viewaxis[ 2 ] );
dir[ 0 ] = front;
dir[ 1 ] = left;
dir[ 2 ] = 0;
dist = VectorLength( dir );
if( dist < 0.1f )
dist = 0.1f;
cg.v_dmg_roll = kick * left;
cg.v_dmg_pitch = -kick * front;
if( front <= 0.1 )
front = 0.1f;
cg.damageX = -left / front;
cg.damageY = up / dist;
}
// clamp the position
if( cg.damageX > 1.0 )
cg.damageX = 1.0;
if( cg.damageX < - 1.0 )
cg.damageX = -1.0;
if( cg.damageY > 1.0 )
cg.damageY = 1.0;
if( cg.damageY < - 1.0 )
cg.damageY = -1.0;
// don't let the screen flashes vary as much
if( kick > 10 )
kick = 10;
cg.damageValue = kick;
cg.v_dmg_time = cg.time + DAMAGE_TIME;
cg.damageTime = cg.snap->serverTime;
}
/*
================
CG_Respawn
A respawn happened this snapshot
================
*/
void CG_Respawn( void )
{
// no error decay on player movement
cg.thisFrameTeleport = qtrue;
// display weapons available
cg.weaponSelectTime = cg.time;
// select the weapon the server says we are using
cg.weaponSelect = cg.snap->ps.weapon;
CG_ResetPainBlend( );
}
/*
==============
CG_CheckPlayerstateEvents
==============
*/
void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops )
{
int i;
int event;
centity_t *cent;
if( ps->externalEvent && ps->externalEvent != ops->externalEvent )
{
cent = &cg_entities[ ps->clientNum ];
cent->currentState.event = ps->externalEvent;
cent->currentState.eventParm = ps->externalEventParm;
CG_EntityEvent( cent, cent->lerpOrigin );
}
cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
// go through the predictable events buffer
for( i = ps->eventSequence - MAX_PS_EVENTS; i < ps->eventSequence; i++ )
{
// if we have a new predictable event
if( i >= ops->eventSequence ||
// or the server told us to play another event instead of a predicted event we already issued
// or something the server told us changed our prediction causing a different event
( i > ops->eventSequence - MAX_PS_EVENTS && ps->events[ i & ( MAX_PS_EVENTS - 1 ) ] !=
ops->events[ i & ( MAX_PS_EVENTS - 1 ) ] ) )
{
event = ps->events[ i & ( MAX_PS_EVENTS - 1 ) ];
cent->currentState.event = event;
cent->currentState.eventParm = ps->eventParms[ i & ( MAX_PS_EVENTS - 1 ) ];
CG_EntityEvent( cent, cent->lerpOrigin );
cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] = event;
cg.eventSequence++;
}
}
}
/*
==================
CG_CheckChangedPredictableEvents
==================
*/
void CG_CheckChangedPredictableEvents( playerState_t *ps )
{
int i;
int event;
centity_t *cent;
cent = &cg.predictedPlayerEntity;
for( i = ps->eventSequence - MAX_PS_EVENTS; i < ps->eventSequence; i++ )
{
//
if( i >= cg.eventSequence )
continue;
// if this event is not further back in than the maximum predictable events we remember
if( i > cg.eventSequence - MAX_PREDICTED_EVENTS )
{
// if the new playerstate event is different from a previously predicted one
if( ps->events[ i & ( MAX_PS_EVENTS - 1 ) ] != cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] )
{
event = ps->events[ i & ( MAX_PS_EVENTS - 1 ) ];
cent->currentState.event = event;
cent->currentState.eventParm = ps->eventParms[ i & ( MAX_PS_EVENTS - 1 ) ];
CG_EntityEvent( cent, cent->lerpOrigin );
cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] = event;
if( cg_showmiss.integer )
CG_Printf( "WARNING: changed predicted event\n" );
}
}
}
}
/*
==================
CG_CheckLocalSounds
==================
*/
void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops )
{
int reward;
// don't play the sounds if the player just changed teams
if( ps->persistant[ PERS_TEAM ] != ops->persistant[ PERS_TEAM ] )
return;
// health changes of more than -1 should make pain sounds
if( ps->stats[ STAT_HEALTH ] < ops->stats[ STAT_HEALTH ] - 1 )
{
if( ps->stats[ STAT_HEALTH ] > 0 )
CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[ STAT_HEALTH ] );
}
// if we are going into the intermission, don't start any voices
if( cg.intermissionStarted )
return;
// reward sounds
reward = qfalse;
}
/*
===============
CG_TransitionPlayerState
===============
*/
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops )
{
// check for changing follow mode
if( ps->clientNum != ops->clientNum )
{
cg.thisFrameTeleport = qtrue;
// make sure we don't get any unwanted transition effects
*ops = *ps;
CG_ResetPainBlend( );
}
// damage events (player is getting wounded)
if( ps->damageEvent != ops->damageEvent && ps->damageCount )
CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
// respawning
if( ps->persistant[ PERS_SPAWN_COUNT ] != ops->persistant[ PERS_SPAWN_COUNT ] )
CG_Respawn( );
if( cg.mapRestart )
{
CG_Respawn( );
cg.mapRestart = qfalse;
}
if( cg.snap->ps.pm_type != PM_INTERMISSION &&
ps->persistant[ PERS_TEAM ] != TEAM_SPECTATOR )
CG_CheckLocalSounds( ps, ops );
// run events
CG_CheckPlayerstateEvents( ps, ops );
// smooth the ducking viewheight change
if( ps->viewheight != ops->viewheight )
{
cg.duckChange = ps->viewheight - ops->viewheight;
cg.duckTime = cg.time;
}
}
+878 -878
View File
File diff suppressed because it is too large. Load diff
+81 -81
View File
@@ -1,81 +1,81 @@
/*
===========================================================================
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_ptr.c -- post timeout restoration handling
#include "cg_local.h"
#define PTRC_FILE "ptrc.cfg"
/*
===============
CG_ReadPTRCode
Read a PTR code from disk
===============
*/
int CG_ReadPTRCode( void )
{
int len;
char text[ 16 ];
fileHandle_t f;
// load the file
len = trap_FS_FOpenFile( PTRC_FILE, &f, FS_READ );
if( len <= 0 )
return 0;
// should never happen - malformed write
if( len >= sizeof( text ) - 1 )
return 0;
trap_FS_Read( text, len, f );
text[ len ] = 0;
trap_FS_FCloseFile( f );
return atoi( text );
}
/*
===============
CG_WritePTRCode
Write a PTR code to disk
===============
*/
void CG_WritePTRCode( int code )
{
char text[ 16 ];
fileHandle_t f;
Com_sprintf( text, 16, "%d", code );
// open file
if( trap_FS_FOpenFile( PTRC_FILE, &f, FS_WRITE ) < 0 )
return;
// write the code
trap_FS_Write( text, strlen( text ), f );
trap_FS_FCloseFile( f );
}
/*
===========================================================================
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_ptr.c -- post timeout restoration handling
#include "cg_local.h"
#define PTRC_FILE "ptrc.cfg"
/*
===============
CG_ReadPTRCode
Read a PTR code from disk
===============
*/
int CG_ReadPTRCode( void )
{
int len;
char text[ 16 ];
fileHandle_t f;
// load the file
len = trap_FS_FOpenFile( PTRC_FILE, &f, FS_READ );
if( len <= 0 )
return 0;
// should never happen - malformed write
if( len >= sizeof( text ) - 1 )
return 0;
trap_FS_Read( text, len, f );
text[ len ] = 0;
trap_FS_FCloseFile( f );
return atoi( text );
}
/*
===============
CG_WritePTRCode
Write a PTR code to disk
===============
*/
void CG_WritePTRCode( int code )
{
char text[ 16 ];
fileHandle_t f;
Com_sprintf( text, 16, "%d", code );
// open file
if( trap_FS_FOpenFile( PTRC_FILE, &f, FS_WRITE ) < 0 )
return;
// write the code
trap_FS_Write( text, strlen( text ), f );
trap_FS_FCloseFile( f );
}
+252 -252
View File
@@ -1,252 +1,252 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#define CMD_BACKUP 64
#define CMD_MASK (CMD_BACKUP - 1)
// allow a lot of command backups for very fast systems
// multiple commands may be combined into a single packet, so this
// needs to be larger than PACKET_BACKUP
#define MAX_ENTITIES_IN_SNAPSHOT 256
// snapshots are a view of the server at a given time
// Snapshots are generated at regular time intervals by the server,
// but they may not be sent if a client's rate level is exceeded, or
// they may be dropped by the network.
typedef struct
{
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
int ping;
int serverTime; // server time the message is valid for (in msec)
byte areamask[ MAX_MAP_AREA_BYTES ]; // portalarea visibility bits
playerState_t ps; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
entityState_t entities[ MAX_ENTITIES_IN_SNAPSHOT ]; // at the time of this snapshot
int numServerCommands; // text based server commands to execute when this
int serverCommandSequence; // snapshot becomes current
} snapshot_t;
enum
{
CGAME_EVENT_NONE,
CGAME_EVENT_TEAMMENU,
CGAME_EVENT_SCOREBOARD,
CGAME_EVENT_EDITHUD
};
/*
==================================================================
functions imported from the main executable
==================================================================
*/
#define CGAME_IMPORT_API_VERSION 4
typedef enum
{
CG_PRINT,
CG_ERROR,
CG_MILLISECONDS,
CG_CVAR_REGISTER,
CG_CVAR_UPDATE,
CG_CVAR_SET,
CG_CVAR_VARIABLESTRINGBUFFER,
CG_ARGC,
CG_ARGV,
CG_ARGS,
CG_FS_FOPENFILE,
CG_FS_READ,
CG_FS_WRITE,
CG_FS_FCLOSEFILE,
CG_SENDCONSOLECOMMAND,
CG_ADDCOMMAND,
CG_SENDCLIENTCOMMAND,
CG_UPDATESCREEN,
CG_CM_LOADMAP,
CG_CM_NUMINLINEMODELS,
CG_CM_INLINEMODEL,
CG_CM_LOADMODEL,
CG_CM_TEMPBOXMODEL,
CG_CM_POINTCONTENTS,
CG_CM_TRANSFORMEDPOINTCONTENTS,
CG_CM_BOXTRACE,
CG_CM_TRANSFORMEDBOXTRACE,
CG_CM_MARKFRAGMENTS,
CG_S_STARTSOUND,
CG_S_STARTLOCALSOUND,
CG_S_CLEARLOOPINGSOUNDS,
CG_S_ADDLOOPINGSOUND,
CG_S_UPDATEENTITYPOSITION,
CG_S_RESPATIALIZE,
CG_S_REGISTERSOUND,
CG_S_STARTBACKGROUNDTRACK,
CG_R_LOADWORLDMAP,
CG_R_REGISTERMODEL,
CG_R_REGISTERSKIN,
CG_R_REGISTERSHADER,
CG_R_CLEARSCENE,
CG_R_ADDREFENTITYTOSCENE,
CG_R_ADDPOLYTOSCENE,
CG_R_ADDLIGHTTOSCENE,
CG_R_RENDERSCENE,
CG_R_SETCOLOR,
CG_R_DRAWSTRETCHPIC,
CG_R_MODELBOUNDS,
CG_R_LERPTAG,
CG_GETGLCONFIG,
CG_GETGAMESTATE,
CG_GETCURRENTSNAPSHOTNUMBER,
CG_GETSNAPSHOT,
CG_GETSERVERCOMMAND,
CG_GETCURRENTCMDNUMBER,
CG_GETUSERCMD,
CG_SETUSERCMDVALUE,
CG_R_REGISTERSHADERNOMIP,
CG_MEMORY_REMAINING,
CG_R_REGISTERFONT,
CG_KEY_ISDOWN,
CG_KEY_GETCATCHER,
CG_KEY_SETCATCHER,
CG_KEY_GETKEY,
CG_S_STOPBACKGROUNDTRACK,
CG_REAL_TIME,
CG_SNAPVECTOR,
CG_REMOVECOMMAND,
CG_R_LIGHTFORPOINT,
CG_CIN_PLAYCINEMATIC,
CG_CIN_STOPCINEMATIC,
CG_CIN_RUNCINEMATIC,
CG_CIN_DRAWCINEMATIC,
CG_CIN_SETEXTENTS,
CG_R_REMAP_SHADER,
CG_S_ADDREALLOOPINGSOUND,
CG_S_STOPLOOPINGSOUND,
CG_CM_TEMPCAPSULEMODEL,
CG_CM_CAPSULETRACE,
CG_CM_TRANSFORMEDCAPSULETRACE,
CG_R_ADDADDITIVELIGHTTOSCENE,
CG_GET_ENTITY_TOKEN,
CG_R_ADDPOLYSTOSCENE,
CG_R_INPVS,
CG_FS_SEEK,
CG_FS_GETFILELIST,
CG_LITERAL_ARGS,
CG_CM_BISPHERETRACE,
CG_CM_TRANSFORMEDBISPHERETRACE,
CG_GETDEMOSTATE,
CG_GETDEMOPOS,
CG_GETDEMONAME,
CG_KEY_KEYNUMTOSTRINGBUF,
CG_KEY_GETBINDINGBUF,
CG_KEY_SETBINDING,
CG_PARSE_ADD_GLOBAL_DEFINE,
CG_PARSE_LOAD_SOURCE,
CG_PARSE_FREE_SOURCE,
CG_PARSE_READ_TOKEN,
CG_PARSE_SOURCE_FILE_AND_LINE,
CG_MEMSET = 200,
CG_MEMCPY,
CG_STRNCPY,
CG_SIN,
CG_COS,
CG_ATAN2,
CG_SQRT,
CG_FLOOR,
CG_CEIL,
CG_TESTPRINTINT,
CG_TESTPRINTFLOAT,
CG_ACOS
} cgameImport_t;
/*
==================================================================
functions exported to the main executable
==================================================================
*/
typedef enum
{
CG_INIT,
// void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
// called when the level loads or when the renderer is restarted
// all media should be registered at this time
// cgame will display loading status by calling SCR_Update, which
// will call CG_DrawInformation during the loading process
// reliableCommandSequence will be 0 on fresh loads, but higher for
// demos, tourney restarts, or vid_restarts
CG_SHUTDOWN,
// void (*CG_Shutdown)( void );
// oportunity to flush and close any open files
CG_CONSOLE_COMMAND,
// qboolean (*CG_ConsoleCommand)( void );
// a console command has been issued locally that is not recognized by the
// main game system.
// use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
// command is not known to the game
CG_DRAW_ACTIVE_FRAME,
// void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
// Generates and draws a game scene and status information at the given time.
// If demoPlayback is set, local movement prediction will not be enabled
CG_CROSSHAIR_PLAYER,
// int (*CG_CrosshairPlayer)( void );
CG_LAST_ATTACKER,
// int (*CG_LastAttacker)( void );
CG_KEY_EVENT,
// void (*CG_KeyEvent)( int key, qboolean down );
CG_MOUSE_EVENT,
// void (*CG_MouseEvent)( int dx, int dy );
CG_EVENT_HANDLING,
// void (*CG_EventHandling)(int type);
CG_CONSOLE_TEXT
// void (*CG_ConsoleText)( void );
// pass text that has been printed to the console to cgame
// use Cmd_Argc() / Cmd_Argv() to read it
} cgameExport_t;
//----------------------------------------------
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#define CMD_BACKUP 64
#define CMD_MASK (CMD_BACKUP - 1)
// allow a lot of command backups for very fast systems
// multiple commands may be combined into a single packet, so this
// needs to be larger than PACKET_BACKUP
#define MAX_ENTITIES_IN_SNAPSHOT 256
// snapshots are a view of the server at a given time
// Snapshots are generated at regular time intervals by the server,
// but they may not be sent if a client's rate level is exceeded, or
// they may be dropped by the network.
typedef struct
{
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
int ping;
int serverTime; // server time the message is valid for (in msec)
byte areamask[ MAX_MAP_AREA_BYTES ]; // portalarea visibility bits
playerState_t ps; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
entityState_t entities[ MAX_ENTITIES_IN_SNAPSHOT ]; // at the time of this snapshot
int numServerCommands; // text based server commands to execute when this
int serverCommandSequence; // snapshot becomes current
} snapshot_t;
enum
{
CGAME_EVENT_NONE,
CGAME_EVENT_TEAMMENU,
CGAME_EVENT_SCOREBOARD,
CGAME_EVENT_EDITHUD
};
/*
==================================================================
functions imported from the main executable
==================================================================
*/
#define CGAME_IMPORT_API_VERSION 4
typedef enum
{
CG_PRINT,
CG_ERROR,
CG_MILLISECONDS,
CG_CVAR_REGISTER,
CG_CVAR_UPDATE,
CG_CVAR_SET,
CG_CVAR_VARIABLESTRINGBUFFER,
CG_ARGC,
CG_ARGV,
CG_ARGS,
CG_FS_FOPENFILE,
CG_FS_READ,
CG_FS_WRITE,
CG_FS_FCLOSEFILE,
CG_SENDCONSOLECOMMAND,
CG_ADDCOMMAND,
CG_SENDCLIENTCOMMAND,
CG_UPDATESCREEN,
CG_CM_LOADMAP,
CG_CM_NUMINLINEMODELS,
CG_CM_INLINEMODEL,
CG_CM_LOADMODEL,
CG_CM_TEMPBOXMODEL,
CG_CM_POINTCONTENTS,
CG_CM_TRANSFORMEDPOINTCONTENTS,
CG_CM_BOXTRACE,
CG_CM_TRANSFORMEDBOXTRACE,
CG_CM_MARKFRAGMENTS,
CG_S_STARTSOUND,
CG_S_STARTLOCALSOUND,
CG_S_CLEARLOOPINGSOUNDS,
CG_S_ADDLOOPINGSOUND,
CG_S_UPDATEENTITYPOSITION,
CG_S_RESPATIALIZE,
CG_S_REGISTERSOUND,
CG_S_STARTBACKGROUNDTRACK,
CG_R_LOADWORLDMAP,
CG_R_REGISTERMODEL,
CG_R_REGISTERSKIN,
CG_R_REGISTERSHADER,
CG_R_CLEARSCENE,
CG_R_ADDREFENTITYTOSCENE,
CG_R_ADDPOLYTOSCENE,
CG_R_ADDLIGHTTOSCENE,
CG_R_RENDERSCENE,
CG_R_SETCOLOR,
CG_R_DRAWSTRETCHPIC,
CG_R_MODELBOUNDS,
CG_R_LERPTAG,
CG_GETGLCONFIG,
CG_GETGAMESTATE,
CG_GETCURRENTSNAPSHOTNUMBER,
CG_GETSNAPSHOT,
CG_GETSERVERCOMMAND,
CG_GETCURRENTCMDNUMBER,
CG_GETUSERCMD,
CG_SETUSERCMDVALUE,
CG_R_REGISTERSHADERNOMIP,
CG_MEMORY_REMAINING,
CG_R_REGISTERFONT,
CG_KEY_ISDOWN,
CG_KEY_GETCATCHER,
CG_KEY_SETCATCHER,
CG_KEY_GETKEY,
CG_S_STOPBACKGROUNDTRACK,
CG_REAL_TIME,
CG_SNAPVECTOR,
CG_REMOVECOMMAND,
CG_R_LIGHTFORPOINT,
CG_CIN_PLAYCINEMATIC,
CG_CIN_STOPCINEMATIC,
CG_CIN_RUNCINEMATIC,
CG_CIN_DRAWCINEMATIC,
CG_CIN_SETEXTENTS,
CG_R_REMAP_SHADER,
CG_S_ADDREALLOOPINGSOUND,
CG_S_STOPLOOPINGSOUND,
CG_CM_TEMPCAPSULEMODEL,
CG_CM_CAPSULETRACE,
CG_CM_TRANSFORMEDCAPSULETRACE,
CG_R_ADDADDITIVELIGHTTOSCENE,
CG_GET_ENTITY_TOKEN,
CG_R_ADDPOLYSTOSCENE,
CG_R_INPVS,
CG_FS_SEEK,
CG_FS_GETFILELIST,
CG_LITERAL_ARGS,
CG_CM_BISPHERETRACE,
CG_CM_TRANSFORMEDBISPHERETRACE,
CG_GETDEMOSTATE,
CG_GETDEMOPOS,
CG_GETDEMONAME,
CG_KEY_KEYNUMTOSTRINGBUF,
CG_KEY_GETBINDINGBUF,
CG_KEY_SETBINDING,
CG_PARSE_ADD_GLOBAL_DEFINE,
CG_PARSE_LOAD_SOURCE,
CG_PARSE_FREE_SOURCE,
CG_PARSE_READ_TOKEN,
CG_PARSE_SOURCE_FILE_AND_LINE,
CG_MEMSET = 200,
CG_MEMCPY,
CG_STRNCPY,
CG_SIN,
CG_COS,
CG_ATAN2,
CG_SQRT,
CG_FLOOR,
CG_CEIL,
CG_TESTPRINTINT,
CG_TESTPRINTFLOAT,
CG_ACOS
} cgameImport_t;
/*
==================================================================
functions exported to the main executable
==================================================================
*/
typedef enum
{
CG_INIT,
// void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
// called when the level loads or when the renderer is restarted
// all media should be registered at this time
// cgame will display loading status by calling SCR_Update, which
// will call CG_DrawInformation during the loading process
// reliableCommandSequence will be 0 on fresh loads, but higher for
// demos, tourney restarts, or vid_restarts
CG_SHUTDOWN,
// void (*CG_Shutdown)( void );
// oportunity to flush and close any open files
CG_CONSOLE_COMMAND,
// qboolean (*CG_ConsoleCommand)( void );
// a console command has been issued locally that is not recognized by the
// main game system.
// use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the
// command is not known to the game
CG_DRAW_ACTIVE_FRAME,
// void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback );
// Generates and draws a game scene and status information at the given time.
// If demoPlayback is set, local movement prediction will not be enabled
CG_CROSSHAIR_PLAYER,
// int (*CG_CrosshairPlayer)( void );
CG_LAST_ATTACKER,
// int (*CG_LastAttacker)( void );
CG_KEY_EVENT,
// void (*CG_KeyEvent)( int key, qboolean down );
CG_MOUSE_EVENT,
// void (*CG_MouseEvent)( int dx, int dy );
CG_EVENT_HANDLING,
// void (*CG_EventHandling)(int type);
CG_CONSOLE_TEXT
// void (*CG_ConsoleText)( void );
// pass text that has been printed to the console to cgame
// use Cmd_Argc() / Cmd_Argv() to read it
} cgameExport_t;
//----------------------------------------------
+365 -365
View File
@@ -1,365 +1,365 @@
/*
===========================================================================
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
static entityPos_t entityPositions;
#define HUMAN_SCANNER_UPDATE_PERIOD 700
/*
=============
CG_UpdateEntityPositions
Update this client's perception of entity positions
=============
*/
void CG_UpdateEntityPositions( void )
{
centity_t *cent = NULL;
int i;
if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
{
if( entityPositions.lastUpdateTime + HUMAN_SCANNER_UPDATE_PERIOD > cg.time )
return;
}
VectorCopy( cg.refdef.vieworg, entityPositions.origin );
VectorCopy( cg.refdefViewAngles, entityPositions.vangles );
entityPositions.lastUpdateTime = cg.time;
entityPositions.numAlienBuildables = 0;
entityPositions.numHumanBuildables = 0;
entityPositions.numAlienClients = 0;
entityPositions.numHumanClients = 0;
for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
if( cent->currentState.eType == ET_BUILDABLE )
{
//TA: add to list of item positions (for creep)
if( cent->currentState.modelindex2 == BIT_ALIENS )
{
VectorCopy( cent->lerpOrigin, entityPositions.alienBuildablePos[
entityPositions.numAlienBuildables ] );
entityPositions.alienBuildableTimes[
entityPositions.numAlienBuildables ] = cent->miscTime;
if( entityPositions.numAlienBuildables < MAX_GENTITIES )
entityPositions.numAlienBuildables++;
}
else if( cent->currentState.modelindex2 == BIT_HUMANS )
{
VectorCopy( cent->lerpOrigin, entityPositions.humanBuildablePos[
entityPositions.numHumanBuildables ] );
if( entityPositions.numHumanBuildables < MAX_GENTITIES )
entityPositions.numHumanBuildables++;
}
}
else if( cent->currentState.eType == ET_PLAYER )
{
int team = cent->currentState.powerups & 0x00FF;
if( team == PTE_ALIENS )
{
VectorCopy( cent->lerpOrigin, entityPositions.alienClientPos[
entityPositions.numAlienClients ] );
if( entityPositions.numAlienClients < MAX_CLIENTS )
entityPositions.numAlienClients++;
}
else if( team == PTE_HUMANS )
{
VectorCopy( cent->lerpOrigin, entityPositions.humanClientPos[
entityPositions.numHumanClients ] );
if( entityPositions.numHumanClients < MAX_CLIENTS )
entityPositions.numHumanClients++;
}
}
}
}
#define STALKWIDTH 2.0f
#define BLIPX 16.0f
#define BLIPY 8.0f
#define FAR_ALPHA 0.8f
#define NEAR_ALPHA 1.2f
/*
=============
CG_DrawBlips
Draw blips and stalks for the human scanner
=============
*/
static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
vec3_t drawOrigin;
vec3_t up = { 0, 0, 1 };
float alphaMod = 1.0f;
float timeFractionSinceRefresh = 1.0f -
( (float)( cg.time - entityPositions.lastUpdateTime ) /
(float)HUMAN_SCANNER_UPDATE_PERIOD );
vec4_t localColour;
Vector4Copy( colour, localColour );
RotatePointAroundVector( drawOrigin, up, origin, -entityPositions.vangles[ 1 ] - 90 );
drawOrigin[ 0 ] /= ( 2 * HELMET_RANGE / rect->w );
drawOrigin[ 1 ] /= ( 2 * HELMET_RANGE / rect->h );
drawOrigin[ 2 ] /= ( 2 * HELMET_RANGE / rect->w );
alphaMod = FAR_ALPHA +
( ( drawOrigin[ 1 ] + ( rect->h / 2.0f ) ) / rect->h ) * ( NEAR_ALPHA - FAR_ALPHA );
localColour[ 3 ] *= alphaMod;
localColour[ 3 ] *= ( 0.5f + ( timeFractionSinceRefresh * 0.5f ) );
if( localColour[ 3 ] > 1.0f )
localColour[ 3 ] = 1.0f;
else if( localColour[ 3 ] < 0.0f )
localColour[ 3 ] = 0.0f;
trap_R_SetColor( localColour );
if( drawOrigin[ 2 ] > 0 )
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
STALKWIDTH, drawOrigin[ 2 ], cgs.media.scannerLineShader );
else
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ],
STALKWIDTH, -drawOrigin[ 2 ], cgs.media.scannerLineShader );
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX / 2 ) - drawOrigin[ 0 ],
rect->y + ( rect->h / 2 ) - ( BLIPY / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
BLIPX, BLIPY, cgs.media.scannerBlipShader );
trap_R_SetColor( NULL );
}
#define BLIPX2 24.0f
#define BLIPY2 24.0f
/*
=============
CG_DrawDir
Draw dot marking the direction to an enemy
=============
*/
static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
vec3_t drawOrigin;
vec3_t noZOrigin;
vec3_t normal, antinormal, normalDiff;
vec3_t view, noZview;
vec3_t up = { 0.0f, 0.0f, 1.0f };
vec3_t top = { 0.0f, -1.0f, 0.0f };
float angle;
playerState_t *ps = &cg.snap->ps;
if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
{
if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
VectorSet( normal, 0.0f, 0.0f, -1.0f );
else
VectorCopy( ps->grapplePoint, normal );
}
else
VectorSet( normal, 0.0f, 0.0f, 1.0f );
AngleVectors( entityPositions.vangles, view, NULL, NULL );
ProjectPointOnPlane( noZOrigin, origin, normal );
ProjectPointOnPlane( noZview, view, normal );
VectorNormalize( noZOrigin );
VectorNormalize( noZview );
//calculate the angle between the images of the blip and the view
angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) );
CrossProduct( noZOrigin, noZview, antinormal );
VectorNormalize( antinormal );
//decide which way to rotate
VectorSubtract( normal, antinormal, normalDiff );
if( VectorLength( normalDiff ) < 1.0f )
angle = 360.0f - angle;
RotatePointAroundVector( drawOrigin, up, top, angle );
trap_R_SetColor( colour );
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ),
rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ),
BLIPX2, BLIPY2, cgs.media.scannerBlipShader );
trap_R_SetColor( NULL );
}
/*
=============
CG_AlienSense
=============
*/
void CG_AlienSense( rectDef_t *rect )
{
int i;
vec3_t origin;
vec3_t relOrigin;
vec4_t buildable = { 1.0f, 0.0f, 0.0f, 0.7f };
vec4_t client = { 0.0f, 0.0f, 1.0f, 0.7f };
VectorCopy( entityPositions.origin, origin );
//draw human buildables
for( i = 0; i < entityPositions.numHumanBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < ALIENSENSE_RANGE )
CG_DrawDir( rect, relOrigin, buildable );
}
//draw human clients
for( i = 0; i < entityPositions.numHumanClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < ALIENSENSE_RANGE )
CG_DrawDir( rect, relOrigin, client );
}
}
/*
=============
CG_Scanner
=============
*/
void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color )
{
int i;
vec3_t origin;
vec3_t relOrigin;
vec4_t hIabove;
vec4_t hIbelow;
vec4_t aIabove = { 1.0f, 0.0f, 0.0f, 0.75f };
vec4_t aIbelow = { 1.0f, 0.0f, 0.0f, 0.5f };
Vector4Copy( color, hIabove );
hIabove[ 3 ] *= 1.5f;
Vector4Copy( color, hIbelow );
VectorCopy( entityPositions.origin, origin );
//draw human buildables below scanner plane
for( i = 0; i < entityPositions.numHumanBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, hIbelow );
}
//draw alien buildables below scanner plane
for( i = 0; i < entityPositions.numAlienBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, aIbelow );
}
//draw human clients below scanner plane
for( i = 0; i < entityPositions.numHumanClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, hIbelow );
}
//draw alien buildables below scanner plane
for( i = 0; i < entityPositions.numAlienClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, aIbelow );
}
if( !cg_disableScannerPlane.integer )
{
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
}
//draw human buildables above scanner plane
for( i = 0; i < entityPositions.numHumanBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, hIabove );
}
//draw alien buildables above scanner plane
for( i = 0; i < entityPositions.numAlienBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, aIabove );
}
//draw human clients above scanner plane
for( i = 0; i < entityPositions.numHumanClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, hIabove );
}
//draw alien clients above scanner plane
for( i = 0; i < entityPositions.numAlienClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, aIabove );
}
}
/*
===========================================================================
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "cg_local.h"
static entityPos_t entityPositions;
#define HUMAN_SCANNER_UPDATE_PERIOD 700
/*
=============
CG_UpdateEntityPositions
Update this client's perception of entity positions
=============
*/
void CG_UpdateEntityPositions( void )
{
centity_t *cent = NULL;
int i;
if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
{
if( entityPositions.lastUpdateTime + HUMAN_SCANNER_UPDATE_PERIOD > cg.time )
return;
}
VectorCopy( cg.refdef.vieworg, entityPositions.origin );
VectorCopy( cg.refdefViewAngles, entityPositions.vangles );
entityPositions.lastUpdateTime = cg.time;
entityPositions.numAlienBuildables = 0;
entityPositions.numHumanBuildables = 0;
entityPositions.numAlienClients = 0;
entityPositions.numHumanClients = 0;
for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
if( cent->currentState.eType == ET_BUILDABLE )
{
//TA: add to list of item positions (for creep)
if( cent->currentState.modelindex2 == BIT_ALIENS )
{
VectorCopy( cent->lerpOrigin, entityPositions.alienBuildablePos[
entityPositions.numAlienBuildables ] );
entityPositions.alienBuildableTimes[
entityPositions.numAlienBuildables ] = cent->miscTime;
if( entityPositions.numAlienBuildables < MAX_GENTITIES )
entityPositions.numAlienBuildables++;
}
else if( cent->currentState.modelindex2 == BIT_HUMANS )
{
VectorCopy( cent->lerpOrigin, entityPositions.humanBuildablePos[
entityPositions.numHumanBuildables ] );
if( entityPositions.numHumanBuildables < MAX_GENTITIES )
entityPositions.numHumanBuildables++;
}
}
else if( cent->currentState.eType == ET_PLAYER )
{
int team = cent->currentState.powerups & 0x00FF;
if( team == PTE_ALIENS )
{
VectorCopy( cent->lerpOrigin, entityPositions.alienClientPos[
entityPositions.numAlienClients ] );
if( entityPositions.numAlienClients < MAX_CLIENTS )
entityPositions.numAlienClients++;
}
else if( team == PTE_HUMANS )
{
VectorCopy( cent->lerpOrigin, entityPositions.humanClientPos[
entityPositions.numHumanClients ] );
if( entityPositions.numHumanClients < MAX_CLIENTS )
entityPositions.numHumanClients++;
}
}
}
}
#define STALKWIDTH 2.0f
#define BLIPX 16.0f
#define BLIPY 8.0f
#define FAR_ALPHA 0.8f
#define NEAR_ALPHA 1.2f
/*
=============
CG_DrawBlips
Draw blips and stalks for the human scanner
=============
*/
static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
vec3_t drawOrigin;
vec3_t up = { 0, 0, 1 };
float alphaMod = 1.0f;
float timeFractionSinceRefresh = 1.0f -
( (float)( cg.time - entityPositions.lastUpdateTime ) /
(float)HUMAN_SCANNER_UPDATE_PERIOD );
vec4_t localColour;
Vector4Copy( colour, localColour );
RotatePointAroundVector( drawOrigin, up, origin, -entityPositions.vangles[ 1 ] - 90 );
drawOrigin[ 0 ] /= ( 2 * HELMET_RANGE / rect->w );
drawOrigin[ 1 ] /= ( 2 * HELMET_RANGE / rect->h );
drawOrigin[ 2 ] /= ( 2 * HELMET_RANGE / rect->w );
alphaMod = FAR_ALPHA +
( ( drawOrigin[ 1 ] + ( rect->h / 2.0f ) ) / rect->h ) * ( NEAR_ALPHA - FAR_ALPHA );
localColour[ 3 ] *= alphaMod;
localColour[ 3 ] *= ( 0.5f + ( timeFractionSinceRefresh * 0.5f ) );
if( localColour[ 3 ] > 1.0f )
localColour[ 3 ] = 1.0f;
else if( localColour[ 3 ] < 0.0f )
localColour[ 3 ] = 0.0f;
trap_R_SetColor( localColour );
if( drawOrigin[ 2 ] > 0 )
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
STALKWIDTH, drawOrigin[ 2 ], cgs.media.scannerLineShader );
else
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ],
STALKWIDTH, -drawOrigin[ 2 ], cgs.media.scannerLineShader );
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX / 2 ) - drawOrigin[ 0 ],
rect->y + ( rect->h / 2 ) - ( BLIPY / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
BLIPX, BLIPY, cgs.media.scannerBlipShader );
trap_R_SetColor( NULL );
}
#define BLIPX2 24.0f
#define BLIPY2 24.0f
/*
=============
CG_DrawDir
Draw dot marking the direction to an enemy
=============
*/
static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
vec3_t drawOrigin;
vec3_t noZOrigin;
vec3_t normal, antinormal, normalDiff;
vec3_t view, noZview;
vec3_t up = { 0.0f, 0.0f, 1.0f };
vec3_t top = { 0.0f, -1.0f, 0.0f };
float angle;
playerState_t *ps = &cg.snap->ps;
if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
{
if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
VectorSet( normal, 0.0f, 0.0f, -1.0f );
else
VectorCopy( ps->grapplePoint, normal );
}
else
VectorSet( normal, 0.0f, 0.0f, 1.0f );
AngleVectors( entityPositions.vangles, view, NULL, NULL );
ProjectPointOnPlane( noZOrigin, origin, normal );
ProjectPointOnPlane( noZview, view, normal );
VectorNormalize( noZOrigin );
VectorNormalize( noZview );
//calculate the angle between the images of the blip and the view
angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) );
CrossProduct( noZOrigin, noZview, antinormal );
VectorNormalize( antinormal );
//decide which way to rotate
VectorSubtract( normal, antinormal, normalDiff );
if( VectorLength( normalDiff ) < 1.0f )
angle = 360.0f - angle;
RotatePointAroundVector( drawOrigin, up, top, angle );
trap_R_SetColor( colour );
CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ),
rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ),
BLIPX2, BLIPY2, cgs.media.scannerBlipShader );
trap_R_SetColor( NULL );
}
/*
=============
CG_AlienSense
=============
*/
void CG_AlienSense( rectDef_t *rect )
{
int i;
vec3_t origin;
vec3_t relOrigin;
vec4_t buildable = { 1.0f, 0.0f, 0.0f, 0.7f };
vec4_t client = { 0.0f, 0.0f, 1.0f, 0.7f };
VectorCopy( entityPositions.origin, origin );
//draw human buildables
for( i = 0; i < entityPositions.numHumanBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < ALIENSENSE_RANGE )
CG_DrawDir( rect, relOrigin, buildable );
}
//draw human clients
for( i = 0; i < entityPositions.numHumanClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < ALIENSENSE_RANGE )
CG_DrawDir( rect, relOrigin, client );
}
}
/*
=============
CG_Scanner
=============
*/
void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color )
{
int i;
vec3_t origin;
vec3_t relOrigin;
vec4_t hIabove;
vec4_t hIbelow;
vec4_t aIabove = { 1.0f, 0.0f, 0.0f, 0.75f };
vec4_t aIbelow = { 1.0f, 0.0f, 0.0f, 0.5f };
Vector4Copy( color, hIabove );
hIabove[ 3 ] *= 1.5f;
Vector4Copy( color, hIbelow );
VectorCopy( entityPositions.origin, origin );
//draw human buildables below scanner plane
for( i = 0; i < entityPositions.numHumanBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, hIbelow );
}
//draw alien buildables below scanner plane
for( i = 0; i < entityPositions.numAlienBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, aIbelow );
}
//draw human clients below scanner plane
for( i = 0; i < entityPositions.numHumanClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, hIbelow );
}
//draw alien buildables below scanner plane
for( i = 0; i < entityPositions.numAlienClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
CG_DrawBlips( rect, relOrigin, aIbelow );
}
if( !cg_disableScannerPlane.integer )
{
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
trap_R_SetColor( NULL );
}
//draw human buildables above scanner plane
for( i = 0; i < entityPositions.numHumanBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, hIabove );
}
//draw alien buildables above scanner plane
for( i = 0; i < entityPositions.numAlienBuildables; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, aIabove );
}
//draw human clients above scanner plane
for( i = 0; i < entityPositions.numHumanClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, hIabove );
}
//draw alien clients above scanner plane
for( i = 0; i < entityPositions.numAlienClients; i++ )
{
VectorClear( relOrigin );
VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
CG_DrawBlips( rect, relOrigin, aIabove );
}
}
+1016 -1016
View File
File diff suppressed because it is too large. Load diff
+411 -411
View File
@@ -1,411 +1,411 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_snapshot.c -- things that happen on snapshot transition,
// not necessarily every single rendered frame
#include "cg_local.h"
/*
==================
CG_ResetEntity
==================
*/
static void CG_ResetEntity( centity_t *cent )
{
// if the previous snapshot this entity was updated in is at least
// an event window back in time then we can reset the previous event
if( cent->snapShotTime < cg.time - EVENT_VALID_MSEC )
cent->previousEvent = 0;
cent->trailTime = cg.snap->serverTime;
VectorCopy( cent->currentState.origin, cent->lerpOrigin );
VectorCopy( cent->currentState.angles, cent->lerpAngles );
if( cent->currentState.eType == ET_PLAYER )
CG_ResetPlayerEntity( cent );
}
/*
===============
CG_TransitionEntity
cent->nextState is moved to cent->currentState and events are fired
===============
*/
static void CG_TransitionEntity( centity_t *cent )
{
cent->currentState = cent->nextState;
cent->currentValid = qtrue;
// reset if the entity wasn't in the last frame or was teleported
if( !cent->interpolate )
CG_ResetEntity( cent );
// clear the next state. if will be set by the next CG_SetNextSnap
cent->interpolate = qfalse;
// check for events
CG_CheckEvents( cent );
}
/*
==================
CG_SetInitialSnapshot
This will only happen on the very first snapshot, or
on tourney restarts. All other times will use
CG_TransitionSnapshot instead.
FIXME: Also called by map_restart?
==================
*/
void CG_SetInitialSnapshot( snapshot_t *snap )
{
int i;
centity_t *cent;
entityState_t *state;
cg.snap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
// sort out solid entities
CG_BuildSolidList( );
CG_ExecuteNewServerCommands( snap->serverCommandSequence );
// set our local weapon selection pointer to
// what the server has indicated the current weapon is
CG_Respawn( );
for( i = 0; i < cg.snap->numEntities; i++ )
{
state = &cg.snap->entities[ i ];
cent = &cg_entities[ state->number ];
memcpy( &cent->currentState, state, sizeof( entityState_t ) );
//cent->currentState = *state;
cent->interpolate = qfalse;
cent->currentValid = qtrue;
CG_ResetEntity( cent );
// check for events
CG_CheckEvents( cent );
}
}
/*
===================
CG_TransitionSnapshot
The transition point from snap to nextSnap has passed
===================
*/
static void CG_TransitionSnapshot( void )
{
centity_t *cent;
snapshot_t *oldFrame;
int i;
if( !cg.snap )
CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
if( !cg.nextSnap )
CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
// execute any server string commands before transitioning entities
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
// if we had a map_restart, set everthing with initial
if( !cg.snap ) { } //TA: ?
// clear the currentValid flag for all entities in the existing snapshot
for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
cent->currentValid = qfalse;
}
// move nextSnap to snap and do the transitions
oldFrame = cg.snap;
cg.snap = cg.nextSnap;
BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
CG_TransitionEntity( cent );
// remember time of snapshot this entity was last updated in
cent->snapShotTime = cg.snap->serverTime;
}
cg.nextSnap = NULL;
// check for playerstate transition events
if( oldFrame )
{
playerState_t *ops, *ps;
ops = &oldFrame->ps;
ps = &cg.snap->ps;
// teleporting checks are irrespective of prediction
if( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT )
cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
// if we are not doing client side movement prediction for any
// reason, then the client events and view changes will be issued now
if( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) ||
cg_nopredict.integer || cg_synchronousClients.integer )
CG_TransitionPlayerState( ps, ops );
}
}
/*
===================
CG_SetNextSnap
A new snapshot has just been read in from the client system.
===================
*/
static void CG_SetNextSnap( snapshot_t *snap )
{
int num;
entityState_t *es;
centity_t *cent;
cg.nextSnap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
// check for extrapolation errors
for( num = 0 ; num < snap->numEntities ; num++ )
{
es = &snap->entities[ num ];
cent = &cg_entities[ es->number ];
memcpy( &cent->nextState, es, sizeof( entityState_t ) );
//cent->nextState = *es;
// if this frame is a teleport, or the entity wasn't in the
// previous frame, don't interpolate
if( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) )
cent->interpolate = qfalse;
else
cent->interpolate = qtrue;
}
// if the next frame is a teleport for the playerstate, we
// can't interpolate during demos
if( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) )
cg.nextFrameTeleport = qtrue;
else
cg.nextFrameTeleport = qfalse;
// if changing follow mode, don't interpolate
if( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum )
cg.nextFrameTeleport = qtrue;
// if changing server restarts, don't interpolate
if( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT )
cg.nextFrameTeleport = qtrue;
// sort out solid entities
CG_BuildSolidList( );
}
/*
========================
CG_ReadNextSnapshot
This is the only place new snapshots are requested
This may increment cgs.processedSnapshotNum multiple
times if the client system fails to return a
valid snapshot.
========================
*/
static snapshot_t *CG_ReadNextSnapshot( void )
{
qboolean r;
snapshot_t *dest;
if( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 )
{
CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
cg.latestSnapshotNum, cgs.processedSnapshotNum );
}
while( cgs.processedSnapshotNum < cg.latestSnapshotNum )
{
// decide which of the two slots to load it into
if( cg.snap == &cg.activeSnapshots[ 0 ] )
dest = &cg.activeSnapshots[ 1 ];
else
dest = &cg.activeSnapshots[ 0 ];
// try to read the snapshot from the client system
cgs.processedSnapshotNum++;
r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
// FIXME: why would trap_GetSnapshot return a snapshot with the same server time
if( cg.snap && r && dest->serverTime == cg.snap->serverTime )
{
//continue;
}
// if it succeeded, return
if( r )
{
CG_AddLagometerSnapshotInfo( dest );
return dest;
}
// a GetSnapshot will return failure if the snapshot
// never arrived, or is so old that its entities
// have been shoved off the end of the circular
// buffer in the client system.
// record as a dropped packet
CG_AddLagometerSnapshotInfo( NULL );
// If there are additional snapshots, continue trying to
// read them.
}
// nothing left to read
return NULL;
}
/*
============
CG_ProcessSnapshots
We are trying to set up a renderable view, so determine
what the simulated time is, and try to get snapshots
both before and after that time if available.
If we don't have a valid cg.snap after exiting this function,
then a 3D game view cannot be rendered. This should only happen
right after the initial connection. After cg.snap has been valid
once, it will never turn invalid.
Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
hasn't arrived yet (it becomes an extrapolating situation instead
of an interpolating one)
============
*/
void CG_ProcessSnapshots( void )
{
snapshot_t *snap;
int n;
// see what the latest snapshot the client system has is
trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
if( n != cg.latestSnapshotNum )
{
if( n < cg.latestSnapshotNum )
{
// this should never happen
CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
}
cg.latestSnapshotNum = n;
}
// If we have yet to receive a snapshot, check for it.
// Once we have gotten the first snapshot, cg.snap will
// always have valid data for the rest of the game
while( !cg.snap )
{
snap = CG_ReadNextSnapshot( );
if( !snap )
{
// we can't continue until we get a snapshot
return;
}
// set our weapon selection to what
// the playerstate is currently using
if( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) )
CG_SetInitialSnapshot( snap );
}
// loop until we either have a valid nextSnap with a serverTime
// greater than cg.time to interpolate towards, or we run
// out of available snapshots
do
{
// if we don't have a nextframe, try and read a new one in
if( !cg.nextSnap )
{
snap = CG_ReadNextSnapshot( );
// if we still don't have a nextframe, we will just have to
// extrapolate
if( !snap )
break;
CG_SetNextSnap( snap );
// if time went backwards, we have a level restart
if( cg.nextSnap->serverTime < cg.snap->serverTime )
CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
}
// if our time is < nextFrame's, we have a nice interpolating state
if( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime )
break;
// we have passed the transition from nextFrame to frame
CG_TransitionSnapshot( );
} while( 1 );
// assert our valid conditions upon exiting
if( cg.snap == NULL )
CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
if( cg.time < cg.snap->serverTime )
{
// this can happen right after a vid_restart
cg.time = cg.snap->serverTime;
}
if( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time )
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
}
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus
This file is part of Tremulous.
Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cg_snapshot.c -- things that happen on snapshot transition,
// not necessarily every single rendered frame
#include "cg_local.h"
/*
==================
CG_ResetEntity
==================
*/
static void CG_ResetEntity( centity_t *cent )
{
// if the previous snapshot this entity was updated in is at least
// an event window back in time then we can reset the previous event
if( cent->snapShotTime < cg.time - EVENT_VALID_MSEC )
cent->previousEvent = 0;
cent->trailTime = cg.snap->serverTime;
VectorCopy( cent->currentState.origin, cent->lerpOrigin );
VectorCopy( cent->currentState.angles, cent->lerpAngles );
if( cent->currentState.eType == ET_PLAYER )
CG_ResetPlayerEntity( cent );
}
/*
===============
CG_TransitionEntity
cent->nextState is moved to cent->currentState and events are fired
===============
*/
static void CG_TransitionEntity( centity_t *cent )
{
cent->currentState = cent->nextState;
cent->currentValid = qtrue;
// reset if the entity wasn't in the last frame or was teleported
if( !cent->interpolate )
CG_ResetEntity( cent );
// clear the next state. if will be set by the next CG_SetNextSnap
cent->interpolate = qfalse;
// check for events
CG_CheckEvents( cent );
}
/*
==================
CG_SetInitialSnapshot
This will only happen on the very first snapshot, or
on tourney restarts. All other times will use
CG_TransitionSnapshot instead.
FIXME: Also called by map_restart?
==================
*/
void CG_SetInitialSnapshot( snapshot_t *snap )
{
int i;
centity_t *cent;
entityState_t *state;
cg.snap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
// sort out solid entities
CG_BuildSolidList( );
CG_ExecuteNewServerCommands( snap->serverCommandSequence );
// set our local weapon selection pointer to
// what the server has indicated the current weapon is
CG_Respawn( );
for( i = 0; i < cg.snap->numEntities; i++ )
{
state = &cg.snap->entities[ i ];
cent = &cg_entities[ state->number ];
memcpy( &cent->currentState, state, sizeof( entityState_t ) );
//cent->currentState = *state;
cent->interpolate = qfalse;
cent->currentValid = qtrue;
CG_ResetEntity( cent );
// check for events
CG_CheckEvents( cent );
}
}
/*
===================
CG_TransitionSnapshot
The transition point from snap to nextSnap has passed
===================
*/
static void CG_TransitionSnapshot( void )
{
centity_t *cent;
snapshot_t *oldFrame;
int i;
if( !cg.snap )
CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
if( !cg.nextSnap )
CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
// execute any server string commands before transitioning entities
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
// if we had a map_restart, set everthing with initial
if( !cg.snap ) { } //TA: ?
// clear the currentValid flag for all entities in the existing snapshot
for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
cent->currentValid = qfalse;
}
// move nextSnap to snap and do the transitions
oldFrame = cg.snap;
cg.snap = cg.nextSnap;
BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
CG_TransitionEntity( cent );
// remember time of snapshot this entity was last updated in
cent->snapShotTime = cg.snap->serverTime;
}
cg.nextSnap = NULL;
// check for playerstate transition events
if( oldFrame )
{
playerState_t *ops, *ps;
ops = &oldFrame->ps;
ps = &cg.snap->ps;
// teleporting checks are irrespective of prediction
if( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT )
cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
// if we are not doing client side movement prediction for any
// reason, then the client events and view changes will be issued now
if( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) ||
cg_nopredict.integer || cg_synchronousClients.integer )
CG_TransitionPlayerState( ps, ops );
}
}
/*
===================
CG_SetNextSnap
A new snapshot has just been read in from the client system.
===================
*/
static void CG_SetNextSnap( snapshot_t *snap )
{
int num;
entityState_t *es;
centity_t *cent;
cg.nextSnap = snap;
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
// check for extrapolation errors
for( num = 0 ; num < snap->numEntities ; num++ )
{
es = &snap->entities[ num ];
cent = &cg_entities[ es->number ];
memcpy( &cent->nextState, es, sizeof( entityState_t ) );
//cent->nextState = *es;
// if this frame is a teleport, or the entity wasn't in the
// previous frame, don't interpolate
if( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) )
cent->interpolate = qfalse;
else
cent->interpolate = qtrue;
}
// if the next frame is a teleport for the playerstate, we
// can't interpolate during demos
if( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) )
cg.nextFrameTeleport = qtrue;
else
cg.nextFrameTeleport = qfalse;
// if changing follow mode, don't interpolate
if( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum )
cg.nextFrameTeleport = qtrue;
// if changing server restarts, don't interpolate
if( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT )
cg.nextFrameTeleport = qtrue;
// sort out solid entities
CG_BuildSolidList( );
}
/*
========================
CG_ReadNextSnapshot
This is the only place new snapshots are requested
This may increment cgs.processedSnapshotNum multiple
times if the client system fails to return a
valid snapshot.
========================
*/
static snapshot_t *CG_ReadNextSnapshot( void )
{
qboolean r;
snapshot_t *dest;
if( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 )
{
CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
cg.latestSnapshotNum, cgs.processedSnapshotNum );
}
while( cgs.processedSnapshotNum < cg.latestSnapshotNum )
{
// decide which of the two slots to load it into
if( cg.snap == &cg.activeSnapshots[ 0 ] )
dest = &cg.activeSnapshots[ 1 ];
else
dest = &cg.activeSnapshots[ 0 ];
// try to read the snapshot from the client system
cgs.processedSnapshotNum++;
r = trap_GetSnapshot( cgs.processedSnapshotNum, dest );
// FIXME: why would trap_GetSnapshot return a snapshot with the same server time
if( cg.snap && r && dest->serverTime == cg.snap->serverTime )
{
//continue;
}
// if it succeeded, return
if( r )
{
CG_AddLagometerSnapshotInfo( dest );
return dest;
}
// a GetSnapshot will return failure if the snapshot
// never arrived, or is so old that its entities
// have been shoved off the end of the circular
// buffer in the client system.
// record as a dropped packet
CG_AddLagometerSnapshotInfo( NULL );
// If there are additional snapshots, continue trying to
// read them.
}
// nothing left to read
return NULL;
}
/*
============
CG_ProcessSnapshots
We are trying to set up a renderable view, so determine
what the simulated time is, and try to get snapshots
both before and after that time if available.
If we don't have a valid cg.snap after exiting this function,
then a 3D game view cannot be rendered. This should only happen
right after the initial connection. After cg.snap has been valid
once, it will never turn invalid.
Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot
hasn't arrived yet (it becomes an extrapolating situation instead
of an interpolating one)
============
*/
void CG_ProcessSnapshots( void )
{
snapshot_t *snap;
int n;
// see what the latest snapshot the client system has is
trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
if( n != cg.latestSnapshotNum )
{
if( n < cg.latestSnapshotNum )
{
// this should never happen
CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
}
cg.latestSnapshotNum = n;
}
// If we have yet to receive a snapshot, check for it.
// Once we have gotten the first snapshot, cg.snap will
// always have valid data for the rest of the game
while( !cg.snap )
{
snap = CG_ReadNextSnapshot( );
if( !snap )
{
// we can't continue until we get a snapshot
return;
}
// set our weapon selection to what
// the playerstate is currently using
if( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) )
CG_SetInitialSnapshot( snap );
}
// loop until we either have a valid nextSnap with a serverTime
// greater than cg.time to interpolate towards, or we run
// out of available snapshots
do
{
// if we don't have a nextframe, try and read a new one in
if( !cg.nextSnap )
{
snap = CG_ReadNextSnapshot( );
// if we still don't have a nextframe, we will just have to
// extrapolate
if( !snap )
break;
CG_SetNextSnap( snap );
// if time went backwards, we have a level restart
if( cg.nextSnap->serverTime < cg.snap->serverTime )
CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
}
// if our time is < nextFrame's, we have a nice interpolating state
if( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime )
break;
// we have passed the transition from nextFrame to frame
CG_TransitionSnapshot( );
} while( 1 );
// assert our valid conditions upon exiting
if( cg.snap == NULL )
CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
if( cg.time < cg.snap->serverTime )
{
// this can happen right after a vid_restart
cg.time = cg.snap->serverTime;
}
if( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time )
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
}
+116 -116
View File
@@ -1,116 +1,116 @@
code
equ trap_Print -1
equ trap_Error -2
equ trap_Milliseconds -3
equ trap_Cvar_Register -4
equ trap_Cvar_Update -5
equ trap_Cvar_Set -6
equ trap_Cvar_VariableStringBuffer -7
equ trap_Argc -8
equ trap_Argv -9
equ trap_Args -10
equ trap_FS_FOpenFile -11
equ trap_FS_Read -12
equ trap_FS_Write -13
equ trap_FS_FCloseFile -14
equ trap_SendConsoleCommand -15
equ trap_AddCommand -16
equ trap_SendClientCommand -17
equ trap_UpdateScreen -18
equ trap_CM_LoadMap -19
equ trap_CM_NumInlineModels -20
equ trap_CM_InlineModel -21
equ trap_CM_LoadModel -22
equ trap_CM_TempBoxModel -23
equ trap_CM_PointContents -24
equ trap_CM_TransformedPointContents -25
equ trap_CM_BoxTrace -26
equ trap_CM_TransformedBoxTrace -27
equ trap_CM_MarkFragments -28
equ trap_S_StartSound -29
equ trap_S_StartLocalSound -30
equ trap_S_ClearLoopingSounds -31
equ trap_S_AddLoopingSound -32
equ trap_S_UpdateEntityPosition -33
equ trap_S_Respatialize -34
equ trap_S_RegisterSound -35
equ trap_S_StartBackgroundTrack -36
equ trap_R_LoadWorldMap -37
equ trap_R_RegisterModel -38
equ trap_R_RegisterSkin -39
equ trap_R_RegisterShader -40
equ trap_R_ClearScene -41
equ trap_R_AddRefEntityToScene -42
equ trap_R_AddPolyToScene -43
equ trap_R_AddLightToScene -44
equ trap_R_RenderScene -45
equ trap_R_SetColor -46
equ trap_R_DrawStretchPic -47
equ trap_R_ModelBounds -48
equ trap_R_LerpTag -49
equ trap_GetGlconfig -50
equ trap_GetGameState -51
equ trap_GetCurrentSnapshotNumber -52
equ trap_GetSnapshot -53
equ trap_GetServerCommand -54
equ trap_GetCurrentCmdNumber -55
equ trap_GetUserCmd -56
equ trap_SetUserCmdValue -57
equ trap_R_RegisterShaderNoMip -58
equ trap_MemoryRemaining -59
equ trap_R_RegisterFont -60
equ trap_Key_IsDown -61
equ trap_Key_GetCatcher -62
equ trap_Key_SetCatcher -63
equ trap_Key_GetKey -64
equ trap_S_StopBackgroundTrack -65
equ trap_RealTime -66
equ trap_SnapVector -67
equ trap_RemoveCommand -68
equ trap_R_LightForPoint -69
equ trap_CIN_PlayCinematic -70
equ trap_CIN_StopCinematic -71
equ trap_CIN_RunCinematic -72
equ trap_CIN_DrawCinematic -73
equ trap_CIN_SetExtents -74
equ trap_R_RemapShader -75
equ trap_S_AddRealLoopingSound -76
equ trap_S_StopLoopingSound -77
equ trap_CM_TempCapsuleModel -78
equ trap_CM_CapsuleTrace -79
equ trap_CM_TransformedCapsuleTrace -80
equ trap_R_AddAdditiveLightToScene -81
equ trap_GetEntityToken -82
equ trap_R_AddPolysToScene -83
equ trap_R_inPVS -84
equ trap_FS_Seek -85
equ trap_FS_GetFileList -86
equ trap_LiteralArgs -87
equ trap_CM_BiSphereTrace -88
equ trap_CM_TransformedBiSphereTrace -89
equ trap_GetDemoState -90
equ trap_GetDemoPos -91
equ trap_GetDemoName -92
equ trap_Key_KeynumToStringBuf -93
equ trap_Key_GetBindingBuf -94
equ trap_Key_SetBinding -95
equ trap_Parse_AddGlobalDefine -96
equ trap_Parse_LoadSource -97
equ trap_Parse_FreeSource -98
equ trap_Parse_ReadToken -99
equ trap_Parse_SourceFileAndLine -100
equ memset -201
equ memcpy -202
equ strncpy -203
equ sin -204
equ cos -205
equ atan2 -206
equ sqrt -207
equ floor -208
equ ceil -209
equ testPrintInt -210
equ testPrintFloat -211
code
equ trap_Print -1
equ trap_Error -2
equ trap_Milliseconds -3
equ trap_Cvar_Register -4
equ trap_Cvar_Update -5
equ trap_Cvar_Set -6
equ trap_Cvar_VariableStringBuffer -7
equ trap_Argc -8
equ trap_Argv -9
equ trap_Args -10
equ trap_FS_FOpenFile -11
equ trap_FS_Read -12
equ trap_FS_Write -13
equ trap_FS_FCloseFile -14
equ trap_SendConsoleCommand -15
equ trap_AddCommand -16
equ trap_SendClientCommand -17
equ trap_UpdateScreen -18
equ trap_CM_LoadMap -19
equ trap_CM_NumInlineModels -20
equ trap_CM_InlineModel -21
equ trap_CM_LoadModel -22
equ trap_CM_TempBoxModel -23
equ trap_CM_PointContents -24
equ trap_CM_TransformedPointContents -25
equ trap_CM_BoxTrace -26
equ trap_CM_TransformedBoxTrace -27
equ trap_CM_MarkFragments -28
equ trap_S_StartSound -29
equ trap_S_StartLocalSound -30
equ trap_S_ClearLoopingSounds -31
equ trap_S_AddLoopingSound -32
equ trap_S_UpdateEntityPosition -33
equ trap_S_Respatialize -34
equ trap_S_RegisterSound -35
equ trap_S_StartBackgroundTrack -36
equ trap_R_LoadWorldMap -37
equ trap_R_RegisterModel -38
equ trap_R_RegisterSkin -39
equ trap_R_RegisterShader -40
equ trap_R_ClearScene -41
equ trap_R_AddRefEntityToScene -42
equ trap_R_AddPolyToScene -43
equ trap_R_AddLightToScene -44
equ trap_R_RenderScene -45
equ trap_R_SetColor -46
equ trap_R_DrawStretchPic -47
equ trap_R_ModelBounds -48
equ trap_R_LerpTag -49
equ trap_GetGlconfig -50
equ trap_GetGameState -51
equ trap_GetCurrentSnapshotNumber -52
equ trap_GetSnapshot -53
equ trap_GetServerCommand -54
equ trap_GetCurrentCmdNumber -55
equ trap_GetUserCmd -56
equ trap_SetUserCmdValue -57
equ trap_R_RegisterShaderNoMip -58
equ trap_MemoryRemaining -59
equ trap_R_RegisterFont -60
equ trap_Key_IsDown -61
equ trap_Key_GetCatcher -62
equ trap_Key_SetCatcher -63
equ trap_Key_GetKey -64
equ trap_S_StopBackgroundTrack -65
equ trap_RealTime -66
equ trap_SnapVector -67
equ trap_RemoveCommand -68
equ trap_R_LightForPoint -69
equ trap_CIN_PlayCinematic -70
equ trap_CIN_StopCinematic -71
equ trap_CIN_RunCinematic -72
equ trap_CIN_DrawCinematic -73
equ trap_CIN_SetExtents -74
equ trap_R_RemapShader -75
equ trap_S_AddRealLoopingSound -76
equ trap_S_StopLoopingSound -77
equ trap_CM_TempCapsuleModel -78
equ trap_CM_CapsuleTrace -79
equ trap_CM_TransformedCapsuleTrace -80
equ trap_R_AddAdditiveLightToScene -81
equ trap_GetEntityToken -82
equ trap_R_AddPolysToScene -83
equ trap_R_inPVS -84
equ trap_FS_Seek -85
equ trap_FS_GetFileList -86
equ trap_LiteralArgs -87
equ trap_CM_BiSphereTrace -88
equ trap_CM_TransformedBiSphereTrace -89
equ trap_GetDemoState -90
equ trap_GetDemoPos -91
equ trap_GetDemoName -92
equ trap_Key_KeynumToStringBuf -93
equ trap_Key_GetBindingBuf -94
equ trap_Key_SetBinding -95
equ trap_Parse_AddGlobalDefine -96
equ trap_Parse_LoadSource -97
equ trap_Parse_FreeSource -98
equ trap_Parse_ReadToken -99
equ trap_Parse_SourceFileAndLine -100
equ memset -201
equ memcpy -202
equ strncpy -203
equ sin -204
equ cos -205
equ atan2 -206
equ sqrt -207
equ floor -208
equ ceil -209
equ testPrintInt -210
equ testPrintFloat -211
+570 -570
View File
File diff suppressed because it is too large. Load diff
+1500 -1500
View File
File diff suppressed because it is too large. Load diff
+1340 -1340
View File
File diff suppressed because it is too large. Load diff
+1845 -1845
View File
File diff suppressed because it is too large. Load diff