📄 cg_playerstate.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; 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_CheckAmmo
If the ammo has gone low enough to generate the warning, play a sound
==============
*/
void CG_CheckAmmo( void ) {
int i;
int total;
int previous;
int weapons;
// see about how many seconds of ammo we have remaining
weapons = cg.snap->ps.stats[ STAT_WEAPONS ];
total = 0;
for ( i = WP_MACHINEGUN ; i < WP_NUM_WEAPONS ; i++ ) {
if ( ! ( weapons & ( 1 << i ) ) ) {
continue;
}
switch ( i ) {
case WP_ROCKET_LAUNCHER:
case WP_GRENADE_LAUNCHER:
case WP_RAILGUN:
case WP_SHOTGUN:
#ifdef MISSIONPACK
case WP_PROX_LAUNCHER:
#endif
total += cg.snap->ps.ammo[i] * 1000;
break;
default:
total += cg.snap->ps.ammo[i] * 200;
break;
}
if ( total >= 5000 ) {
cg.lowAmmoWarning = 0;
return;
}
}
previous = cg.lowAmmoWarning;
if ( total == 0 ) {
cg.lowAmmoWarning = 2;
} else {
cg.lowAmmoWarning = 1;
}
// play a sound on transitions
if ( cg.lowAmmoWarning != previous ) {
trap_S_StartLocalSound( cgs.media.noAmmoSound, CHAN_LOCAL_SOUND );
}
}
/*
==============
CG_DamageFeedback
==============
*/
void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
float left, front, up;
float kick;
int health;
float scale;
vec3_t dir;
vec3_t angles;
float dist;
float yaw, pitch;
// show the attacking player's head and name in corner
cg.attackerTime = cg.time;
// the lower on health you are, the greater the view kick will be
health = cg.snap->ps.stats[STAT_HEALTH];
if ( health < 40 ) {
scale = 1;
} else {
scale = 40.0 / health;
}
kick = damage * scale;
if (kick < 5)
kick = 5;
if (kick > 10)
kick = 10;
// if yaw and pitch are both 255, make the damage always centered (falling, etc)
if ( yawByte == 255 && pitchByte == 255 ) {
cg.damageX = 0;
cg.damageY = 0;
cg.v_dmg_roll = 0;
cg.v_dmg_pitch = -kick;
} else {
// positional
pitch = pitchByte / 255.0 * 360;
yaw = yawByte / 255.0 * 360;
angles[PITCH] = pitch;
angles[YAW] = yaw;
angles[ROLL] = 0;
AngleVectors( angles, dir, NULL, NULL );
VectorSubtract( vec3_origin, dir, dir );
front = DotProduct (dir, cg.refdef.viewaxis[0] );
left = DotProduct (dir, cg.refdef.viewaxis[1] );
up = DotProduct (dir, cg.refdef.viewaxis[2] );
dir[0] = front;
dir[1] = left;
dir[2] = 0;
dist = VectorLength( dir );
if ( dist < 0.1 ) {
dist = 0.1f;
}
cg.v_dmg_roll = kick * left;
cg.v_dmg_pitch = -kick * front;
if ( front <= 0.1 ) {
front = 0.1f;
}
cg.damageX = -left / front;
cg.damageY = up / dist;
}
// clamp the position
if ( cg.damageX > 1.0 ) {
cg.damageX = 1.0;
}
if ( cg.damageX < - 1.0 ) {
cg.damageX = -1.0;
}
if ( cg.damageY > 1.0 ) {
cg.damageY = 1.0;
}
if ( cg.damageY < - 1.0 ) {
cg.damageY = -1.0;
}
// don't let the screen flashes vary as much
if ( kick > 10 ) {
kick = 10;
}
cg.damageValue = kick;
cg.v_dmg_time = cg.time + DAMAGE_TIME;
cg.damageTime = cg.snap->serverTime;
}
/*
================
CG_Respawn
A respawn happened this snapshot
================
*/
void CG_Respawn( void ) {
// no error decay on player movement
cg.thisFrameTeleport = qtrue;
// display weapons available
cg.weaponSelectTime = cg.time;
// select the weapon the server says we are using
cg.weaponSelect = cg.snap->ps.weapon;
}
extern char *eventnames[];
/*
==============
CG_CheckPlayerstateEvents
==============
*/
void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) {
int i;
int event;
centity_t *cent;
if ( ps->externalEvent && ps->externalEvent != ops->externalEvent ) {
cent = &cg_entities[ ps->clientNum ];
cent->currentState.event = ps->externalEvent;
cent->currentState.eventParm = ps->externalEventParm;
CG_EntityEvent( cent, cent->lerpOrigin );
}
cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ];
// go through the predictable events buffer
for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
// if we have a new predictable event
if ( i >= ops->eventSequence
// or the server told us to play another event instead of a predicted event we already issued
// or something the server told us changed our prediction causing a different event
|| (i > ops->eventSequence - MAX_PS_EVENTS && ps->events[i & (MAX_PS_EVENTS-1)] != ops->events[i & (MAX_PS_EVENTS-1)]) ) {
event = ps->events[ i & (MAX_PS_EVENTS-1) ];
cent->currentState.event = event;
cent->currentState.eventParm = ps->eventParms[ i & (MAX_PS_EVENTS-1) ];
CG_EntityEvent( cent, cent->lerpOrigin );
cg.predictableEvents[ i & (MAX_PREDICTED_EVENTS-1) ] = event;
cg.eventSequence++;
}
}
}
/*
==================
CG_CheckChangedPredictableEvents
==================
*/
void CG_CheckChangedPredictableEvents( playerState_t *ps ) {
int i;
int event;
centity_t *cent;
cent = &cg.predictedPlayerEntity;
for ( i = ps->eventSequence - MAX_PS_EVENTS ; i < ps->eventSequence ; i++ ) {
//
if (i >= cg.eventSequence) {
continue;
}
// if this event is not further back in than the maximum predictable events we remember
if (i > cg.eventSequence - MAX_PREDICTED_EVENTS) {
// if the new playerstate event is different from a previously predicted one
if ( ps->events[i & (MAX_PS_EVENTS-1)] != cg.predictableEvents[i & (MAX_PREDICTED_EVENTS-1) ] ) {
event = ps->events[ i & (MAX_PS_EVENTS-1) ];
cent->currentState.event = event;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -