2013-04-19 02:52:48 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
// bg_slidemove.c -- part of bg_pmove functionality
# include "q_shared.h"
# include "bg_public.h"
# include "bg_local.h"
# ifdef QAGAME //yeah, this is kind of bad
# include "g_local.h"
# endif
/*
input : origin , velocity , bounds , groundPlane , trace function
output : origin , velocity , impacts , stairup boolean
*/
//do vehicle impact stuff
// slight rearrangement by BTO (VV) so that we only have one namespace include
# ifdef QAGAME
extern void G_FlyVehicleSurfaceDestruction ( gentity_t * veh , trace_t * trace , int magnitude , qboolean force ) ; //g_vehicle.c
extern qboolean G_CanBeEnemy ( gentity_t * self , gentity_t * enemy ) ; //w_saber.c
# endif
extern qboolean BG_UnrestrainedPitchRoll ( playerState_t * ps , Vehicle_t * pVeh ) ;
# include "../namespace_begin.h"
extern bgEntity_t * pm_entSelf ;
extern bgEntity_t * pm_entVeh ;
//vehicle impact stuff continued...
# ifndef QAGAME //kind of hacky
extern void trap_FX_PlayEffectID ( int id , vec3_t org , vec3_t fwd , int vol , int rad ) ;
# endif
# ifdef QAGAME
extern qboolean FighterIsLanded ( Vehicle_t * pVeh , playerState_t * parentPS ) ;
extern void G_DamageFromKiller ( gentity_t * pEnt , gentity_t * pVehEnt , gentity_t * attacker , vec3_t org , int damage , int dflags , int mod ) ;
# endif
extern void PM_SetPMViewAngle ( playerState_t * ps , vec3_t angle , usercmd_t * ucmd ) ;
# define MAX_IMPACT_TURN_ANGLE 45.0f
void PM_VehicleImpact ( bgEntity_t * pEnt , trace_t * trace )
{
// See if the vehicle has crashed into the ground.
Vehicle_t * pSelfVeh = pEnt - > m_pVehicle ;
float magnitude = VectorLength ( pm - > ps - > velocity ) * pSelfVeh - > m_pVehicleInfo - > mass / 50.0f ;
qboolean forceSurfDestruction = qfalse ;
# ifdef QAGAME
gentity_t * hitEnt = trace ! = NULL ? & g_entities [ trace - > entityNum ] : NULL ;
if ( ! hitEnt | | //nothing to hit
( pSelfVeh & & pSelfVeh - > m_pPilot & & //I'm a piloted vehicle
hitEnt & & hitEnt - > s . eType = = ET_MISSILE & & hitEnt - > inuse & & //that hit a missile
hitEnt - > r . ownerNum = = pSelfVeh - > m_pPilot - > s . number ) //and the missile is owned by my pilot
)
{ //don't hit it
return ;
}
if ( pSelfVeh //I have a vehicle struct
& & pSelfVeh - > m_iRemovedSurfaces ) //vehicle has bits removed
{ //spiralling to our deaths, explode on any solid impact
if ( hitEnt - > s . NPC_class = = CLASS_VEHICLE )
{ //hit another vehicle, explode!
//Give credit to whoever got me into this death spiral state
G_DamageFromKiller ( ( gentity_t * ) pEnt , ( gentity_t * ) pSelfVeh - > m_pParentEntity , ( gentity_t * ) hitEnt , pm - > ps - > origin , 999999 , DAMAGE_NO_ARMOR , MOD_COLLISION ) ;
return ;
}
else if ( ! VectorCompare ( trace - > plane . normal , vec3_origin )
& & ( trace - > entityNum = = ENTITYNUM_WORLD | | hitEnt - > r . bmodel ) )
{ //have a valid hit plane and we hit a solid brush
vec3_t moveDir ;
float impactDot ;
VectorCopy ( pm - > ps - > velocity , moveDir ) ;
VectorNormalize ( moveDir ) ;
impactDot = DotProduct ( moveDir , trace - > plane . normal ) ;
if ( impactDot < = - 0.7f ) //hit rather head-on and hard
{ // Just DIE now
//Give credit to whoever got me into this death spiral state
G_DamageFromKiller ( ( gentity_t * ) pEnt , ( gentity_t * ) pSelfVeh - > m_pParentEntity , ( gentity_t * ) hitEnt , pm - > ps - > origin , 999999 , DAMAGE_NO_ARMOR , MOD_FALLING ) ;
return ;
}
}
}
if ( trace - > entityNum < ENTITYNUM_WORLD
& & hitEnt - > s . eType = = ET_MOVER
& & hitEnt - > s . apos . trType ! = TR_STATIONARY //rotating
& & ( hitEnt - > spawnflags & 16 ) //IMPACT
& & Q_stricmp ( " func_rotating " , hitEnt - > classname ) = = 0 )
{ //hit a func_rotating that is supposed to destroy anything it touches!
//guarantee the hit will happen, thereby taking off a piece of the ship
forceSurfDestruction = qtrue ;
}
else if ( ( fabs ( pm - > ps - > velocity [ 0 ] ) + fabs ( pm - > ps - > velocity [ 1 ] ) ) < 100.0f
& & pm - > ps - > velocity [ 2 ] > - 100.0f )
# else
if ( ( fabs ( pm - > ps - > velocity [ 0 ] ) + fabs ( pm - > ps - > velocity [ 1 ] ) ) < 100.0f
& & pm - > ps - > velocity [ 2 ] > - 100.0f )
# endif
/*
if ( ( pSelfVeh - > m_ulFlags & VEH_GEARSOPEN )
& & trace - > plane . normal [ 2 ] > 0.7f
& & fabs ( pSelfVeh - > m_vOrientation [ PITCH ] ) < 0.2f
& & fabs ( pSelfVeh - > m_vOrientation [ ROLL ] ) < 0.2f ) */
{ //we're landing, we're cool
//FIXME: some sort of landing "thump", not the impactFX
/*
if ( pSelfVeh - > m_pVehicleInfo - > iImpactFX )
{
vec3_t up = { 0 , 0 , 1 } ;
# ifdef QAGAME
G_PlayEffectID ( pSelfVeh - > m_pVehicleInfo - > iImpactFX , pm - > ps - > origin , up ) ;
# else
trap_FX_PlayEffectID ( pSelfVeh - > m_pVehicleInfo - > iImpactFX , pm - > ps - > origin , up , - 1 , - 1 ) ;
# endif
}
*/
//this was annoying me -rww
//FIXME: this shouldn't even be getting called when the vehicle is at rest!
# ifdef QAGAME
if ( hitEnt & & ( hitEnt - > s . eType = = ET_PLAYER | | hitEnt - > s . eType = = ET_NPC ) & & pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //always smack players
}
else
# endif
{
return ;
}
}
if ( pSelfVeh & &
( pSelfVeh - > m_pVehicleInfo - > type = = VH_SPEEDER | | pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER ) & & //this is kind of weird on tauntauns and atst's..
( magnitude > = 100 | | forceSurfDestruction ) )
{
if ( pEnt - > m_pVehicle - > m_iHitDebounce < pm - > cmd . serverTime
| | forceSurfDestruction )
{ //a bit of a hack, may conflict with getting shot, but...
//FIXME: impact sound and effect should be gotten from g_vehicleInfo...?
//FIXME: should pass in trace.endpos and trace.plane.normal
vec3_t vehUp ;
# ifdef QAGAME
qboolean noDamage = qfalse ;
# else
bgEntity_t * hitEnt ;
# endif
if ( trace & & ! pSelfVeh - > m_iRemovedSurfaces & & ! forceSurfDestruction )
{
qboolean turnFromImpact = qfalse , turnHitEnt = qfalse ;
float l = pm - > ps - > speed * 0.5f ;
vec3_t bounceDir ;
# ifndef QAGAME
bgEntity_t * hitEnt = PM_BGEntForNum ( trace - > entityNum ) ;
# endif
if ( ( trace - > entityNum = = ENTITYNUM_WORLD | | hitEnt - > s . solid = = SOLID_BMODEL ) //bounce off any brush
& & ! VectorCompare ( trace - > plane . normal , vec3_origin ) ) //have a valid plane to bounce off of
{ //bounce off in the opposite direction of the impact
if ( pSelfVeh - > m_pVehicleInfo - > type = = VH_SPEEDER )
{
pm - > ps - > speed * = pml . frametime ;
VectorCopy ( trace - > plane . normal , bounceDir ) ;
}
else if ( trace - > plane . normal [ 2 ] > = MIN_LANDING_SLOPE //flat enough to land on
& & pSelfVeh - > m_LandTrace . fraction < 1.0f //ground present
& & pm - > ps - > speed < = MIN_LANDING_SPEED )
{ //could land here, don't bounce off, in fact, return altogether!
return ;
}
else
{
if ( pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER )
{
turnFromImpact = qtrue ;
}
VectorCopy ( trace - > plane . normal , bounceDir ) ;
}
}
else if ( pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //check for impact with another fighter
# ifndef QAGAME
bgEntity_t * hitEnt = PM_BGEntForNum ( trace - > entityNum ) ;
# endif
if ( hitEnt - > s . NPC_class = = CLASS_VEHICLE
& & hitEnt - > m_pVehicle
& & hitEnt - > m_pVehicle - > m_pVehicleInfo
& & hitEnt - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //two vehicles hit each other, turn away from the impact
turnFromImpact = qtrue ;
turnHitEnt = qtrue ;
# ifndef QAGAME
VectorSubtract ( pm - > ps - > origin , hitEnt - > s . origin , bounceDir ) ;
# else
VectorSubtract ( pm - > ps - > origin , hitEnt - > r . currentOrigin , bounceDir ) ;
# endif
VectorNormalize ( bounceDir ) ;
}
}
if ( turnFromImpact )
{ //bounce off impact surf and turn away
vec3_t pushDir = { 0 } , turnAwayAngles , turnDelta ;
float turnStrength , pitchTurnStrength , yawTurnStrength ;
vec3_t moveDir ;
float bounceDot , turnDivider ;
//bounce
if ( ! turnHitEnt )
{ //hit wall
VectorScale ( bounceDir , ( pm - > ps - > speed * 0.25f / pSelfVeh - > m_pVehicleInfo - > mass ) , pushDir ) ;
}
else
{ //hit another fighter
# ifndef QAGAME
VectorScale ( bounceDir , ( pm - > ps - > speed + hitEnt - > s . speed ) * 0.5f , bounceDir ) ;
# else
if ( hitEnt - > client )
{
VectorScale ( bounceDir , ( pm - > ps - > speed + hitEnt - > client - > ps . speed ) * 0.5f , pushDir ) ;
}
else
{
VectorScale ( bounceDir , ( pm - > ps - > speed + hitEnt - > s . speed ) * 0.5f , pushDir ) ;
}
# endif
VectorScale ( pushDir , ( l / pSelfVeh - > m_pVehicleInfo - > mass ) , pushDir ) ;
VectorScale ( pushDir , 0.1f , pushDir ) ;
}
VectorNormalize2 ( pm - > ps - > velocity , moveDir ) ;
bounceDot = DotProduct ( moveDir , bounceDir ) * - 1 ;
if ( bounceDot < 0.1f )
{
bounceDot = 0.1f ;
}
VectorScale ( pushDir , bounceDot , pushDir ) ;
VectorAdd ( pm - > ps - > velocity , pushDir , pm - > ps - > velocity ) ;
//turn
turnDivider = ( pSelfVeh - > m_pVehicleInfo - > mass / 400.0f ) ;
if ( turnHitEnt )
{ //don't turn as much when hit another ship
turnDivider * = 4.0f ;
}
if ( turnDivider < 0.5f )
{
turnDivider = 0.5f ;
}
turnStrength = ( magnitude / 2000.0f ) ;
if ( turnStrength < 0.1f )
{
turnStrength = 0.1f ;
}
else if ( turnStrength > 2.0f )
{
turnStrength = 2.0f ;
}
//get the angles we are going to turn towards
vectoangles ( bounceDir , turnAwayAngles ) ;
//get the delta from our current angles to those new angles
AnglesSubtract ( turnAwayAngles , pSelfVeh - > m_vOrientation , turnDelta ) ;
//now do pitch
if ( ! bounceDir [ 2 ] )
{ //shouldn't be any pitch
}
else
{
pitchTurnStrength = turnStrength * turnDelta [ PITCH ] ;
if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
{
pitchTurnStrength = MAX_IMPACT_TURN_ANGLE ;
}
else if ( pitchTurnStrength < - MAX_IMPACT_TURN_ANGLE )
{
pitchTurnStrength = - MAX_IMPACT_TURN_ANGLE ;
}
//pSelfVeh->m_vOrientation[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
pSelfVeh - > m_vFullAngleVelocity [ PITCH ] = AngleNormalize180 ( pSelfVeh - > m_vOrientation [ PITCH ] + pitchTurnStrength / turnDivider * pSelfVeh - > m_fTimeModifier ) ;
}
//now do yaw
if ( ! bounceDir [ 0 ]
& & ! bounceDir [ 1 ] )
{ //shouldn't be any yaw
}
else
{
yawTurnStrength = turnStrength * turnDelta [ YAW ] ;
if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
{
yawTurnStrength = MAX_IMPACT_TURN_ANGLE ;
}
else if ( yawTurnStrength < - MAX_IMPACT_TURN_ANGLE )
{
yawTurnStrength = - MAX_IMPACT_TURN_ANGLE ;
}
//pSelfVeh->m_vOrientation[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
pSelfVeh - > m_vFullAngleVelocity [ ROLL ] = AngleNormalize180 ( pSelfVeh - > m_vOrientation [ ROLL ] - yawTurnStrength / turnDivider * pSelfVeh - > m_fTimeModifier ) ;
}
/*
PM_SetPMViewAngle ( pm - > ps , pSelfVeh - > m_vOrientation , & pSelfVeh - > m_ucmd ) ;
if ( pm_entVeh )
{ //I'm a vehicle, so pm_entVeh is actually my pilot
bgEntity_t * pilot = pm_entVeh ;
if ( ! BG_UnrestrainedPitchRoll ( pilot - > playerState , pSelfVeh ) )
{
//set the rider's viewangles to the vehicle's viewangles
PM_SetPMViewAngle ( pilot - > playerState , pSelfVeh - > m_vOrientation , & pSelfVeh - > m_ucmd ) ;
}
}
*/
# ifdef QAGAME //server-side, turn the guy we hit away from us, too
if ( turnHitEnt //make the other guy turn and get pushed
& & hitEnt - > client //must be a valid client
& & ! FighterIsLanded ( hitEnt - > m_pVehicle , & hitEnt - > client - > ps ) //but not if landed
& & ! ( hitEnt - > spawnflags & 2 ) ) //and not if suspended
{
l = hitEnt - > client - > ps . speed ;
//now bounce *them* away and turn them
//flip the bounceDir
VectorScale ( bounceDir , - 1 , bounceDir ) ;
//do bounce
VectorScale ( bounceDir , ( pm - > ps - > speed + l ) * 0.5f , pushDir ) ;
VectorScale ( pushDir , ( l * 0.5f / hitEnt - > m_pVehicle - > m_pVehicleInfo - > mass ) , pushDir ) ;
VectorNormalize2 ( hitEnt - > client - > ps . velocity , moveDir ) ;
bounceDot = DotProduct ( moveDir , bounceDir ) * - 1 ;
if ( bounceDot < 0.1f )
{
bounceDot = 0.1f ;
}
VectorScale ( pushDir , bounceDot , pushDir ) ;
VectorAdd ( hitEnt - > client - > ps . velocity , pushDir , hitEnt - > client - > ps . velocity ) ;
//turn
turnDivider = ( hitEnt - > m_pVehicle - > m_pVehicleInfo - > mass / 400.0f ) ;
if ( turnHitEnt )
{ //don't turn as much when hit another ship
turnDivider * = 4.0f ;
}
if ( turnDivider < 0.5f )
{
turnDivider = 0.5f ;
}
//get the angles we are going to turn towards
vectoangles ( bounceDir , turnAwayAngles ) ;
//get the delta from our current angles to those new angles
AnglesSubtract ( turnAwayAngles , hitEnt - > m_pVehicle - > m_vOrientation , turnDelta ) ;
//now do pitch
if ( ! bounceDir [ 2 ] )
{ //shouldn't be any pitch
}
else
{
pitchTurnStrength = turnStrength * turnDelta [ PITCH ] ;
if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
{
pitchTurnStrength = MAX_IMPACT_TURN_ANGLE ;
}
else if ( pitchTurnStrength < - MAX_IMPACT_TURN_ANGLE )
{
pitchTurnStrength = - MAX_IMPACT_TURN_ANGLE ;
}
//hitEnt->m_pVehicle->m_vOrientation[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
hitEnt - > m_pVehicle - > m_vFullAngleVelocity [ PITCH ] = AngleNormalize180 ( hitEnt - > m_pVehicle - > m_vOrientation [ PITCH ] + pitchTurnStrength / turnDivider * pSelfVeh - > m_fTimeModifier ) ;
}
//now do yaw
if ( ! bounceDir [ 0 ]
& & ! bounceDir [ 1 ] )
{ //shouldn't be any yaw
}
else
{
yawTurnStrength = turnStrength * turnDelta [ YAW ] ;
if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
{
yawTurnStrength = MAX_IMPACT_TURN_ANGLE ;
}
else if ( yawTurnStrength < - MAX_IMPACT_TURN_ANGLE )
{
yawTurnStrength = - MAX_IMPACT_TURN_ANGLE ;
}
//hitEnt->m_pVehicle->m_vOrientation[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
hitEnt - > m_pVehicle - > m_vFullAngleVelocity [ ROLL ] = AngleNormalize180 ( hitEnt - > m_pVehicle - > m_vOrientation [ ROLL ] - yawTurnStrength / turnDivider * pSelfVeh - > m_fTimeModifier ) ;
}
//NOTE: will these angle changes stick or will they be stomped
// when the vehicle goes through its own update and re-grabs
// its angles from its pilot...? Should we do a
// SetClientViewAngles on the pilot?
/*
SetClientViewAngle ( hitEnt , hitEnt - > m_pVehicle - > m_vOrientation ) ;
if ( hitEnt - > m_pVehicle - > m_pPilot
& & ( ( gentity_t * ) hitEnt - > m_pVehicle - > m_pPilot ) - > client )
{
SetClientViewAngle ( ( gentity_t * ) hitEnt - > m_pVehicle - > m_pPilot , hitEnt - > m_pVehicle - > m_vOrientation ) ;
}
*/
}
# endif
}
}
# ifdef QAGAME
if ( ! hitEnt )
{
return ;
}
AngleVectors ( pSelfVeh - > m_vOrientation , NULL , NULL , vehUp ) ;
if ( pSelfVeh - > m_pVehicleInfo - > iImpactFX )
{
//G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp );
//tempent use bad!
G_AddEvent ( ( gentity_t * ) pEnt , EV_PLAY_EFFECT_ID , pSelfVeh - > m_pVehicleInfo - > iImpactFX ) ;
}
pEnt - > m_pVehicle - > m_iHitDebounce = pm - > cmd . serverTime + 200 ;
magnitude / = pSelfVeh - > m_pVehicleInfo - > toughness * 50.0f ;
if ( hitEnt
& & ( hitEnt - > s . eType ! = ET_TERRAIN | | ! ( hitEnt - > spawnflags & 1 ) | | pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER ) )
{ //don't damage the vehicle from terrain that doesn't want to damage vehicles
gentity_t * killer = NULL ;
if ( pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //increase the damage...
float mult = ( pSelfVeh - > m_vOrientation [ PITCH ] * 0.1f ) ;
if ( mult < 1.0f )
{
mult = 1.0f ;
}
if ( hitEnt - > inuse & & hitEnt - > takedamage )
{ //if the other guy takes damage, don't hurt us a lot for ramming him
//unless it's a vehicle, then we get 1.5 times damage
if ( hitEnt - > s . eType = = ET_NPC & &
hitEnt - > s . NPC_class = = CLASS_VEHICLE & &
hitEnt - > m_pVehicle )
{
mult = 1.5f ;
}
else
{
mult = 0.5f ;
}
}
magnitude * = mult ;
}
pSelfVeh - > m_iLastImpactDmg = magnitude ;
//FIXME: what about proper death credit to the guy who shot you down?
//FIXME: actually damage part of the ship that impacted?
if ( hitEnt - > s . eType = = ET_MISSILE ) //missile
{
//FIX: NEVER do or take impact damage from a missile...
noDamage = qtrue ;
if ( ( hitEnt - > s . eFlags & EF_JETPACK_ACTIVE ) //vehicle missile
& & ( ( gentity_t * ) hitEnt ) - > r . ownerNum < MAX_CLIENTS ) //valid client owner
{ //I ran into a missile and died because of the impact, give credit to the missile's owner (PROBLEM: might this ever accidently give improper credit to client 0?)
/*
if ( ( ( gentity_t * ) hitEnt ) - > r . ownerNum = = pEnt - > s . number )
{ //hit our own missile? Don't damage ourselves or it... (so we don't kill ourselves!) if it hits *us*, then fine, but not here
noDamage = qtrue ;
}
*/
killer = & g_entities [ ( ( gentity_t * ) hitEnt ) - > r . ownerNum ] ;
}
}
if ( ! noDamage )
{
G_Damage ( ( gentity_t * ) pEnt , ( ( gentity_t * ) hitEnt ) , killer ! = NULL ? killer : ( ( gentity_t * ) hitEnt ) , NULL , pm - > ps - > origin , magnitude * 5 , DAMAGE_NO_ARMOR , ( hitEnt - > s . NPC_class = = CLASS_VEHICLE ? MOD_COLLISION : MOD_FALLING ) ) ; //FIXME: MOD_IMPACT
}
if ( pSelfVeh - > m_pVehicleInfo - > surfDestruction )
{
G_FlyVehicleSurfaceDestruction ( ( gentity_t * ) pEnt , trace , magnitude , forceSurfDestruction ) ;
}
pSelfVeh - > m_ulFlags | = VEH_CRASHING ;
}
if ( hitEnt & &
hitEnt - > inuse & &
hitEnt - > takedamage )
{ //damage this guy because we hit him
float pmult = 1.0f ;
int finalD ;
gentity_t * attackEnt ;
if ( ( hitEnt - > s . eType = = ET_PLAYER & & hitEnt - > s . number < MAX_CLIENTS ) | |
( hitEnt - > s . eType = = ET_NPC & & hitEnt - > s . NPC_class ! = CLASS_VEHICLE ) )
{ //probably a humanoid, or something
if ( pSelfVeh - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //player die good.. if me fighter
pmult = 2000.0f ;
}
else
{
pmult = 40.0f ;
}
if ( hitEnt - > client & &
BG_KnockDownable ( & hitEnt - > client - > ps ) & &
G_CanBeEnemy ( ( gentity_t * ) pEnt , hitEnt ) )
{ //smash!
if ( hitEnt - > client - > ps . forceHandExtend ! = HANDEXTEND_KNOCKDOWN )
{
hitEnt - > client - > ps . forceHandExtend = HANDEXTEND_KNOCKDOWN ;
hitEnt - > client - > ps . forceHandExtendTime = pm - > cmd . serverTime + 1100 ;
hitEnt - > client - > ps . forceDodgeAnim = 0 ; //this toggles between 1 and 0, when it's 1 we should play the get up anim
}
hitEnt - > client - > ps . otherKiller = pEnt - > s . number ;
hitEnt - > client - > ps . otherKillerTime = pm - > cmd . serverTime + 5000 ;
hitEnt - > client - > ps . otherKillerDebounceTime = pm - > cmd . serverTime + 100 ;
hitEnt - > client - > otherKillerMOD = MOD_COLLISION ;
hitEnt - > client - > otherKillerVehWeapon = 0 ;
hitEnt - > client - > otherKillerWeaponType = WP_NONE ;
//add my velocity into his to force him along in the correct direction from impact
VectorAdd ( hitEnt - > client - > ps . velocity , pm - > ps - > velocity , hitEnt - > client - > ps . velocity ) ;
//upward thrust
hitEnt - > client - > ps . velocity [ 2 ] + = 200.0f ;
}
}
if ( pSelfVeh - > m_pPilot )
{
attackEnt = ( gentity_t * ) pSelfVeh - > m_pPilot ;
}
else
{
attackEnt = ( gentity_t * ) pEnt ;
}
finalD = magnitude * pmult ;
if ( finalD < 1 )
{
finalD = 1 ;
}
if ( ! noDamage )
{
G_Damage ( hitEnt , attackEnt , attackEnt , NULL , pm - > ps - > origin , finalD , 0 , ( hitEnt - > s . NPC_class = = CLASS_VEHICLE ? MOD_COLLISION : MOD_FALLING /*MOD_MELEE*/ ) ) ; //FIXME: MOD_IMPACT
}
}
# else //this is gonna result in "double effects" for the client doing the prediction.
//it doesn't look bad though. could just use predicted events, but I'm too lazy.
hitEnt = PM_BGEntForNum ( trace - > entityNum ) ;
if ( ! hitEnt | | hitEnt - > s . owner ! = pEnt - > s . number )
{ //don't hit your own missiles!
AngleVectors ( pSelfVeh - > m_vOrientation , NULL , NULL , vehUp ) ;
pEnt - > m_pVehicle - > m_iHitDebounce = pm - > cmd . serverTime + 200 ;
trap_FX_PlayEffectID ( pSelfVeh - > m_pVehicleInfo - > iImpactFX , pm - > ps - > origin , vehUp , - 1 , - 1 ) ;
pSelfVeh - > m_ulFlags | = VEH_CRASHING ;
}
# endif
}
}
}
qboolean PM_GroundSlideOkay ( float zNormal )
{
if ( zNormal > 0 )
{
if ( pm - > ps - > velocity [ 2 ] > 0 )
{
if ( pm - > ps - > legsAnim = = BOTH_WALL_RUN_RIGHT
| | pm - > ps - > legsAnim = = BOTH_WALL_RUN_LEFT
| | pm - > ps - > legsAnim = = BOTH_WALL_RUN_RIGHT_STOP
| | pm - > ps - > legsAnim = = BOTH_WALL_RUN_LEFT_STOP
| | pm - > ps - > legsAnim = = BOTH_FORCEWALLRUNFLIP_START
| | pm - > ps - > legsAnim = = BOTH_FORCELONGLEAP_START
| | pm - > ps - > legsAnim = = BOTH_FORCELONGLEAP_ATTACK
| | pm - > ps - > legsAnim = = BOTH_FORCELONGLEAP_LAND
| | BG_InReboundJump ( pm - > ps - > legsAnim ) )
{
return qfalse ;
}
}
}
return qtrue ;
}
/*
= = = = = = = = = = = = = = =
qboolean PM_ClientImpact ( trace_t * trace , qboolean damageSelf )
= = = = = = = = = = = = = = =
*/
# ifdef QAGAME
extern void Client_CheckImpactBBrush ( gentity_t * self , gentity_t * other ) ;
qboolean PM_ClientImpact ( trace_t * trace )
{
//don't try to predict this
gentity_t * traceEnt ;
int otherEntityNum = trace - > entityNum ;
if ( ! pm_entSelf )
{
return qfalse ;
}
if ( otherEntityNum > = ENTITYNUM_WORLD )
{
return qfalse ;
}
traceEnt = & g_entities [ otherEntityNum ] ;
if ( VectorLength ( pm - > ps - > velocity ) > = 100
& & pm_entSelf - > s . NPC_class ! = CLASS_VEHICLE
& & pm - > ps - > lastOnGround + 100 < level . time )
//&& pm->ps->groundEntityNum == ENTITYNUM_NONE )
{
Client_CheckImpactBBrush ( ( gentity_t * ) ( pm_entSelf ) , & g_entities [ otherEntityNum ] ) ;
}
if ( ! traceEnt
| | ! ( traceEnt - > r . contents & pm - > tracemask ) )
{ //it's dead or not in my way anymore, don't clip against it
return qtrue ;
}
return qfalse ;
}
# endif
/*
= = = = = = = = = = = = = = = = = =
PM_SlideMove
Returns qtrue if the velocity was clipped in some way
= = = = = = = = = = = = = = = = = =
*/
# define MAX_CLIP_PLANES 5
qboolean PM_SlideMove ( qboolean gravity ) {
int bumpcount , numbumps ;
vec3_t dir ;
float d ;
int numplanes ;
vec3_t normal , planes [ MAX_CLIP_PLANES ] ;
vec3_t primal_velocity ;
vec3_t clipVelocity ;
int i , j , k ;
trace_t trace ;
vec3_t end ;
float time_left ;
float into ;
vec3_t endVelocity ;
vec3_t endClipVelocity ;
//qboolean damageSelf = qtrue;
numbumps = 4 ;
VectorCopy ( pm - > ps - > velocity , primal_velocity ) ;
if ( gravity ) {
VectorCopy ( pm - > ps - > velocity , endVelocity ) ;
endVelocity [ 2 ] - = pm - > ps - > gravity * pml . frametime ;
pm - > ps - > velocity [ 2 ] = ( pm - > ps - > velocity [ 2 ] + endVelocity [ 2 ] ) * 0.5 ;
primal_velocity [ 2 ] = endVelocity [ 2 ] ;
if ( pml . groundPlane ) {
if ( PM_GroundSlideOkay ( pml . groundTrace . plane . normal [ 2 ] ) )
{ // slide along the ground plane
PM_ClipVelocity ( pm - > ps - > velocity , pml . groundTrace . plane . normal ,
pm - > ps - > velocity , OVERCLIP ) ;
}
}
}
time_left = pml . frametime ;
// never turn against the ground plane
if ( pml . groundPlane ) {
numplanes = 1 ;
VectorCopy ( pml . groundTrace . plane . normal , planes [ 0 ] ) ;
if ( ! PM_GroundSlideOkay ( planes [ 0 ] [ 2 ] ) )
{
planes [ 0 ] [ 2 ] = 0 ;
VectorNormalize ( planes [ 0 ] ) ;
}
} else {
numplanes = 0 ;
}
// never turn against original velocity
VectorNormalize2 ( pm - > ps - > velocity , planes [ numplanes ] ) ;
numplanes + + ;
for ( bumpcount = 0 ; bumpcount < numbumps ; bumpcount + + ) {
// calculate position we are trying to move to
VectorMA ( pm - > ps - > origin , time_left , pm - > ps - > velocity , end ) ;
// see if we can make it there
pm - > trace ( & trace , pm - > ps - > origin , pm - > mins , pm - > maxs , end , pm - > ps - > clientNum , pm - > tracemask ) ;
if ( trace . allsolid ) {
// entity is completely trapped in another solid
pm - > ps - > velocity [ 2 ] = 0 ; // don't build up falling damage, but allow sideways acceleration
return qtrue ;
}
if ( trace . fraction > 0 ) {
// actually covered some distance
VectorCopy ( trace . endpos , pm - > ps - > origin ) ;
}
if ( trace . fraction = = 1 ) {
break ; // moved the entire distance
}
// save entity for contact
PM_AddTouchEnt ( trace . entityNum ) ;
if ( pm - > ps - > clientNum > = MAX_CLIENTS )
{
bgEntity_t * pEnt = pm_entSelf ;
if ( pEnt & & pEnt - > s . eType = = ET_NPC & & pEnt - > s . NPC_class = = CLASS_VEHICLE & &
pEnt - > m_pVehicle )
{ //do vehicle impact stuff then
PM_VehicleImpact ( pEnt , & trace ) ;
}
}
# ifdef QAGAME
else
{
if ( PM_ClientImpact ( & trace ) )
{
continue ;
}
}
# endif
time_left - = time_left * trace . fraction ;
if ( numplanes > = MAX_CLIP_PLANES ) {
// this shouldn't really happen
VectorClear ( pm - > ps - > velocity ) ;
return qtrue ;
}
VectorCopy ( trace . plane . normal , normal ) ;
if ( ! PM_GroundSlideOkay ( normal [ 2 ] ) )
{ //wall-running
//never push up off a sloped wall
normal [ 2 ] = 0 ;
VectorNormalize ( normal ) ;
}
//
// if this is the same plane we hit before, nudge velocity
// out along it, which fixes some epsilon issues with
// non-axial planes
//
if ( ! ( pm - > ps - > pm_flags & PMF_STUCK_TO_WALL ) )
{ //no sliding if stuck to wall!
for ( i = 0 ; i < numplanes ; i + + ) {
if ( VectorCompare ( normal , planes [ i ] ) ) { //DotProduct( normal, planes[i] ) > 0.99 ) {
VectorAdd ( normal , pm - > ps - > velocity , pm - > ps - > velocity ) ;
break ;
}
}
if ( i < numplanes ) {
continue ;
}
}
VectorCopy ( normal , planes [ numplanes ] ) ;
numplanes + + ;
//
// modify velocity so it parallels all of the clip planes
//
// find a plane that it enters
for ( i = 0 ; i < numplanes ; i + + ) {
into = DotProduct ( pm - > ps - > velocity , planes [ i ] ) ;
if ( into > = 0.1 ) {
continue ; // move doesn't interact with the plane
}
// see how hard we are hitting things
if ( - into > pml . impactSpeed ) {
pml . impactSpeed = - into ;
}
// slide along the plane
PM_ClipVelocity ( pm - > ps - > velocity , planes [ i ] , clipVelocity , OVERCLIP ) ;
// slide along the plane
PM_ClipVelocity ( endVelocity , planes [ i ] , endClipVelocity , OVERCLIP ) ;
// see if there is a second plane that the new move enters
for ( j = 0 ; j < numplanes ; j + + ) {
if ( j = = i ) {
continue ;
}
if ( DotProduct ( clipVelocity , planes [ j ] ) > = 0.1 ) {
continue ; // move doesn't interact with the plane
}
// try clipping the move to the plane
PM_ClipVelocity ( clipVelocity , planes [ j ] , clipVelocity , OVERCLIP ) ;
PM_ClipVelocity ( endClipVelocity , planes [ j ] , endClipVelocity , OVERCLIP ) ;
// see if it goes back into the first clip plane
if ( DotProduct ( clipVelocity , planes [ i ] ) > = 0 ) {
continue ;
}
// slide the original velocity along the crease
CrossProduct ( planes [ i ] , planes [ j ] , dir ) ;
VectorNormalize ( dir ) ;
d = DotProduct ( dir , pm - > ps - > velocity ) ;
VectorScale ( dir , d , clipVelocity ) ;
CrossProduct ( planes [ i ] , planes [ j ] , dir ) ;
VectorNormalize ( dir ) ;
d = DotProduct ( dir , endVelocity ) ;
VectorScale ( dir , d , endClipVelocity ) ;
// see if there is a third plane the the new move enters
for ( k = 0 ; k < numplanes ; k + + ) {
if ( k = = i | | k = = j ) {
continue ;
}
if ( DotProduct ( clipVelocity , planes [ k ] ) > = 0.1 ) {
continue ; // move doesn't interact with the plane
}
// stop dead at a triple plane interaction
VectorClear ( pm - > ps - > velocity ) ;
return qtrue ;
}
}
// if we have fixed all interactions, try another move
VectorCopy ( clipVelocity , pm - > ps - > velocity ) ;
VectorCopy ( endClipVelocity , endVelocity ) ;
break ;
}
}
if ( gravity ) {
VectorCopy ( endVelocity , pm - > ps - > velocity ) ;
}
// don't change velocity if in a timer (FIXME: is this correct?)
if ( pm - > ps - > pm_time ) {
VectorCopy ( primal_velocity , pm - > ps - > velocity ) ;
}
return ( bumpcount ! = 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
PM_StepSlideMove
= = = = = = = = = = = = = = = = = =
*/
void PM_StepSlideMove ( qboolean gravity ) {
vec3_t start_o , start_v ;
vec3_t down_o , down_v ;
trace_t trace ;
// float down_dist, up_dist;
// vec3_t delta, delta2;
vec3_t up , down ;
float stepSize ;
qboolean isGiant = qfalse ;
bgEntity_t * pEnt ;
qboolean skipStep = qfalse ;
VectorCopy ( pm - > ps - > origin , start_o ) ;
VectorCopy ( pm - > ps - > velocity , start_v ) ;
if ( BG_InReboundHold ( pm - > ps - > legsAnim ) )
{
gravity = qfalse ;
}
if ( PM_SlideMove ( gravity ) = = 0 ) {
return ; // we got exactly where we wanted to go first try
}
pEnt = pm_entSelf ;
if ( pm - > ps - > clientNum > = MAX_CLIENTS )
{
if ( pEnt & & pEnt - > s . NPC_class = = CLASS_VEHICLE & &
pEnt - > m_pVehicle & & pEnt - > m_pVehicle - > m_pVehicleInfo - > hoverHeight > 0 )
{
return ;
}
}
VectorCopy ( start_o , down ) ;
down [ 2 ] - = STEPSIZE ;
pm - > trace ( & trace , start_o , pm - > mins , pm - > maxs , down , pm - > ps - > clientNum , pm - > tracemask ) ;
VectorSet ( up , 0 , 0 , 1 ) ;
// never step up when you still have up velocity
if ( pm - > ps - > velocity [ 2 ] > 0 & & ( trace . fraction = = 1.0 | |
DotProduct ( trace . plane . normal , up ) < 0.7 ) )
{
return ;
}
VectorCopy ( pm - > ps - > origin , down_o ) ;
VectorCopy ( pm - > ps - > velocity , down_v ) ;
VectorCopy ( start_o , up ) ;
if ( pm - > ps - > clientNum > = MAX_CLIENTS )
{
// apply ground friction, even if on ladder
if ( pEnt & &
pEnt - > s . NPC_class = = CLASS_ATST | |
( pEnt - > s . NPC_class = = CLASS_VEHICLE & &
pEnt - > m_pVehicle & &
pEnt - > m_pVehicle - > m_pVehicleInfo - > type = = VH_WALKER )
)
{ //AT-STs can step high
up [ 2 ] + = 66.0f ;
isGiant = qtrue ;
}
else if ( pEnt & & pEnt - > s . NPC_class = = CLASS_RANCOR )
{ //also can step up high
up [ 2 ] + = 64.0f ;
isGiant = qtrue ;
}
else
{
up [ 2 ] + = STEPSIZE ;
}
}
else
{
up [ 2 ] + = STEPSIZE ;
}
// test the player position if they were a stepheight higher
pm - > trace ( & trace , start_o , pm - > mins , pm - > maxs , up , pm - > ps - > clientNum , pm - > tracemask ) ;
if ( trace . allsolid ) {
if ( pm - > debugLevel ) {
Com_Printf ( " %i:bend can't step \n " , c_pmove ) ;
}
return ; // can't step up
}
stepSize = trace . endpos [ 2 ] - start_o [ 2 ] ;
// try slidemove from this position
VectorCopy ( trace . endpos , pm - > ps - > origin ) ;
VectorCopy ( start_v , pm - > ps - > velocity ) ;
PM_SlideMove ( gravity ) ;
// push down the final amount
VectorCopy ( pm - > ps - > origin , down ) ;
down [ 2 ] - = stepSize ;
pm - > trace ( & trace , pm - > ps - > origin , pm - > mins , pm - > maxs , down , pm - > ps - > clientNum , pm - > tracemask ) ;
if ( pm - > stepSlideFix )
{
if ( pm - > ps - > clientNum < MAX_CLIENTS
& & trace . plane . normal [ 2 ] < MIN_WALK_NORMAL )
{ //normal players cannot step up slopes that are too steep to walk on!
vec3_t stepVec ;
//okay, the step up ends on a slope that it too steep to step up onto,
//BUT:
//If the step looks like this:
// (B)\__
// \_____(A)
//Then it might still be okay, so we figure out the slope of the entire move
//from (A) to (B) and if that slope is walk-upabble, then it's okay
VectorSubtract ( trace . endpos , down_o , stepVec ) ;
VectorNormalize ( stepVec ) ;
if ( stepVec [ 2 ] > ( 1.0f - MIN_WALK_NORMAL ) )
{
skipStep = qtrue ;
}
}
}
if ( ! trace . allsolid
& & ! skipStep ) //normal players cannot step up slopes that are too steep to walk on!
{
if ( pm - > ps - > clientNum > = MAX_CLIENTS //NPC
& & isGiant
& & trace . entityNum < MAX_CLIENTS
& & pEnt
& & pEnt - > s . NPC_class = = CLASS_RANCOR )
{ //Rancor don't step on clients
if ( pm - > stepSlideFix )
{
VectorCopy ( down_o , pm - > ps - > origin ) ;
VectorCopy ( down_v , pm - > ps - > velocity ) ;
}
else
{
VectorCopy ( start_o , pm - > ps - > origin ) ;
VectorCopy ( start_v , pm - > ps - > velocity ) ;
}
}
/*
else if ( pm - > ps - > clientNum > = MAX_CLIENTS //NPC
& & isGiant
& & trace . entityNum < MAX_CLIENTS
& & pEnt
& & pEnt - > s . NPC_class = = CLASS_ATST
& & OnSameTeam ( pEnt , traceEnt ) )
{ //NPC AT-ST's don't step up on allies
VectorCopy ( start_o , pm - > ps - > origin ) ;
VectorCopy ( start_v , pm - > ps - > velocity ) ;
}
*/
else
{
VectorCopy ( trace . endpos , pm - > ps - > origin ) ;
if ( pm - > stepSlideFix )
{
if ( trace . fraction < 1.0 ) {
PM_ClipVelocity ( pm - > ps - > velocity , trace . plane . normal , pm - > ps - > velocity , OVERCLIP ) ;
}
}
}
}
else
{
if ( pm - > stepSlideFix )
{
VectorCopy ( down_o , pm - > ps - > origin ) ;
VectorCopy ( down_v , pm - > ps - > velocity ) ;
}
}
if ( ! pm - > stepSlideFix )
{
if ( trace . fraction < 1.0 ) {
PM_ClipVelocity ( pm - > ps - > velocity , trace . plane . normal , pm - > ps - > velocity , OVERCLIP ) ;
}
}
#if 0
// if the down trace can trace back to the original position directly, don't step
pm - > trace ( & trace , pm - > ps - > origin , pm - > mins , pm - > maxs , start_o , pm - > ps - > clientNum , pm - > tracemask ) ;
if ( trace . fraction = = 1.0 ) {
// use the original move
VectorCopy ( down_o , pm - > ps - > origin ) ;
VectorCopy ( down_v , pm - > ps - > velocity ) ;
if ( pm - > debugLevel ) {
Com_Printf ( " %i:bend \n " , c_pmove ) ;
}
} else
# endif
{
// use the step move
float delta ;
delta = pm - > ps - > origin [ 2 ] - start_o [ 2 ] ;
if ( delta > 2 ) {
if ( delta < 7 ) {
PM_AddEvent ( EV_STEP_4 ) ;
} else if ( delta < 11 ) {
PM_AddEvent ( EV_STEP_8 ) ;
} else if ( delta < 15 ) {
PM_AddEvent ( EV_STEP_12 ) ;
} else {
PM_AddEvent ( EV_STEP_16 ) ;
}
}
if ( pm - > debugLevel ) {
Com_Printf ( " %i:stepped \n " , c_pmove ) ;
}
}
}
# include "../namespace_end.h"