codemp/game/AnimalNPC.c

Go to the documentation of this file.
00001 // leave this line at the top for all g_xxxx.cpp files...
00002 #include "g_headers.h"
00003 
00004 //seems to be a compiler bug, it doesn't clean out the #ifdefs between dif-compiles
00005 //or something, so the headers spew errors on these defs from the previous compile.
00006 //this fixes that. -rww
00007 #ifdef _JK2MP
00008 //get rid of all the crazy defs we added for this file
00009 #undef currentAngles
00010 #undef currentOrigin
00011 #undef mins
00012 #undef maxs
00013 #undef legsAnimTimer
00014 #undef torsoAnimTimer
00015 #undef bool
00016 #undef false
00017 #undef true
00018 
00019 #undef sqrtf
00020 #undef Q_flrand
00021 
00022 #undef MOD_EXPLOSIVE
00023 #endif
00024 
00025 #ifdef _JK2 //SP does not have this preprocessor for game like MP does
00026 #ifndef _JK2MP
00027 #define _JK2MP
00028 #endif
00029 #endif
00030 
00031 #ifndef _JK2MP //if single player
00032 #ifndef QAGAME //I don't think we have a QAGAME define
00033 #define QAGAME //but define it cause in sp we're always in the game
00034 #endif
00035 #endif
00036 
00037 #ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
00038 #include "g_local.h"
00039 #elif defined _JK2MP
00040 #include "bg_public.h"
00041 #endif
00042 
00043 #ifndef _JK2MP
00044 #include "g_functions.h"
00045 #include "g_vehicles.h"
00046 #else
00047 #include "bg_vehicles.h"
00048 #endif
00049 
00050 #ifdef _JK2MP
00051 //this is really horrible, but it works! just be sure not to use any locals or anything
00052 //with these names (exluding bool, false, true). -rww
00053 #define currentAngles r.currentAngles
00054 #define currentOrigin r.currentOrigin
00055 #define mins r.mins
00056 #define maxs r.maxs
00057 #define legsAnimTimer legsTimer
00058 #define torsoAnimTimer torsoTimer
00059 #define bool qboolean
00060 #define false qfalse
00061 #define true qtrue
00062 
00063 #define sqrtf sqrt
00064 #define Q_flrand flrand
00065 
00066 #define MOD_EXPLOSIVE MOD_SUICIDE
00067 #else
00068 #define bgEntity_t gentity_t
00069 #endif
00070 
00071 #ifdef QAGAME //we only want a few of these functions for BG
00072 
00073 extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
00074 extern vmCvar_t cg_thirdPersonAlpha;
00075 extern vec3_t playerMins;
00076 extern vec3_t playerMaxs;
00077 extern cvar_t   *g_speederControlScheme;
00078 
00079 #ifdef _JK2MP
00080 #include "../namespace_begin.h"
00081 #endif
00082 extern void PM_SetAnim(pmove_t  *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
00083 extern int PM_AnimLength( int index, animNumber_t anim );
00084 #ifdef _JK2MP
00085 #include "../namespace_end.h"
00086 #endif
00087 
00088 #ifndef _JK2MP
00089 extern void CG_ChangeWeapon( int num );
00090 #endif
00091 
00092 extern void Vehicle_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
00093 extern void G_Knockdown( gentity_t *self, gentity_t *attacker, const vec3_t pushDir, float strength, qboolean breakSaberLock );
00094 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 );
00095 
00096 // Update death sequence.
00097 static void DeathUpdate( Vehicle_t *pVeh )
00098 {
00099         if ( level.time >= pVeh->m_iDieTime )
00100         {
00101                 // If the vehicle is not empty.
00102                 if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
00103                 {
00104                         pVeh->m_pVehicleInfo->EjectAll( pVeh );
00105                 }
00106                 else
00107                 {
00108                         // Waste this sucker.
00109                 }
00110 
00111                 // Die now...
00112 /*              else
00113                 {
00114                         vec3_t  mins, maxs, bottom;
00115                         trace_t trace;
00116 
00117                         if ( pVeh->m_pVehicleInfo->explodeFX )
00118                         {
00119                                 G_PlayEffect( pVeh->m_pVehicleInfo->explodeFX, parent->currentOrigin );
00120                                 //trace down and place mark
00121                                 VectorCopy( parent->currentOrigin, bottom );
00122                                 bottom[2] -= 80;
00123                                 gi.trace( &trace, parent->currentOrigin, vec3_origin, vec3_origin, bottom, parent->s.number, CONTENTS_SOLID );
00124                                 if ( trace.fraction < 1.0f )
00125                                 {
00126                                         VectorCopy( trace.endpos, bottom );
00127                                         bottom[2] += 2;
00128                                         G_PlayEffect( "ships/ship_explosion_mark", trace.endpos );
00129                                 }
00130                         }
00131 
00132                         parent->takedamage = qfalse;//so we don't recursively damage ourselves
00133                         if ( pVeh->m_pVehicleInfo->explosionRadius > 0 && pVeh->m_pVehicleInfo->explosionDamage > 0 )
00134                         {
00135                                 VectorCopy( parent->mins, mins );
00136                                 mins[2] = -4;//to keep it off the ground a *little*
00137                                 VectorCopy( parent->maxs, maxs );
00138                                 VectorCopy( parent->currentOrigin, bottom );
00139                                 bottom[2] += parent->mins[2] - 32;
00140                                 gi.trace( &trace, parent->currentOrigin, mins, maxs, bottom, parent->s.number, CONTENTS_SOLID );
00141                                 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
00142                         }
00143 
00144                         parent->e_ThinkFunc = thinkF_G_FreeEntity;
00145                         parent->nextthink = level.time + FRAMETIME;
00146                 }*/
00147         }
00148 }
00149 
00150 // Like a think or move command, this updates various vehicle properties.
00151 static bool Update( Vehicle_t *pVeh, const usercmd_t *pUcmd )
00152 {
00153         return g_vehicleInfo[VEHICLE_BASE].Update( pVeh, pUcmd );
00154 }
00155 #endif //QAGAME
00156 
00157 #ifdef _JK2MP
00158 #include "../namespace_begin.h"
00159 #endif
00160 
00161 //MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
00162 //If you really need to violate this rule for SP, then use ifdefs.
00163 //By BG-compatible, I mean no use of game-specific data - ONLY use
00164 //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
00165 //as a gentity, but the MP-compatible access restrictions are based
00166 //on the bgEntity structure in the MP codebase) -rww
00167 // ProcessMoveCommands the Vehicle.
00168 static void ProcessMoveCommands( Vehicle_t *pVeh )
00169 {
00170         /************************************************************************************/
00171         /*      BEGIN   Here is where we move the vehicle (forward or back or whatever). BEGIN  */
00172         /************************************************************************************/
00173 
00174         //Client sets ucmds and such for speed alterations
00175         float speedInc, speedIdleDec, speedIdle, speedIdleAccel, speedMin, speedMax;
00176         float fWalkSpeedMax;
00177         int             curTime;
00178         bgEntity_t *parent = pVeh->m_pParentEntity;
00179 #ifdef _JK2MP
00180         playerState_t *parentPS = parent->playerState;
00181 #else
00182         playerState_t *parentPS = &parent->client->ps;
00183 #endif
00184 
00185 #ifndef _JK2MP//SP
00186         curTime = level.time;
00187 #elif QAGAME//MP GAME
00188         curTime = level.time;
00189 #elif CGAME//MP CGAME
00190         //FIXME: pass in ucmd?  Not sure if this is reliable...
00191         curTime = pm->cmd.serverTime;
00192 #endif
00193 
00194 
00195 #ifndef _JK2MP //bad for prediction - fixme
00196         // Bucking so we can't do anything.
00197         if ( pVeh->m_ulFlags & VEH_BUCKING || pVeh->m_ulFlags & VEH_FLYING || pVeh->m_ulFlags & VEH_CRASHING )
00198         {
00199 //#ifdef QAGAME //this was in Update above
00200 //              ((gentity_t *)parent)->client->ps.speed = 0;
00201 //#endif
00202                 parentPS->speed = 0;
00203                 return;
00204         }
00205 #endif
00206         speedIdleDec = pVeh->m_pVehicleInfo->decelIdle * pVeh->m_fTimeModifier;
00207         speedMax = pVeh->m_pVehicleInfo->speedMax;
00208 
00209         speedIdle = pVeh->m_pVehicleInfo->speedIdle;
00210         speedIdleAccel = pVeh->m_pVehicleInfo->accelIdle * pVeh->m_fTimeModifier;
00211         speedMin = pVeh->m_pVehicleInfo->speedMin;
00212 
00213 
00214 
00215         if ( pVeh->m_pPilot /*&& (pilotPS->weapon == WP_NONE || pilotPS->weapon == WP_MELEE )*/ &&
00216                 (pVeh->m_ucmd.buttons & BUTTON_ALT_ATTACK) && pVeh->m_pVehicleInfo->turboSpeed )
00217         {
00218                 if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge)
00219                 {
00220                         pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration);
00221 #ifndef _JK2MP //kill me now
00222                         if (pVeh->m_pVehicleInfo->soundTurbo)
00223                         {
00224                                 G_SoundIndexOnEnt(pVeh->m_pParentEntity, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo);
00225                         }
00226 #endif
00227                         parentPS->speed = pVeh->m_pVehicleInfo->turboSpeed;     // Instantly Jump To Turbo Speed
00228                 }
00229         }
00230 
00231         if ( curTime < pVeh->m_iTurboTime )
00232         {
00233                 speedMax = pVeh->m_pVehicleInfo->turboSpeed;
00234         }
00235         else
00236         {
00237                 speedMax = pVeh->m_pVehicleInfo->speedMax;
00238         }
00239 
00240 #ifdef _JK2MP
00241         if ( !parentPS->m_iVehicleNum  )
00242 #else
00243         if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
00244 #endif
00245         {//drifts to a stop
00246                 speedInc = speedIdle * pVeh->m_fTimeModifier;
00247                 VectorClear( parentPS->moveDir );
00248                 //m_ucmd.forwardmove = 127;
00249                 parentPS->speed = 0;
00250         }
00251         else
00252         {
00253                 speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
00254         }
00255 
00256         if ( parentPS->speed || parentPS->groundEntityNum == ENTITYNUM_NONE  ||
00257                  pVeh->m_ucmd.forwardmove || pVeh->m_ucmd.upmove > 0 )
00258         { 
00259                 if ( pVeh->m_ucmd.forwardmove > 0 && speedInc )
00260                 {
00261                         parentPS->speed += speedInc;
00262                 }
00263                 else if ( pVeh->m_ucmd.forwardmove < 0 )
00264                 {
00265                         if ( parentPS->speed > speedIdle )
00266                         {
00267                                 parentPS->speed -= speedInc;
00268                         }
00269                         else if ( parentPS->speed > speedMin )
00270                         {
00271                                 parentPS->speed -= speedIdleDec;
00272                         }
00273                 }
00274                 // No input, so coast to stop.
00275                 else if ( parentPS->speed > 0.0f )
00276                 {
00277                         parentPS->speed -= speedIdleDec;
00278                         if ( parentPS->speed < 0.0f )
00279                         {
00280                                 parentPS->speed = 0.0f;
00281                         }
00282                 }
00283                 else if ( parentPS->speed < 0.0f )
00284                 {
00285                         parentPS->speed += speedIdleDec;
00286                         if ( parentPS->speed > 0.0f )
00287                         {
00288                                 parentPS->speed = 0.0f;
00289                         }
00290                 }
00291         }
00292         else
00293         {
00294                 if ( pVeh->m_ucmd.forwardmove < 0 )
00295                 {
00296                         pVeh->m_ucmd.forwardmove = 0;
00297                 }
00298                 if ( pVeh->m_ucmd.upmove < 0 )
00299                 {
00300                         pVeh->m_ucmd.upmove = 0;
00301                 }
00302 
00303                 //pVeh->m_ucmd.rightmove = 0;
00304 
00305                 /*if ( !pVeh->m_pVehicleInfo->strafePerc 
00306                         || (!g_speederControlScheme->value && !parent->s.number) )
00307                 {//if in a strafe-capable vehicle, clear strafing unless using alternate control scheme
00308                         pVeh->m_ucmd.rightmove = 0;
00309                 }*/
00310         }
00311 
00312         fWalkSpeedMax = speedMax * 0.275f;
00313         if ( curTime>pVeh->m_iTurboTime && (pVeh->m_ucmd.buttons & BUTTON_WALKING) && parentPS->speed > fWalkSpeedMax )
00314         {
00315                 parentPS->speed = fWalkSpeedMax;
00316         }
00317         else if ( parentPS->speed > speedMax )
00318         {
00319                 parentPS->speed = speedMax;
00320         }
00321         else if ( parentPS->speed < speedMin )
00322         {
00323                 parentPS->speed = speedMin;
00324         }
00325 
00326         /********************************************************************************/
00327         /*      END Here is where we move the vehicle (forward or back or whatever). END        */
00328         /********************************************************************************/
00329 }
00330 
00331 //MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
00332 //If you really need to violate this rule for SP, then use ifdefs.
00333 //By BG-compatible, I mean no use of game-specific data - ONLY use
00334 //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
00335 //as a gentity, but the MP-compatible access restrictions are based
00336 //on the bgEntity structure in the MP codebase) -rww
00337 // ProcessOrientCommands the Vehicle.
00338 static void ProcessOrientCommands( Vehicle_t *pVeh )
00339 {
00340         /********************************************************************************/
00341         /*      BEGIN   Here is where make sure the vehicle is properly oriented.       BEGIN   */
00342         /********************************************************************************/
00343         bgEntity_t *parent = pVeh->m_pParentEntity;
00344         playerState_t *parentPS, *riderPS;
00345         
00346 #ifdef _JK2MP
00347         bgEntity_t *rider = NULL;
00348         if (parent->s.owner != ENTITYNUM_NONE)
00349         {
00350                 rider = PM_BGEntForNum(parent->s.owner); //&g_entities[parent->r.ownerNum];
00351         }
00352 #else
00353         gentity_t *rider = parent->owner;
00354 #endif
00355 
00356         // Bucking so we can't do anything.
00357 #ifndef _JK2MP //bad for prediction - fixme
00358         if ( pVeh->m_ulFlags & VEH_BUCKING || pVeh->m_ulFlags & VEH_FLYING || pVeh->m_ulFlags & VEH_CRASHING )
00359         {
00360                 return;
00361         }
00362 #endif
00363 
00364 #ifdef _JK2MP
00365         if ( !rider )
00366 #else
00367         if ( !rider || !rider->client )
00368 #endif
00369         {
00370                 rider = parent;
00371         }
00372 
00373 
00374 
00375 #ifdef _JK2MP
00376         parentPS = parent->playerState;
00377         riderPS = rider->playerState;
00378 #else
00379         parentPS = &parent->client->ps;
00380         riderPS = &rider->client->ps;
00381 #endif
00382 
00383         if (rider)
00384         {
00385 #ifdef _JK2MP
00386         float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
00387         if (parentPS && parentPS->speed)
00388         {
00389                 float s = parentPS->speed;
00390                 float maxDif = pVeh->m_pVehicleInfo->turningSpeed*4.0f; //magic number hackery
00391                 if (s < 0.0f)
00392                 {
00393                         s = -s;
00394                 }
00395                 angDif *= s/pVeh->m_pVehicleInfo->speedMax;
00396                 if (angDif > maxDif)
00397                 {
00398                         angDif = maxDif;
00399                 }
00400                 else if (angDif < -maxDif)
00401                 {
00402                         angDif = -maxDif;
00403                 }
00404                 pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));
00405         }
00406 #else
00407                 pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
00408 #endif
00409         }
00410 
00411 
00412 /*      speed = VectorLength( parentPS->velocity );
00413 
00414         // If the player is the rider...
00415         if ( rider->s.number < MAX_CLIENTS )
00416         {//FIXME: use the vehicle's turning stat in this calc
00417                 pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
00418         }
00419         else
00420         {
00421                 float turnSpeed = pVeh->m_pVehicleInfo->turningSpeed;
00422                 if ( !pVeh->m_pVehicleInfo->turnWhenStopped 
00423                         && !parentPS->speed )//FIXME: or !pVeh->m_ucmd.forwardmove?
00424                 {//can't turn when not moving
00425                         //FIXME: or ramp up to max turnSpeed?
00426                         turnSpeed = 0.0f;
00427                 }
00428 #ifdef _JK2MP
00429                 if (rider->s.eType == ET_NPC)
00430 #else
00431                 if ( !rider || rider->NPC )
00432 #endif
00433                 {//help NPCs out some
00434                         turnSpeed *= 2.0f;
00435 #ifdef _JK2MP
00436                         if (parentPS->speed > 200.0f)
00437 #else
00438                         if ( parent->client->ps.speed > 200.0f )
00439 #endif
00440                         {
00441                                 turnSpeed += turnSpeed * parentPS->speed/200.0f*0.05f;
00442                         }
00443                 }
00444                 turnSpeed *= pVeh->m_fTimeModifier;
00445 
00446                 //default control scheme: strafing turns, mouselook aims
00447                 if ( pVeh->m_ucmd.rightmove < 0 )
00448                 {
00449                         pVeh->m_vOrientation[YAW] += turnSpeed;
00450                 }
00451                 else if ( pVeh->m_ucmd.rightmove > 0 )
00452                 {
00453                         pVeh->m_vOrientation[YAW] -= turnSpeed;
00454                 }
00455 
00456                 if ( pVeh->m_pVehicleInfo->malfunctionArmorLevel && pVeh->m_iArmor <= pVeh->m_pVehicleInfo->malfunctionArmorLevel )
00457                 {//damaged badly
00458                 }
00459         }*/
00460 
00461         /********************************************************************************/
00462         /*      END     Here is where make sure the vehicle is properly oriented.       END                     */
00463         /********************************************************************************/
00464 }
00465 
00466 #ifdef _JK2MP //temp hack til mp speeder controls are sorted -rww
00467 void AnimalProcessOri(Vehicle_t *pVeh)
00468 {
00469         ProcessOrientCommands(pVeh);
00470 }
00471 #endif
00472 
00473 #ifdef QAGAME //back to our game-only functions
00474 static void AnimateVehicle( Vehicle_t *pVeh )
00475 {
00476         animNumber_t    Anim = BOTH_VT_IDLE; 
00477         int                             iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
00478         gentity_t *             pilot = (gentity_t *)pVeh->m_pPilot;
00479         gentity_t *             parent = (gentity_t *)pVeh->m_pParentEntity;
00480         playerState_t * pilotPS;
00481         playerState_t * parentPS;
00482         float                   fSpeedPercToMax;
00483 
00484 #ifdef _JK2MP
00485         pilotPS = (pilot)?(pilot->playerState):(0);
00486         parentPS = parent->playerState;
00487 #else
00488         pilotPS = (pilot)?(&pilot->client->ps):(0);
00489         parentPS = &parent->client->ps;
00490 #endif
00491 
00492         // We're dead (boarding is reused here so I don't have to make another variable :-).
00493         if ( parent->health <= 0 ) 
00494         {
00495                 /*
00496                 if ( pVeh->m_iBoarding != -999 )        // Animate the death just once!
00497                 {
00498                         pVeh->m_iBoarding = -999;
00499                         iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD; 
00500 
00501                         // FIXME! Why do you keep repeating over and over!!?!?!? Bastard!
00502                         //Vehicle_SetAnim( parent, SETANIM_LEGS, BOTH_VT_DEATH1, iFlags, iBlend );
00503                 }
00504                 */
00505                 return;
00506         }
00507 
00508         // If they're bucking, play the animation and leave...
00509         if ( parent->client->ps.legsAnim == BOTH_VT_BUCK )
00510         {
00511                 // Done with animation? Erase the flag.
00512                 if ( parent->client->ps.legsAnimTimer <= 0 )
00513                 {
00514                         pVeh->m_ulFlags &= ~VEH_BUCKING;
00515                 }
00516                 else
00517                 {
00518                         return;
00519                 }
00520         }
00521         else if ( pVeh->m_ulFlags & VEH_BUCKING )
00522         {
00523                 iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
00524                 Anim = BOTH_VT_BUCK;
00525                 iBlend = 500;
00526                 Vehicle_SetAnim( parent, SETANIM_LEGS, BOTH_VT_BUCK, iFlags, iBlend );
00527                 return;
00528         }
00529 
00530         // Boarding animation.
00531         if ( pVeh->m_iBoarding != 0 )
00532         {
00533                 // We've just started boarding, set the amount of time it will take to finish boarding.
00534                 if ( pVeh->m_iBoarding < 0 )
00535                 {
00536                         int iAnimLen;
00537 
00538                         // Boarding from left...
00539                         if ( pVeh->m_iBoarding == -1 )
00540                         {
00541                                 Anim = BOTH_VT_MOUNT_L;
00542                         }
00543                         else if ( pVeh->m_iBoarding == -2 )
00544                         {
00545                                 Anim = BOTH_VT_MOUNT_R;
00546                         }
00547                         else if ( pVeh->m_iBoarding == -3 )
00548                         {
00549                                 Anim = BOTH_VT_MOUNT_B;
00550                         }
00551 
00552                         // Set the delay time (which happens to be the time it takes for the animation to complete).
00553                         // NOTE: Here I made it so the delay is actually 70% (0.7f) of the animation time.
00554 #ifdef _JK2MP
00555                         iAnimLen = BG_AnimLength( parent->localAnimIndex, Anim ) * 0.7f;
00556 #else
00557                         iAnimLen = PM_AnimLength( parent->client->clientInfo.animFileIndex, Anim ) * 0.7f;
00558 #endif
00559                         pVeh->m_iBoarding = level.time + iAnimLen;
00560 
00561                         // Set the animation, which won't be interrupted until it's completed.
00562                         // TODO: But what if he's killed? Should the animation remain persistant???
00563                         iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
00564 
00565                         Vehicle_SetAnim( parent, SETANIM_LEGS, Anim, iFlags, iBlend );
00566                         if (pilot)
00567                         {
00568                                 Vehicle_SetAnim(pilot, SETANIM_BOTH, Anim, iFlags, iBlend );
00569                         }
00570                         return;
00571                 }
00572                 // Otherwise we're done.
00573                 else if ( pVeh->m_iBoarding <= level.time )
00574                 {
00575                         pVeh->m_iBoarding = 0;
00576                 }
00577         }
00578 
00579         // Percentage of maximum speed relative to current speed.
00580         //float fSpeed = VectorLength( client->ps.velocity );
00581         fSpeedPercToMax = parent->client->ps.speed / pVeh->m_pVehicleInfo->speedMax; 
00582 
00583 
00584         // Going in reverse...
00585         if ( fSpeedPercToMax < -0.01f )
00586         {
00587                 Anim = BOTH_VT_WALK_REV;
00588                 iBlend = 600;
00589         }
00590         else
00591         {
00592                 bool            Turbo           = (fSpeedPercToMax>0.0f && level.time<pVeh->m_iTurboTime);
00593                 bool            Walking         = (fSpeedPercToMax>0.0f && ((pVeh->m_ucmd.buttons&BUTTON_WALKING) || fSpeedPercToMax<=0.275f));
00594                 bool            Running         = (fSpeedPercToMax>0.275f);
00595 
00596 
00597                 // Remove Crashing Flag
00598                 //----------------------
00599                 pVeh->m_ulFlags &= ~VEH_CRASHING;
00600 
00601                 if (Turbo)
00602                 {// Kicked In Turbo
00603                         iBlend  = 50;
00604                         iFlags  = SETANIM_FLAG_OVERRIDE;
00605                         Anim    = BOTH_VT_TURBO;
00606                 }
00607                 else
00608                 {// No Special Moves
00609                         iBlend  = 300;
00610                         iFlags  = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
00611                         Anim    = (Walking)?(BOTH_VT_WALK_FWD  ):((Running)?(BOTH_VT_RUN_FWD  ):(BOTH_VT_IDLE1));
00612                 }
00613         }
00614         Vehicle_SetAnim( parent, SETANIM_LEGS, Anim, iFlags, iBlend );
00615 }
00616 
00617 //rwwFIXMEFIXME: This is all going to have to be predicted I think, or it will feel awful
00618 //and lagged
00619 // This function makes sure that the rider's in this vehicle are properly animated.
00620 static void AnimateRiders( Vehicle_t *pVeh )
00621 {
00622         animNumber_t Anim = BOTH_VT_IDLE;
00623         int iFlags = SETANIM_FLAG_NORMAL, iBlend = 500;
00624         gentity_t *pilot = (gentity_t *)pVeh->m_pPilot;
00625         gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
00626         playerState_t *pilotPS;
00627         playerState_t *parentPS;
00628         float fSpeedPercToMax;
00629 
00630 #ifdef _JK2MP
00631         pilotPS = pVeh->m_pPilot->playerState;
00632         parentPS = pVeh->m_pPilot->playerState;
00633 #else
00634         pilotPS = &pVeh->m_pPilot->client->ps;
00635         parentPS = &pVeh->m_pParentEntity->client->ps;
00636 #endif
00637 
00638         // Boarding animation.
00639         if ( pVeh->m_iBoarding != 0 )
00640         {
00641                 return;
00642         }
00643 
00644         // Percentage of maximum speed relative to current speed.
00645         fSpeedPercToMax = parent->client->ps.speed / pVeh->m_pVehicleInfo->speedMax;
00646 
00647         // Going in reverse...
00648 #ifdef _JK2MP //handled in pmove in mp
00649         if (0)
00650 #else
00651         if ( fSpeedPercToMax < -0.01f )
00652 #endif
00653         {
00654                 Anim = BOTH_VT_WALK_REV;
00655                 iBlend = 600;
00656         }
00657         else
00658         {
00659                 bool            HasWeapon       = ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE));
00660                 bool            Attacking       = (HasWeapon && !!(pVeh->m_ucmd.buttons&BUTTON_ATTACK));
00661                 bool            Right           = (pVeh->m_ucmd.rightmove>0);
00662                 bool            Left            = (pVeh->m_ucmd.rightmove<0);
00663                 bool            Turbo           = (fSpeedPercToMax>0.0f && level.time<pVeh->m_iTurboTime);
00664                 bool            Walking         = (fSpeedPercToMax>0.0f && ((pVeh->m_ucmd.buttons&BUTTON_WALKING) || fSpeedPercToMax<=0.275f));
00665                 bool            Running         = (fSpeedPercToMax>0.275f);
00666                 EWeaponPose     WeaponPose      = WPOSE_NONE;
00667 
00668 
00669                 // Remove Crashing Flag
00670                 //----------------------
00671                 pVeh->m_ulFlags &= ~VEH_CRASHING;
00672 
00673 
00674                 // Put Away Saber When It Is Not Active
00675                 //--------------------------------------
00676 #ifndef _JK2MP
00677                 if (HasWeapon && (Turbo || (pilotPS->weapon==WP_SABER && !pilotPS->SaberActive())))
00678                 {
00679                         if (pVeh->m_pPilot->s.number<MAX_CLIENTS)
00680                         {
00681                                 CG_ChangeWeapon(WP_NONE);
00682                         }
00683 
00684                         pVeh->m_pPilot->client->ps.weapon = WP_NONE;
00685                         G_RemoveWeaponModels(pVeh->m_pPilot);
00686                 }
00687 #endif
00688 
00689                 // Don't Interrupt Attack Anims
00690                 //------------------------------
00691 #ifdef _JK2MP
00692                 if (pilotPS->weaponTime>0)
00693                 {
00694                         return;
00695                 }
00696 #else           
00697                 if (pilotPS->torsoAnim>=BOTH_VT_ATL_S && pilotPS->torsoAnim<=BOTH_VT_ATF_G)
00698                 {
00699                         float           bodyCurrent       = 0.0f;
00700                         int                     bodyEnd           = 0;
00701                         if (!!gi.G2API_GetBoneAnimIndex(&pVeh->m_pPilot->ghoul2[pVeh->m_pPilot->playerModel], pVeh->m_pPilot->rootBone, level.time, &bodyCurrent, NULL, &bodyEnd, NULL, NULL, NULL))
00702                         {
00703                                 if (bodyCurrent<=((float)(bodyEnd)-1.5f))
00704                                 {
00705                                         return;
00706                                 }
00707                         }
00708                 }
00709 #endif
00710 
00711                 // Compute The Weapon Pose
00712                 //--------------------------
00713                 if (pilotPS->weapon==WP_BLASTER)
00714                 {
00715                         WeaponPose = WPOSE_BLASTER;
00716                 }
00717                 else if (pilotPS->weapon==WP_SABER)
00718                 {
00719                         if ( (pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VT_ATL_TO_R_S)
00720                         {
00721                                 pVeh->m_ulFlags &= ~VEH_SABERINLEFTHAND;
00722                         }
00723                         if (!(pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VT_ATR_TO_L_S)
00724                         {
00725                                 pVeh->m_ulFlags |=  VEH_SABERINLEFTHAND;
00726                         }
00727                         WeaponPose = (pVeh->m_ulFlags&VEH_SABERINLEFTHAND)?(WPOSE_SABERLEFT):(WPOSE_SABERRIGHT);
00728                 }
00729                 
00730 
00731                 if (Attacking && WeaponPose)
00732                 {// Attack!
00733                         iBlend  = 100;
00734                         iFlags  = SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART;
00735 
00736                         if (Turbo)
00737                         {
00738                                 Right = true;
00739                                 Left = false;
00740                         }
00741 
00742                         // Auto Aiming
00743                         //===============================================
00744                         if (!Left && !Right)            // Allow player strafe keys to override
00745                         {
00746 #ifndef _JK2MP
00747                                 if (pVeh->m_pPilot->enemy)
00748                                 {
00749                                         vec3_t  toEnemy;
00750                                         float   toEnemyDistance;
00751                                         vec3_t  actorRight;
00752                                         float   actorRightDot;
00753 
00754                                         VectorSubtract(pVeh->m_pPilot->currentOrigin, pVeh->m_pPilot->enemy->currentOrigin, toEnemy);
00755                                         toEnemyDistance = VectorNormalize(toEnemy);
00756 
00757                                         AngleVectors(pVeh->m_pParentEntity->currentAngles, 0, actorRight, 0);
00758                                         actorRightDot = DotProduct(toEnemy, actorRight);
00759 
00760                                         if (fabsf(actorRightDot)>0.5f || pilotPS->weapon==WP_SABER)
00761                                         {
00762                                                 Left    = (actorRightDot>0.0f);
00763                                                 Right   = !Left;
00764                                         }
00765                                         else
00766                                         {
00767                                                 Right = Left = false;
00768                                         }
00769                                 }
00770                                 else
00771 #endif
00772                                 if (pilotPS->weapon==WP_SABER && !Left && !Right)
00773                                 {
00774                                         Left = (WeaponPose==WPOSE_SABERLEFT);
00775                                         Right   = !Left;
00776                                 }
00777                         }
00778 
00779 
00780                         if (Left)
00781                         {// Attack Left
00782                                 switch(WeaponPose)
00783                                 {
00784                                 case WPOSE_BLASTER:             Anim = BOTH_VT_ATL_G;           break;
00785                                 case WPOSE_SABERLEFT:   Anim = BOTH_VT_ATL_S;           break;
00786                                 case WPOSE_SABERRIGHT:  Anim = BOTH_VT_ATR_TO_L_S;      break;
00787                                 default:                                assert(0);
00788                                 }
00789                         }
00790                         else if (Right)
00791                         {// Attack Right
00792                                 switch(WeaponPose)
00793                                 {
00794                                 case WPOSE_BLASTER:             Anim = BOTH_VT_ATR_G;           break;
00795                                 case WPOSE_SABERLEFT:   Anim = BOTH_VT_ATL_TO_R_S;      break;
00796                                 case WPOSE_SABERRIGHT:  Anim = BOTH_VT_ATR_S;           break;
00797                                 default:                                assert(0);
00798                                 }
00799                         }
00800                         else
00801                         {// Attack Ahead
00802                                 switch(WeaponPose)
00803                                 {
00804                                 case WPOSE_BLASTER:             Anim = BOTH_VT_ATF_G;           break;
00805                                 default:                                assert(0);
00806                                 }
00807                         }
00808                 }
00809                 else if (Turbo)
00810                 {// Kicked In Turbo
00811                         iBlend  = 50;
00812                         iFlags  = SETANIM_FLAG_OVERRIDE;
00813                         Anim    = BOTH_VT_TURBO;
00814                 }
00815                 else
00816                 {// No Special Moves
00817                         iBlend  = 300;
00818                         iFlags  = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
00819 
00820                         if (WeaponPose==WPOSE_NONE)
00821                         {
00822                                 if (Walking)
00823                                 {
00824                                         Anim = BOTH_VT_WALK_FWD;
00825                                 }
00826                                 else if (Running)
00827                                 {
00828                                         Anim = BOTH_VT_RUN_FWD;
00829                                 }
00830                                 else
00831                                 {
00832                                         Anim = BOTH_VT_IDLE1;//(Q_irand(0,1)==0)?(BOTH_VT_IDLE):(BOTH_VT_IDLE1);
00833                                 }
00834                         }
00835                         else
00836                         {
00837                                 switch(WeaponPose)
00838                                 {
00839                                 case WPOSE_BLASTER:             Anim = BOTH_VT_IDLE_G;                  break;
00840                                 case WPOSE_SABERLEFT:   Anim = BOTH_VT_IDLE_SL;                 break;
00841                                 case WPOSE_SABERRIGHT:  Anim = BOTH_VT_IDLE_SR;                 break;
00842                                 default:                                assert(0);
00843                                 }
00844                         }
00845                 }// No Special Moves
00846         }
00847 
00848         Vehicle_SetAnim( pilot, SETANIM_BOTH, Anim, iFlags, iBlend );
00849 }
00850 #endif //QAGAME
00851 
00852 #ifndef QAGAME
00853 void AttachRidersGeneric( Vehicle_t *pVeh );
00854 #endif
00855 
00856 //on the client this function will only set up the process command funcs
00857 void G_SetAnimalVehicleFunctions( vehicleInfo_t *pVehInfo )
00858 {
00859 #ifdef QAGAME
00860         pVehInfo->AnimateVehicle                        =               AnimateVehicle;
00861         pVehInfo->AnimateRiders                         =               AnimateRiders;
00862 //      pVehInfo->ValidateBoard                         =               ValidateBoard;
00863 //      pVehInfo->SetParent                                     =               SetParent;
00864 //      pVehInfo->SetPilot                                      =               SetPilot;
00865 //      pVehInfo->AddPassenger                          =               AddPassenger;
00866 //      pVehInfo->Animate                                       =               Animate;
00867 //      pVehInfo->Board                                         =               Board;
00868 //      pVehInfo->Eject                                         =               Eject;
00869 //      pVehInfo->EjectAll                                      =               EjectAll;
00870 //      pVehInfo->StartDeathDelay                       =               StartDeathDelay;
00871         pVehInfo->DeathUpdate                           =               DeathUpdate;
00872 //      pVehInfo->RegisterAssets                        =               RegisterAssets;
00873 //      pVehInfo->Initialize                            =               Initialize;
00874         pVehInfo->Update                                        =               Update;
00875 //      pVehInfo->UpdateRider                           =               UpdateRider;
00876 #endif //QAGAME
00877         pVehInfo->ProcessMoveCommands           =               ProcessMoveCommands;
00878         pVehInfo->ProcessOrientCommands         =               ProcessOrientCommands;
00879 
00880 #ifndef QAGAME //cgame prediction attachment func
00881         pVehInfo->AttachRiders                          =               AttachRidersGeneric;
00882 #endif
00883 //      pVehInfo->AttachRiders                          =               AttachRiders;
00884 //      pVehInfo->Ghost                                         =               Ghost;
00885 //      pVehInfo->UnGhost                                       =               UnGhost;
00886 //      pVehInfo->Inhabited                                     =               Inhabited;
00887 }
00888 
00889 // Following is only in game, not in namespace
00890 #ifdef _JK2MP
00891 #include "../namespace_end.h"
00892 #endif
00893 
00894 #ifdef QAGAME
00895 extern void G_AllocateVehicleObject(Vehicle_t **pVeh);
00896 #endif
00897 
00898 #ifdef _JK2MP
00899 #include "../namespace_begin.h"
00900 #endif
00901 
00902 // Create/Allocate a new Animal Vehicle (initializing it as well).
00903 //this is a BG function too in MP so don't un-bg-compatibilify it -rww
00904 void G_CreateAnimalNPC( Vehicle_t **pVeh, const char *strAnimalType )
00905 {
00906         // Allocate the Vehicle.
00907 #ifdef _JK2MP
00908 #ifdef QAGAME
00909         //these will remain on entities on the client once allocated because the pointer is
00910         //never stomped. on the server, however, when an ent is freed, the entity struct is
00911         //memset to 0, so this memory would be lost..
00912     G_AllocateVehicleObject(pVeh);
00913 #else
00914         if (!*pVeh)
00915         { //only allocate a new one if we really have to
00916                 (*pVeh) = (Vehicle_t *) BG_Alloc( sizeof(Vehicle_t) );
00917         }
00918 #endif
00919         memset(*pVeh, 0, sizeof(Vehicle_t));
00920         (*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strAnimalType )];
00921 #else
00922         (*pVeh) = (Vehicle_t *) gi.Malloc( sizeof(Vehicle_t), TAG_G_ALLOC, qtrue );
00923         (*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strAnimalType )];
00924 #endif
00925 }
00926 
00927 #ifdef _JK2MP
00928 
00929 #include "../namespace_end.h"
00930 
00931 //get rid of all the crazy defs we added for this file
00932 #undef currentAngles
00933 #undef currentOrigin
00934 #undef mins
00935 #undef maxs
00936 #undef legsAnimTimer
00937 #undef torsoAnimTimer
00938 #undef bool
00939 #undef false
00940 #undef true
00941 
00942 #undef sqrtf
00943 #undef Q_flrand
00944 
00945 #undef MOD_EXPLOSIVE
00946 #endif