2013-04-19 02:52:48 +00:00
// leave this line at the top for all g_xxxx.cpp files...
# include "g_headers.h"
//seems to be a compiler bug, it doesn't clean out the #ifdefs between dif-compiles
//or something, so the headers spew errors on these defs from the previous compile.
//this fixes that. -rww
# ifdef _JK2MP
//get rid of all the crazy defs we added for this file
# undef currentAngles
# undef currentOrigin
# undef mins
# undef maxs
# undef legsAnimTimer
# undef torsoAnimTimer
# undef bool
# undef false
# undef true
# undef sqrtf
# undef Q_flrand
# undef MOD_EXPLOSIVE
# endif
# ifdef _JK2 //SP does not have this preprocessor for game like MP does
# ifndef _JK2MP
# define _JK2MP
# endif
# endif
# ifndef _JK2MP //if single player
# ifndef QAGAME //I don't think we have a QAGAME define
# define QAGAME //but define it cause in sp we're always in the game
# endif
# endif
# ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
# include "g_local.h"
# elif defined _JK2MP
# include "bg_public.h"
# endif
# ifndef _JK2MP
# include "g_functions.h"
# include "g_vehicles.h"
2013-04-19 03:47:29 +00:00
# include "../game/wp_saber.h"
2013-04-19 02:52:48 +00:00
# else
# include "bg_vehicles.h"
# endif
# ifdef _JK2MP
//this is really horrible, but it works! just be sure not to use any locals or anything
//with these names (exluding bool, false, true). -rww
# define currentAngles r.currentAngles
# define currentOrigin r.currentOrigin
# define mins r.mins
# define maxs r.maxs
# define legsAnimTimer legsTimer
# define torsoAnimTimer torsoTimer
# define bool qboolean
# define false qfalse
# define true qtrue
# define sqrtf sqrt
# define Q_flrand flrand
# define MOD_EXPLOSIVE MOD_SUICIDE
# else
# define bgEntity_t gentity_t
# endif
# ifdef QAGAME //we only want a few of these functions for BG
extern float DotToSpot ( vec3_t spot , vec3_t from , vec3_t fromAngles ) ;
extern vmCvar_t cg_thirdPersonAlpha ;
extern vec3_t playerMins ;
extern vec3_t playerMaxs ;
extern cvar_t * g_speederControlScheme ;
# ifdef _JK2MP
# include "../namespace_begin.h"
# endif
extern void PM_SetAnim ( pmove_t * pm , int setAnimParts , int anim , int setAnimFlags , int blendTime ) ;
extern int PM_AnimLength ( int index , animNumber_t anim ) ;
# ifdef _JK2MP
# include "../namespace_end.h"
# endif
# ifndef _JK2MP
extern void CG_ChangeWeapon ( int num ) ;
# endif
extern void Vehicle_SetAnim ( gentity_t * ent , int setAnimParts , int anim , int setAnimFlags , int iBlend ) ;
extern void G_Knockdown ( gentity_t * self , gentity_t * attacker , const vec3_t pushDir , float strength , qboolean breakSaberLock ) ;
extern void G_VehicleTrace ( trace_t * results , const vec3_t start , const vec3_t tMins , const vec3_t tMaxs , const vec3_t end , int passEntityNum , int contentmask ) ;
// Update death sequence.
static void DeathUpdate ( Vehicle_t * pVeh )
{
if ( level . time > = pVeh - > m_iDieTime )
{
// If the vehicle is not empty.
if ( pVeh - > m_pVehicleInfo - > Inhabited ( pVeh ) )
{
pVeh - > m_pVehicleInfo - > EjectAll ( pVeh ) ;
}
else
{
// Waste this sucker.
}
// Die now...
/* else
{
vec3_t mins , maxs , bottom ;
trace_t trace ;
if ( pVeh - > m_pVehicleInfo - > explodeFX )
{
G_PlayEffect ( pVeh - > m_pVehicleInfo - > explodeFX , parent - > currentOrigin ) ;
//trace down and place mark
VectorCopy ( parent - > currentOrigin , bottom ) ;
bottom [ 2 ] - = 80 ;
gi . trace ( & trace , parent - > currentOrigin , vec3_origin , vec3_origin , bottom , parent - > s . number , CONTENTS_SOLID ) ;
if ( trace . fraction < 1.0f )
{
VectorCopy ( trace . endpos , bottom ) ;
bottom [ 2 ] + = 2 ;
G_PlayEffect ( " ships/ship_explosion_mark " , trace . endpos ) ;
}
}
parent - > takedamage = qfalse ; //so we don't recursively damage ourselves
if ( pVeh - > m_pVehicleInfo - > explosionRadius > 0 & & pVeh - > m_pVehicleInfo - > explosionDamage > 0 )
{
VectorCopy ( parent - > mins , mins ) ;
mins [ 2 ] = - 4 ; //to keep it off the ground a *little*
VectorCopy ( parent - > maxs , maxs ) ;
VectorCopy ( parent - > currentOrigin , bottom ) ;
bottom [ 2 ] + = parent - > mins [ 2 ] - 32 ;
gi . trace ( & trace , parent - > currentOrigin , mins , maxs , bottom , parent - > s . number , CONTENTS_SOLID ) ;
G_RadiusDamage ( trace . endpos , NULL , pVeh - > m_pVehicleInfo - > explosionDamage , pVeh - > m_pVehicleInfo - > explosionRadius , NULL , MOD_EXPLOSIVE ) ; //FIXME: extern damage and radius or base on fuel
}
parent - > e_ThinkFunc = thinkF_G_FreeEntity ;
parent - > nextthink = level . time + FRAMETIME ;
} */
}
}
// Like a think or move command, this updates various vehicle properties.
static bool Update ( Vehicle_t * pVeh , const usercmd_t * pUcmd )
{
return g_vehicleInfo [ VEHICLE_BASE ] . Update ( pVeh , pUcmd ) ;
}
# endif //QAGAME
# ifdef _JK2MP
# include "../namespace_begin.h"
# endif
//MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
//If you really need to violate this rule for SP, then use ifdefs.
//By BG-compatible, I mean no use of game-specific data - ONLY use
//stuff available in the MP bgEntity (in SP, the bgEntity is #defined
//as a gentity, but the MP-compatible access restrictions are based
//on the bgEntity structure in the MP codebase) -rww
// ProcessMoveCommands the Vehicle.
static void ProcessMoveCommands ( Vehicle_t * pVeh )
{
/************************************************************************************/
/* BEGIN Here is where we move the vehicle (forward or back or whatever). BEGIN */
/************************************************************************************/
//Client sets ucmds and such for speed alterations
float speedInc , speedIdleDec , speedIdle , speedIdleAccel , speedMin , speedMax ;
float fWalkSpeedMax ;
int curTime ;
bgEntity_t * parent = pVeh - > m_pParentEntity ;
# ifdef _JK2MP
playerState_t * parentPS = parent - > playerState ;
# else
playerState_t * parentPS = & parent - > client - > ps ;
# endif
# ifndef _JK2MP //SP
curTime = level . time ;
2013-04-23 14:36:59 +00:00
# elif defined QAGAME //MP GAME
2013-04-19 02:52:48 +00:00
curTime = level . time ;
2013-04-23 14:36:59 +00:00
# elif defined CGAME //MP CGAME
2013-04-19 02:52:48 +00:00
//FIXME: pass in ucmd? Not sure if this is reliable...
curTime = pm - > cmd . serverTime ;
# endif
# ifndef _JK2MP //bad for prediction - fixme
// Bucking so we can't do anything.
if ( pVeh - > m_ulFlags & VEH_BUCKING | | pVeh - > m_ulFlags & VEH_FLYING | | pVeh - > m_ulFlags & VEH_CRASHING )
{
//#ifdef QAGAME //this was in Update above
// ((gentity_t *)parent)->client->ps.speed = 0;
//#endif
parentPS - > speed = 0 ;
return ;
}
# endif
speedIdleDec = pVeh - > m_pVehicleInfo - > decelIdle * pVeh - > m_fTimeModifier ;
speedMax = pVeh - > m_pVehicleInfo - > speedMax ;
speedIdle = pVeh - > m_pVehicleInfo - > speedIdle ;
speedIdleAccel = pVeh - > m_pVehicleInfo - > accelIdle * pVeh - > m_fTimeModifier ;
speedMin = pVeh - > m_pVehicleInfo - > speedMin ;
if ( pVeh - > m_pPilot /*&& (pilotPS->weapon == WP_NONE || pilotPS->weapon == WP_MELEE )*/ & &
( pVeh - > m_ucmd . buttons & BUTTON_ALT_ATTACK ) & & pVeh - > m_pVehicleInfo - > turboSpeed )
{
if ( ( curTime - pVeh - > m_iTurboTime ) > pVeh - > m_pVehicleInfo - > turboRecharge )
{
pVeh - > m_iTurboTime = ( curTime + pVeh - > m_pVehicleInfo - > turboDuration ) ;
# ifndef _JK2MP //kill me now
if ( pVeh - > m_pVehicleInfo - > soundTurbo )
{
G_SoundIndexOnEnt ( pVeh - > m_pParentEntity , CHAN_AUTO , pVeh - > m_pVehicleInfo - > soundTurbo ) ;
}
# endif
parentPS - > speed = pVeh - > m_pVehicleInfo - > turboSpeed ; // Instantly Jump To Turbo Speed
}
}
if ( curTime < pVeh - > m_iTurboTime )
{
speedMax = pVeh - > m_pVehicleInfo - > turboSpeed ;
}
else
{
speedMax = pVeh - > m_pVehicleInfo - > speedMax ;
}
# ifdef _JK2MP
if ( ! parentPS - > m_iVehicleNum )
# else
if ( ! pVeh - > m_pVehicleInfo - > Inhabited ( pVeh ) )
# endif
{ //drifts to a stop
speedInc = speedIdle * pVeh - > m_fTimeModifier ;
VectorClear ( parentPS - > moveDir ) ;
//m_ucmd.forwardmove = 127;
parentPS - > speed = 0 ;
}
else
{
speedInc = pVeh - > m_pVehicleInfo - > acceleration * pVeh - > m_fTimeModifier ;
}
if ( parentPS - > speed | | parentPS - > groundEntityNum = = ENTITYNUM_NONE | |
pVeh - > m_ucmd . forwardmove | | pVeh - > m_ucmd . upmove > 0 )
{
if ( pVeh - > m_ucmd . forwardmove > 0 & & speedInc )
{
parentPS - > speed + = speedInc ;
}
else if ( pVeh - > m_ucmd . forwardmove < 0 )
{
if ( parentPS - > speed > speedIdle )
{
parentPS - > speed - = speedInc ;
}
else if ( parentPS - > speed > speedMin )
{
parentPS - > speed - = speedIdleDec ;
}
}
// No input, so coast to stop.
else if ( parentPS - > speed > 0.0f )
{
parentPS - > speed - = speedIdleDec ;
if ( parentPS - > speed < 0.0f )
{
parentPS - > speed = 0.0f ;
}
}
else if ( parentPS - > speed < 0.0f )
{
parentPS - > speed + = speedIdleDec ;
if ( parentPS - > speed > 0.0f )
{
parentPS - > speed = 0.0f ;
}
}
}
else
{
if ( pVeh - > m_ucmd . forwardmove < 0 )
{
pVeh - > m_ucmd . forwardmove = 0 ;
}
if ( pVeh - > m_ucmd . upmove < 0 )
{
pVeh - > m_ucmd . upmove = 0 ;
}
//pVeh->m_ucmd.rightmove = 0;
/*if ( !pVeh->m_pVehicleInfo->strafePerc
| | ( ! g_speederControlScheme - > value & & ! parent - > s . number ) )
{ //if in a strafe-capable vehicle, clear strafing unless using alternate control scheme
pVeh - > m_ucmd . rightmove = 0 ;
} */
}
fWalkSpeedMax = speedMax * 0.275f ;
if ( curTime > pVeh - > m_iTurboTime & & ( pVeh - > m_ucmd . buttons & BUTTON_WALKING ) & & parentPS - > speed > fWalkSpeedMax )
{
parentPS - > speed = fWalkSpeedMax ;
}
else if ( parentPS - > speed > speedMax )
{
parentPS - > speed = speedMax ;
}
else if ( parentPS - > speed < speedMin )
{
parentPS - > speed = speedMin ;
}
/********************************************************************************/
/* END Here is where we move the vehicle (forward or back or whatever). END */
/********************************************************************************/
}
//MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
//If you really need to violate this rule for SP, then use ifdefs.
//By BG-compatible, I mean no use of game-specific data - ONLY use
//stuff available in the MP bgEntity (in SP, the bgEntity is #defined
//as a gentity, but the MP-compatible access restrictions are based
//on the bgEntity structure in the MP codebase) -rww
// ProcessOrientCommands the Vehicle.
static void ProcessOrientCommands ( Vehicle_t * pVeh )
{
/********************************************************************************/
/* BEGIN Here is where make sure the vehicle is properly oriented. BEGIN */
/********************************************************************************/
bgEntity_t * parent = pVeh - > m_pParentEntity ;
playerState_t * parentPS , * riderPS ;
# ifdef _JK2MP
bgEntity_t * rider = NULL ;
if ( parent - > s . owner ! = ENTITYNUM_NONE )
{
rider = PM_BGEntForNum ( parent - > s . owner ) ; //&g_entities[parent->r.ownerNum];
}
# else
gentity_t * rider = parent - > owner ;
# endif
// Bucking so we can't do anything.
# ifndef _JK2MP //bad for prediction - fixme
if ( pVeh - > m_ulFlags & VEH_BUCKING | | pVeh - > m_ulFlags & VEH_FLYING | | pVeh - > m_ulFlags & VEH_CRASHING )
{
return ;
}
# endif
# ifdef _JK2MP
if ( ! rider )
# else
if ( ! rider | | ! rider - > client )
# endif
{
rider = parent ;
}
# ifdef _JK2MP
parentPS = parent - > playerState ;
riderPS = rider - > playerState ;
# else
parentPS = & parent - > client - > ps ;
riderPS = & rider - > client - > ps ;
# endif
if ( rider )
{
# ifdef _JK2MP
float angDif = AngleSubtract ( pVeh - > m_vOrientation [ YAW ] , riderPS - > viewangles [ YAW ] ) ;
if ( parentPS & & parentPS - > speed )
{
float s = parentPS - > speed ;
float maxDif = pVeh - > m_pVehicleInfo - > turningSpeed * 4.0f ; //magic number hackery
if ( s < 0.0f )
{
s = - s ;
}
angDif * = s / pVeh - > m_pVehicleInfo - > speedMax ;
if ( angDif > maxDif )
{
angDif = maxDif ;
}
else if ( angDif < - maxDif )
{
angDif = - maxDif ;
}
pVeh - > m_vOrientation [ YAW ] = AngleNormalize180 ( pVeh - > m_vOrientation [ YAW ] - angDif * ( pVeh - > m_fTimeModifier * 0.2f ) ) ;
}
# else
pVeh - > m_vOrientation [ YAW ] = riderPS - > viewangles [ YAW ] ;
# endif
}
/* speed = VectorLength( parentPS->velocity );
// If the player is the rider...
if ( rider - > s . number < MAX_CLIENTS )
{ //FIXME: use the vehicle's turning stat in this calc
pVeh - > m_vOrientation [ YAW ] = riderPS - > viewangles [ YAW ] ;
}
else
{
float turnSpeed = pVeh - > m_pVehicleInfo - > turningSpeed ;
if ( ! pVeh - > m_pVehicleInfo - > turnWhenStopped
& & ! parentPS - > speed ) //FIXME: or !pVeh->m_ucmd.forwardmove?
{ //can't turn when not moving
//FIXME: or ramp up to max turnSpeed?
turnSpeed = 0.0f ;
}
# ifdef _JK2MP
if ( rider - > s . eType = = ET_NPC )
# else
if ( ! rider | | rider - > NPC )
# endif
{ //help NPCs out some
turnSpeed * = 2.0f ;
# ifdef _JK2MP
if ( parentPS - > speed > 200.0f )
# else
if ( parent - > client - > ps . speed > 200.0f )
# endif
{
turnSpeed + = turnSpeed * parentPS - > speed / 200.0f * 0.05f ;
}
}
turnSpeed * = pVeh - > m_fTimeModifier ;
//default control scheme: strafing turns, mouselook aims
if ( pVeh - > m_ucmd . rightmove < 0 )
{
pVeh - > m_vOrientation [ YAW ] + = turnSpeed ;
}
else if ( pVeh - > m_ucmd . rightmove > 0 )
{
pVeh - > m_vOrientation [ YAW ] - = turnSpeed ;
}
if ( pVeh - > m_pVehicleInfo - > malfunctionArmorLevel & & pVeh - > m_iArmor < = pVeh - > m_pVehicleInfo - > malfunctionArmorLevel )
{ //damaged badly
}
} */
/********************************************************************************/
/* END Here is where make sure the vehicle is properly oriented. END */
/********************************************************************************/
}
# ifdef _JK2MP //temp hack til mp speeder controls are sorted -rww
void AnimalProcessOri ( Vehicle_t * pVeh )
{
ProcessOrientCommands ( pVeh ) ;
}
# endif
# ifdef QAGAME //back to our game-only functions
// This function makes sure that the vehicle is properly animated.
/*
static void AnimalTailSwipe ( Vehicle_t * pVeh , gentity_t * parent , gentity_t * pilot )
{
trace_t trace ;
vec3_t angles ;
vec3_t vRoot , vTail ;
vec3_t lMins , lMaxs ;
mdxaBone_t boltMatrix ;
int iRootBone ;
int iRootTail ;
VectorSet ( angles , 0 , parent - > currentAngles [ YAW ] , 0 ) ;
VectorSet ( lMins , parent - > mins [ 0 ] - 1 , parent - > mins [ 1 ] - 1 , 0 ) ;
VectorSet ( lMaxs , parent - > maxs [ 0 ] + 1 , parent - > maxs [ 1 ] + 1 , 1 ) ;
# ifdef _JK2MP
iRootBone = trap_G2API_AddBolt ( parent - > ghoul2 , 0 , " tail_01 " ) ;
iRootTail = trap_G2API_AddBolt ( parent - > ghoul2 , 0 , " tail_04 " ) ;
// Get the positions of the root of the tail and the tail end of it.
trap_G2API_GetBoltMatrix ( parent - > ghoul2 , 0 , iRootBone ,
& boltMatrix , angles , parent - > currentOrigin , level . time ,
NULL , parent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , vRoot ) ;
trap_G2API_GetBoltMatrix ( parent - > ghoul2 , 0 , iRootTail ,
& boltMatrix , angles , parent - > currentOrigin , level . time ,
NULL , parent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , vTail ) ;
# else
iRootBone = gi . G2API_GetBoneIndex ( & parent - > ghoul2 [ parent - > playerModel ] , " tail_01 " , qtrue ) ;
iRootTail = gi . G2API_GetBoneIndex ( & parent - > ghoul2 [ parent - > playerModel ] , " tail_04 " , qtrue ) ;
// Get the positions of the root of the tail and the tail end of it.
gi . G2API_GetBoltMatrix ( parent - > ghoul2 , parent - > playerModel , iRootBone ,
& boltMatrix , angles , parent - > currentOrigin , ( cg . time ? cg . time : level . time ) ,
NULL , parent - > s . modelScale ) ;
gi . G2API_GiveMeVectorFromMatrix ( boltMatrix , ORIGIN , vRoot ) ;
gi . G2API_GetBoltMatrix ( parent - > ghoul2 , parent - > playerModel , iRootTail ,
& boltMatrix , angles , parent - > currentOrigin , ( cg . time ? cg . time : level . time ) ,
NULL , parent - > s . modelScale ) ;
gi . G2API_GiveMeVectorFromMatrix ( boltMatrix , ORIGIN , vTail ) ;
# endif
// Trace from the root of the tail to the very end.
G_VehicleTrace ( & trace , vRoot , lMins , lMaxs , vTail , parent - > s . number , MASK_NPCSOLID ) ;
if ( trace . fraction < 1.0f )
{
if ( ENTITYNUM_NONE ! = trace . entityNum & & g_entities [ trace . entityNum ] . client & &
# ifndef _JK2MP //no rancor in jk2mp (at least not currently)
g_entities [ trace . entityNum ] . client - > NPC_class ! = CLASS_RANCOR & &
# else //and in mp want to check inuse
g_entities [ trace . entityNum ] . inuse & &
# endif
g_entities [ trace . entityNum ] . client - > NPC_class ! = CLASS_VEHICLE )
{
vec3_t pushDir ;
vec3_t angs ;
int iDamage = 10 ;
// Get the direction we're facing.
VectorCopy ( parent - > client - > ps . viewangles , angs ) ;
// Add some fudge.
angs [ YAW ] + = Q_flrand ( 5 , 15 ) ;
angs [ PITCH ] = Q_flrand ( - 20 , - 10 ) ;
AngleVectors ( angs , pushDir , NULL , NULL ) ;
// Reverse direction.
pushDir [ YAW ] = - pushDir [ YAW ] ;
// Smack this ho down.
# ifdef _JK2MP
G_Sound ( & g_entities [ trace . entityNum ] , CHAN_AUTO , G_SoundIndex ( " sound/chars/rancor/swipehit.wav " ) ) ;
# else
G_Sound ( & g_entities [ trace . entityNum ] , G_SoundIndex ( " sound/chars/rancor/swipehit.wav " ) ) ;
# endif
G_Throw ( & g_entities [ trace . entityNum ] , pushDir , 50 ) ;
if ( g_entities [ trace . entityNum ] . health > 0 )
{
// Knock down and dish out some hurt.
gentity_t * hit = & g_entities [ trace . entityNum ] ;
# ifdef _JK2MP
if ( BG_KnockDownable ( & hit - > client - > ps ) )
{
hit - > client - > ps . forceHandExtend = HANDEXTEND_KNOCKDOWN ;
hit - > client - > ps . forceHandExtendTime = pm - > cmd . serverTime + 1100 ;
hit - > client - > ps . forceDodgeAnim = 0 ; //this toggles between 1 and 0, when it's 1 we should play the get up anim
hit - > client - > ps . otherKiller = pilot - > s . number ;
hit - > client - > ps . otherKillerTime = level . time + 5000 ;
hit - > client - > ps . otherKillerDebounceTime = level . time + 100 ;
hit - > client - > ps . velocity [ 0 ] = pushDir [ 0 ] * 80 ;
hit - > client - > ps . velocity [ 1 ] = pushDir [ 1 ] * 80 ;
hit - > client - > ps . velocity [ 2 ] = 100 ;
}
# else
G_Knockdown ( hit , parent , pushDir , 300 , qtrue ) ;
# endif
G_Damage ( hit , parent , parent , NULL , NULL , iDamage , DAMAGE_NO_KNOCKBACK | DAMAGE_IGNORE_TEAM , MOD_MELEE ) ;
//G_PlayEffect( pVeh->m_pVehicleInfo->explodeFX, parent->currentOrigin );
} // Not Dead
} // Not Rancor & In USe
} // Trace Hit Anything?
}
*/
static void AnimateVehicle ( Vehicle_t * pVeh )
{
animNumber_t Anim = BOTH_VT_IDLE ;
int iFlags = SETANIM_FLAG_NORMAL , iBlend = 300 ;
gentity_t * pilot = ( gentity_t * ) pVeh - > m_pPilot ;
gentity_t * parent = ( gentity_t * ) pVeh - > m_pParentEntity ;
playerState_t * pilotPS ;
playerState_t * parentPS ;
float fSpeedPercToMax ;
# ifdef _JK2MP
pilotPS = ( pilot ) ? ( pilot - > playerState ) : ( 0 ) ;
parentPS = parent - > playerState ;
# else
pilotPS = ( pilot ) ? ( & pilot - > client - > ps ) : ( 0 ) ;
parentPS = & parent - > client - > ps ;
# endif
// We're dead (boarding is reused here so I don't have to make another variable :-).
if ( parent - > health < = 0 )
{
if ( pVeh - > m_iBoarding ! = - 999 ) // Animate the death just once!
{
pVeh - > m_iBoarding = - 999 ;
iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ;
// FIXME! Why do you keep repeating over and over!!?!?!? Bastard!
//Vehicle_SetAnim( parent, SETANIM_LEGS, BOTH_VT_DEATH1, iFlags, iBlend );
}
return ;
}
// If they're bucking, play the animation and leave...
if ( parent - > client - > ps . legsAnim = = BOTH_VT_BUCK )
{
// Done with animation? Erase the flag.
if ( parent - > client - > ps . legsAnimTimer < = 0 )
{
pVeh - > m_ulFlags & = ~ VEH_BUCKING ;
}
else
{
return ;
}
}
else if ( pVeh - > m_ulFlags & VEH_BUCKING )
{
iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ;
Anim = BOTH_VT_BUCK ;
iBlend = 500 ;
Vehicle_SetAnim ( parent , SETANIM_LEGS , BOTH_VT_BUCK , iFlags , iBlend ) ;
return ;
}
// Boarding animation.
if ( pVeh - > m_iBoarding ! = 0 )
{
// We've just started boarding, set the amount of time it will take to finish boarding.
if ( pVeh - > m_iBoarding < 0 )
{
int iAnimLen ;
// Boarding from left...
if ( pVeh - > m_iBoarding = = - 1 )
{
Anim = BOTH_VT_MOUNT_L ;
}
else if ( pVeh - > m_iBoarding = = - 2 )
{
Anim = BOTH_VT_MOUNT_R ;
}
else if ( pVeh - > m_iBoarding = = - 3 )
{
Anim = BOTH_VT_MOUNT_B ;
}
// Set the delay time (which happens to be the time it takes for the animation to complete).
// NOTE: Here I made it so the delay is actually 70% (0.7f) of the animation time.
# ifdef _JK2MP
iAnimLen = BG_AnimLength ( parent - > localAnimIndex , Anim ) * 0.7f ;
# else
iAnimLen = PM_AnimLength ( parent - > client - > clientInfo . animFileIndex , Anim ) * 0.7f ;
# endif
pVeh - > m_iBoarding = level . time + iAnimLen ;
// Set the animation, which won't be interrupted until it's completed.
// TODO: But what if he's killed? Should the animation remain persistant???
iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ;
Vehicle_SetAnim ( parent , SETANIM_LEGS , Anim , iFlags , iBlend ) ;
if ( pilot )
{
Vehicle_SetAnim ( pilot , SETANIM_BOTH , Anim , iFlags , iBlend ) ;
}
return ;
}
// Otherwise we're done.
else if ( pVeh - > m_iBoarding < = level . time )
{
pVeh - > m_iBoarding = 0 ;
}
}
// Percentage of maximum speed relative to current speed.
//float fSpeed = VectorLength( client->ps.velocity );
fSpeedPercToMax = parent - > client - > ps . speed / pVeh - > m_pVehicleInfo - > speedMax ;
// Going in reverse...
if ( fSpeedPercToMax < - 0.01f )
{
Anim = BOTH_VT_WALK_REV ;
iBlend = 600 ;
}
else
{
bool Turbo = ( fSpeedPercToMax > 0.0f & & level . time < pVeh - > m_iTurboTime ) ;
bool Walking = ( fSpeedPercToMax > 0.0f & & ( ( pVeh - > m_ucmd . buttons & BUTTON_WALKING ) | | fSpeedPercToMax < = 0.275f ) ) ;
bool Running = ( fSpeedPercToMax > 0.275f ) ;
// Remove Crashing Flag
//----------------------
pVeh - > m_ulFlags & = ~ VEH_CRASHING ;
if ( Turbo )
{ // Kicked In Turbo
iBlend = 50 ;
iFlags = SETANIM_FLAG_OVERRIDE ;
Anim = BOTH_VT_TURBO ;
}
else
{ // No Special Moves
iBlend = 300 ;
iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS ;
Anim = ( Walking ) ? ( BOTH_VT_WALK_FWD ) : ( ( Running ) ? ( BOTH_VT_RUN_FWD ) : ( BOTH_VT_IDLE1 ) ) ;
}
}
Vehicle_SetAnim ( parent , SETANIM_LEGS , Anim , iFlags , iBlend ) ;
}
//rwwFIXMEFIXME: This is all going to have to be predicted I think, or it will feel awful
//and lagged
// This function makes sure that the rider's in this vehicle are properly animated.
static void AnimateRiders ( Vehicle_t * pVeh )
{
animNumber_t Anim = BOTH_VT_IDLE ;
int iFlags = SETANIM_FLAG_NORMAL , iBlend = 500 ;
gentity_t * pilot = ( gentity_t * ) pVeh - > m_pPilot ;
gentity_t * parent = ( gentity_t * ) pVeh - > m_pParentEntity ;
playerState_t * pilotPS ;
playerState_t * parentPS ;
float fSpeedPercToMax ;
# ifdef _JK2MP
pilotPS = pVeh - > m_pPilot - > playerState ;
parentPS = pVeh - > m_pPilot - > playerState ;
# else
pilotPS = & pVeh - > m_pPilot - > client - > ps ;
parentPS = & pVeh - > m_pParentEntity - > client - > ps ;
# endif
// Boarding animation.
if ( pVeh - > m_iBoarding ! = 0 )
{
return ;
}
// Percentage of maximum speed relative to current speed.
fSpeedPercToMax = parent - > client - > ps . speed / pVeh - > m_pVehicleInfo - > speedMax ;
/* // Going in reverse...
# ifdef _JK2MP //handled in pmove in mp
if ( 0 )
# else
if ( fSpeedPercToMax < - 0.01f )
# endif
{
Anim = BOTH_VT_WALK_REV ;
iBlend = 600 ;
bool HasWeapon = ( ( pilotPS - > weapon ! = WP_NONE ) & & ( pilotPS - > weapon ! = WP_MELEE ) ) ;
if ( HasWeapon )
{
if ( pVeh - > m_pPilot - > s . number < MAX_CLIENTS )
{
CG_ChangeWeapon ( WP_NONE ) ;
}
pVeh - > m_pPilot - > client - > ps . weapon = WP_NONE ;
G_RemoveWeaponModels ( pVeh - > m_pPilot ) ;
}
}
else
*/
{
bool HasWeapon = ( ( pilotPS - > weapon ! = WP_NONE ) & & ( pilotPS - > weapon ! = WP_MELEE ) ) ;
bool Attacking = ( HasWeapon & & ! ! ( pVeh - > m_ucmd . buttons & BUTTON_ATTACK ) ) ;
bool Right = ( pVeh - > m_ucmd . rightmove > 0 ) ;
bool Left = ( pVeh - > m_ucmd . rightmove < 0 ) ;
bool Turbo = ( fSpeedPercToMax > 0.0f & & level . time < pVeh - > m_iTurboTime ) ;
bool Walking = ( fSpeedPercToMax > 0.0f & & ( ( pVeh - > m_ucmd . buttons & BUTTON_WALKING ) | | fSpeedPercToMax < = 0.275f ) ) ;
bool Running = ( fSpeedPercToMax > 0.275f ) ;
EWeaponPose WeaponPose = WPOSE_NONE ;
// Remove Crashing Flag
//----------------------
pVeh - > m_ulFlags & = ~ VEH_CRASHING ;
// Put Away Saber When It Is Not Active
//--------------------------------------
# ifndef _JK2MP
if ( HasWeapon & &
( pVeh - > m_pPilot - > s . number > = MAX_CLIENTS | | ( cg . weaponSelectTime + 500 ) < cg . time ) & &
( pilotPS - > weapon = = WP_SABER & & ( Turbo | | ! pilotPS - > SaberActive ( ) ) ) )
{
if ( pVeh - > m_pPilot - > s . number < MAX_CLIENTS )
{
CG_ChangeWeapon ( WP_NONE ) ;
}
pVeh - > m_pPilot - > client - > ps . weapon = WP_NONE ;
G_RemoveWeaponModels ( pVeh - > m_pPilot ) ;
}
# endif
// Don't Interrupt Attack Anims
//------------------------------
# ifdef _JK2MP
if ( pilotPS - > weaponTime > 0 )
{
return ;
}
# else
if ( pilotPS - > torsoAnim > = BOTH_VT_ATL_S & & pilotPS - > torsoAnim < = BOTH_VT_ATF_G )
{
float bodyCurrent = 0.0f ;
int bodyEnd = 0 ;
if ( ! ! gi . G2API_GetBoneAnimIndex ( & pVeh - > m_pPilot - > ghoul2 [ pVeh - > m_pPilot - > playerModel ] , pVeh - > m_pPilot - > rootBone , level . time , & bodyCurrent , NULL , & bodyEnd , NULL , NULL , NULL ) )
{
if ( bodyCurrent < = ( ( float ) ( bodyEnd ) - 1.5f ) )
{
return ;
}
}
}
# endif
// Compute The Weapon Pose
//--------------------------
if ( pilotPS - > weapon = = WP_BLASTER )
{
WeaponPose = WPOSE_BLASTER ;
}
else if ( pilotPS - > weapon = = WP_SABER )
{
if ( ( pVeh - > m_ulFlags & VEH_SABERINLEFTHAND ) & & pilotPS - > torsoAnim = = BOTH_VT_ATL_TO_R_S )
{
pVeh - > m_ulFlags & = ~ VEH_SABERINLEFTHAND ;
}
if ( ! ( pVeh - > m_ulFlags & VEH_SABERINLEFTHAND ) & & pilotPS - > torsoAnim = = BOTH_VT_ATR_TO_L_S )
{
pVeh - > m_ulFlags | = VEH_SABERINLEFTHAND ;
}
WeaponPose = ( pVeh - > m_ulFlags & VEH_SABERINLEFTHAND ) ? ( WPOSE_SABERLEFT ) : ( WPOSE_SABERRIGHT ) ;
}
if ( Attacking & & WeaponPose )
{ // Attack!
iBlend = 100 ;
iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_RESTART ;
if ( Turbo )
{
Right = true ;
Left = false ;
}
// Auto Aiming
//===============================================
if ( ! Left & & ! Right ) // Allow player strafe keys to override
{
# ifndef _JK2MP
if ( pVeh - > m_pPilot - > enemy )
{
vec3_t toEnemy ;
float toEnemyDistance ;
vec3_t actorRight ;
float actorRightDot ;
VectorSubtract ( pVeh - > m_pPilot - > currentOrigin , pVeh - > m_pPilot - > enemy - > currentOrigin , toEnemy ) ;
toEnemyDistance = VectorNormalize ( toEnemy ) ;
AngleVectors ( pVeh - > m_pParentEntity - > currentAngles , 0 , actorRight , 0 ) ;
actorRightDot = DotProduct ( toEnemy , actorRight ) ;
if ( fabsf ( actorRightDot ) > 0.5f | | pilotPS - > weapon = = WP_SABER )
{
Left = ( actorRightDot > 0.0f ) ;
Right = ! Left ;
}
else
{
Right = Left = false ;
}
}
else
# endif
if ( pilotPS - > weapon = = WP_SABER & & ! Left & & ! Right )
{
Left = ( WeaponPose = = WPOSE_SABERLEFT ) ;
Right = ! Left ;
}
}
if ( Left )
{ // Attack Left
switch ( WeaponPose )
{
case WPOSE_BLASTER : Anim = BOTH_VT_ATL_G ; break ;
case WPOSE_SABERLEFT : Anim = BOTH_VT_ATL_S ; break ;
case WPOSE_SABERRIGHT : Anim = BOTH_VT_ATR_TO_L_S ; break ;
default : assert ( 0 ) ;
}
}
else if ( Right )
{ // Attack Right
switch ( WeaponPose )
{
case WPOSE_BLASTER : Anim = BOTH_VT_ATR_G ; break ;
case WPOSE_SABERLEFT : Anim = BOTH_VT_ATL_TO_R_S ; break ;
case WPOSE_SABERRIGHT : Anim = BOTH_VT_ATR_S ; break ;
default : assert ( 0 ) ;
}
}
else
{ // Attack Ahead
switch ( WeaponPose )
{
case WPOSE_BLASTER : Anim = BOTH_VT_ATF_G ; break ;
default : assert ( 0 ) ;
}
}
}
else if ( Turbo )
{ // Kicked In Turbo
iBlend = 50 ;
iFlags = SETANIM_FLAG_OVERRIDE ;
Anim = BOTH_VT_TURBO ;
}
else
{ // No Special Moves
iBlend = 300 ;
iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS ;
if ( WeaponPose = = WPOSE_NONE )
{
if ( Walking )
{
Anim = BOTH_VT_WALK_FWD ;
}
else if ( Running )
{
Anim = BOTH_VT_RUN_FWD ;
}
else
{
Anim = BOTH_VT_IDLE1 ; //(Q_irand(0,1)==0)?(BOTH_VT_IDLE):(BOTH_VT_IDLE1);
}
}
else
{
switch ( WeaponPose )
{
case WPOSE_BLASTER : Anim = BOTH_VT_IDLE_G ; break ;
case WPOSE_SABERLEFT : Anim = BOTH_VT_IDLE_SL ; break ;
case WPOSE_SABERRIGHT : Anim = BOTH_VT_IDLE_SR ; break ;
default : assert ( 0 ) ;
}
}
} // No Special Moves
}
Vehicle_SetAnim ( pilot , SETANIM_BOTH , Anim , iFlags , iBlend ) ;
}
# endif //QAGAME
# ifndef QAGAME
void AttachRidersGeneric ( Vehicle_t * pVeh ) ;
# endif
//on the client this function will only set up the process command funcs
void G_SetAnimalVehicleFunctions ( vehicleInfo_t * pVehInfo )
{
# ifdef QAGAME
pVehInfo - > AnimateVehicle = AnimateVehicle ;
pVehInfo - > AnimateRiders = AnimateRiders ;
// pVehInfo->ValidateBoard = ValidateBoard;
// pVehInfo->SetParent = SetParent;
// pVehInfo->SetPilot = SetPilot;
// pVehInfo->AddPassenger = AddPassenger;
// pVehInfo->Animate = Animate;
// pVehInfo->Board = Board;
// pVehInfo->Eject = Eject;
// pVehInfo->EjectAll = EjectAll;
// pVehInfo->StartDeathDelay = StartDeathDelay;
pVehInfo - > DeathUpdate = DeathUpdate ;
// pVehInfo->RegisterAssets = RegisterAssets;
// pVehInfo->Initialize = Initialize;
pVehInfo - > Update = Update ;
// pVehInfo->UpdateRider = UpdateRider;
# endif //QAGAME
pVehInfo - > ProcessMoveCommands = ProcessMoveCommands ;
pVehInfo - > ProcessOrientCommands = ProcessOrientCommands ;
# ifndef QAGAME //cgame prediction attachment func
pVehInfo - > AttachRiders = AttachRidersGeneric ;
# endif
// pVehInfo->AttachRiders = AttachRiders;
// pVehInfo->Ghost = Ghost;
// pVehInfo->UnGhost = UnGhost;
// pVehInfo->Inhabited = Inhabited;
}
// Following is only in game, not in namespace
# ifdef _JK2MP
# include "../namespace_end.h"
# endif
# ifdef QAGAME
extern void G_AllocateVehicleObject ( Vehicle_t * * pVeh ) ;
# endif
# ifdef _JK2MP
# include "../namespace_begin.h"
# endif
// Create/Allocate a new Animal Vehicle (initializing it as well).
//this is a BG function too in MP so don't un-bg-compatibilify it -rww
void G_CreateAnimalNPC ( Vehicle_t * * pVeh , const char * strAnimalType )
{
// Allocate the Vehicle.
# ifdef _JK2MP
# ifdef QAGAME
//these will remain on entities on the client once allocated because the pointer is
//never stomped. on the server, however, when an ent is freed, the entity struct is
//memset to 0, so this memory would be lost..
G_AllocateVehicleObject ( pVeh ) ;
# else
if ( ! * pVeh )
{ //only allocate a new one if we really have to
( * pVeh ) = ( Vehicle_t * ) BG_Alloc ( sizeof ( Vehicle_t ) ) ;
}
# endif
memset ( * pVeh , 0 , sizeof ( Vehicle_t ) ) ;
( * pVeh ) - > m_pVehicleInfo = & g_vehicleInfo [ BG_VehicleGetIndex ( strAnimalType ) ] ;
# else
( * pVeh ) = ( Vehicle_t * ) gi . Malloc ( sizeof ( Vehicle_t ) , TAG_G_ALLOC , qtrue ) ;
( * pVeh ) - > m_pVehicleInfo = & g_vehicleInfo [ BG_VehicleGetIndex ( strAnimalType ) ] ;
# endif
}
# ifdef _JK2MP
# include "../namespace_end.h"
//get rid of all the crazy defs we added for this file
# undef currentAngles
# undef currentOrigin
# undef mins
# undef maxs
# undef legsAnimTimer
# undef torsoAnimTimer
# undef bool
# undef false
# undef true
# undef sqrtf
# undef Q_flrand
# undef MOD_EXPLOSIVE
# endif