📄 bg_pmove.c
字号:
point[0] += (float) i;
point[1] += (float) j;
point[2] += (float) k;
pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
if ( !trace->allsolid ) {
point[0] = pm->ps->origin[0];
point[1] = pm->ps->origin[1];
point[2] = pm->ps->origin[2] - 0.25;
pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
pml.groundTrace = *trace;
return qtrue;
}
}
}
}
pm->ps->groundEntityNum = ENTITYNUM_NONE;
pml.groundPlane = qfalse;
pml.walking = qfalse;
return qfalse;
}
/*
=============
PM_GroundTraceMissed
The ground trace didn't hit a surface, so we are in freefall
=============
*/
static void PM_GroundTraceMissed( void ) {
trace_t trace;
vec3_t point;
if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
// we just transitioned into freefall
if ( pm->debugLevel ) {
Com_Printf("%i:lift\n", c_pmove);
}
// if they aren't in a jumping animation and the ground is a ways away, force into it
// if we didn't do the trace, the player would be backflipping down staircases
VectorCopy( pm->ps->origin, point );
point[2] -= 64;
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
if ( trace.fraction == 1.0 ) {
if ( pm->cmd.forwardmove >= 0 ) {
PM_ForceLegsAnim( LEGS_JUMP );
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
} else {
PM_ForceLegsAnim( LEGS_JUMPB );
pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
}
}
}
pm->ps->groundEntityNum = ENTITYNUM_NONE;
pml.groundPlane = qfalse;
pml.walking = qfalse;
}
/*
=============
PM_GroundTrace
=============
*/
static void PM_GroundTrace( void ) {
vec3_t point;
trace_t trace;
point[0] = pm->ps->origin[0];
point[1] = pm->ps->origin[1];
point[2] = pm->ps->origin[2] - 0.25;
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
pml.groundTrace = trace;
// do something corrective if the trace starts in a solid...
if ( trace.allsolid ) {
if ( !PM_CorrectAllSolid(&trace) )
return;
}
// if the trace didn't hit anything, we are in free fall
if ( trace.fraction == 1.0 ) {
PM_GroundTraceMissed();
pml.groundPlane = qfalse;
pml.walking = qfalse;
return;
}
// check if getting thrown off the ground
if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
if ( pm->debugLevel ) {
Com_Printf("%i:kickoff\n", c_pmove);
}
// go into jump animation
if ( pm->cmd.forwardmove >= 0 ) {
PM_ForceLegsAnim( LEGS_JUMP );
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
} else {
PM_ForceLegsAnim( LEGS_JUMPB );
pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
}
pm->ps->groundEntityNum = ENTITYNUM_NONE;
pml.groundPlane = qfalse;
pml.walking = qfalse;
return;
}
// slopes that are too steep will not be considered onground
if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
if ( pm->debugLevel ) {
Com_Printf("%i:steep\n", c_pmove);
}
// FIXME: if they can't slide down the slope, let them
// walk (sharp crevices)
pm->ps->groundEntityNum = ENTITYNUM_NONE;
pml.groundPlane = qtrue;
pml.walking = qfalse;
return;
}
pml.groundPlane = qtrue;
pml.walking = qtrue;
// hitting solid ground will end a waterjump
if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
{
pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
pm->ps->pm_time = 0;
}
if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
// just hit the ground
if ( pm->debugLevel ) {
Com_Printf("%i:Land\n", c_pmove);
}
PM_CrashLand();
// don't do landing time if we were just going down a slope
if ( pml.previous_velocity[2] < -200 ) {
// don't allow another jump for a little while
pm->ps->pm_flags |= PMF_TIME_LAND;
pm->ps->pm_time = 250;
}
}
pm->ps->groundEntityNum = trace.entityNum;
// don't reset the z velocity for slopes
// pm->ps->velocity[2] = 0;
PM_AddTouchEnt( trace.entityNum );
}
/*
=============
PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving
=============
*/
static void PM_SetWaterLevel( void ) {
vec3_t point;
int cont;
int sample1;
int sample2;
//
// get waterlevel, accounting for ducking
//
pm->waterlevel = 0;
pm->watertype = 0;
point[0] = pm->ps->origin[0];
point[1] = pm->ps->origin[1];
point[2] = pm->ps->origin[2] + MINS_Z + 1;
cont = pm->pointcontents( point, pm->ps->clientNum );
if ( cont & MASK_WATER ) {
sample2 = pm->ps->viewheight - MINS_Z;
sample1 = sample2 / 2;
pm->watertype = cont;
pm->waterlevel = 1;
point[2] = pm->ps->origin[2] + MINS_Z + sample1;
cont = pm->pointcontents (point, pm->ps->clientNum );
if ( cont & MASK_WATER ) {
pm->waterlevel = 2;
point[2] = pm->ps->origin[2] + MINS_Z + sample2;
cont = pm->pointcontents (point, pm->ps->clientNum );
if ( cont & MASK_WATER ){
pm->waterlevel = 3;
}
}
}
}
/*
==============
PM_CheckDuck
Sets mins, maxs, and pm->ps->viewheight
==============
*/
static void PM_CheckDuck (void)
{
trace_t trace;
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
// invulnerability sphere has a 42 units radius
VectorSet( pm->mins, -42, -42, -42 );
VectorSet( pm->maxs, 42, 42, 42 );
}
else {
VectorSet( pm->mins, -15, -15, MINS_Z );
VectorSet( pm->maxs, 15, 15, 16 );
}
pm->ps->pm_flags |= PMF_DUCKED;
pm->ps->viewheight = CROUCH_VIEWHEIGHT;
return;
}
pm->ps->pm_flags &= ~PMF_INVULEXPAND;
pm->mins[0] = -15;
pm->mins[1] = -15;
pm->maxs[0] = 15;
pm->maxs[1] = 15;
pm->mins[2] = MINS_Z;
if (pm->ps->pm_type == PM_DEAD)
{
pm->maxs[2] = -8;
pm->ps->viewheight = DEAD_VIEWHEIGHT;
return;
}
if (pm->cmd.upmove < 0)
{ // duck
pm->ps->pm_flags |= PMF_DUCKED;
}
else
{ // stand up if possible
if (pm->ps->pm_flags & PMF_DUCKED)
{
// try to stand up
pm->maxs[2] = 32;
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
if (!trace.allsolid)
pm->ps->pm_flags &= ~PMF_DUCKED;
}
}
if (pm->ps->pm_flags & PMF_DUCKED)
{
pm->maxs[2] = 16;
pm->ps->viewheight = CROUCH_VIEWHEIGHT;
}
else
{
pm->maxs[2] = 32;
pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
}
}
//===================================================================
/*
===============
PM_Footsteps
===============
*/
static void PM_Footsteps( void ) {
float bobmove;
int old;
qboolean footstep;
//
// calculate speed and cycle to be used for
// all cyclic walking effects
//
pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
+ pm->ps->velocity[1] * pm->ps->velocity[1] );
if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
PM_ContinueLegsAnim( LEGS_IDLECR );
}
// airborne leaves position in cycle intact, but doesn't advance
if ( pm->waterlevel > 1 ) {
PM_ContinueLegsAnim( LEGS_SWIM );
}
return;
}
// if not trying to move
if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
if ( pm->xyspeed < 5 ) {
pm->ps->bobCycle = 0; // start at beginning of cycle again
if ( pm->ps->pm_flags & PMF_DUCKED ) {
PM_ContinueLegsAnim( LEGS_IDLECR );
} else {
PM_ContinueLegsAnim( LEGS_IDLE );
}
}
return;
}
footstep = qfalse;
if ( pm->ps->pm_flags & PMF_DUCKED ) {
bobmove = 0.5; // ducked characters bob much faster
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
PM_ContinueLegsAnim( LEGS_BACKCR );
}
else {
PM_ContinueLegsAnim( LEGS_WALKCR );
}
// ducked characters never play footsteps
/*
} else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
bobmove = 0.4; // faster speeds bob faster
footstep = qtrue;
} else {
bobmove = 0.3;
}
PM_ContinueLegsAnim( LEGS_BACK );
*/
} else {
if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
bobmove = 0.4f; // faster speeds bob faster
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
PM_ContinueLegsAnim( LEGS_BACK );
}
else {
PM_ContinueLegsAnim( LEGS_RUN );
}
footstep = qtrue;
} else {
bobmove = 0.3f; // walking bobs slow
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
PM_ContinueLegsAnim( LEGS_BACKWALK );
}
else {
PM_ContinueLegsAnim( LEGS_WALK );
}
}
}
// check for footstep / splash sounds
old = pm->ps->bobCycle;
pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
// if we just crossed a cycle boundary, play an apropriate footstep event
if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
if ( pm->waterlevel == 0 ) {
// on ground will only play sounds if running
if ( footstep && !pm->noFootsteps ) {
PM_AddEvent( PM_FootstepForSurface() );
}
} else if ( pm->waterlevel == 1 ) {
// splashing
PM_AddEvent( EV_FOOTSPLASH );
} else if ( pm->waterlevel == 2 ) {
// wading / swimming at surface
PM_AddEvent( EV_SWIM );
} else if ( pm->waterlevel == 3 ) {
// no sound when completely underwater
}
}
}
/*
==============
PM_WaterEvents
Generate sound events for entering and leaving water
==============
*/
static void PM_WaterEvents( void ) { // FIXME?
//
// if just entered a water volume, play a sound
//
if (!pml.previous_waterlevel && pm->waterlevel) {
PM_AddEvent( EV_WATER_TOUCH );
}
//
// if just completely exited a water volume, play a sound
//
if (pml.previous_waterlevel && !pm->waterlevel) {
PM_AddEvent( EV_WATER_LEAVE );
}
//
// check for head just going under water
//
if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
PM_AddEvent( EV_WATER_UNDER );
}
//
// check for head just coming out of water
//
if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
PM_AddEvent( EV_WATER_CLEAR );
}
}
/*
===============
PM_BeginWeaponChange
===============
*/
static void PM_BeginWeaponChange( int weapon ) {
if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
return;
}
if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
return;
}
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
return;
}
PM_AddEvent( EV_CHANGE_WEAPON );
pm->ps->weaponstate = WEAPON_DROPPING;
pm->ps->weaponTime += 200;
PM_StartTorsoAnim( TORSO_DROP );
}
/*
===============
PM_FinishWeaponChange
===============
*/
static void PM_FinishWeaponChange( void ) {
int weapon;
weapon = pm->cmd.weapon;
if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
weapon = WP_NONE;
}
if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
weapon = WP_NONE;
}
pm->ps->weapon = weapon;
pm->ps->weaponstate = WEAPON_RAISING;
pm->ps->weaponTime += 250;
PM_StartTorsoAnim( TORSO_RAISE );
}
/*
==============
PM_TorsoAnimation
==============
*/
static void PM_TorsoAnimation( void ) {
if ( pm->ps->weaponstate == WEAPON_READY ) {
if ( pm->ps->weapon == WP_GAUNTLET ) {
PM_ContinueTorsoAnim( TORSO_STAND2 );
} else {
PM_ContinueTorsoAnim( TORSO_STAND );
}
return;
}
}
/*
==============
PM_Weapon
Generates weapon events and modifes the weapon counter
==============
*/
static void PM_Weapon( void ) {
int addTime;
// don't allow attack until all buttons are up
if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
return;
}
// ignore if spectator
if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
return;
}
// check for dead player
if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
pm->ps->weapon = WP_NONE;
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -