📄 bg_pmove.c
字号:
}
// check for item using
if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
&& pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {
// don't use medkit if at max health
} else {
pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
}
return;
}
} else {
pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
}
// make weapon function
if ( pm->ps->weaponTime > 0 ) {
pm->ps->weaponTime -= pml.msec;
}
// check for weapon change
// can't change if weapon is firing, but can change
// again if lowering or raising
if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
if ( pm->ps->weapon != pm->cmd.weapon ) {
PM_BeginWeaponChange( pm->cmd.weapon );
}
}
if ( pm->ps->weaponTime > 0 ) {
return;
}
// change weapon if time
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
PM_FinishWeaponChange();
return;
}
if ( pm->ps->weaponstate == WEAPON_RAISING ) {
pm->ps->weaponstate = WEAPON_READY;
if ( pm->ps->weapon == WP_GAUNTLET ) {
PM_StartTorsoAnim( TORSO_STAND2 );
} else {
PM_StartTorsoAnim( TORSO_STAND );
}
return;
}
// check for fire
if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
// start the animation even if out of ammo
if ( pm->ps->weapon == WP_GAUNTLET ) {
// the guantlet only "fires" when it actually hits something
if ( !pm->gauntletHit ) {
pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
PM_StartTorsoAnim( TORSO_ATTACK2 );
} else {
PM_StartTorsoAnim( TORSO_ATTACK );
}
pm->ps->weaponstate = WEAPON_FIRING;
// check for out of ammo
if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
PM_AddEvent( EV_NOAMMO );
pm->ps->weaponTime += 500;
return;
}
// take an ammo away if not infinite
if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {
pm->ps->ammo[ pm->ps->weapon ]--;
}
// fire weapon
PM_AddEvent( EV_FIRE_WEAPON );
switch( pm->ps->weapon ) {
default:
case WP_GAUNTLET:
addTime = 400;
break;
case WP_LIGHTNING:
addTime = 50;
break;
case WP_SHOTGUN:
addTime = 1000;
break;
case WP_MACHINEGUN:
addTime = 100;
break;
case WP_GRENADE_LAUNCHER:
addTime = 800;
break;
case WP_ROCKET_LAUNCHER:
addTime = 800;
break;
case WP_PLASMAGUN:
addTime = 100;
break;
case WP_RAILGUN:
addTime = 1500;
break;
case WP_BFG:
addTime = 200;
break;
case WP_GRAPPLING_HOOK:
addTime = 400;
break;
#ifdef MISSIONPACK
case WP_NAILGUN:
addTime = 1000;
break;
case WP_PROX_LAUNCHER:
addTime = 800;
break;
case WP_CHAINGUN:
addTime = 30;
break;
#endif
}
#ifdef MISSIONPACK
if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
addTime /= 1.5;
}
else
if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
addTime /= 1.3;
}
else
#endif
if ( pm->ps->powerups[PW_HASTE] ) {
addTime /= 1.3;
}
pm->ps->weaponTime += addTime;
}
/*
================
PM_Animate
================
*/
static void PM_Animate( void ) {
if ( pm->cmd.buttons & BUTTON_GESTURE ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_GESTURE );
pm->ps->torsoTimer = TIMER_GESTURE;
PM_AddEvent( EV_TAUNT );
}
#ifdef MISSIONPACK
} else if ( pm->cmd.buttons & BUTTON_GETFLAG ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_GETFLAG );
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
}
} else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_GUARDBASE );
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
}
} else if ( pm->cmd.buttons & BUTTON_PATROL ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_PATROL );
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
}
} else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_FOLLOWME );
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
}
} else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_AFFIRMATIVE);
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
}
} else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) {
if ( pm->ps->torsoTimer == 0 ) {
PM_StartTorsoAnim( TORSO_NEGATIVE );
pm->ps->torsoTimer = 600; //TIMER_GESTURE;
}
#endif
}
}
/*
================
PM_DropTimers
================
*/
static void PM_DropTimers( void ) {
// drop misc timing counter
if ( pm->ps->pm_time ) {
if ( pml.msec >= pm->ps->pm_time ) {
pm->ps->pm_flags &= ~PMF_ALL_TIMES;
pm->ps->pm_time = 0;
} else {
pm->ps->pm_time -= pml.msec;
}
}
// drop animation counter
if ( pm->ps->legsTimer > 0 ) {
pm->ps->legsTimer -= pml.msec;
if ( pm->ps->legsTimer < 0 ) {
pm->ps->legsTimer = 0;
}
}
if ( pm->ps->torsoTimer > 0 ) {
pm->ps->torsoTimer -= pml.msec;
if ( pm->ps->torsoTimer < 0 ) {
pm->ps->torsoTimer = 0;
}
}
}
/*
================
PM_UpdateViewAngles
This can be used as another entry point when only the viewangles
are being updated isntead of a full move
================
*/
void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
short temp;
int i;
if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
return; // no view changes at all
}
if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
return; // no view changes at all
}
// circularly clamp the angles with deltas
for (i=0 ; i<3 ; i++) {
temp = cmd->angles[i] + ps->delta_angles[i];
if ( i == PITCH ) {
// don't let the player look up or down more than 90 degrees
if ( temp > 16000 ) {
ps->delta_angles[i] = 16000 - cmd->angles[i];
temp = 16000;
} else if ( temp < -16000 ) {
ps->delta_angles[i] = -16000 - cmd->angles[i];
temp = -16000;
}
}
ps->viewangles[i] = SHORT2ANGLE(temp);
}
}
/*
================
PmoveSingle
================
*/
void trap_SnapVector( float *v );
void PmoveSingle (pmove_t *pmove) {
pm = pmove;
// this counter lets us debug movement problems with a journal
// by setting a conditional breakpoint fot the previous frame
c_pmove++;
// clear results
pm->numtouch = 0;
pm->watertype = 0;
pm->waterlevel = 0;
if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies
}
// make sure walking button is clear if they are running, to avoid
// proxy no-footsteps cheats
if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
pm->cmd.buttons &= ~BUTTON_WALKING;
}
// set the talk balloon flag
if ( pm->cmd.buttons & BUTTON_TALK ) {
pm->ps->eFlags |= EF_TALK;
} else {
pm->ps->eFlags &= ~EF_TALK;
}
// set the firing flag for continuous beam weapons
if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION
&& ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
pm->ps->eFlags |= EF_FIRING;
} else {
pm->ps->eFlags &= ~EF_FIRING;
}
// clear the respawned flag if attack and use are cleared
if ( pm->ps->stats[STAT_HEALTH] > 0 &&
!( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
pm->ps->pm_flags &= ~PMF_RESPAWNED;
}
// if talk button is down, dissallow all other input
// this is to prevent any possible intercept proxy from
// adding fake talk balloons
if ( pmove->cmd.buttons & BUTTON_TALK ) {
// keep the talk button set tho for when the cmd.serverTime > 66 msec
// and the same cmd is used multiple times in Pmove
pmove->cmd.buttons = BUTTON_TALK;
pmove->cmd.forwardmove = 0;
pmove->cmd.rightmove = 0;
pmove->cmd.upmove = 0;
}
// clear all pmove local vars
memset (&pml, 0, sizeof(pml));
// determine the time
pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
if ( pml.msec < 1 ) {
pml.msec = 1;
} else if ( pml.msec > 200 ) {
pml.msec = 200;
}
pm->ps->commandTime = pmove->cmd.serverTime;
// save old org in case we get stuck
VectorCopy (pm->ps->origin, pml.previous_origin);
// save old velocity for crashlanding
VectorCopy (pm->ps->velocity, pml.previous_velocity);
pml.frametime = pml.msec * 0.001;
// update the viewangles
PM_UpdateViewAngles( pm->ps, &pm->cmd );
AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
if ( pm->cmd.upmove < 10 ) {
// not holding jump
pm->ps->pm_flags &= ~PMF_JUMP_HELD;
}
// decide if backpedaling animations should be used
if ( pm->cmd.forwardmove < 0 ) {
pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
} else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
}
if ( pm->ps->pm_type >= PM_DEAD ) {
pm->cmd.forwardmove = 0;
pm->cmd.rightmove = 0;
pm->cmd.upmove = 0;
}
if ( pm->ps->pm_type == PM_SPECTATOR ) {
PM_CheckDuck ();
PM_FlyMove ();
PM_DropTimers ();
return;
}
if ( pm->ps->pm_type == PM_NOCLIP ) {
PM_NoclipMove ();
PM_DropTimers ();
return;
}
if (pm->ps->pm_type == PM_FREEZE) {
return; // no movement at all
}
if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {
return; // no movement at all
}
// set watertype, and waterlevel
PM_SetWaterLevel();
pml.previous_waterlevel = pmove->waterlevel;
// set mins, maxs, and viewheight
PM_CheckDuck ();
// set groundentity
PM_GroundTrace();
if ( pm->ps->pm_type == PM_DEAD ) {
PM_DeadMove ();
}
PM_DropTimers();
#ifdef MISSIONPACK
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
PM_InvulnerabilityMove();
} else
#endif
if ( pm->ps->powerups[PW_FLIGHT] ) {
// flight powerup doesn't allow jump and has different friction
PM_FlyMove();
} else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
PM_GrappleMove();
// We can wiggle a bit
PM_AirMove();
} else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
PM_WaterJumpMove();
} else if ( pm->waterlevel > 1 ) {
// swimming
PM_WaterMove();
} else if ( pml.walking ) {
// walking on ground
PM_WalkMove();
} else {
// airborne
PM_AirMove();
}
PM_Animate();
// set groundentity, watertype, and waterlevel
PM_GroundTrace();
PM_SetWaterLevel();
// weapons
PM_Weapon();
// torso animation
PM_TorsoAnimation();
// footstep events / legs animations
PM_Footsteps();
// entering / leaving water splashes
PM_WaterEvents();
// snap some parts of playerstate to save network bandwidth
trap_SnapVector( pm->ps->velocity );
}
/*
================
Pmove
Can be called by either the server or the client
================
*/
void Pmove (pmove_t *pmove) {
int finalTime;
finalTime = pmove->cmd.serverTime;
if ( finalTime < pmove->ps->commandTime ) {
return; // should not happen
}
if ( finalTime > pmove->ps->commandTime + 1000 ) {
pmove->ps->commandTime = finalTime - 1000;
}
pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);
// chop the move up if it is too long, to prevent framerate
// dependent behavior
while ( pmove->ps->commandTime != finalTime ) {
int msec;
msec = finalTime - pmove->ps->commandTime;
if ( pmove->pmove_fixed ) {
if ( msec > pmove->pmove_msec ) {
msec = pmove->pmove_msec;
}
}
else {
if ( msec > 66 ) {
msec = 66;
}
}
pmove->cmd.serverTime = pmove->ps->commandTime + msec;
PmoveSingle( pmove );
if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {
pmove->cmd.upmove = 20;
}
}
//PM_CheckStuck();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -